/* Flintt — web-native layout on the shared design tokens (tokens.css).
   Left sidebar shell + content column + the two page bands + cards + the docked inspector.
   There is no drawer and no scrim: overlay drawers are forbidden (DESIGN.md §1). */
*{box-sizing:border-box;margin:0}
html,body{height:100%}
body{background:var(--surface-page);color:var(--text-primary);
  font:var(--font-size-body)/var(--line-body) var(--font-sans);
  letter-spacing:var(--tracking-body);font-feature-settings:"cv11","ss01";
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
button{font:inherit;cursor:pointer}
input,select{font:inherit;color:var(--text-primary)}
::selection{background:var(--accent-soft-line)}
:is(a,button,summary,[role="button"]):focus-visible{outline:2px solid var(--focus-ring);
  outline-offset:2px;border-radius:var(--radius-sm)}
.num,.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.muted{color:var(--text-tertiary)}
.small{font-size:var(--font-size-label)}
/* ---- icons: one set, no glyphs (DESIGN.md §4) — geometry from core/icons.js, stroke
   rides currentColor, size is the only knob (20 nav · 16 buttons/inline · 14 dense rows) */
.ic{display:block;flex:none}

/* ---- app frame: fixed left sidebar + content column ------------------------------------- */
/* ONE frame, ONE width (DESIGN.md §2):
     .appframe = sidebar 220px (56px collapsed <900px) + .content
     .content  = flex:1, min-width:0 — a flex row so the inspector can dock after .page
     .page     = max-width 1440px · padding 20px 24px 80px · margin 0 auto
   Every page uses .page UNCHANGED. No page-specific max-width, no per-tab padding: tabs of
   the same page (BOM / Settings) are the same width, always. A width that changes when you
   switch tabs is a bug, not a style — do not add a `.page:has(...)` override here. */
.appframe{display:flex;min-height:100vh;align-items:stretch}
.sidebar{position:sticky;top:0;height:100vh;width:220px;flex:none;display:flex;flex-direction:column;
  background:var(--surface-side);border-right:1px solid var(--border);
  padding:var(--space-3) var(--space-2)}
.brand{display:flex;align-items:center;gap:9px;padding:6px 10px 12px;margin:0 2px var(--space-3);
  border-bottom:1px solid var(--border)}
.brand:hover{text-decoration:none}
.brand .mark{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:6px;background:var(--accent);color:var(--text-on-accent);
  font:var(--font-weight-selected) 12px var(--font-sans);flex:none}
.brand .mark svg{display:block}
.brand .word{font:600 13px var(--font-sans);letter-spacing:.26em;text-transform:uppercase;
  color:var(--text-primary)}
.sidenav{display:flex;flex-direction:column;gap:2px;flex:1;min-height:0;padding:0 2px}
.sidenav a{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:var(--radius-sm);
  color:var(--text-secondary);font-size:var(--font-size-label);font-weight:var(--font-weight-medium)}
.sidenav a:hover{color:var(--text-primary);background:var(--surface-raised);text-decoration:none}
.sidenav a.on{color:var(--text-primary);background:var(--accent-soft);
  box-shadow:inset 0 0 0 1px var(--accent-soft-line);font-weight:var(--font-weight-strong)}
.sidenav .glyph{width:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;
  line-height:1}
.sidefoot{flex:none;border-top:1px solid var(--border);margin:0 2px;padding:var(--space-2) 0 2px;
  display:flex;flex-direction:column;gap:4px}
.userchip{display:flex;align-items:center;gap:var(--space-2);padding:4px 10px;
  font-size:var(--font-size-label);color:var(--text-secondary);min-width:0}
.userchip .dot{width:7px;height:7px;border-radius:50%;background:var(--success);flex:none}
.userchip .email{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sidefoot .btn{justify-content:flex-start;padding-left:10px}
.navfoot{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:var(--radius-sm);
  color:var(--text-secondary);font-size:var(--font-size-label);font-weight:var(--font-weight-medium)}
.navfoot:hover{color:var(--text-primary);background:var(--surface-raised);text-decoration:none}
.navfoot.on{color:var(--text-primary);background:var(--accent-soft);
  box-shadow:inset 0 0 0 1px var(--accent-soft-line);font-weight:var(--font-weight-strong)}
.navfoot .glyph{width:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;
  line-height:1}
.sidefoot .btn .glyph{width:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;
  line-height:1}
/* Connect is the "setup" affordance: a quiet outlined pill, stronger text — not a button. */
.navsetup{color:var(--text-primary);font-weight:var(--font-weight-strong);
  box-shadow:inset 0 0 0 1px var(--accent-soft-line)}
.navsetup:hover{box-shadow:inset 0 0 0 1px var(--border-strong)}
.content{flex:1;min-width:0;display:flex;align-items:flex-start}
/* No `margin:0 auto` here: a main-axis auto margin eats the free space BEFORE flex-grow, so
   docking the 360px inspector would slide the whole page 180px left (DESIGN.md §2: "Page
   chrome never shifts horizontally when it opens"). flex-grow does the sizing instead — the
   page's left edge is pinned to the content column's, and the space past 1440px is exactly
   where the inspector docks. */
.page{flex:1 1 auto;min-width:0;max-width:1440px;margin:0;padding:20px 24px 80px}
@media (max-width:900px){
  .sidebar{width:56px;padding:var(--space-3) 6px}
  .brand{justify-content:center;padding:6px 4px 12px;margin:0 0 var(--space-3)}
  .brand .word,.sidenav .navlabel,.userchip .email,.sidefoot .signoutlabel,.navfoot .navlabel{display:none}
  .sidenav{padding:0}
  .sidenav a{justify-content:center;padding:7px 4px}
  .navfoot{justify-content:center;padding:7px 4px}
  .sidefoot{margin:0}
  .userchip{justify-content:center;padding:4px}
  .sidefoot .btn{justify-content:center;padding-left:9px}
}

/* ---- buttons / inputs ------------------------------------------------------------- */
.btn{display:inline-flex;align-items:center;gap:6px;border-radius:var(--radius-md);
  padding:7px 13px;font:var(--font-weight-strong) var(--font-size-label) var(--font-sans);
  border:1px solid transparent;transition:all var(--dur-fast) var(--ease);white-space:nowrap}
.btn.primary{background:var(--accent);color:var(--text-on-accent);border-color:var(--accent)}
.btn.primary:hover{background:var(--accent-strong)}
.btn.outline{background:var(--surface-card);color:var(--text-secondary);border-color:var(--border-strong)}
.btn.outline:hover{border-color:var(--text-tertiary);color:var(--text-primary)}
.btn.ghost{background:transparent;color:var(--text-secondary);border-color:transparent}
.btn.ghost:hover{background:var(--surface-raised);color:var(--text-primary)}
.btn.danger{color:var(--error)}
.btn.danger:hover{border-color:var(--error)}
.btn.sm{padding:4px 9px;font-size:10px}
.btn:disabled{opacity:.45;cursor:default;pointer-events:none}
/* icon + word inline (external links, row actions) — icons never appear alone where a
   word fits (DESIGN.md §4) */
.iconlink{display:inline-flex;align-items:center;gap:5px}
.input,select.input{border:1px solid var(--border-strong);border-radius:var(--radius-md);
  padding:7px 11px;background:var(--surface-card);font-size:var(--font-size-label);
  outline:none;min-width:0}
.input:focus{border-color:var(--focus-ring);box-shadow:0 0 0 2px var(--accent-soft-line)}
.input::placeholder{color:var(--text-muted)}
label.field{display:flex;flex-direction:column;gap:4px;font-size:10px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-tertiary)}
label.field .input,label.field select.input{text-transform:none;letter-spacing:0;
  font-size:var(--font-size-label);color:var(--text-primary)}
.check{display:inline-flex;align-items:center;gap:6px;font-size:var(--font-size-label);
  color:var(--text-secondary);cursor:pointer;white-space:nowrap}
.check input{accent-color:var(--accent);width:14px;height:14px;margin:0;cursor:pointer}
.segc{display:inline-flex;border:1px solid var(--border-strong);border-radius:var(--radius-md);
  overflow:hidden;background:var(--surface-card)}
.segc button{border:none;background:transparent;padding:5px 11px;font-size:var(--font-size-label);
  color:var(--text-tertiary)}
.segc button:hover{color:var(--text-primary);background:var(--surface-raised)}
.segc button.on{background:var(--surface-inset);color:var(--text-primary);
  font-weight:var(--font-weight-strong)}
.segc button.on[data-tone="warn"]{color:var(--warning)}
.segc button.on[data-tone="ok"]{color:var(--success)}
/* Tabs are a segmented control in band 1 (DESIGN.md §3), and tabs are links — same skin. */
.segc a{display:inline-flex;align-items:center;padding:5px 11px;font-size:var(--font-size-label);
  color:var(--text-tertiary)}
.segc a:hover{color:var(--text-primary);background:var(--surface-raised);text-decoration:none}
.segc a.on{background:var(--surface-inset);color:var(--text-primary);
  font-weight:var(--font-weight-strong)}

/* ---- cards ------------------------------------------------------------------------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:var(--space-3)}
.card{background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:var(--space-card);transition:border-color var(--dur-fast) var(--ease)}
.card.hoverable:hover{border-color:var(--border-strong)}
.card h3{font:var(--font-weight-selected) var(--font-size-body) var(--font-sans)}
.cardlink{display:block;color:inherit}
.cardlink:hover{text-decoration:none;border-color:var(--accent)}
.kv{display:flex;gap:8px;align-items:baseline;font-size:var(--font-size-label)}
.kv .k{color:var(--text-tertiary);flex:none}
.stack{display:flex;flex-direction:column;gap:var(--space-3)}
.rowflex{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}

/* ---- chips: TWO kinds only (DESIGN.md §6) ------------------------------------------------ */
/* status chip = semantic color, read-only. The filter chip (.fchip) lives with band 2. */
.chip{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:var(--font-weight-strong);
  letter-spacing:.04em;padding:1.5px 8px;border-radius:6px;border:1px solid var(--border-strong);
  color:var(--text-tertiary);white-space:nowrap;text-transform:uppercase}
.chip.ok{color:var(--success);border-color:var(--success-line);background:var(--success-soft)}
.chip.warn{color:var(--warning);border-color:var(--warning-line);background:var(--warning-soft)}
.chip.err{color:var(--error);border-color:var(--error-line);background:var(--error-soft)}
.chip.accent{color:var(--accent);border-color:var(--accent-soft-line);background:var(--accent-soft)}
.chip.sm{padding:0 6px}

/* ---- table identity bits (the tables themselves live with .bomtbl below) ----------------- */
.mpnlink{font-family:var(--font-mono);color:var(--accent);cursor:pointer;background:none;
  border:none;padding:0;font-size:inherit;text-align:left}
.mpnlink:hover{text-decoration:underline}
.subl{font-size:10px;color:var(--text-tertiary);margin-top:1px}

/* ---- inspector: the ONE docked detail surface (DESIGN.md §1.2) ------------------------- */
/* 360px, a sibling of .page inside .content: it NARROWS the page, never covers it. No
   scrim, no fixed positioning, no z-index race — the page reflows around it. */
.inspector{flex:none;width:360px;position:sticky;top:0;height:100vh;
  display:flex;flex-direction:column;background:var(--surface-card);
  border-left:1px solid var(--border);animation:fade var(--dur-fast) var(--ease)}
.inspector .ihead{flex:none;display:flex;align-items:flex-start;gap:var(--space-2);
  padding:var(--space-4) var(--space-3) var(--space-3) var(--space-4);
  border-bottom:1px solid var(--border)}
.inspector .ihead h2{font:var(--font-weight-selected) 15px var(--font-sans);word-break:break-all}
/* identity case: an MPN is the row's name — mono, never truncated, never ellipsized (§5) */
.inspector .ihead h2.mono{font-family:var(--font-mono);font-size:14px;letter-spacing:-.01em}
.inspector .ihead .sub{color:var(--text-tertiary);font-size:var(--font-size-label);margin-top:2px}
.inspector .ibody{flex:1;overflow:auto;padding:var(--space-4)}
/* Below the split breakpoint there is no room to dock BESIDE the table, so the ONE detail
   surface reflows rather than disappearing: the same panel, the same content, full width
   under the table it describes (never a drawer, never a modal — §1). openInspector scrolls
   it into view there. Hiding it outright would delete part detail, alternates, identify and
   revert on every viewport under 1100px. */
@media (max-width:1100px){
  .content{flex-wrap:wrap}
  .inspector{position:static;flex:1 0 100%;width:auto;height:auto;
    border-left:none;border-top:1px solid var(--border)}
  .inspector .ibody{overflow:visible}
}

/* ---- panel bits shared by the inspector ------------------------------------------------- */
@keyframes fade{from{opacity:0}to{opacity:1}}
.xbtn{margin-left:auto;flex:none;width:30px;height:30px;border:none;background:transparent;
  color:var(--text-tertiary);border-radius:var(--radius-md);
  display:inline-flex;align-items:center;justify-content:center}
.xbtn:hover{background:var(--surface-raised);color:var(--text-primary)}
.sec{margin-bottom:var(--space-4)}
/* NOT child-scoped: `.secttl` is the app's one small-caps label, and Settings' field() and
   the login card use it outside any `.sec`. Scoping it to `.sec >` left every Settings field
   label and the "Sign in" heading rendering as plain body text. */
.secttl{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--text-tertiary);
  margin-bottom:var(--space-2)}
.spectbl{width:100%;border-collapse:collapse;font-size:var(--font-size-label)}
.spectbl td{padding:4px 8px;border-bottom:1px solid var(--border)}
.spectbl td:first-child{color:var(--text-tertiary);width:40%}
.spectbl td:last-child{font-family:var(--font-mono);font-size:var(--font-size-mono)}
.caption{font-size:10px;color:var(--text-muted);line-height:1.5}

/* ---- candidate explanations (the alternates mode's "how does it differ" block) ------------ */
.expl{margin-top:6px;font-size:var(--font-size-label);line-height:1.5;color:var(--text-secondary)}
.expldiffs,.explsame{margin-top:4px;font-size:var(--font-size-label)}
.expldiffs>summary,.explsame>summary{cursor:pointer;color:var(--text-tertiary)}
.expldiffs>summary:hover,.explsame>summary:hover{color:var(--text-primary)}
.explsame{margin-left:8px}
.expltbl{margin-top:4px}
.expltbl th{padding:4px 8px;border-bottom:1px solid var(--border);text-align:left;
  font-weight:var(--font-weight-medium);color:var(--text-tertiary)}
.expltbl td:first-child{width:32%}
.expltbl td:last-child{font-family:inherit;font-size:inherit}
/* Six levels, not three. The old scale could not say which DIRECTION a difference went, so a
   50V part offered for a 16V one was painted the same amber as a 6.3V one that will fail. */
.expltbl tr.blocking td{color:var(--error);background:var(--error-soft)}
.expltbl tr.worse td{color:var(--warning);background:var(--warning-soft)}
.expltbl tr.changed td{color:var(--warning)}
.expltbl tr.better td{color:var(--success)}
.expltbl tr.missing td{color:var(--text-muted)}
.expltbl td.note{font-size:10px;color:var(--text-tertiary);font-family:var(--font-sans)}

/* The one-line verdict above the diff table — the thing you read instead of the table. */
.vrd{display:flex;align-items:flex-start;gap:6px;margin-top:6px;padding:6px 8px;
  border-radius:var(--radius-sm);font-size:var(--font-size-label);line-height:1.45}
.vrd.not_drop_in{color:var(--error);background:var(--error-soft);border:1px solid var(--error-line)}
.vrd.check{color:var(--warning);background:var(--warning-soft);border:1px solid var(--warning-line)}
.vrd.drop_in{color:var(--success);background:var(--success-soft);border:1px solid var(--success-line)}
.vrd.insufficient{color:var(--text-tertiary);background:var(--surface-sunken);border:1px solid var(--border)}

/* ---- offer rows ------------------------------------------------------------------------ */
.offer{border:1px solid var(--border);border-radius:var(--radius-md);padding:10px 12px;
  background:var(--surface-card)}
.offer+.offer{margin-top:8px}
.offer.avoided{opacity:.62}
.offer .oline{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.offer .seller{font-weight:var(--font-weight-selected);color:var(--text-primary)}
.offer .stock{font-family:var(--font-mono);font-size:var(--font-size-mono)}
.offer .stock.out{color:var(--text-muted)}
.breaks{width:100%;border-collapse:collapse;margin-top:6px;font-size:var(--font-size-mono);
  font-family:var(--font-mono)}
.breaks td{padding:2px 0;color:var(--text-secondary)}
.breaks td:last-child{text-align:right;color:var(--text-primary)}

/* ---- menus ----------------------------------------------------------------------------- */
.menuwrap{position:relative;display:inline-block}
.menu{position:absolute;right:0;top:calc(100% + 4px);z-index:35;min-width:180px;
  background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-md);
  box-shadow:var(--shadow-float);padding:4px;display:none}
.menu.open{display:block;animation:fade var(--dur-fast) var(--ease)}
.menu button{display:flex;width:100%;align-items:center;gap:8px;border:none;background:none;
  padding:7px 10px;border-radius:var(--radius-sm);font-size:var(--font-size-label);
  color:var(--text-secondary);text-align:left}
.menu button:hover{background:var(--surface-raised);color:var(--text-primary)}
.menu button.danger{color:var(--error)}

/* ---- states ------------------------------------------------------------------------------ */
.empty{padding:48px 24px;text-align:center;color:var(--text-tertiary)}
.empty .big{font-size:15px;color:var(--text-secondary);margin-bottom:6px}
.empty .hint{font-size:var(--font-size-label);max-width:420px;margin:0 auto 14px;line-height:1.6}
.errbox{padding:24px;text-align:center;color:var(--error);font-size:var(--font-size-label)}
.infobox{padding:10px 14px;border:1px solid var(--accent-soft-line);border-radius:var(--radius-md);
  background:var(--surface-card);color:var(--text-secondary);font-size:var(--font-size-label);
  margin-bottom:var(--space-3)}
.skel{position:relative;overflow:hidden;background:var(--surface-raised);border-radius:var(--radius-md)}
.skel::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,var(--skel-sheen),transparent);
  animation:shimmer 1.2s infinite}
@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}
.skelrow{height:44px;margin-bottom:8px}
.skelcard{height:120px}

/* ---- toast --------------------------------------------------------------------------------- */
#toasts{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:60;
  display:flex;flex-direction:column;gap:8px;align-items:center}
.toast{background:var(--surface-card);border:1px solid var(--border-strong);color:var(--text-primary);
  border-radius:var(--radius-md);padding:9px 16px;font-size:var(--font-size-label);
  box-shadow:var(--shadow-float);animation:fade var(--dur-fast) var(--ease);
  display:flex;align-items:center;gap:8px}
.toast .ic{color:var(--success)}
.toast.err{border-color:var(--error);color:var(--error)}
.toast.err .ic{color:var(--error)}

/* ---- page-specific -------------------------------------------------------------------------- */
.presence{display:inline-flex;align-items:center;gap:6px;font-size:var(--font-size-label);
  color:var(--text-secondary)}
.presence .pulse{width:7px;height:7px;border-radius:50%;background:var(--success)}
/* The alerts feed is a .bomtbl like every other list in the app (§6 density) — no card row
   vocabulary, no second selected-row treatment. Unread is a dot in its own narrow cell. */
.bomtbl td.unc,.bomtbl th.unc{width:18px;padding:0 0 0 10px}
.undot{display:block;width:6px;height:6px;border-radius:50%;background:var(--accent)}
.bomtbl td.sumc{max-width:420px;overflow:hidden;text-overflow:ellipsis;color:var(--text-secondary)}
.bomtbl td.condc .chipset{flex-wrap:nowrap}
/* condition mark: icon + the condition chip's word beside it, never color alone */
.alerticon{flex:none;display:inline-flex;align-items:center;margin-top:1px;color:var(--text-tertiary)}
.alerticon.ok{color:var(--success)}
.alerticon.warn{color:var(--warning)}
.alerticon.err{color:var(--error)}
.chipset{display:flex;gap:6px;flex-wrap:wrap;align-items:center}

/* ---- search page (S2 expansion + S3 typed tokens; facets live in band 2) ----------------- */
/* No .page width override here: the frame law is one rule (DESIGN.md §2). The query bar is
   band 1 and EVERY filter — typed token, facet pick, in-stock — is a band-2 chip. There is
   no facet rail: a second sidebar is forbidden (§1), and §3 already assigns filtering to
   band 2, so the facets browse from a band-2 menu and land as removable chips beside it. */
.fmenu .menu{min-width:230px;max-height:320px;overflow:auto}
.fmenu .menu button{justify-content:space-between}
.fmenu .ct{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--text-muted);
  font-size:11px}
.fmenu .fl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bomtbl.stbl tbody td,.bomtbl.stbl thead th{padding:0 8px} /* 9 columns: tighter gutters */
.bomtbl.stbl td.mpnc{white-space:nowrap} /* mono MPN never truncated */
.bomtbl.stbl td.mpnc .xchev{margin-right:4px}
.bomtbl.stbl td.mpnc .chip{margin-left:6px}
.bomtbl.stbl td.mfrc{max-width:120px;overflow:hidden;text-overflow:ellipsis;font-size:12px}
.bomtbl.stbl td.desc{max-width:210px;overflow:hidden;text-overflow:ellipsis;font-size:12px;
  color:var(--text-secondary)}
.bomtbl.stbl td.pkgc{font-family:var(--font-mono);font-size:10.5px;color:var(--text-tertiary)}
.bomtbl.stbl td.stockc,.bomtbl.stbl td.pricec,.bomtbl.stbl td.sellc{text-align:right}
.bomtbl.stbl td .ts{font-size:9px;color:var(--text-muted);font-family:var(--font-sans);
  line-height:1.2}
.bomtbl.stbl td.actc{width:40px;text-align:right;overflow:visible}
.alsorow{margin-top:10px;font-size:11px;color:var(--text-muted)}

/* ---- feedback shutter (approved design H2: pen always on, no tool picker) ---- */
#fb-fab { position:fixed; right:calc(24px + env(safe-area-inset-right, 0px));
  bottom:calc(24px + env(safe-area-inset-bottom, 0px)); width:52px; height:52px; border-radius:50%;
  background:var(--text-primary); color:var(--text-on-accent); border:none; cursor:pointer; z-index:80;
  display:flex; align-items:center; justify-content:center;
  box-shadow:var(--shadow-pop); transition:transform var(--dur-fast) var(--ease); }
#fb-fab svg { width:24px; height:24px; }
#fb-fab:hover { transform:scale(1.05); }
#fb-fab:disabled { opacity:.6; }
#fb-modal { position:fixed; inset:0; background:var(--scrim); z-index:90;
  display:flex; align-items:center; justify-content:center; }
.fb-card { background:var(--surface-card); border-radius:16px; width:min(940px, 94vw);
  max-height:92vh; display:flex; flex-direction:column; padding:16px;
  box-shadow:var(--shadow-float); }
.fb-head { display:flex; align-items:baseline; gap:10px; margin:0 2px 12px; }
.fb-head h2 { font-size:15px; font-weight:600; color:var(--text-primary); }
.fb-esc { font-size:11px; color:var(--text-tertiary); }
.fb-undo { margin-left:auto; background:none; border:none; cursor:pointer; font-size:12px;
  color:var(--text-secondary); text-decoration:underline; text-underline-offset:2px;
  padding:6px 8px; }
.fb-x { background:none; border:none; cursor:pointer; line-height:1;
  color:var(--text-tertiary); padding:6px 8px;
  display:inline-flex; align-items:center; justify-content:center; }
.fb-x:hover { color:var(--text-primary); }
.fb-capturing { position:relative; overflow:hidden; height:180px;
  display:flex; align-items:center; justify-content:center; }
.fb-capturing::after { content:""; position:absolute; inset:0;
  background:linear-gradient(100deg, transparent 30%, var(--skel-sheen) 50%, transparent 70%);
  animation:fbshimmer 1.1s infinite; }
@keyframes fbshimmer { from { transform:translateX(-100%); } to { transform:translateX(100%); } }
.fb-capmsg { font-size:13px; color:var(--text-tertiary); }
.fb-stage { border:1px solid var(--border); border-radius:10px; overflow:hidden;
  min-height:120px; min-width:0; display:flex; justify-content:center; align-items:center;
  background:var(--surface-inset); }
.fb-shotbox { position:relative; max-width:100%; min-width:0; font-size:0; }
.fb-shot { display:block; max-width:100%; max-height:calc(92vh - 230px);
  max-height:calc(92dvh - 230px); width:auto; height:auto; }
.fb-ink { position:absolute; inset:0; width:100%; height:100%; cursor:crosshair;
  touch-action:none; }
.fb-noshot { display:flex; align-items:center; justify-content:center; height:160px;
  color:var(--text-tertiary); font-size:13px; }
.fb-foot { display:flex; gap:12px; margin-top:12px; align-items:flex-end; }
.fb-fieldwrap { flex:1; }
.fb-field { width:100%; border:1px solid var(--border-strong); border-radius:10px;
  padding:10px 12px; font-size:13.5px; font-family:var(--font-sans); background:var(--surface-card);
  color:var(--text-primary); resize:none; overflow:hidden; line-height:1.5; outline:none; }
.fb-field:focus { border-color:var(--focus-ring); box-shadow:0 0 0 2px var(--accent-soft-line); }
.fb-cap { font-size:11px; color:var(--text-tertiary); margin:7px 0 0 2px; }
.fb-send { background:var(--text-primary); color:var(--text-on-accent); border:none; border-radius:10px;
  padding:12px 28px; font-size:13.5px; font-weight:600; cursor:pointer; margin-bottom:24px; }
.fb-send:disabled { opacity:.7; }
@media (max-width:640px){
  #fb-modal { align-items:stretch; }
  .fb-card { width:100%; max-height:none; height:100dvh; border-radius:0;
    padding:calc(12px + env(safe-area-inset-top, 0px)) 12px calc(12px + env(safe-area-inset-bottom, 0px)); }
  .fb-esc { display:none; }
  .fb-stage { min-height:0; }
  .fb-shot { max-height:46dvh; }
  .fb-field { font-size:16px; }
  .fb-foot { align-items:stretch; flex-direction:column; }
  .fb-send { margin-bottom:0; padding:14px 0; }
}

/* ---- board page: TWO bands, then data (DESIGN.md §3) -------------------------------------- */
/* No .page width override here — one frame law (§2). Detail docks in .inspector (§1.2), so
   there is no page-local panel and no split wrapper: the shared inspector narrows .page. */

/* band 1 (56px) — back · title (inline-editable where relevant) · meta chips · tabs or the
   query bar | right: the page's ONE primary action. Every page builds it from ui.js band1() */
/* Band 1 NEVER wraps: a wrapped band is ~112px of chrome, which turns a two-band page into
   a de-facto three-band one — exactly the budget §3 sets. The title (and the meta strip) are
   the elastic items and ellipsize; the controls keep their size. */
.band1{display:flex;align-items:center;gap:var(--space-3);min-height:56px;flex-wrap:nowrap}
.band1 .spacer{flex:1}
.band1>.b1title{flex:0 1 auto;min-width:0}
.band1>.bmeta,.band1>.segc,.band1>.qtyfield,.band1>.btn,.band1>a.btn,.band1>label{flex:none}
.band1>.bmeta{min-width:0} /* chips still ellipsize inside via .mchip's max-width */
.b1title{display:flex;flex-direction:column;min-width:0}
/* ONE band-1 title type, whether the page renders a plain h1 or the board's editable name */
.b1title h1,.bname{font:var(--font-weight-selected) 20px var(--font-sans);letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.b1title .sub{color:var(--text-tertiary);font-size:var(--font-size-label);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* the centered control (the search page's query bar) owns the free space, not a spacer */
.b1c{flex:1;display:flex;gap:var(--space-2);min-width:260px}
.b1q{flex:1;padding:9px 13px;font-size:var(--font-size-body)}
.bnamewrap{display:flex;align-items:center;gap:2px;min-width:0}
.bname{cursor:text;max-width:260px}
.bnameinput{font:var(--font-weight-selected) 18px var(--font-sans);padding:4px 8px;width:260px}
.bmeta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.mchip{display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 8px;max-width:220px;
  border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface-card);
  font-size:var(--font-size-label);color:var(--text-tertiary);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
a.mchip:hover{color:var(--text-primary);border-color:var(--border-strong);text-decoration:none}
.mchip .ic{color:var(--text-muted)}
.mchip .pulse{width:6px;height:6px;border-radius:50%;background:var(--success);flex:none}
.qtyfield{display:inline-flex;align-items:center;gap:6px;font-size:var(--font-size-label);
  color:var(--text-tertiary);white-space:nowrap}

/* band 2 (44px) — the health summary IS the filter row; neutral chips only (§6) */
.band2{display:flex;align-items:center;gap:8px;min-height:44px;flex-wrap:wrap}
.band2 .spacer{flex:1}
.band2 select.input{padding:5px 8px}
.b2hint{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:10px;
  color:var(--text-muted)}
.b2hint .mono{font-size:10px;letter-spacing:0}
.b2count{font-size:var(--font-size-label);color:var(--text-secondary);
  font-weight:var(--font-weight-medium)}
.b2note{display:inline-flex;align-items:center;gap:6px;font-size:var(--font-size-label);
  color:var(--warning)}
/* the ONE filter chip: neutral, toggles, carries its count; `.x` makes it a removable
   applied filter (query tokens, facet selections, supplier lists — all the same chip) */
.fchip{display:inline-flex;align-items:center;gap:7px;height:26px;padding:0 11px;border-radius:999px;
  border:1px solid var(--border);background:var(--surface-card);color:var(--text-secondary);
  font:inherit;font-size:var(--font-size-label);cursor:pointer}
.fchip:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary)}
.fchip.on{background:var(--accent-soft);border-color:var(--accent-soft-line);color:var(--text-primary)}
.fchip .n{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--text-primary)}
.fchip .kind{color:var(--text-tertiary)}
.fchip b{font-weight:var(--font-weight-medium)}
.fchip:disabled{opacity:.45;cursor:default}
.fchip:disabled .n{color:var(--text-muted)}
.fchip:has(.x){padding-right:4px;cursor:default}
.fchip .x{border:none;background:none;color:var(--text-muted);width:16px;height:16px;
  border-radius:6px;padding:0;cursor:pointer;line-height:1;
  display:inline-flex;align-items:center;justify-content:center}
.fchip .x:hover{background:var(--surface-raised);color:var(--text-primary)}
/* the inline fix action an attention row carries in the filtered state */

/* dense 38px table, 1px separators, no zebra, status pinned right */
.bomcard{background:var(--surface-card);border:1px solid var(--border);
  border-radius:var(--radius-md);overflow:hidden}
.bomwrap{overflow-x:auto}
table.bomtbl{width:100%;border-collapse:collapse;font-size:var(--font-size-label);
  font-variant-numeric:tabular-nums}
.bomtbl thead th{height:30px;padding:0 10px;text-align:left;font-size:10px;
  font-weight:var(--font-weight-medium);letter-spacing:.06em;text-transform:uppercase;
  color:var(--text-muted);background:var(--surface-page);
  border-bottom:1px solid var(--border-strong);white-space:nowrap}
.bomtbl th.num,.bomtbl td.num{text-align:right}
.bomtbl td.num{font-family:var(--font-mono);font-size:var(--font-size-mono)}
.bomtbl tbody td{height:38px;padding:0 10px;border-top:1px solid var(--border);
  vertical-align:middle;white-space:nowrap}
/* density control (band 2): 34 dense · 38 default · 44 comfortable (§6) */
.bomtbl.dense tbody td{height:34px}
.bomtbl.roomy tbody td{height:44px}
.bomtbl tbody tr:first-child td{border-top:none}
.bomtbl tbody tr.line{cursor:pointer}
.bomtbl tbody tr.line:hover td{background:var(--surface-raised)}
.bomtbl tbody tr.sel td{background:var(--accent-soft)}
.bomtbl tr.dim td{opacity:.5}
.bomtbl td.ckc,.bomtbl th.ckc{width:26px;padding:0 0 0 8px}
.rowck{opacity:0;width:13px;height:13px;accent-color:var(--accent);cursor:pointer;margin:0;
  transition:opacity var(--dur-fast) var(--ease)}
.bomtbl tr.line:hover .rowck,.rowck:checked,.rowck:focus-visible{opacity:1}
.xchev{border:none;background:none;color:var(--text-muted);width:16px;height:16px;
  padding:0;cursor:pointer;margin-right:2px;
  display:inline-flex;align-items:center;justify-content:center;vertical-align:middle}
.xchev:hover{color:var(--text-primary)}
.bomtbl td.refc{font-family:var(--font-mono);font-size:var(--font-size-mono);
  max-width:130px;overflow:hidden;text-overflow:ellipsis}
.bomtbl td.qtyc{text-align:right;color:var(--text-secondary);
  font-family:var(--font-mono);font-size:var(--font-size-mono)}
.bomtbl td.valc{max-width:150px;overflow:hidden;text-overflow:ellipsis;font-size:12px}
.bomtbl td.fpc{font-family:var(--font-mono);font-size:10.5px;color:var(--text-muted);
  max-width:150px;overflow:hidden;text-overflow:ellipsis}
.bomtbl td.mpnc{font-family:var(--font-mono);font-size:var(--font-size-mono)} /* never truncated */
.bomtbl td.mpnc .mpnlink{font-size:inherit}
.bomtbl td.stcell,.bomtbl th.stcell{position:sticky;right:0;background:var(--surface-card);
  border-left:1px solid var(--border);z-index:1}
.bomtbl th.stcell{background:var(--surface-page)}
.bomtbl tr.line:hover td.stcell{background:var(--surface-raised)}
.bomtbl tr.sel td.stcell{background:var(--accent-soft)}
.stbadge{display:inline-flex;align-items:center;gap:6px;font-size:11px;
  font-weight:var(--font-weight-medium)}
.stbadge svg{display:block;flex:none}
.stbadge.ok{color:var(--success)}
/* A failed check on data we trust: the user's problem, so it gets the warning colour. */
.stbadge.risk{color:var(--warning)}
.stbadge.unsourced{color:var(--error)}
/* "No data" and "Stale" are OUR problem and a refresh respectively, not findings about the
   board — so they read muted. Alarm colour on a line we simply could not check is how a status
   column teaches people to ignore it. */
.stbadge.nodata{color:var(--text-muted)}
.stbadge.stale{color:var(--text-secondary)}
.stbadge.dnp{color:var(--text-muted)}
/* icon + word for facts that are NOT the 4-level status scale (alerts on/off, the chosen
   plan). Neutral on purpose: borrowing .stbadge's colors would teach "grey = DNP" and then
   use it for "alerts off" on the next page (DESIGN.md §5 — ONE status vocabulary). */
.imark{display:inline-flex;align-items:center;gap:6px;font-size:11px;
  font-weight:var(--font-weight-medium);color:var(--text-secondary)}
.imark svg{display:block;flex:none}
.imark.quiet{color:var(--text-muted)}

/* best-offer cell: seller + stock left, price @qty + honest as-of stamp right */
.offer2{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:190px}
.offer2 .os{min-width:0}
.offer2 .os .s1{font-size:12px;display:flex;align-items:center;gap:5px;line-height:1.3}
.offer2 .os .s2{font-size:10px;color:var(--text-muted);line-height:1.3;font-variant-numeric:tabular-nums}
.offer2 .op{text-align:right;flex:none}
.offer2 .op .p{font-family:var(--font-mono);font-size:12px;font-weight:var(--font-weight-strong);line-height:1.3}
.offer2 .op .p small{font-family:var(--font-sans);font-size:9px;font-weight:400;
  color:var(--text-muted);margin-left:2px}
.offer2 .op .ts{font-size:9px;color:var(--text-muted);line-height:1.3}

/* inline seller expansion (price-break mini-table) */
.bomtbl tr.xrow>td{padding:0;background:var(--surface-inset);border-top:1px solid var(--border);
  height:auto;white-space:normal}
.xp{padding:10px 16px 12px 44px}
.xp-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:6px}
.xp-cap{font-size:10px;letter-spacing:.07em;text-transform:uppercase;color:var(--text-muted);
  font-weight:var(--font-weight-medium)}
.xp-asof{font-size:10px;color:var(--text-muted)}
table.xt{border-collapse:collapse;min-width:560px}
.xt th{height:22px;padding:0 10px;font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text-muted);font-weight:var(--font-weight-medium);text-align:right;
  border-bottom:1px solid var(--border);white-space:nowrap}
.xt th:first-child{text-align:left;padding-left:0}
.xt td{height:26px;padding:0 10px;font-size:11px;border-bottom:1px solid var(--border);
  text-align:right;font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  color:var(--text-secondary);white-space:nowrap}
.xt tr:last-child td{border-bottom:none}
.xt td.xseller{text-align:left;font-family:var(--font-sans);font-size:12px;
  color:var(--text-primary);font-weight:var(--font-weight-medium);padding-left:0}
.xt td.xbest{color:var(--text-primary);font-weight:var(--font-weight-strong)}
.xt a.buy{font-family:var(--font-sans);font-size:10.5px;
  display:inline-flex;align-items:center;gap:4px}

/* table footer strip */
.bomfoot{display:flex;justify-content:space-between;align-items:center;gap:12px;min-height:32px;
  padding:6px 12px;border-top:1px solid var(--border);background:var(--surface-page);
  font-size:var(--font-size-label);color:var(--text-muted);flex-wrap:wrap}
.bomfoot b{color:var(--text-secondary);font-weight:var(--font-weight-medium)}

/* parts page: the tracked-parts table (Library + Watches merged) reuses .bomtbl density,
   but its card must NOT clip overflow — every row carries a row-menu dropdown */
.partscard{background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-md)}
.partscard thead th:first-child{border-top-left-radius:var(--radius-md)}
.partscard thead th:last-child{border-top-right-radius:var(--radius-md)}
.partscard .bomfoot{border-radius:0 0 var(--radius-md) var(--radius-md)}

/* inspector body vocabulary (identity · status · facts · offers · actions) — the panel
   chrome itself lives with .inspector above; these are the blocks pages paint into it */
.imono{font-family:var(--font-mono);font-size:15px;font-weight:var(--font-weight-strong);
  word-break:break-all} /* MPN: never truncated, never ellipsized (§5) */
.imono.small{font-size:var(--font-size-mono);font-weight:var(--font-weight-selected)}
.isub{font-size:var(--font-size-label);color:var(--text-tertiary);margin-top:2px}
.istatus{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px}
.istatus .stbadge{font-size:12px}
.idesc{font-size:var(--font-size-label);color:var(--text-tertiary);line-height:1.5;margin-top:10px}
.iact{display:flex;flex-direction:column;gap:8px;margin-top:var(--space-4)}
.centerlink{justify-content:center}
.ifoot{margin-top:var(--space-4);padding-top:var(--space-3);border-top:1px solid var(--border)}
.ibackbtn{margin:-4px 0 8px -6px}
.provcap{margin-top:10px} /* the ONE page-level provenance caption (§5) */

/* floating bulk-selection bar */
.bulkbar{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:30;height:40px;
  display:flex;align-items:center;gap:10px;padding:0 8px 0 14px;background:var(--surface-tool);
  color:var(--text-on-tool);border-radius:var(--radius-md);box-shadow:var(--shadow-pop);
  white-space:nowrap;animation:fade var(--dur-fast) var(--ease)}
.bulkbar .cnt{font-size:12px;font-weight:var(--font-weight-strong)}
.bulkbar .vsep{width:1px;height:16px;background:var(--text-on-tool);opacity:.2}
.bulkbar button{background:none;border:none;color:var(--text-on-tool);font-size:12px;
  padding:5px 8px;border-radius:6px;cursor:pointer;opacity:.85;
  display:inline-flex;align-items:center;gap:6px}
.bulkbar button:hover{opacity:1}
