:root {
  --blue: #1868C4;
  --blue-dark: #1868C4;
  --gold: #f5a623;
  --purple: #7c5cf0;
  --green: #18a463;
  --page-bg: #f2f4f9;
  --card-bg: #ffffff;
  --card-border: #e6e9f2;
  --fg: #16213e;
  --muted: #6b7280;
  --row-alt: #f7f8fc;
  --bad: #c23b2e;
  --warn: #b5790a;
  --good: #18a463;
}

@media (prefers-color-scheme: dark) {
  :root {
    --blue: #4d7bf0;
    --blue-dark: #0d1f66;
    --gold: #f5b942;
    --purple: #9b82f7;
    --green: #34c481;
    --page-bg: #0d1220;
    --card-bg: #161b2c;
    --card-border: #262d45;
    --fg: #e8ebf7;
    --muted: #9aa4c2;
    --row-alt: #1b2136;
    --bad: #ff8b7d;
    --warn: #e8b74a;
    --good: #34c481;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--page-bg);
  color: var(--fg);
}

/* Topbar */
.topbar {
  background: linear-gradient(90deg, var(--blue-dark), var(--blue));
  border-bottom: 3px solid var(--gold);
  padding: 14px 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #ffffff;
}

.topbar-left { display: flex; align-items: center; gap: 16px; }

.logo-badge {
  display: inline-flex;
  align-items: center;
  background: #ffffff;
  border-radius: 8px;
  padding: 5px 12px;
}
.logo-img { height: 26px; width: auto; display: block; }

.topbar-divider {
  width: 3px;
  height: 22px;
  background: var(--gold);
  border-radius: 2px;
}

.topbar-title { font-size: 1.35rem; font-weight: 700; }
.version-badge {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 999px;
  padding: 2px 8px;
  align-self: center;
}

.topbar-right { display: flex; align-items: center; gap: 10px; font-size: 0.85rem; }
.topbar-label { color: #cfdcff; }
.topbar-pill {
  border: 2px solid var(--gold);
  border-radius: 999px;
  padding: 5px 14px;
  font-weight: 700;
  color: #ffffff;
}

/* Subbar */
.subbar {
  background: var(--card-bg);
  border-bottom: 1px solid var(--card-border);
  padding: 10px 28px;
  font-size: 0.85rem;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 8px;
}

.live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 25%, transparent);
  flex-shrink: 0;
}
.live-dot.error { background: var(--bad); box-shadow: 0 0 0 3px color-mix(in srgb, var(--bad) 25%, transparent); }

/* Tab nav - sticky at the very top of the viewport so it's always clear which page you're on,
   per explicit request. thead th (below) stacks directly beneath it at TAB_NAV_HEIGHT. */
.tab-nav {
  background: var(--card-bg);
  border-bottom: 1px solid var(--card-border);
  padding: 0 28px;
  display: flex;
  align-items: center;
  gap: 4px;
  height: 44px;
  position: sticky;
  top: 0;
  z-index: 30;
}
.tab-link {
  display: inline-block;
  padding: 10px 16px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
}
.tab-link:hover { color: var(--fg); }
.tab-link-active { color: var(--blue); border-bottom-color: var(--blue); }

/* Upload/toolbar row (Manage Pricelist controls) */
.upload-bar {
  background: var(--card-bg);
  border-bottom: 1px solid var(--card-border);
  padding: 10px 28px;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.upload-bar-spacer { flex: 1; }
.upload-btn {
  font: inherit;
  font-weight: 600;
  color: #ffffff;
  background: var(--blue);
  border: none;
  border-radius: 6px;
  padding: 5px 14px;
  cursor: pointer;
}
.upload-btn:disabled { opacity: 0.6; cursor: default; }
.upload-btn-primary { background: var(--good); }
.upload-status { color: var(--muted); }
.upload-status.upload-status-error { color: var(--bad); }

/* Pricing-rule toggles (Manage Pricelist controls), distinct from .upload-bar's action buttons -
   a checkbox here changes how a number is calculated, not what data gets imported/saved. */
.settings-bar {
  background: var(--card-bg);
  border-bottom: 1px solid var(--card-border);
  padding: 10px 28px;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.settings-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: var(--fg);
  cursor: pointer;
  white-space: nowrap;
}
.settings-rate-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--fg);
  white-space: nowrap;
}
.settings-rate-input {
  font: inherit;
  color: var(--fg);
  background: var(--page-bg);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 4px 6px;
  width: 64px;
  text-align: right;
}
.settings-note { color: var(--muted); }

main { padding: 24px 28px 40px; max-width: 1400px; margin: 0 auto; }

/* Card shell */
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(20, 30, 60, 0.06);
  padding: 20px 22px;
}

.card-header { margin-bottom: 14px; }
.card-header h2 { margin: 0 0 4px; font-size: 1.15rem; font-weight: 800; color: var(--fg); }
.card-subtitle { margin: 0; font-size: 0.85rem; color: var(--muted); }

.search-bar { margin-bottom: 14px; }
.search-input {
  width: 100%;
  max-width: 360px;
  font: inherit;
  font-size: 0.85rem;
  padding: 8px 12px;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: var(--page-bg);
  color: var(--fg);
}
.search-input:focus { outline: 2px solid var(--blue); outline-offset: -1px; }

/* Table */
/* No overflow-x here (there used to be one) - CSS promotes overflow-y from its
   default `visible` to `auto` whenever overflow-x is anything but `visible`, so this div
   quietly became its own scroll container. thead th's `position: sticky` then anchored to
   *this* box (whose own scroll offset never moves) instead of the real page viewport that
   .tab-nav sticks to - permanently shoving the header down by its `top` offset, gap above
   it and hiding the row beneath, regardless of actual page scroll position. Matching
   .tab-nav's sticky behavior requires no overflow-non-visible ancestor between the sticky
   th and the page viewport, so the table can no longer get its own horizontal scrollbar -
   a table wider than the viewport now scrolls the whole page horizontally instead. */
.table-wrap {
  border: 1px solid var(--card-border);
  border-radius: 8px;
}

/* separate (not collapse) - position: sticky on a th is unreliable under the collapsed
   border model in some browsers (backgrounds/borders can fail to paint over the row behind),
   which is exactly what a sticky thead needs. border-spacing: 0 keeps cells visually flush,
   same as collapse, since only border-bottom is ever used (no shared top/bottom edge to
   double up). */
table { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 760px; font-size: 0.9rem; }

thead th {
  background: var(--row-alt);
  color: var(--muted);
  border-bottom: 2px solid var(--blue);
  padding: 11px 14px;
  text-align: center;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 0.72rem;
  white-space: nowrap;
}
thead th.col-sku { text-align: left; }

/* .table-wrap no longer clips (see the overflow-x comment above), so the header row's own
   corners need to round themselves to match .table-wrap's 8px border-radius. Scoped with a
   direct-child combinator (>), not a descendant (space) - a descendant selector here still
   matches the nested per-MO "See MOs" table's own header even though it's an ID-prefixed
   selector, because that table lives nested many levels deep inside one of #report-table's own
   `<td>` cells, and a descendant combinator matches at ANY depth, not just #report-table's own
   direct <thead>. (Found real, live 2026-07-20 - see the sticky rule below, which had the exact
   same bug.) */
#report-table > thead > tr:first-child > th:first-child,
#pricelist-table > thead > tr:first-child > th:first-child,
#co-table > thead > tr:first-child > th:first-child { border-top-left-radius: 8px; }
#report-table > thead > tr:first-child > th:last-child,
#pricelist-table > thead > tr:first-child > th:last-child,
#co-table > thead > tr:first-child > th:last-child { border-top-right-radius: 8px; }

/* Sticky directly beneath .tab-nav (44px tall) so it's always clear what each column is, per
   explicit request - column headers never scroll out of view.
   Direct-child combinator (>), not descendant (space) - real bug found 2026-07-20 (Zoey caught a
   real screenshot showing the "See MOs" list's own header overlapping its first data row): the
   original 2026-07-15 fix used `#report-table thead th` (a descendant selector) specifically to
   exclude the nested "See MOs" table's own header from becoming sticky too - but a descendant
   selector matches at ANY nesting depth, and that nested table's `<thead>` genuinely is a
   descendant of #report-table (it lives inside one of #report-table's own `<td>` cells), so it
   was ALSO getting position: sticky this whole time, fighting the outer header for the same
   on-screen position. `>` requires <thead> to be #report-table's own DIRECT child, which the
   nested table's <thead> never is - correctly excluding it this time. Never caught earlier because
   sticky is turned off below the responsive breakpoint (see there), which is where this was being
   tested most recently. */
#report-table > thead > tr > th,
#pricelist-table > thead > tr > th,
#co-table > thead > tr > th {
  position: sticky;
  top: 44px;
  z-index: 20;
}

tbody td {
  padding: 10px 14px;
  border-bottom: 1px solid var(--card-border);
  text-align: center;
  vertical-align: top;
}
tbody tr.sku-row.row-alt,
tbody tr.breakdown-row.row-alt { background: var(--row-alt); }
tbody tr.sku-row:hover { background: color-mix(in srgb, var(--blue) 6%, transparent); }

.col-sku { min-width: 240px; text-align: left; }
.sku-row-inner { display: flex; align-items: flex-start; gap: 8px; }
.sku-title { font-weight: 700; color: var(--fg); }
.sku-code { color: var(--muted); font-size: 0.78rem; }

.expand-toggle {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 4px;
  transition: transform 0.15s ease;
}
.expand-toggle:hover { background: color-mix(in srgb, var(--blue) 10%, transparent); color: var(--blue); }
.expand-toggle[aria-expanded="true"] { transform: rotate(90deg); }

tr.breakdown-row td { background: transparent; cursor: default; }

/* Nested inside the breakdown panel - expands the MO list in place, within the already-open
   cost-breakdown section, rather than as its own independent sibling control. */
.mo-inline-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 12px;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1;
  padding: 4px 0;
  cursor: pointer;
}
.mo-inline-toggle:hover { color: var(--blue); }
.mo-inline-toggle[aria-expanded="true"] { color: var(--blue); }
.mo-inline-arrow { display: inline-block; font-size: 0.72rem; transition: transform 0.15s ease; }
.mo-inline-toggle[aria-expanded="true"] .mo-inline-arrow { transform: rotate(90deg); }
.mo-inline-panel { margin-top: 6px; }

/* Gives the nested "See MOs" table its own independent horizontal scroll, decoupled from the
   outer #report-table's auto-layout width - see app.js's moListPanel for why this matters. No
   sticky-header conflict here the way .table-wrap once had (the gotcha documented above): this
   table's own <thead> is never made sticky (deliberately excluded from that selector), so nothing
   inside depends on this wrapper's overflow staying `visible`. */
.mo-list-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mo-list-table { border-collapse: collapse; width: auto; min-width: 0; font-size: 0.82rem; }
.mo-list-table th {
  text-align: left;
  color: var(--muted);
  font-weight: 700;
  font-size: 0.68rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 4px 16px 6px 0;
  border-bottom: 1px solid var(--card-border);
  white-space: nowrap;
}
.mo-list-table td {
  padding: 5px 16px 5px 0;
  border-bottom: 1px solid var(--card-border);
  text-align: left;
  white-space: nowrap;
}
.mo-list-table tr:last-child td { border-bottom: none; }
.mo-list-code { font-weight: 600; }

/* Small inline status badges - "Old stock" (MO list) and "Over/Under time" (per-operation lines) */
.pill {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
  margin-left: 7px;
  vertical-align: middle;
  white-space: nowrap;
}
.pill-oldstock { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.pill-overtime { background: color-mix(in srgb, var(--bad) 16%, transparent); color: var(--bad); }
.pill-undertime { background: color-mix(in srgb, var(--good) 16%, transparent); color: var(--good); }
.pill-planned-time { background: color-mix(in srgb, var(--muted) 14%, transparent); color: var(--muted); cursor: help; }
/* Planned Overhead's interim rate (see Methodology tab) - purple to stay visually distinct from
   the warn/bad-toned pills above, since this isn't a problem flag, just a "not final yet" note. */
.pill-estimate { background: color-mix(in srgb, var(--purple) 16%, transparent); color: var(--purple); cursor: help; }
/* MO ran during MRPeasy's confirmed overhead-calculation breakage (Jan 12-Jul 13, 2026) - warn-
   toned like "Old stock" (a caution about data trust, not a hard error like the bad-toned pills). */
.pill-overhead-breakage { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); cursor: help; }

/* Per-MO expand toggle, sitting inline before that MO's own code in the "See MOs" list. */
.mo-detail-toggle {
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
  margin-right: 4px;
  padding: 0;
  transition: transform 0.15s ease;
}
.mo-detail-toggle:hover { color: var(--blue); }
.mo-detail-toggle[aria-expanded="true"] { color: var(--blue); transform: rotate(90deg); }
tr.mo-detail-row td {
  background: transparent;
  padding: 4px 16px 14px 22px;
  border-bottom: 1px solid var(--card-border);
  white-space: normal;
}
tr.mo-detail-row:last-child td { border-bottom: none; }
.mo-time-variance { text-align: center; font-size: 0.85rem; font-weight: 600; margin-top: 10px; }
.mo-time-variance-over { color: var(--bad); }
.mo-time-variance-under { color: var(--good); }
/* Flush, no box - plain text sitting on the row background, matching the reference mockup
   exactly (no border/background/radius around the breakdown content). text-align: left
   overrides the table's default centered `tbody td` text-align, which was otherwise inherited
   here and centering the column titles/empty-state text. */
.breakdown-panel { padding: 10px 4px 16px; text-align: left; }
.breakdown-cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  gap: 20px;
}
.breakdown-col-title {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--fg);
  margin-bottom: 10px;
}
.breakdown-coverage { font-weight: 400; color: var(--muted); font-size: 0.75rem; }
/* CO Profitability's own breakdown panel (co-app.js) stacks two .breakdown-col sections (Lines,
   then MOs) directly, rather than side-by-side via .breakdown-cols' grid - scoped to a direct
   sibling so it doesn't affect .breakdown-cols' own (unrelated) children elsewhere. */
.breakdown-panel > .breakdown-col + .breakdown-col { margin-top: 14px; }
/* Label and value sit close together (fixed label width + small gap) rather than being pushed
   to opposite edges of the column - that's what "too much distance" meant. */
.breakdown-line {
  display: flex;
  gap: 10px;
  font-size: 0.85rem;
  padding: 4px 0;
}
/* Wide enough to fit the longest label ("Labor (blended w/ machine)") without wrapping, so
   every value in a column starts at the same x position - a narrower fixed width let long
   labels push their own value further right than the shorter rows above/below them. */
.breakdown-line-label { color: var(--muted); min-width: 190px; white-space: nowrap; }
.breakdown-line-value { font-weight: 400; text-align: left; }
.breakdown-empty { color: var(--muted); font-size: 0.82rem; font-style: italic; max-width: 260px; }

/* Per-component/per-operation drill-down sitting directly under a Materials/Labor/Applied
   Overhead breakdown-line - indented and smaller than the summary line it belongs to, so it
   reads as "what that total is made of" rather than a peer figure. */
.detail-sub-list { margin: 0 0 6px 14px; }
.detail-sub-line {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 0.78rem;
  color: var(--muted);
  padding: 2px 0;
  border-left: 2px solid var(--card-border);
  padding-left: 8px;
}
.detail-sub-name { flex-shrink: 1; }
.detail-sub-code { color: var(--muted); }
.detail-sub-value { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* The specific SKU an individual MO built, shown at the top of its own expanded detail - distinct
   from the row's own pooled parent SKU, since one row can pool several color/variant children. */
.mo-detail-sku { margin-bottom: 10px; }
.mo-detail-sku-title { font-weight: 700; color: var(--fg); }
.mo-detail-sku-code { color: var(--muted); font-size: 0.82rem; }

.col-cost { min-width: 130px; font-weight: 600; }
.col-stack { min-width: 220px; text-align: left; }

.channel-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 2px 0;
  white-space: nowrap;
}
.channel-line .channel-name { color: var(--muted); display: flex; align-items: center; gap: 6px; }
.channel-line .channel-value { font-weight: 600; }

/* Margins-column tier dots (Retail/Online/Dealer/Commercial) - Sales column doesn't use these,
   stackLine() only passes a dotClass for the Margins stack. */
.channel-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.channel-dot.Retail { background: var(--blue); }
.channel-dot.Online { background: var(--green); }
.channel-dot.Dealer { background: var(--gold); }
.channel-dot.Commercial { background: var(--purple); }

.cell-na { color: var(--muted); }
.margin-positive { color: var(--good); }
.margin-negative { color: var(--bad); }
.flag-partial::after {
  content: " *";
  color: var(--warn);
  font-weight: 700;
}

.empty-state, .error-state {
  text-align: center !important;
  color: var(--muted);
  padding: 24px !important;
}
.error-state { color: var(--bad); }

/* Manage Pricelist editable grid */
.pl-input {
  font: inherit;
  color: var(--fg);
  background: var(--page-bg);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 4px 8px;
  width: 100%;
  box-sizing: border-box;
}
.pl-price { max-width: 110px; }
.pl-remove-row {
  font: inherit;
  color: var(--muted);
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px 8px;
}
.pl-remove-row:hover { color: var(--bad); }

/* Workstation Rates tab */
.wr-paste-panel {
  background: var(--row-alt);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 12px 14px;
  margin-bottom: 14px;
}
.wr-paste-help { margin: 0 0 8px; font-size: 0.82rem; color: var(--muted); }
.wr-paste-textarea {
  font: inherit;
  font-family: "SF Mono", Consolas, "Courier New", monospace;
  font-size: 0.82rem;
  color: var(--fg);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 8px 10px;
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
}
.wr-paste-actions { display: flex; gap: 8px; margin-top: 10px; }
.wr-type-code { font-weight: 600; }
.wr-help { margin-top: 20px; }
.wr-help h3 { margin: 0 0 8px; font-size: 0.95rem; font-weight: 800; color: var(--fg); }
.wr-help p, .wr-help li { font-size: 0.85rem; line-height: 1.55; color: var(--fg); }
.wr-help ol { margin: 0 0 12px; padding-left: 22px; }
.wr-help li { margin-bottom: 4px; }

.footnote {
  margin-top: 12px;
  font-size: 0.78rem;
  color: var(--muted);
  max-width: 900px;
}

/* Methodology tab - plain prose sections, reusing the app's existing type/color scale rather
   than introducing a second visual language for a page that's read, not interacted with. */
.methodology-card { max-width: 900px; }
.method-block { margin: 0 0 26px; }
.method-block:last-child { margin-bottom: 0; }
.method-block h3 {
  margin: 0 0 8px;
  font-size: 0.95rem;
  font-weight: 800;
  color: var(--fg);
}
.method-block p { margin: 0 0 10px; font-size: 0.88rem; line-height: 1.55; color: var(--fg); }
.method-block code {
  background: var(--row-alt);
  border: 1px solid var(--card-border);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 0.85em;
}
.method-formula {
  font-family: "SF Mono", Consolas, "Courier New", monospace;
  font-size: 0.82rem;
  background: var(--row-alt);
  border: 1px solid var(--card-border);
  border-left: 3px solid var(--blue);
  border-radius: 6px;
  padding: 10px 14px;
  margin: 0 0 10px;
  color: var(--fg);
}
.method-note { font-size: 0.82rem; color: var(--muted); }
.method-list { margin: 0 0 10px; padding-left: 22px; font-size: 0.88rem; line-height: 1.55; }
.method-list li { margin-bottom: 6px; }

/* Small/narrow screens. Tightens spacing/type scale everywhere, and stacks the two-column cost
   breakdown into one column - two 200px-min columns side by side just doesn't fit under ~480px
   of actual content width.
   Threshold widened from 720px to 1024px 2026-07-20, found real (not assumed): the table's own
   desktop min-width (760px) plus surrounding page chrome forces real page-level horizontal
   scrolling anywhere from 721px up to ~1019px - a real, common browser-window range (a
   non-maximized window, a smaller laptop display, a window shared with another app), not just a
   phone. Verified empirically across a full width sweep (700-1100px in 10px steps) that 1024px is
   safely past where the overflow actually stops (0px confirmed from 1020px up), not a guessed
   round number. */
@media (max-width: 1024px) {
  main { padding: 14px 12px 32px; }
  .topbar { padding: 10px 14px; flex-wrap: wrap; row-gap: 8px; }
  .topbar-title { font-size: 1.05rem; }
  .topbar-right { font-size: 0.78rem; }
  .tab-nav { padding: 0 10px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tab-link { padding: 10px 12px; font-size: 0.82rem; white-space: nowrap; }
  .subbar, .upload-bar, .settings-bar { padding: 8px 14px; font-size: 0.78rem; }
  .search-bar { margin-bottom: 10px; }
  .search-input { max-width: none; }
  .card { padding: 14px 12px; border-radius: 8px; }
  .card-header h2 { font-size: 1.02rem; }
  .card-subtitle { font-size: 0.8rem; }

  /* The column headers' position: sticky (see the big comment further up) deliberately depends
     on .table-wrap having no overflow of its own, so a table wider than the viewport scrolls the
     whole page instead - a fine trade on desktop, but not on a phone, where scrolling the entire
     page sideways (topbar and all) to read one wide table is disorienting. Below this breakpoint,
     trade the sticky header back for a horizontal scrollbar scoped to just the table itself
     (position: static overrides the sticky rule above it by simple source order) - a card that
     scrolls sideways under a thumb is a completely normal, expected mobile pattern.
     Safe to bring back here (per the CSS Overflow spec, overflow-x: auto silently promotes
     overflow-y to auto too, which is exactly the mechanism that broke sticky positioning in the
     first place) only because sticky is also turned off at this same breakpoint, below. */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  #report-table > thead > tr > th, #pricelist-table > thead > tr > th, #co-table > thead > tr > th { position: static; }
  table { min-width: 560px; font-size: 0.82rem; }
  thead th { padding: 8px 8px; font-size: 0.64rem; }
  tbody td { padding: 8px 8px; }
  .col-sku { min-width: 160px; }
  .col-cost { min-width: 92px; }
  .col-stack { min-width: 150px; }

  .breakdown-cols { grid-template-columns: 1fr; gap: 16px; }
  .breakdown-panel { padding: 8px 2px 12px; }
  .breakdown-line-label { min-width: 130px; }
  .mo-list-table { font-size: 0.76rem; }
  .mo-list-table th, .mo-list-table td { padding: 4px 10px 5px 0; }

  /* A `<td colspan>` in an auto-layout table has no width of its own to hand down to its
     descendants - it sizes itself to fit its content (bottom-up: column widths are DERIVED from
     cell content, not the other way around), so any wide nested content (a long unwrapped
     component name, or the whole nested "See MOs" table) rendered at its full natural width and
     quietly forced the ENTIRE outer table wider - which then widens every OTHER row's columns too,
     even ones with nothing expanded.
     First attempt here used `display: block` on the cell, which turned out to be wrong (found by
     measuring the real rendered widths, not assumed): overriding a table-cell's `display` drops
     its `colspan` entirely (colspan only means something for real table-cell boxes), so the box
     collapsed down to a SINGLE spanned column's width (~140px) instead of all 5 (or 7, for the
     nested "See MOs" per-MO row) columns combined - and since that collapse compounds at each
     level of nesting (this row's own detail lives inside another such cell, inside the nested
     "See MOs" table), content ended up genuinely clipped, not just scrollable.
     The fix that actually works and keeps colspan intact: `width: 1%` is a well-established
     auto-layout hint, not a real box size - it tells the algorithm "don't size the table around
     THIS cell's own content," so column widths are driven entirely by the real header/data cells
     instead. The cell still renders (post-layout) at its true full colspan width, same as before -
     only its CONTRIBUTION to that computation is suppressed. Content still too wide for the
     resulting width genuinely scrolls within its own nested region (.mo-list-scroll already does
     this for the "See MOs" table; the flex-wrap fix below handles individual long lines). */
  tr.breakdown-row > td, tr.mo-detail-row > td { width: 1%; }
  .detail-sub-line { flex-wrap: wrap; row-gap: 2px; }
  /* max-width, not just flex-basis: 100% - once the cell above correctly keeps its full colspan
     width (which can genuinely be 600-700px, well more than a phone screen), "100% of available
     space" is no longer a small number, so text renders as one long unwrapped line again, just a
     legitimately-wide one now instead of one that silently inflated the table. A real pixel cap
     here makes the drill-down content readable on its own terms, independent of whatever the
     surrounding table happened to resolve to. */
  .detail-sub-name, .detail-sub-value { flex: 1 1 100%; max-width: 280px; }
  .detail-sub-value { text-align: left; white-space: normal; }

  .methodology-card { max-width: 100%; }
  .method-formula { font-size: 0.76rem; padding: 8px 10px; white-space: pre-wrap; }
  .method-block h3 { font-size: 0.9rem; }
}

@media (max-width: 460px) {
  .topbar-left { gap: 10px; }
  .topbar-title { font-size: 0.95rem; }
  .topbar-divider { display: none; }
  .topbar-right { width: 100%; justify-content: flex-end; }
  .settings-bar { flex-direction: column; align-items: flex-start; gap: 6px; }
  .col-sku { min-width: 140px; }
}
