/* =====================================================================
   Material Pricer app.css
   Gottify DNA on night #0b0e14. Signature motif: "Conduit Run" (a night
   warehouse aisle) painted by #pfx + pricer-fx.js.
   Mac-feel chrome: 16px radii, diffuse shadows, backdrop blur, one cream
   CTA, one refined sans, muted palette, semantic colour only for state.
   Self-contained: no CDN, no webfont fetch, no build step.
   ===================================================================== */

*{box-sizing:border-box;margin:0;padding:0}

/* The [hidden] attribute is how this app toggles the cancel button, the
   settings sheet, the results panel and the demo banner. Any rule that
   sets an explicit display (.btn is inline-flex) would otherwise beat the
   UA [hidden] rule and leak the element onto the page. Assert it once. */
[hidden]{display:none !important}

:root{
  --night:#0b0e14; --bg2:#0f141c; --panel:#161d27; --panel2:#1c2532;
  --line:#242d39; --line2:#2a333f; --steel:#3a4654;
  --ink:#eef1f5; --body:#cfd5dd; --mut:#9aa4b2; --mist:#7c8a9c;
  --teal:#45d8c0; --cyan:#0090c0; --cream:#fef3da;
  --ok:#5dcaa5; --warn:#ffb257; --bad:#e8756b;
  --r-card:18px; --r-ctl:14px; --r-pill:999px;
  --shadow:0 10px 28px rgba(0,0,0,.28);
  --shadow-lift:0 16px 44px rgba(0,0,0,.34);
  --ease:cubic-bezier(.2,.8,.2,1);
  --sans:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Inter,
         "Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
}

html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--sans);
  background:var(--night);
  color:var(--body);
  font-size:15.5px;line-height:1.6;
  -webkit-font-smoothing:antialiased;
  min-height:100vh;
}
a{color:inherit}
:focus-visible{outline:2px solid var(--cream);outline-offset:3px;border-radius:8px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.wrap{max-width:1180px;margin:0 auto;padding:0 26px}

/* ── SIGNATURE BACKGROUND: Conduit Run ───────────────────────────────
   Fixed stack behind everything: a CSS floor gradient, two additive
   blooms whose opacity rides --run (idle to working), the canvas that
   draws the conduit rails and the pick lights, and a veil that keeps
   text above AA over the brightest band. */
#pfx{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;background:var(--night)}
#pfx > *{position:absolute;inset:0}
:root{--run:0}

.pfx-floor{
  background:
    linear-gradient(180deg,#080b11 0%,#0b0e14 32%,#0d1620 62%,#0a1119 84%,#080a0f 100%);
}
/* Cool aisle light. Always on, lifts a little while a batch runs. */
.pfx-bloom-cool{
  opacity:calc(.30 + var(--run) * .34);
  background:radial-gradient(120% 58% at 50% 78%,
    rgba(69,216,192,.30) 0%, rgba(0,144,192,.22) 30%, rgba(0,80,140,.10) 52%, transparent 74%);
  mix-blend-mode:screen;
  transition:opacity .9s var(--ease);
}
/* Warm resolve. Only meaningful once results land. */
.pfx-bloom-warm{
  opacity:calc(var(--settled,0) * .30);
  background:radial-gradient(130% 64% at 50% 86%,
    rgba(255,226,172,.36) 0%, rgba(255,182,104,.20) 26%, transparent 62%);
  mix-blend-mode:screen;
  transition:opacity 1.4s var(--ease);
}
#pfxCanvas{width:100%;height:100%;display:block}
.pfx-veil{
  background:linear-gradient(180deg,
    rgba(6,9,14,.72) 0%, rgba(6,9,14,.34) 16%,
    rgba(6,9,14,.20) 44%, rgba(6,9,14,.34) 78%, rgba(6,9,14,.66) 100%);
}
body > header,body > main,body > footer,body > .sheet{position:relative;z-index:1}

/* ── TOP BAR ─────────────────────────────────────────────────────── */
.topbar{
  position:sticky;top:0;z-index:40;
  background:rgba(11,14,20,.72);
  backdrop-filter:blur(16px) saturate(140%);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  border-bottom:1px solid var(--line);
}
.bar{display:flex;align-items:center;gap:18px;height:70px}
.brand{display:flex;align-items:center;gap:12px;margin-right:auto}
.mark{width:38px;height:38px;border-radius:11px;object-fit:cover;flex:none;
  box-shadow:0 4px 14px rgba(0,0,0,.4)}
.bname{display:flex;flex-direction:column;line-height:1.15;font-weight:650;
  font-size:15.5px;color:var(--ink);letter-spacing:-.01em}
.bname i{font-style:normal;font-size:11px;font-weight:600;color:var(--mist);
  letter-spacing:.16em;text-transform:uppercase}
.barright{display:flex;align-items:center;gap:10px}

.chip{display:inline-flex;align-items:center;gap:8px;border-radius:var(--r-pill);
  padding:7px 14px;font-size:12.5px;font-weight:600;color:var(--mut);
  background:rgba(28,37,50,.62);border:1px solid var(--line2)}
.dot{width:7px;height:7px;border-radius:50%;background:var(--warn);flex:none}
.chip.live .dot{background:var(--ok)}
.chip.live{color:var(--ink)}

/* ── BUTTONS ─────────────────────────────────────────────────────── */
.btn{font-family:inherit;font-size:14.5px;font-weight:650;cursor:pointer;border:none;
  border-radius:var(--r-ctl);padding:12px 22px;display:inline-flex;align-items:center;
  justify-content:center;gap:8px;transition:transform .18s var(--ease),
  box-shadow .18s var(--ease),background .18s var(--ease),opacity .18s var(--ease)}
.btn.sm{padding:9px 15px;font-size:13px;border-radius:12px}
.btn:hover{transform:translateY(-1px)}
.btn:active{transform:scale(.97)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none}
.btn-cream{background:var(--cream);color:#161d27;box-shadow:0 6px 20px rgba(254,243,218,.14)}
.btn-cream:hover{box-shadow:0 10px 26px rgba(254,243,218,.2)}
.btn-ghost{background:rgba(28,37,50,.55);color:var(--ink);border:1px solid var(--line2)}
.btn-ghost:hover{background:rgba(34,45,60,.75)}

/* ── SETTINGS SHEET ──────────────────────────────────────────────── */
.sheet{
  overflow:hidden;border-bottom:1px solid var(--line);
  background:rgba(15,20,28,.86);
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  animation:sheetIn .26s var(--ease);
}
@keyframes sheetIn{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:none}}
.sheetin{display:grid;grid-template-columns:1fr 1fr;gap:18px 24px;padding:22px 26px}
.field label{display:block;font-size:12.5px;font-weight:650;color:var(--mut);margin-bottom:7px}
input[type=text],textarea{
  width:100%;font-family:var(--sans);font-size:14.5px;color:var(--ink);
  background:rgba(11,14,20,.6);border:1px solid var(--line2);border-radius:var(--r-ctl);
  padding:12px 14px;transition:border-color .18s var(--ease),background .18s var(--ease);
}
input[type=text]{font-family:var(--mono);letter-spacing:.02em}
input[type=text]:focus,textarea:focus{outline:none;border-color:var(--steel);background:rgba(11,14,20,.85)}
input::placeholder,textarea::placeholder{color:#5d6b7c}
.hint{font-size:12.5px;color:var(--mist);margin-top:7px}
.sheetfoot{grid-column:1/-1;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.sheetfoot .hint{margin:0}
@media(max-width:760px){.sheetin{grid-template-columns:1fr}}

/* ── PANELS ──────────────────────────────────────────────────────── */
main{padding:30px 0 60px}
.panel{
  position:relative;background:rgba(22,29,39,.82);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border:1px solid var(--line);border-radius:var(--r-card);
  box-shadow:var(--shadow);margin-bottom:22px;overflow:hidden;
  /* clears the 70px sticky bar when results scroll themselves into view,
     so the demo banner is never parked underneath it */
  scroll-margin-top:88px;
}
.hero .heroin{position:relative;padding:34px 34px 30px}
.heroplate{
  position:absolute;inset:0;pointer-events:none;
  background-image:url("assets/hero-pricer-materials.jpg");
  background-size:cover;background-position:center 32%;
  opacity:.14;
}
.hero::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(22,29,39,.42) 0%,rgba(22,29,39,.88) 46%,rgba(22,29,39,.97) 100%);
}
.hero .heroin{z-index:1}
@media(max-width:640px){.hero .heroin{padding:26px 20px 24px}}

.eyebrow{display:flex;align-items:center;gap:10px;font-size:11.5px;font-weight:700;
  letter-spacing:.15em;text-transform:uppercase;color:var(--mist);margin-bottom:12px}
.eyebrow::before{content:"";width:20px;height:2px;background:var(--teal);border-radius:2px;opacity:.8}
h1{font-size:clamp(28px,4vw,40px);font-weight:640;line-height:1.08;letter-spacing:-.022em;
  color:var(--ink);margin-bottom:12px;text-wrap:balance}
h2{font-size:clamp(20px,2.4vw,25px);font-weight:640;letter-spacing:-.015em;color:var(--ink);line-height:1.2}
.lead{font-size:16px;color:var(--body);max-width:660px}

/* ── EDITOR ──────────────────────────────────────────────────────── */
.editor{margin-top:24px}
textarea{
  min-height:190px;resize:vertical;line-height:1.7;
  font-family:var(--mono);font-size:13.5px;letter-spacing:.01em;
  border-radius:var(--r-card);padding:16px 18px;
}
.editorbar{display:flex;align-items:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.editorbar .spacer{flex:1}
.count{font-size:13px;color:var(--mut);font-variant-numeric:tabular-nums}
.count b{color:var(--ink);font-weight:650}
.count.over{color:var(--bad)}

.preview{margin-top:16px;border:1px solid var(--line);border-radius:var(--r-ctl);
  background:rgba(11,14,20,.42)}
.preview summary{cursor:pointer;padding:12px 16px;font-size:13.5px;font-weight:600;color:var(--mut)}
.preview summary:hover{color:var(--ink)}
.preview[open] summary{border-bottom:1px solid var(--line)}
.preview .tscroll{max-height:280px}

.runrow{display:flex;align-items:center;gap:14px;margin-top:22px;flex-wrap:wrap}
.runnote{font-size:13px;color:var(--mist);flex:1;min-width:220px}

/* Progress: no fake percentage. The bar is an indeterminate sweep, the
   text carries the real elapsed clock and a clearly labelled estimate. */
.progress{margin-top:18px}
.pline{height:3px;border-radius:3px;background:rgba(58,70,84,.4);overflow:hidden}
.pline i{display:block;height:100%;width:34%;border-radius:3px;
  background:linear-gradient(90deg,transparent,var(--cyan),var(--teal),transparent);
  animation:sweep 1.6s var(--ease) infinite}
@keyframes sweep{0%{transform:translateX(-110%)}100%{transform:translateX(320%)}}
.pstat{margin-top:10px;font-size:13.5px;color:var(--mut);font-variant-numeric:tabular-nums}
.pstat b{color:var(--ink);font-weight:650}

.alert{display:block;margin-top:18px;padding:14px 16px;border-radius:var(--r-ctl);
  font-size:14px;color:var(--ink);background:rgba(232,117,107,.1);
  border:1px solid rgba(232,117,107,.34)}
.alert b{display:block;font-weight:650;margin-bottom:3px}
.alert.warn{background:rgba(255,178,87,.1);border-color:rgba(255,178,87,.34)}
.alert[hidden]{display:none}

/* ── RESULTS ─────────────────────────────────────────────────────── */
.results{padding:26px 30px 22px}
@media(max-width:640px){.results{padding:20px 16px 16px}}

.demobanner{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding:13px 16px;margin-bottom:20px;border-radius:var(--r-ctl);
  background:rgba(255,178,87,.09);border:1px solid rgba(255,178,87,.36);
}
.demobanner strong{font-size:11.5px;font-weight:800;letter-spacing:.16em;color:var(--warn);flex:none}
.demobanner span{font-size:13.5px;color:var(--body)}
.demobanner[hidden]{display:none}

.rhead{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap}
.stats{display:flex;gap:10px;flex-wrap:wrap;margin:18px 0 16px}
.stat{background:rgba(11,14,20,.52);border:1px solid var(--line);border-radius:var(--r-ctl);
  padding:12px 16px;min-width:118px}
.stat .k{display:block;font-size:11px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:var(--mist);margin-bottom:5px}
.stat .v{font-size:19px;font-weight:650;color:var(--ink);font-variant-numeric:tabular-nums;
  letter-spacing:-.01em}
.stat.accent .v{color:var(--cream)}
.stat.flagged .v{color:var(--warn)}

/* ── TABLE ───────────────────────────────────────────────────────── */
.tscroll{overflow:auto;border:1px solid var(--line);border-radius:var(--r-ctl);
  background:rgba(11,14,20,.35)}
.tbl{width:100%;border-collapse:collapse;font-size:13.5px;min-width:880px}
.tbl.slim{min-width:600px;font-size:13px}
.tbl th,.tbl td{text-align:left;padding:11px 14px;border-bottom:1px solid var(--line);
  vertical-align:top}
.tbl thead th{position:sticky;top:0;z-index:2;background:#131a24;
  font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--mist);white-space:nowrap;padding:0}
.tbl thead th:not(.sortable){padding:11px 14px}
.tbl thead th.sortable button{
  width:100%;background:none;border:none;cursor:pointer;font:inherit;color:inherit;
  letter-spacing:inherit;text-transform:inherit;text-align:left;padding:11px 14px;
}
.tbl thead th.sortable button:hover{color:var(--ink)}
.tbl thead th.num,.tbl thead th.num button{text-align:right}
.tbl thead th[aria-sort] button{color:var(--teal)}
.tbl thead th[aria-sort] button::after{content:" \2191";font-size:10px}
.tbl thead th[aria-sort=descending] button::after{content:" \2193"}
.tbl tbody tr:last-child td{border-bottom:none}
.tbl tbody tr:hover{background:rgba(28,37,50,.4)}
.tbl td.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.pn{font-family:var(--mono);font-size:12.5px;color:var(--ink);white-space:nowrap}
.title{color:var(--body);max-width:300px}
.muted{color:var(--mist)}
.price{font-weight:650;color:var(--ink);font-size:14px}
.notes{color:var(--mist);font-size:12.5px;max-width:220px}
.olink{color:var(--teal);font-size:12.5px;white-space:nowrap}
.olink:hover{color:var(--cream)}

/* Row states */
tr.best td{background:rgba(69,216,192,.075)}
tr.best td:first-child{box-shadow:inset 3px 0 0 var(--teal)}
tr.flag td{background:rgba(255,178,87,.055)}
tr.flag td:first-child{box-shadow:inset 3px 0 0 rgba(255,178,87,.7)}
tr.alt td{background:rgba(11,14,20,.55);font-size:12.5px}
tr.alt td:first-child{padding-left:30px;color:var(--mist)}
tbody tr.demo .price::after{content:"";}

/* Chips inside cells */
.tag{display:inline-flex;align-items:center;gap:5px;border-radius:var(--r-pill);
  padding:3px 10px;font-size:11.5px;font-weight:650;white-space:nowrap;
  background:rgba(58,70,84,.4);color:var(--mut);border:1px solid var(--line2)}
.tag.in{background:rgba(93,202,165,.14);color:var(--ok);border-color:rgba(93,202,165,.34)}
.tag.out{background:rgba(232,117,107,.13);color:var(--bad);border-color:rgba(232,117,107,.32)}
.tag.net{background:rgba(254,243,218,.12);color:var(--cream);border-color:rgba(254,243,218,.3)}
.tag.bestflag{background:rgba(69,216,192,.14);color:var(--teal);border-color:rgba(69,216,192,.34)}

/* Confidence bar */
.conf{display:flex;align-items:center;gap:9px;min-width:104px}
.confbar{flex:1;height:5px;border-radius:3px;background:rgba(58,70,84,.45);overflow:hidden}
/* Fill animates on transform, never width, so a 200-row table does not
   thrash layout. JS sets --c (0 to 1) per row. */
.confbar i{display:block;height:100%;width:100%;border-radius:3px;background:var(--teal);
  transform-origin:left center;transform:scaleX(var(--c,0));
  transition:transform .5s var(--ease)}
.conf.mid .confbar i{background:var(--warn)}
.conf.low .confbar i{background:var(--bad)}
.confnum{font-size:12px;color:var(--mut);font-variant-numeric:tabular-nums;width:26px;text-align:right}

tfoot td{border-top:1px solid var(--line2);font-weight:650;color:var(--ink);
  background:rgba(19,26,36,.8)}

.legend{display:flex;gap:20px;flex-wrap:wrap;margin-top:14px;font-size:12.5px;color:var(--mist)}
.lg{display:inline-flex;align-items:center;gap:8px}
.sw{width:14px;height:8px;border-radius:3px;flex:none;background:var(--line2)}
.sw.best{background:var(--teal)}
.sw.net{background:var(--cream)}
.sw.flag{background:var(--warn)}

/* ── FOOTER ──────────────────────────────────────────────────────── */
.foot{border-top:1px solid var(--line);padding:26px 0 40px}
.foot .wrap{display:flex;align-items:center;justify-content:space-between;gap:14px;
  flex-wrap:wrap;font-size:12.5px;color:var(--mist)}
.foot b{color:var(--body);font-weight:650}
.mist{color:var(--mist)}

/* ── ENTRANCE (choreographed, cheap, reduced-motion safe) ────────── */
.js .panel{animation:riseIn .5s var(--ease) both}
.js #resultsPanel{animation-delay:.06s}
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ── SCROLL STORYTELLING ─────────────────────────────────────────
   Results arrive as beats rather than a wall: stat tiles, then rows,
   revealed as they enter the viewport while you scroll the list.
   Usability first. The hiding class .rv is added by JS only after the
   IntersectionObserver is confirmed available, so a failed observer, a
   dead script or no-JS all leave every row plainly visible. */
@media(prefers-reduced-motion:no-preference){
  .rv{opacity:0}
  tbody tr.rv{transform:translateY(6px)}
  .stat.rv{transform:translateY(10px)}
  .rv.in{opacity:1;transform:none;
    transition:opacity .42s var(--ease),transform .42s var(--ease)}
}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important}
  .pline i{width:100%;animation:none;background:var(--cyan)}
}
