/* ═══════════════════════════════════════════════════════════════════════════
   Market page v2 — styles.css (the "looks" drawer).
   RELOCATED 1:1 from market.html's <style> block (the 2026-07 file split —
   see Sales Dashboard/SPLIT-HANDOFF.md for the pattern and RULEBOOK Rule 6's
   split rule). Loaded in the same cascade position the inline block had:
   BEFORE /Shared Data/shell.css, so shell.css keeps winning ties exactly as
   it did on the single-file page.
   ═══════════════════════════════════════════════════════════════════════════ */
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f6fa; color: #2d3436; }

  /* Sidebar (classic skeleton — shell.js restyles it) */
  .sidebar { position: fixed; top: 0; left: 0; width: 150px; height: 100vh; background: #1a1f2e; color: #fff; display: flex; flex-direction: column; z-index: 100; }
  .sidebar .logo { padding: 14px 10px; border-bottom: 1px solid #2d3450; display: flex; align-items: center; gap: 8px; }
  .sidebar .logo svg { width: 28px; height: 28px; flex-shrink: 0; }
  .sidebar .logo span { font-size: 16px; font-weight: 800; font-style: italic; letter-spacing: 1.5px; color: #e8eaed; }
  .sidebar nav { flex: 1; padding: 12px 0; }
  .sidebar nav a { display: flex; align-items: center; gap: 10px; padding: 11px 18px; color: #8892a4; text-decoration: none; font-size: 13px; font-weight: 500; transition: all .15s; }
  .sidebar nav a:hover { background: #252b3d; color: #fff; }
  .sidebar nav a.active { background: #252b3d; color: #ff9900; border-left: 3px solid #ff9900; }
  .sidebar nav a .icon { width: 18px; text-align: center; font-size: 15px; }
  .sidebar .sidebar-footer { padding: 14px 14px; border-top: 1px solid #2d3450; font-size: 11px; color: #555e70; }

  .main { margin-left: 150px; }
  .topbar { background: #232f3e; color: #fff; padding: 14px 28px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 50; }
  .topbar h1 { font-size: 18px; font-weight: 600; letter-spacing: .3px; }
  .topbar .subtitle { font-size: 12px; color: #a0aec0; margin-top: 2px; }
  .refresh-btn { background: #2563eb; color: #fff; border: 0; border-radius: 8px; padding: 7px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .token-chip { font-size: 11.5px; font-weight: 600; color: #5b6472; background: #eef1f6; border: 1px solid #dfe4ec; border-radius: 999px; padding: 4px 11px; white-space: nowrap; cursor: help; }
  .token-chip.low { color: #b45309; background: #fef4e6; border-color: #f3d9b0; }
  .analyze-btn { background: #2563eb; color: #fff; border: 0; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .analyze-btn:hover:not(:disabled) { background: #1e4fd1; }
  .analyze-btn:disabled { opacity: .55; cursor: default; }
  .analyze-dl-btn { background: #e3f3e9; color: #2f7d52; border: 1px solid #bfe3cd; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .analyze-dl-btn:hover { background: #d4ecdd; }
  .reports-wrap { position: relative; display: inline-block; }
  .reports-menu { position: absolute; top: 100%; left: 0; margin-top: 4px; background: #fff; border: 1px solid #d7dde6; border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,.14); z-index: 200; min-width: 280px; max-height: 340px; overflow: auto; }
  .report-item { display: flex; align-items: center; gap: 10px; padding: 8px 12px; cursor: pointer; border-bottom: 1px solid #f0f2f5; font-size: 12px; }
  .report-item:last-child { border-bottom: 0; }
  .report-item:hover { background: #f4f7fd; }
  .report-item .ri-main { font-weight: 600; color: #1a1d23; }
  .report-item .ri-sub { color: #8a93a2; margin-left: auto; white-space: nowrap; }
  .report-item .ri-dl { color: #2f7d52; font-weight: 700; }
  /* ── Compare Products: full-screen side-by-side comparison overlay ──
     Products as COLUMNS, RANKED by market share (Seller 1 = biggest), spec
     rows down the side — the in-app version of the team's Excel comparison
     sheets. Numeric rows are heat-shaded soft-red→green (worst→best,
     normalised to each row's range). Every comparison is saved
     (amazon.market_comparisons) and reopens frozen from Comparisons. */
  .cmp-overlay { position: fixed; inset: 0; background: rgba(20,24,33,.5); z-index: 400; display: flex; align-items: center; justify-content: center; padding: 20px; }
  /* The card sizes to its CONTENT (each product is a fixed, readable column),
     capped at the viewport — so few products = a tidy centred card, not a
     stretched one with big empty gaps; many products just scroll. */
  .cmp-card { background: #fff; border-radius: 14px; box-shadow: 0 16px 48px rgba(0,0,0,.28); width: auto; max-width: 95vw; max-height: 92vh; display: flex; flex-direction: column; overflow: hidden; }
  .cmp-head { display: flex; align-items: center; gap: 10px; padding: 14px 20px; border-bottom: 1px solid #e6eaf2; }
  .cmp-head h2 { margin: 0; font-size: 17px; color: #1a1d23; }
  .cmp-head .cmp-when { font-size: 12px; color: #5b6472; }
  .cmp-head .cmp-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
  .cmp-close { background: none; border: 0; font-size: 20px; color: #5b6472; cursor: pointer; line-height: 1; padding: 4px 8px; font-family: inherit; }
  .cmp-close:hover { color: #1a1d23; }
  /* The window's body pads its own sides. Without this every block inside a
     popup — the summary line, each fact row, the advice box, the note — started
     hard against the frame (owner 2026-08-15: "no gaps between the text and the
     left border of the window"). Measured: 5 blocks at a 0–2px gap. It belongs
     HERE and not on each block, because the next block added would have the
     same fault. Tables opt out: a .table-scroll wants the full width so its
     sideways scrollbar reaches both edges. */
  .cmp-scroll { overflow: auto; flex: 1; padding: 14px 20px 16px; }
  .cmp-scroll > .table-scroll { margin: 0 -20px -16px; padding: 0 20px; }
  .cmp-scroll > .seas-loading, .cmp-scroll > .seas-empty { margin: 0; }
  .cmp-table { border-collapse: separate; border-spacing: 0; width: auto; }
  .cmp-table th, .cmp-table td { border-bottom: 1px solid #edf0f5; border-right: 1px solid #f1f4f8; padding: 10px 16px; font-size: 13.5px; text-align: center; vertical-align: middle; background: #fff; width: 232px; min-width: 232px; }
  .cmp-table td.cmp-label, .cmp-table th.cmp-label { position: sticky; left: 0; text-align: left; font-weight: 700; color: #3f4653; background: #f7f9fc; z-index: 2; width: 172px; min-width: 172px; max-width: 172px; font-size: 13px; }
  .cmp-table thead th { position: sticky; top: 0; z-index: 3; background: var(--cg-th-bg); border-bottom: 2px solid var(--cg-th-line); padding-top: 14px; padding-bottom: 14px; }
  /* the frozen label column paints itself; its HEADER cell follows the header row */
  .cmp-table thead th.cmp-label { background: var(--cg-th-bg); color: var(--cg-th-fg); }
  .cmp-table thead th.cmp-label { z-index: 4; }
  .cmp-rank { font-size: 16px; font-weight: 800; color: #1a1d23; }
  .cmp-rank .cmp-ours-tag { font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; background: #e3f3e9; color: #2f7d52; border-radius: 20px; padding: 2px 8px; margin-left: 6px; vertical-align: 2px; }
  .cmp-img { width: 132px; height: 132px; object-fit: contain; border-radius: 8px; background: #f5f6fa; }
  .cmp-noimg { display: inline-block; width: 132px; height: 132px; border-radius: 8px; background: #f1f3f6; }
  .cmp-title { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; line-height: 1.35; font-size: 12.5px; }
  .cmp-table tr.cmp-sec td { background: #eef2fb; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #46618f; text-align: left; padding-top: 7px; padding-bottom: 7px; }
  .cmp-btn { background: #2563eb; color: #fff; border: 0; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .cmp-btn:disabled { opacity: .45; cursor: default; }
  .cmp-dl { background: #e3f3e9; color: #2f7d52; border: 1px solid #bfe3cd; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .cmp-dl:hover { background: #d4ecdd; }
  .cmp-zoom { cursor: zoom-in; }
  .cmp-play { display: inline-flex; align-items: center; gap: 4px; color: #2563eb; font-weight: 600; cursor: pointer; }
  .cmp-play:hover { text-decoration: underline; }
  .cmp-vids { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
  .cmp-vids .cmp-play { background: #eef4ff; border: 1px solid #cfe0fb; border-radius: 6px; padding: 3px 9px; }
  .cmp-gallery { display: flex; flex-wrap: wrap; gap: 5px; justify-content: center; }
  .cmp-thumb { width: 52px; height: 52px; object-fit: contain; border-radius: 5px; background: #f5f6fa; }
  .cmp-bullets .cmp-blist { margin: 0; padding-left: 16px; text-align: left; font-size: 12px; line-height: 1.35; color: #2d3436; }
  .cmp-bullets .cmp-blist li { margin: 2px 0; }
  .cmp-table td.cmp-bullets { text-align: left; vertical-align: top; }
  .cmp-kwrank .cmp-kw { display: block; font-size: 10.5px; color: #8a93a2; margin-top: 1px; max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .cmp-amz-vid { color: #2563eb; font-weight: 600; text-decoration: none; white-space: nowrap; }
  .cmp-amz-vid:hover { text-decoration: underline; }
  .mkt-units-click { cursor: pointer; border-bottom: 1px dotted #9aa7b2; }
  .mkt-units-click:hover { color: #2563eb; border-bottom-color: #2563eb; }
  .mkt-badge-pop { position: fixed; z-index: 99999; background: #232f3e; color: #e8eaed; font-size: 12px; line-height: 1.5; padding: 8px 12px; border-radius: 6px; max-width: 300px; box-shadow: 0 4px 14px rgba(0,0,0,.28); }
  .cmp-sec-caret { display: inline-block; color: #8a93a2; font-size: 11px; transition: transform .15s; }
  .cmp-sec-caret.open { transform: rotate(90deg); }
  /* Click-to-enlarge lightbox for images + the product video. */
  .cmp-lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.82); z-index: 500; display: flex; align-items: center; justify-content: center; cursor: zoom-out; padding: 24px; }
  .cmp-lightbox img, .cmp-lightbox video { max-width: 92vw; max-height: 88vh; border-radius: 8px; background: #fff; }
  /* Video: give it a real base size so it opens BIG, not the browser's tiny
     300x150 default (the intrinsic size isn't known until it loads). */
  .cmp-lightbox video { width: min(1100px, 92vw); height: auto; background: #000; }
  .cmp-lb-vid { display: flex; flex-direction: column; align-items: center; gap: 12px; cursor: default; }
  .cmp-lb-open { color: #fff; font-weight: 600; font-size: 14px; text-decoration: underline; }
  .cmp-lb-open:hover { color: #dbe6ff; }
  .refresh-btn:hover { background: #1e4fd1; }

  /* Comfortable width: wide enough for the full table, capped so a big
     monitor doesn't stretch everything apart (tables still scroll if needed). */
  /* FULL width like Sales/Keywords — no max-width cap. The 1440px cap made
     the card stop mid-screen on wide monitors and the table looked cropped
     (asked repeatedly 2026-07-14; the cap predated the wide tables). */
  .content { padding: var(--cg-row, 14px) var(--cg-gutter, 28px); }   /* page rhythm: gaps come from --cg-row / --cg-gutter (shell.css, RULEBOOK Rule 6) */
  /* Notices read as proper cards — same inset, radius and shadow as the timebar
     / summary cards below them, with a colour accent instead of a raw bar. */
  .app-notice { padding: 12px 18px; border-radius: 10px; font-size: 13px; margin: 0 0 14px; box-shadow: 0 1px 3px rgba(0,0,0,.06); }
  .app-notice.info { background: #eef6ff; color: #1e3a8a; border-left: 3px solid #2563eb; }
  .app-notice.danger { background: #fef2f2; color: #b42318; font-weight: 600; border-left: 3px solid #b42318; }

  .table-card { background: #fff; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,.06); overflow: hidden; margin-bottom: var(--cg-row, 14px); }
  /* Tables never get cut off: on a narrow window they scroll sideways inside
     their own strip (same behavior as the Sales/PPC tables). */
  .table-scroll { overflow-x: auto; }
  /* Fixed horizontal-scrollbar proxy pinned to the viewport bottom (Sales-
     dashboard pattern): the niche table strip is tall, so its own bottom
     scrollbar can sit below the fold — this mirror is ALWAYS reachable without
     scrolling the page down. It only shows when the strip overflows sideways
     AND its own scrollbar is off-screen. */
  .mkt-sticky-scroll { position: fixed; bottom: 0; z-index: 300; overflow-x: auto; overflow-y: hidden; height: 15px; background: rgba(245,246,248,0.97); border-top: 1px solid #cbd5e0; display: none; }
  .mkt-sticky-scroll .mkt-sticky-inner { height: 1px; }
  .mkt-sticky-scroll::-webkit-scrollbar { height: 12px; }
  .mkt-sticky-scroll::-webkit-scrollbar-thumb { background: #b3bdca; border-radius: 6px; }
  .mkt-sticky-scroll::-webkit-scrollbar-thumb:hover { background: #98a5b6; }
  .mkt-sticky-scroll::-webkit-scrollbar-track { background: #f1f3f7; }
  .table-card h2 { font-size: 14px; padding: 14px 18px; border-bottom: 1px solid #eef0f3; display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
  .table-card h2 .asof { font-size: 11.5px; font-weight: 400; color: #98a1b0; }
  /* The filter bar is the shell's `.filters-bar` now (2026-09-03) — the card
     chrome, the padding, the margins and the label style all come from
     shell.css, so nothing about them is declared here (RULEBOOK Rule 6: "the
     default is CODE, not memory"). What IS still ours: this card holds the
     research-market picker, whose drop-down has to hang BELOW the card, so it
     must not clip (owner 2026-08-12: the list was clipped to a 4px sliver and
     picking a market looked impossible). */
  .filters-bar.top-card { overflow: visible; }
  /* The Market ASINs button stays lit while its card is open */
  /* CLOSED = solid blue "open me". OPEN = inverted (white with a blue frame),
     reading as pressed and matching the blue panel it opened right below —
     plus the label itself flips to "Hide Market ASINs". */
  #asinsBtn.on { background: #fff; border: 2px solid #2563eb; color: #2563eb; padding: 4px 10px; box-shadow: inset 0 2px 5px rgba(37,99,235,.14); }

  /* ── The Market ASINs card is a SETUP panel, not data ──────────────────
     It used to look exactly like the market table below it, so nobody could
     tell which table they were reading (user report 2026-07-30). It now wears
     a completely different skin: blue frame, blue titled header, tinted body,
     and its own grey table head — unmistakably "the settings drawer". */
  /* Deliberately NARROW and tight — a small window where you define ASINs,
     nothing like the full-width market table (user request 2026-07-30). */
  #asinsCard { background: #f4f8ff; border: 2px solid #2563eb; box-shadow: 0 8px 26px rgba(37,99,235,.16); max-width: 880px; }
  #asinsCard table { font-size: 12px; }
  #asinsCard table th { padding: 7px 9px; font-size: 10.5px; }
  #asinsCard table td { padding: 5px 9px; }
  #asinsCard .fname { font-size: 12px; }
  #asinsCard .fnote { font-size: 10.5px; }
  #asinsCard .edit-input { width: 108px; padding: 3px 6px; font-size: 12px; }
  #asinsCard .remove-btn { padding: 2px 8px; font-size: 11px; }
  #asinsCard .add-form { padding: 10px 12px; gap: 7px; }
  #asinsCard .add-form input[type="text"] { padding: 5px 8px; font-size: 12px; }
  #asinsCard .add-form input#f_asin { width: 190px; }
  #asinsCard .add-form input#f_label { width: 120px; }
  #asinsCard > h2 { background: #2563eb; color: #fff; border-bottom: 0; padding: 12px 18px; }
  #asinsCard > h2 .asof { color: #d5e4ff; }
  #asinsCard > h2 .rename-btn { background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.5); color: #fff; }
  #asinsCard > h2 .rename-btn:hover { background: #fff; color: #2563eb; }
  #asinsCard > h2 .kind-btn { background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.5); color: #fff; border-radius: 20px; padding: 2px 9px; }
  #asinsCard > h2 .kind-btn:hover { background: #fff; color: #2563eb; text-decoration: none; }
  #asinsCard > h2 .mkt-kind { color: #fff; border-color: rgba(255,255,255,.55); background: rgba(255,255,255,.2); }
  .setup-tag { font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; background: rgba(255,255,255,.2); border: 1px solid rgba(255,255,255,.55); border-radius: 20px; padding: 3px 9px; margin-right: 9px; }
  .setup-note { padding: 9px 18px; font-size: 12px; color: #46618f; background: #e8f0fe; border-bottom: 1px solid #d3e0f7; }
  #asinsCard .add-form { background: #fff; border-bottom: 1px solid #d9e4f5; }
  #asinsCard .table-scroll { background: #fff; margin: 0 12px 12px; border: 1px solid #dbe5f4; border-radius: 8px; }
  #asinsCard table thead th { background: var(--cg-th-bg); color: var(--cg-th-fg); }
  #asinsCard .empty { margin: 0 12px 12px; background: #fff; border: 1px solid #dbe5f4; border-radius: 8px; }
  .setup-done { display: block; margin: 0 12px 14px auto; }
  table { width: 100%; border-collapse: collapse; font-size: 12px; }
  /* Table concept copied from the Keywords page (the house look): headers
     may wrap to two lines so columns stay narrow, and everything is
     centered except product names. */
  /* Geometry (centring, wrapping, padding, height) comes from the HOUSE TABLE
     STANDARD in Shared Data/shell.css — swept 2026-08-06. This page's values
     already matched it; only colour/weight stay here. */
  /* Headers: SENTENCE CASE, not shouty uppercase. Uppercase + letter-spacing
     is the single biggest reason a header eats width and reads as noise; X-Ray
     uses plain sentence case and the labels get shorter AND calmer at once. */
  /* header COLOURS come from the shell's house table tokens (Rule 6 §5a) */
  thead th { font-size: 11.5px; font-weight: 600; text-transform: none; letter-spacing: 0; }
  thead th.sortable { cursor: pointer; }
  thead th.sortable:hover { color: #2563eb; }
  thead th .sort-arrow { color: #2563eb; font-size: 9px; margin-left: 3px; }
  /* ⓘ info badge in the header corner: click it to read the column's meaning
     (a normal click on the label still sorts). Absolutely placed so it never
     shifts the label; every .niche-card th is already position:sticky, which is
     its positioning context. */
  /* PINNED to the header's top-right corner, not inline (owner 2026-08-12:
     "H10 columns are more compact width wise, why aren't ours?"). Two reasons
     ours were wider: the H10 headers carry no ⓘ at all, and ours sat INSIDE
     the label, so every column had to be ~16px wider just to hold it. The
     shell already reserves 15px of right padding on every th for exactly this
     kind of corner control, so moving it there costs no width and no height —
     and the label gets the space back. */
  .th-i { position: absolute; right: 4px; top: 2px; width: 8px; height: 10px; line-height: 10px;
    text-align: center; cursor: pointer; color: #aab2c0; background: none; border: 0; }
  .th-i::before { content: 'i'; font-size: 9px; font-weight: 700; font-style: italic;
    font-family: Georgia, "Times New Roman", serif; text-transform: none; letter-spacing: 0; }
  .th-i:hover { color: #2563eb; }
  /* An empty curve cell explains itself on click (owner 2026-08-12). Marked
     with a dotted underline so it reads as "there is something behind this". */
  .curve-why { border-bottom: 1px dotted #c8d0dc; cursor: pointer; }
  .curve-why:hover { color: #2563eb; border-bottom-color: #2563eb; }
  .niche-card thead th .cg-grip::before { border-right: 1px solid #eef1f5; }
  .niche-card thead th .cg-grip:hover::before, .niche-card thead th .cg-grip.on::before { border-right: 2px solid #2563eb; }
  /* Targeted-by coverage chips — same style family as the Sales dashboard's
     ACOS chips: red = competitor with NO product-target at all, orange =
     only paused targets aim at it. */
  .tg-none { background: #ef9a9a; color: #b71c1c; padding: 2px 8px; border-radius: 4px; font-weight: 700; }
  .tg-paused { background: #ffe0b2; color: #e65100; padding: 2px 8px; border-radius: 4px; font-weight: 700; }
  /* Rating + review count: bold (they're primary quality signals). */
  .niche-card td.col-strong { font-weight: 400; }   /* rating + review count: no longer bold (owner 2026-08-12) */
  /* A brand that makes >40% of this market's estimated revenue — its name gets
     a light-red BACKGROUND chip (same style as the Targeted-by red) on every
     one of its rows: beware, it dominates. */
  .brand-dom { background: #ef9a9a; color: #b71c1c; padding: 2px 8px; border-radius: 4px; font-weight: 700; }
  /* The niche table is sized DETERMINISTICALLY (sizeNicheTable in ui.js sets
     fixed layout + one explicit width per column) — auto-layout was handing
     random extra width to whichever column had the longest content, making
     the two revenue columns different for no reason. Columns stay draggable. */
  /* The parent column's "+N untracked siblings" note sits CENTERED on its own
     line UNDER the revenue figure, not squeezed next to it. */
  .niche-card .prev-extra { display: block; text-align: center; font-size: 11px; font-weight: 600; color: #b45309; margin-top: 1px; }
  /* "−N" = products you removed, already taken OFF this total. Red, and a
     different sign from the amber "+N" siblings that were added IN, so the two
     can never be read as the same thing. */
  .niche-card .prev-excl { display: block; text-align: center; font-size: 11px; font-weight: 600; color: #b91c1c; margin-top: 1px; }
  /* The same idea from the other side: a row in "Not in the table" saying its
     figure is the WHOLE family, siblings still upstairs included (owners
     2026-09-08). Amber, not red — nothing is wrong here, it is a reading note. */
  .niche-card .prev-whole { display: block; text-align: center; font-size: 11px;
    font-weight: 600; color: #b45309; margin-top: 1px; cursor: help; }
  /* "⚠" = this family has MORE variations than we read (owners 2026-09-07).
     It rides the figure itself rather than its own line, because it is a
     warning ABOUT that number, not another quantity: "+N" and "−N" say how
     many siblings went in or came off, this says the number is short. Red,
     and INLINE so it cannot be mistaken for either count. */
  .niche-card .prev-cap { color: #b91c1c; font-weight: 700; margin-left: 3px; cursor: help; }
  /* The market-level line, at the very top of the card, before any figure is
     read. Amber, not red: nothing is broken — Amazon simply lets a family be
     bigger than we fetch, and the figures below are the part we can see. */
  .cap-note { margin: 0 0 10px; padding: 7px 10px; border-radius: 6px;
              background: #fffbeb; border: 1px solid #fde68a; color: #92400e;
              font-size: 12px; font-weight: 600; cursor: help; }
  /* Parent est. revenue — the column the table ranks by, by default: bold, in
     the header AND the body, so the table's backbone is obvious at a glance. */
  thead th.th-primary { color: #1a1d23; font-weight: 700; }
  .niche-card td.col-primary { font-weight: 700; }
  /* .num and .name-col alignment, and vertical centring, are the shell's
     (house standard) — not re-declared here.
     house-table-ok: on THIS page every column except the product name is a
     figure, so the whole body centres and `.name-col` (the shell's identity
     marker) pulls the name column back to the left. Stating it once here beats
     tagging ~50 cells; the shell still owns what centred/left MEAN. */
  tbody td { padding: 2px 7px; border-top: 1px solid #f2f4f7; text-align: center; }
  tr.niche-head td { text-align: left; }
  /* Product cell: dot + link + badges stay on ONE line (they used to wrap
     into a 3-line-tall cell when the column got narrow). */
  td.name-col .fname { display: flex; align-items: center; white-space: nowrap; }
  /* Like Sales/Keywords with many columns: the table gets the width it needs
     and the .table-scroll strip scrolls sideways — columns never get squeezed
     into unreadable slivers just to fit the window. */
  .niche-card .table-scroll table { min-width: 1900px; }
  /* Once the shared resizer freezes the table to fixed layout (first drag /
     restored widths), drop the min-width so dragging a data column NARROWER
     actually shrinks it instead of the min-width forcing the freed space back
     into the columns (that redistribution is why resize felt broken here but
     worked on Keywords, which has no min-width). */
  .niche-card .table-scroll table[data-cg-frozen] { min-width: 0; }
  /* FOUR FROZEN COLUMNS: checkbox · # · picture · Title. The first three are
     pinned at 34 · 36 · 34px and each one's sticky `left` below is the sum of
     the widths before it, so those three are NOT the reader's to change —
     their drag grips are hidden on the very next line, and that is what keeps
     the offsets honest. Title is the LAST sticky column, so no offset depends
     on ITS width: it can be dragged as freely as any column to its right, and
     its grip shows normally. */
  .niche-card thead th:nth-child(1) .cg-grip, .niche-card thead th:nth-child(2) .cg-grip, .niche-card thead th:nth-child(3) .cg-grip { display: none; }
  /* Sales-style frozen pane: the strip is a height-capped scroll pane (so its
     horizontal scrollbar is ALWAYS on screen — no scrolling down to find it),
     the header row sticks to the pane top, and the first two columns
     (checkbox · Title) stick left with solid backgrounds. */
  /* NO PAGE-LOCAL HEIGHT (RULEBOOK Rule 6 §8). The two viewport fractions
     that used to be here — calc(100vh - 150px) and 72vh — were the cause of
     the jump the owner reported on 2026-08-27: toggling Comparison columns
     rebuilds this card, so the pane is a BRAND NEW element with no inline
     height, and until the shell adopted it (a 60–150ms debounce, seconds on a
     2,000-product market) it opened at the CSS fraction — far taller than the
     house height — then snapped back. The pane is declared `data-cg-pane` in
     ui.js and the shell owns its height; there is nothing tall to fall back
     to any more. Do NOT re-add a fraction or a pixel guess here. */
  .niche-card .table-scroll { overflow: auto; }
  /* Header row: a clear grey band with a solid divider, so it reads as HEADERS
     (not white-on-white) and is visibly separated from the toolbar above. The
     two frozen header cells get the SAME band (they used to stay #fff, which is
     why the Title header looked white while the rest had colour). */
  /* Headers use the SHELL header colour (#fafbfc, like every other dashboard)
     with darker text + a solid divider so they read clearly. Do NOT set a
     background on the frozen header cells (that was making Title a different
     shade) — only the frozen BODY cells need an opaque white. */
  /* A near-white header with ONE hairline under it — no grey band. The
     !important still has to be here: it is what stops the frozen columns
     painting their own #fff and looking like a different header. */
  .niche-card thead th { position: sticky; top: 0; background: var(--cg-th-bg) !important; color: var(--cg-th-fg); z-index: 11; border-bottom: 1px solid var(--cg-th-line); }
  .niche-card th:nth-child(1), .niche-card td:nth-child(1) { position: sticky; left: 0; width: 34px; min-width: 34px; max-width: 34px; z-index: 12; }
  /* # : the market rank (1 = biggest by revenue), a super-narrow frozen column
     right after the checkbox — all ASINs under one parent share the parent’s
     number, so it stays in the frozen pane like an anchor while scrolling. */
  .niche-card th:nth-child(2), .niche-card td:nth-child(2) { position: sticky; left: 34px; width: 36px; min-width: 36px; max-width: 36px; z-index: 12; text-align: center; }
  /* Image: a small product thumbnail (house style, like Sales/Inventory), frozen
     between the rank and the Title so it stays on screen when scrolling sideways. */
  .niche-card th:nth-child(3), .niche-card td:nth-child(3) { position: sticky; left: 70px; width: 34px; min-width: 34px; max-width: 34px; z-index: 12; text-align: center; padding: 2px; }
  /* ⚠ TITLE CARRIES NO WIDTH HERE, AND MUST NOT (owners 2026-09-08: "when
     dragging the title column right vertical border, to widen it, it doesn't
     drag well, and it pulls the picture and checkbox with it. the other
     columns to the right do get dragged well").
     It used to read `width:150px; min-width:120px; max-width:150px` — which
     is also the opposite of what the comment above claimed. What that cap did:
     the drag writes an inline width on the header, the cap held the cell at
     150px anyway, and the TABLE still grew by exactly what you dragged — so
     the browser had surplus width to hand out and spread it across the
     columns, checkbox and picture included. Their sticky offsets (0 · 34 ·
     70 · 104, above) are FIXED numbers, so widening those cells slid them out
     from under their own positions. That is the "it pulls the picture and
     checkbox with it", and the drag going nowhere is the same cap.
     ui.js (sizeNicheTable + nicheColGrips) is the single owner of every
     column's width — Title's 150px default included — and of what a drag
     saves. One owner, no cap, nothing left over to redistribute. */
  .niche-card th:nth-child(4), .niche-card td:nth-child(4) { position: sticky; left: 104px; z-index: 12; }
  /* ── THE FROZEN COLUMNS' HEADERS SIT ABOVE THE ONES THAT SLIDE PAST ──────
     (owner 2026-08-27: "when scrolling right the headers of the frozen columns
     don't stay frozen".) These four cells are sticky in BOTH directions, so
     they must outrank an ordinary header — otherwise the columns to their
     right, which come later in the row, paint straight over them.
     Set through the shell's own token, never as a bare `z-index`: the shell's
     `thead th` rule is more specific than anything this file can write for
     these cells and would simply undo it. The body cells keep 12 above. */
  .niche-card thead th:nth-child(-n+4) { --cg-th-z: 21; }
  /* ── TABLE COLOURS — one system, rebuilt from scratch ─────────────────────
     Exactly THREE surfaces and nothing else:
       • header row        → grey  (the thead rule above)
       • OUR product rows  → green  (the ONLY coloured data rows — ours = green)
       • every other row   → white  (parents included — a parent is NOT coloured
                              just for being a parent; only its ownership colours it)
     EVERY cell — including the frozen checkbox / Age / Image / Title columns —
     takes its colour from its ROW (one rule per surface, applied to all <td>),
     so the frozen columns can NEVER differ from the rest of the row (no white-
     left seam). Hover lightly shades the whole row. Colour means ONE thing:
     this row is OURS. Parents get only a thin grouping line, never a fill.
     Rules are ordered so ‘ours’ green wins over white/parent, and the ‘ours’
     hover wins over the generic hover — NONE needs !important. This is the
     single source of truth for row colour. */
  .niche-card tbody > tr > td { background: #ffffff; }                      /* default: white */
  /* ── THE TOTALS ROW IS ALWAYS ON SCREEN (owner 2026-08-25) ──────────────
     "you can easily not see the total bottom row at times, and you always need
     to see it and just scroll the data rows in between."
     Removing the top-10 fold the same day made this worse, not better: a
     nineteen-product market is now nineteen rows tall and the totals sat at the
     far end of them.
     The table body scrolls INSIDE the card between two pinned rows — the header
     above (already sticky) and the totals below. max-height is in vh so the
     window decides how many rows fit rather than a number someone guessed. */
  .niche-card .table-scroll { overflow-y: auto; }
  .niche-card tbody > tr.totals > td {
    position: sticky; bottom: 0; z-index: 10;
    background: var(--cg-total-bg);
    /* Its own shadow, so a row scrolling under it reads as going BEHIND it
       rather than merging into it. */
    box-shadow: 0 -1px 0 var(--cg-total-line), 0 -6px 12px -8px rgba(15,23,42,.28);
  }
  /* ⚠ THE FIRST FOUR COLUMNS ARE FROZEN SIDEWAYS, and the totals row has to be
     BOTH at once. The rule above is more specific than the nth-child rules that
     give those columns their `left`, so it won them and the totals cells lost
     their horizontal pinning — they slid away under the frozen pane while the
     rest of the row stayed put. That is the broken bottom row the owner saw
     "when scrolling around the first column".
     A cell can only have ONE position, so these re-state the left offsets on
     the totals row and sit ABOVE both panes: pinned down AND pinned left. */
  .niche-card tbody > tr.totals > td:nth-child(1) { left: 0;     z-index: 14; }
  .niche-card tbody > tr.totals > td:nth-child(2) { left: 34px;  z-index: 14; }
  .niche-card tbody > tr.totals > td:nth-child(3) { left: 70px;  z-index: 14; }
  .niche-card tbody > tr.totals > td:nth-child(4) { left: 104px; z-index: 14; }
  /* The frozen header cells must stay above the frozen totals cells where the
     two panes cross, or the corner flickers between them while scrolling. */
  .niche-card thead th:nth-child(-n+4) { z-index: 15; }
  .niche-card tbody > tr.unalloc-row > td { background: #fafbfc; }          /* faded ‘unallocated’ line */
  .niche-card tbody > tr.showmore-row > td { background: #f7f9fc; }         /* show-all toggle */
  .niche-card tbody > tr.parent-row > td { border-top: 1px solid #e2e7ef; } /* parent = a plain grouping line, NO fill */
  .niche-card tbody > tr.ours-row > td { background: #f1faf4; }             /* OURS = green, but a whisper (X-Ray look) */
  .niche-card tbody > tr:hover > td { background: #f8fafc; }                /* subtle hover, whole row */
  .niche-card tbody > tr.ours-row:hover > td { background: #e7f5ed; }       /* ours hover stays green */
  /* Every product row is the SAME height, regardless of how many secondary
     lines a cell has — content is vertically centred and the sub-lines stay on
     ONE line so no row grows to 3 lines. 48px → 38px (owner 2026-08-12: the
     rows were too tall); 38px is the shell's header height, so the header and
     a data row are the same size, exactly like the Sales dashboard. The
     thumbnail below sets the floor, so it shrinks with it. */
  .niche-card tbody td { height: 30px; vertical-align: middle; }
  .niche-card tbody td .fnote { white-space: nowrap; }
  .niche-card tbody td:nth-child(9) { white-space: nowrap; }
  .niche-card thead th:nth-child(-n+4) { z-index: 13; }
  /* The tick column holds a checkbox, not text. The shell's header padding
     (15px on the right) overflows a 34px cell, and with text-overflow:ellipsis
     the browser drew a "…" next to the box (owner screenshot 2026-08-12). */
  .niche-card thead th:nth-child(1) { padding: 0; text-overflow: clip; overflow: visible; }
  /* Product thumbnail — small square, contain (product shots sit on white), a
     light placeholder while it loads / when Keepa hasn't sent one yet. */
  /* Image maxed to the pic column (34px wide, 4px padding → 26px) — the row stays
     30px tall (set below) so a bigger picture doesn't grow the row. */
  .niche-card td.pic-cell img { display: block; width: 26px; height: 26px; object-fit: contain; border-radius: 4px; background: #f5f6fa; margin: 0 auto; }
  .niche-card td.pic-cell .pic-ph { display: inline-block; width: 26px; height: 26px; border-radius: 4px; background: #f1f3f6; }
  /* A GALLERY photo standing in for a missing main one, and MARKED as one
     (owners 2026-09-08). The dot in the corner is the whole point: the
     substitution was rejected on 2026-08-27 for being silent, not for
     existing. Amber, because it is a caveat and not an error. */
  .pic-alt { position: relative; display: inline-block; line-height: 0; }
  .pic-alt::after { content: ''; position: absolute; right: -2px; bottom: -2px;
    width: 8px; height: 8px; border-radius: 50%; background: #e0a020;
    box-shadow: 0 0 0 1.5px #fff; pointer-events: none; }
  /* Parent-group rows (Helium-10 style): the family's shared figures on one
     collapsible row; the ONLY parent marker is the house ▶ caret (no bold).
     Children are marked by a subtle left accent, NOT by indenting the name —
     so every product name starts at the same x. (Colour is in the block above.) */
  .niche-card tbody tr.parent-row { cursor: pointer; }
  /* The Title cell holds the caret in a fixed left gutter (absolute), so the
     product name begins at the SAME x on parent, child AND standalone rows. */
  .niche-card th:nth-child(4), .niche-card td:nth-child(4) { padding-left: 24px; }  /* Title — sticky (above) already makes this the caret's positioning context */
  /* The Product/ASIN column used to keep a 22px left gutter for the chart-dot
     and made itself a positioning context for it. Both went with the dot on
     2026-08-27 — an empty gutter is 22px of a column the house standard says
     should be only as wide as its figures need. */

  .niche-card td:nth-child(4) .cg-expand { position: absolute; left: 5px; top: 50%; margin-top: -6px; margin-right: 0; cursor: pointer; }
  .var-tag { display: inline-block; font-size: 10px; font-weight: 600; background: #eef2fb; color: #46618f; border-radius: 10px; padding: 1px 7px; margin-left: 6px; vertical-align: 1px; white-space: nowrap; }
  .pname { color: #1a1d23; }
  /* Full title stored; the Title column stays NARROW (a couple of words wide) and
     shows the first ~2 lines, ellipsizing the rest. WRAP (not nowrap) is what
     keeps the column from ballooning to fit a long one-line title. Drag the
     Title column wider to reveal more; hover shows the whole thing. */
  /* ONE line since 2026-08-12 (owner: the rows are too tall — copy the Sales
     dashboard). Two clamped lines of title were what set the row height for
     every row in the table, so a column nobody reads in full was costing 16px
     on all of them. Sales truncates to one line with an ellipsis and puts the
     whole string in the hover; so does this now, and the row went 56px → 40px.
     Drag the Title column wider to read more; hover still shows all of it. */
  .niche-card td:nth-child(4) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Category + Dimensions are free text that would otherwise wrap and make one
     row taller than its neighbours. One line, ellipsis, full value on hover —
     the same treatment the Title column gets (X-Ray look, 2026-08-12). */
  .niche-card td.txt-1line { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .niche-card td:nth-child(4) .ttl,
  .niche-card td:nth-child(4) .pname { display: inline; white-space: nowrap; line-height: 1.3; }
  .cindent { color: #c2c9d6; margin-right: 3px; }
  /* ── Frozen-column separators (2026-08-05, owner report) ──────────────────
     These tables use collapsed borders, which are painted by the TABLE, not by
     the cell — so the frozen pane (checkbox · # · image · Title) lost its row
     lines and its right edge the moment the table scrolled sideways. Inset
     shadows are drawn by the cell itself and therefore travel with it. Same
     fix already applied to Sales / PPC / Inventory.
     Written as ONE shadow per case (a later box-shadow REPLACES an earlier
     one), so the child-row indent marker is folded in rather than lost. */
  .niche-card tbody > tr > td:nth-child(-n+3) { box-shadow: inset 0 1px 0 #f2f4f7; }
  .niche-card tbody > tr > td:nth-child(4)    { box-shadow: inset 0 1px 0 #f2f4f7, inset -1px 0 0 #edf0f4; }
  .niche-card tbody > tr.parent-row > td:nth-child(-n+3) { box-shadow: inset 0 1px 0 #e8ecf2; }
  .niche-card tbody > tr.parent-row > td:nth-child(4)    { box-shadow: inset 0 1px 0 #e8ecf2, inset -1px 0 0 #edf0f4; }
  /* child rows keep their blue indent marker on the Title cell */
  .niche-card tbody tr.child-row > td:nth-child(4) { box-shadow: inset 2px 0 0 #dde5f3, inset 0 1px 0 #f2f4f7, inset -1px 0 0 #edf0f4; }
  /* the frozen header cells lose their underline the same way */
  .niche-card thead th:nth-child(-n+3) { box-shadow: inset 0 -1px 0 #e4e7ec; }
  .niche-card thead th:nth-child(4)    { box-shadow: inset 0 -1px 0 #e4e7ec, inset -1px 0 0 #e4e7ec; }
  .unalloc { color: #aab2c0; font-style: italic; }
  /* Top-10 default: markets past the top 10 are hidden until "Show all". */
  .niche-card table.xtr-hide .xtr-row { display: none; }
  /* (row background lives in the one colour block above) */
  .niche-card tbody tr.showmore-row td { text-align: center; padding: 8px; border-top: 1px solid #e6eaf2; position: sticky; left: 0; }
  .showmore-btn { background: none; border: 0; color: #2563eb; font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .showmore-btn:hover { text-decoration: underline; }
  tbody tr:hover { background: #f7f9fc; }
  td .fname { font-weight: 600; color: #1a1d23; }
  td .fnote { font-size: 10px; line-height: 1.15; color: #98a1b0; margin-top: 0; }
  td.nowrap, th.nowrap { white-space: nowrap; }
  td.gray, .gray { color: #98a1b0; }
  a.asin-link { color: #2563eb; text-decoration: none; font-weight: 600; }
  a.asin-link:hover { text-decoration: underline; }
  .niche-card .ours-badge { display: none; }
  .ours-badge { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; background: #e3f3e9; color: #2f7d52; border-radius: 20px; padding: 2px 8px; margin-left: 6px; vertical-align: 1px; }
  .mkt-tag { display: inline-block; font-size: 10px; font-weight: 700; background: #eef0f3; color: #5b6472; border-radius: 4px; padding: 1.5px 5px; margin-left: 6px; vertical-align: 1px; }
  /* ── THE HEADER (owner 2026-08-14, second pass: "fix the UX/UI of the
     headers, it's terrible") ────────────────────────────────────────────────
     What was wrong: three controls sat side by side in three DIFFERENT shapes
     and three different colours (grey outline pills, a filled teal button, an
     amber outline button), so nothing said which of them were alternatives to
     each other and which were actions. Fixed by grouping, not by decoration:

       VIEWS      house underline tabs — the SAME .tabs/.tab control Account
                  Health and Leads use. Alternatives look like alternatives,
                  and only the chosen one is coloured.
       | divider  the eye's full stop between "what am I looking at" and "do
                  something".
       ACTION     one filled accent button. Exactly one on the row, so it reads
                  as the page's primary action.
       ⚙ SETTINGS far right, the PPC orange pill + drop-down, unchanged from
                  that page so the control is recognised, not re-learned.
     ONE OPTICAL LINE. The first attempt hung the tabs off the BOTTOM of the
     bar (align-items:flex-end + a negative margin, so the underline met the
     header's edge) while the title and both buttons stayed centred. Measured:
     the tabs' middle sat at 44px and the buttons' at 26.5px — a 17px step in a
     60px bar, which is exactly the "terrible" the owner saw. Everything is
     centred on one line now, and the active tab's underline is its OWN, drawn
     just under its label. Guarded by the audit: it compares the vertical
     middles of every control and fails on a gap over 3px. */
  /* THE GAP IS THE DESIGN. The title block and the tab strip were flush
     against each other — "Market Share" ran straight into "Our markets" with
     no space, which is the single thing that made the row look amateur. The
     geometry audit passed it because two ADJACENT boxes do not overlap; only
     looking at a screenshot caught it. 36px is the separation, and the title
     block is allowed to shrink before the gap does. */
  .topbar-title { min-width: 0; flex: 0 1 auto; }
  .topbar-title h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .topbar-nav { display: flex; align-items: center; gap: 0; flex: 1 1 auto; min-width: 0;
    margin-left: 36px; }
  .topbar-spacer { flex: 1 1 auto; min-width: 16px; }
  /* A subtitle used to live under the title and was the first thing dropped
     here to win back width at 1024px, where ⚙ Settings was being sliced in
     half by the right edge. The subtitle is gone (owner: invented copy), and
     the title is now narrow enough at every width that nothing needs dropping
     — but the rule it existed to serve still stands and is still tested:
     nothing that can be CLICKED is ever clipped, at any width. */
  @media (max-width: 1200px) { .topbar-nav { margin-left: 24px; } }
  /* A SEGMENTED CONTROL, not underline tabs — and the reason matters, because
     underline tabs were tried here first and looked cheap.
     An underline is a BOTTOM-EDGE pattern: it works on Account Health and
     Leads because the strip sits on the edge of the thing it labels, and the
     underline reads as the seam between the chosen tab and its content. In a
     60px header the switcher is vertically CENTRED, so there is no edge for
     the underline to sit on and the blue bar just floats under one word — a
     stray mark, not "you are here". It also put a second saturated blue on a
     row that already has a blue action button.
     A segmented control is the right pattern for a centred switcher: the track
     groups the three alternatives visibly, the white chip says which is
     chosen, and it is NEUTRAL — so the only saturated things on the row are
     the one action (blue) and ⚙ Settings (orange). Navigation stops shouting.
     Do not "restore" underline tabs here without moving the strip to an edge. */
  #mktTabs { display: flex; align-items: center; gap: 2px; flex: none;
    background: #f1f4f8; border-radius: 9px; padding: 3px; }
  #mktTabs .tab { padding: 5px 13px; border-radius: 7px; font-size: 12.5px; font-weight: 600;
    color: #5b6472; cursor: pointer; white-space: nowrap; background: none; border: 0;
    font-family: inherit; line-height: 18px; }
  #mktTabs .tab:hover { color: #1a1d23; }
  #mktTabs .tab.active { background: #fff; color: #1a1d23;
    box-shadow: 0 1px 2px rgba(16,24,40,.10), 0 0 0 1px rgba(16,24,40,.04); }
  /* The gap between the switcher and the action does the separating now — the
     segmented control is a closed shape, so a divider beside it is one line
     too many. */
  .topbar-sep { width: 14px; flex: none; }
  /* BSR curves — a VIEW, but an occasional one, so it sits in the right-hand
     corner beside ⚙ Settings rather than in the switcher (owner 2026-08-14:
     "not a tab users go between like our markets and the research market").
     Quiet by default so it never competes with the two everyday views; when it
     IS the view on screen it fills in, because a page must always say where
     you are. Ghost-grey, not blue: blue is the action's colour on this row. */
  .aside-btn { margin: 0 10px 0 0; background: #fff; color: #5b6472;
    border: 1px solid #dde2ea; border-radius: 8px; padding: 6px 13px; font-size: 12.5px;
    font-weight: 600; cursor: pointer; font-family: inherit; white-space: nowrap;
    line-height: 16px; flex: none; }
  .aside-btn:hover { color: #1a1d23; border-color: #c3ccd8; background: #f7f9fc; }
  /* SOLID when it is the view on screen. A faint grey tint was tried and is
     not enough: on this view the segmented control correctly shows NEITHER
     market selected, so if this button is only slightly shaded the header
     tells you nothing about where you are. Slate rather than blue — blue is
     the action's colour on this row, even though the action is hidden here. */
  .aside-btn.active { background: #475569; border-color: #475569; color: #fff; }
  .aside-btn.active:hover { background: #3d4a5c; border-color: #3d4a5c; color: #fff; }
  /* "+ Create a new market" — the row's ONE action, in the HOUSE accent.
     It was teal (#0f766e), which was invented here and made four accent
     colours fight inside 40px of height: navy title, blue tabs, teal button,
     orange ⚙. Blue is the platform's accent (shell.css), so the row now reads
     with one accent + the ⚙'s deliberate orange, and the button is the only
     solid fill — which is what makes it read as the action. */
  .new-mkt-btn { margin: 0; background: #2563eb; color: #fff;
    border: 1px solid #2563eb; border-radius: 8px; padding: 7px 15px; font-size: 12.5px;
    font-weight: 600; cursor: pointer; font-family: inherit; white-space: nowrap;
    line-height: 16px; }
  .new-mkt-btn:hover { background: #1e4fd1; border-color: #1e4fd1; }

  /* ── ⚙ Settings — the PPC drop-down, copied on purpose (owner: "the same
     tab style like the ppc dashboard"). Same corner, same orange pill, same
     title + one-line-description rows. ─────────────────────────────────── */
  .set-wrap { position: relative; margin: 0; flex: none; }
  .set-btn { padding: 6px 14px; border: none; border-radius: 16px; background: #ff9900; color: #fff;
    font-size: 12.5px; font-weight: 600; cursor: pointer; font-family: inherit; white-space: nowrap; }
  .set-btn:hover { background: #e68a00; }
  .set-menu { display: none; position: absolute; right: 0; top: calc(100% + 8px); background: #fff;
    color: #2d3436; border-radius: 10px; box-shadow: 0 10px 32px rgba(0,0,0,.28); min-width: 290px;
    z-index: 80; overflow: hidden; text-align: left; }
  .set-menu.open { display: block; }
  .set-item { padding: 11px 16px; font-size: 13px; font-weight: 600; cursor: pointer; }
  .set-item + .set-item { border-top: 1px solid #edf2f7; }
  .set-item:hover { background: #f4f7fb; }
  .set-item span { display: block; font-size: 11px; color: #8a93a0; font-weight: 400; margin-top: 2px; line-height: 1.4; }

  /* AI credit — a quiet link until the last build died for want of it.
     It SHRINKS rather than pushing the ⚙ off the header on a small screen:
     "AI credit" becomes "AI $" under 1280px.

     THE ROW HAS TO GIVE BACK THE WIDTH THIS BUTTON TAKES, and that is the rest
     of this block. A live measurement at 1100px (2026-08-31) found ⚙ Settings
     sliced by the right edge — the row's own scrollWidth was 11px past the
     space it had. The header-clipping test never saw it because it compared
     every control against THE BAR'S OWN rect, and the bar was the thing
     overflowing; at 1024px it had been overflowing by ~26px since before this
     button existed. So: the action shortens its label the same way, and the
     gaps close a little, at the widths where the row is actually tight. */
  #aiCreditBtn { text-decoration: none; }
  #aiCreditBtn .ac-short { display: none; }
  .new-mkt-btn .nmb-short { display: none; }
  @media (max-width: 1280px) {
    #aiCreditBtn .ac-long { display: none; }
    #aiCreditBtn .ac-short { display: inline; }
    #aiCreditBtn { padding-left: 8px; padding-right: 8px; font-weight: 700; }
    .new-mkt-btn .nmb-long { display: none; }
    .new-mkt-btn .nmb-short { display: inline; }
  }
  /* THE GAPS BETWEEN CONTROLS ARE NOT WHERE THE WIDTH COMES FROM. Closing
     them to 6px won the room and immediately failed the house rule this file
     already carries — ten pixels of breathing space between neighbours. The
     width comes out of the row's own margins and the switcher's padding
     instead, which nobody reads as crowding. */
  #tabCurves .bc-short { display: none; }
  @media (max-width: 1120px) {
    .topbar { padding-left: 14px; padding-right: 14px; }
    .topbar-nav { margin-left: 16px; }
    #mktTabs .tab { padding-left: 9px; padding-right: 9px; }
    /* The last word to give way, because it is the least used control on the
       row — and BSR is the half that identifies it. A live page also carries
       the drafts dropdown, which the earlier measurement had no drafts to
       show: with it the row was still 13px over at 1024px. */
    #tabCurves .bc-long { display: none; }
    #tabCurves .bc-short { display: inline; }
    /* And the two pill buttons give up some side padding, exactly as the AI
       credit button already does at 1280px. Added 2026-08-31 after CI caught
       the row 4px over at 1024px while it measured 0 over locally: the same
       text is a few pixels wider in the runner's Chromium build than in a
       developer's, and the row had been sized to the exact measured pixel
       with nothing to spare. Padding is the right thing to spend — it costs
       no word and no gap, and 26px of headroom means a font that renders a
       little wider can never put ⚙ Settings off the screen again. */
    .set-btn { padding-left: 8px; padding-right: 8px; }
    .new-mkt-btn { padding-left: 8px; padding-right: 8px; }
  }
  #aiCreditBtn.is-empty { color: #b42318; border-color: #f3caca; background: #fef4f4; font-weight: 700; }
  #aiCreditBtn.is-empty:hover { background: #fdeaea; }
  /* Topped up, not yet proved by a build: no longer an alarm, not yet a plain
     button either. The hover says which run it was about and when you went. */
  #aiCreditBtn.is-checked { color: #5b6472; border-color: #dfe5ec; background: #fff; }

  /* ── Create a new market — the two-step window ─────────────────────────── */
  .nm-overlay { position: fixed; inset: 0; background: rgba(20,24,33,.5); z-index: 420; display: flex; align-items: center; justify-content: center; padding: 20px; }
  .nm-card { background: #fff; border-radius: 14px; box-shadow: 0 16px 48px rgba(0,0,0,.28); width: 680px; max-width: 95vw; max-height: 92vh; overflow: auto; }
  .nm-head { display: flex; align-items: center; gap: 10px; padding: 15px 20px; border-bottom: 1px solid #e6eaf2; }
  .nm-head h2 { margin: 0; font-size: 17px; color: #1a1d23; border: 0; padding: 0; }
  .nm-head .cmp-close { margin-left: auto; }
  .nm-step { padding: 18px 20px 20px; }
  .nm-q { font-size: 14px; font-weight: 600; color: #1a1d23; margin-bottom: 12px; }
  .nm-choice { display: block; width: 100%; text-align: left; background: #fff; border: 1px solid #d7dde6; border-radius: 10px; padding: 13px 16px; margin-bottom: 10px; cursor: pointer; font-family: inherit; }
  .nm-choice:hover { border-color: #2563eb; background: #f7faff; }
  .nm-choice b { display: block; font-size: 14px; color: #1a1d23; margin-bottom: 3px; }
  .nm-choice span { font-size: 12.5px; color: #5b6472; line-height: 1.5; }
  .nm-kind { font-size: 12.5px; font-weight: 600; color: #2f7d52; background: #e3f3e9; border: 1px solid #bfe3cd; border-radius: 20px; padding: 4px 12px; display: inline-block; margin-bottom: 14px; }
  .nm-kind.research { color: #46618f; background: #eef2fb; border-color: #cfd9ef; }
  .nm-row { display: flex; align-items: center; gap: 9px; margin-bottom: 13px; }
  /* Name + marketplace: one row, two columns, labels ABOVE their boxes (House
     Standard §4) — which also gives every field in this window one left edge. */
  .nm-row.nm-head2 { display: grid; grid-template-columns: 1fr 110px; gap: 14px; align-items: end; }
  .nm-row.nm-head2 label { display: block; margin-bottom: 5px; }
  .nm-row.nm-head2 input, .nm-row.nm-head2 select { width: 100%; }
  .nm-row.nm-col { display: block; }
  .nm-row label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #98a1b0; white-space: nowrap; }
  .nm-row.nm-col label { display: block; margin-bottom: 5px; white-space: normal; }
  /* Wider card: two optional boxes side by side need the room, and the extra
     width is what stops this window scrolling on a laptop. */
  .nm-row input[type="text"], .nm-row select, .nm-row textarea { border: 1px solid #d7dde6; border-radius: 7px; padding: 7px 10px; font-size: 13px; font-family: inherit; color: #2d3436; background: #fff; }
  .nm-row input#nmName { flex: 1; }
  .nm-row textarea { width: 100%; resize: vertical; line-height: 1.5; }
  /* ONLY THE ASIN BOX IS UPPERCASE — an ASIN is. This rule used to name every
     textarea in the window, so the description and the private note came back
     SHOUTING at whoever typed them (owner 2026-08-30: "the description
     shouldn't be uppercase letters by default for some weird reason"). */
  .nm-row textarea#nmAsins { text-transform: uppercase; }
  /* Uppercase what's TYPED, never the hint text (shouty placeholders read as errors) */
  .nm-row textarea#nmAsins::placeholder, .add-form input#f_asin::placeholder { text-transform: none; }
  .nm-row input:focus, .nm-row select:focus, .nm-row textarea:focus { border-color: #2563eb; outline: none; }
  .nm-count { font-size: 12px; color: #5b6472; margin-top: 5px; }
  .nm-count.ok { color: #2f7d52; font-weight: 600; }
  /* A label's second half: what the field is FOR, small and grey, on the same
     line — so the window explains itself without a paragraph under every box. */
  .nm-row label .nm-opt { font-weight: 500; text-transform: none; letter-spacing: 0; color: #98a1b0; margin-left: 6px; }
  /* The two OPTIONAL boxes, side by side. `.one` (paste mode) gives the ASIN
     box the whole width, because there it is the whole point. */
  .nm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
  .nm-grid.one { grid-template-columns: 1fr; }
  .nm-grid .nm-row { margin-bottom: 13px; }
  /* Both optional boxes the same height — different `rows` left one hanging
     below the other and the pair read as unrelated. */
  .nm-grid textarea { height: 86px; }
  /* ONE quiet line, never a boxed paragraph. */
  .nm-hint { font-size: 12.5px; color: #5b6472; line-height: 1.55; margin-bottom: 13px; }
  /* The cost of the build sits on the decision line, left of the buttons. */
  .nm-actions { display: flex; gap: 8px; justify-content: flex-end; align-items: center; }
  .nm-est { margin-right: auto; font-size: 12px; color: #5b6472; }
  .nm-est b { color: #3f4653; }
  /* Research search results — floats under the search box (reuses the reports-menu
     look, inside the house .reports-wrap so it anchors to the BOX, not the page). */
  #resSearch { border: 1px solid #d7dde6; border-radius: 7px; padding: 6px 10px; font-size: 13px; font-family: inherit; }
  #resSearch:focus { border-color: #2563eb; outline: none; }
  #resResults { min-width: 100%; max-height: 340px; overflow-y: auto; }
  #resResults .res-item { padding: 8px 12px; cursor: pointer; border-bottom: 1px solid #f0f2f5; font-size: 12.5px; }
  #resResults .res-item:hover { background: #f4f7fc; }
  #resResults .res-item b { display: block; }
  #resResults .res-item .res-sub { color: #98a1b0; font-size: 11.5px; }
  /* Frozen-snapshot banner on a research market. */
  .res-banner { margin: 10px 18px 0; }
  .approx { color: #b45309; font-weight: 700; cursor: default; }
  /* Age column: green when researched today, amber once it's a few days stale. */
  .age-cell { font-size: 12.5px; font-weight: 700; }
  .age-fresh { color: #2f7d52; }
  .age-stale { color: #b45309; }
  /* # (market rank): centred, quiet; children show the shared parent number in grey. */
  .niche-card td.rank-cell { text-align: center; font-size: 12.5px; font-weight: 700; color: #3f4653; }
  .niche-card td.rank-cell .gray { font-weight: 400; }
  /* Age now scrolls with the body (moved out of the frozen pane, next to Product) — keep it centred. */
  .niche-card td.age-td { text-align: center; }
  .loading, .empty { padding: 28px; text-align: center; color: #98a1b0; font-size: 13px; }

  /* Add form (inside the Market ASINs card) */
  .add-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 12px 18px; border-bottom: 1px solid #eef0f3; background: #fafbfd; }
  .add-form label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #98a1b0; }
  .add-form input[type="text"], .add-form select { border: 1px solid #d7dbe2; border-radius: 7px; padding: 6px 9px; font-size: 12.5px; font-family: inherit; color: #2d3436; background: #fff; }
  .add-form input#f_asin { width: 210px; text-transform: uppercase; }
  .add-form input#f_niche { width: 160px; }
  .add-form input#f_label { width: 150px; }
  .add-form .ours-wrap { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; color: #5b6472; white-space: nowrap; cursor: pointer; }
  .add-form .ours-wrap input { width: 15px; height: 15px; accent-color: #2563eb; cursor: pointer; }
  .add-btn { background: #2563eb; color: #fff; border: 0; border-radius: 7px; padding: 7px 16px; font-size: 12.5px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .add-btn:hover { background: #1e4fd1; }
  .add-btn:disabled { opacity: .5; cursor: default; }
  .ours-toggle { width: 15px; height: 15px; accent-color: #2563eb; cursor: pointer; vertical-align: middle; }
  .remove-btn { background: #fff; color: #dc2626; border: 1px solid #f3caca; border-radius: 6px; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .remove-btn:hover { background: #fef2f2; }
  .niche-head td { background: #f7f9fc; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #5b6472; }

  /* Copy-ASIN chip + "check & search on Amazon" toolbar (shared house look —
     same as the Keywords breakdown). Copy chip uses the house ⧉→✓ convention. */
  /* the copy chip's look moved to Shared Data/shell.css on 2026-08-30 */
  .amz-check, .amz-check-all { accent-color: #ff9900; cursor: pointer; margin: 0; vertical-align: middle; }
  .amz-tools { display: flex; align-items: center; gap: 12px; margin: 0 0 10px; flex-wrap: wrap; }
  /* ── Bulk actions bar (user request 2026-07-30) ─────────────────────────
     One strip above the table: a "N selected" read-out, then every action
     that works ON the selection, then a divider, then the always-available
     things (saved reports, comparisons, Excel). */
  .bulk-bar { gap: 8px; padding: 8px 14px; margin: 0; background: #fcfcfd; border-bottom: 1px solid #e4e7ec; }
  .bulk-count { font-weight: 800; font-variant-numeric: tabular-nums; }
  .bulk-count.on { color: #2563eb; }
  .bulk-sep { width: 1px; align-self: stretch; background: #e3e7ee; margin: 0 4px; }
  /* Select ▾ and Bulk actions ▾ — the two menus that own the selection */
  .sel-btn { background: #fff; color: #3f4653; border: 1px solid #d7dde6; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .sel-btn:hover { border-color: #2563eb; color: #2563eb; }
  .bulk-btn { background: #2563eb; color: #fff; border: 0; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .bulk-btn:hover:not(:disabled) { background: #1e4fd1; }
  .bulk-btn:disabled { opacity: .45; cursor: default; }
  .bulk-menu, .sel-menu { min-width: 260px; }
  .bulk-item .ri-main { display: inline-flex; align-items: center; gap: 6px; }
  .bulk-item.off { opacity: .4; cursor: default; }
  .bulk-item.off:hover { background: #fff; }
  .bulk-danger .ri-main { color: #bf360c; }
  /* The real action buttons stay in the DOM (every handler keeps working) but
     out of sight — only the mid-refresh Stop button shows itself. */
  .bulk-proxies > button { display: none; }
  .bulk-proxies > button.show-proxy { display: inline-block; }
  .bulk-del-btn { background: #fff; color: #bf360c; border: 1px solid #f0c6b6; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; }
  .bulk-del-btn:hover:not(:disabled) { background: #bf360c; border-color: #bf360c; color: #fff; }
  .bulk-del-btn:disabled { opacity: .45; cursor: default; }
  .amz-search-btn { background: #2563eb; color: #fff; border: 0; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; display: inline-flex; align-items: center; gap: 6px; }
  .amz-search-btn:hover:not(:disabled) { background: #ff9900; color: #131a22; }
  .amz-search-btn:disabled { opacity: .45; cursor: default; }

  /* ── The filter bar's insides ────────────────────────────────────────────
     The BAR itself (card, padding, margins) and the LABEL above each control
     are the shell's — `.filters-bar` / `.filter-group > label` in shell.css.
     Nothing here re-declares either of those.

     `.fg-row` is the only thing this page adds: several controls that belong
     to ONE label and sit side by side under it (the period dropdown with its
     two dates and the day walker). It is the same inline flex the Sales
     dashboard writes into its own Period group — RULEBOOK Rule 6 §4 puts the
     label above the group, not above each box. */
  .fg-row { display: flex; align-items: center; gap: 5px; flex-wrap: nowrap; }
  .fg-sep { font-size: 12px; color: #98a1b0; }
  /* The action group has no label of its own; its &nbsp; placeholder keeps the
     button on the same baseline as the controls beside it. */
  .fg-act > label { visibility: hidden; }
  /* The find-a-market box is the widest thing on the bar and is not what most
     visits use — the dropdown beside it is. So it takes a modest width at rest
     and the room it needs while it is being typed in (owner 2026-08-27: keep
     the bar to ONE row). */
  .filters-bar .mkt-find { min-width: 170px; width: 170px; transition: width .16s ease; }
  .filters-bar .mkt-find:focus { width: 330px; }
  .filters-bar input[type="date"] { width: 128px; }
  .tb-arrow { padding: 5px 9px; font-size: 14px; line-height: 1; }
  #nicheSelMain { max-width: 230px; }
  #periodSel { max-width: 132px; }
  .filters-bar input[type="date"] { border: 1px solid #d7dbe2; border-radius: 7px; padding: 5px 8px; font-size: 12.5px; font-family: inherit; color: #2d3436; background: #fff; }
  .filters-bar select { border: 1px solid #d7dbe2; border-radius: 7px; padding: 5px 8px; font-size: 12.5px; font-family: inherit; color: #2d3436; background: #fff; cursor: pointer; }
  .tb-btn { background: #fff; color: #2563eb; border: 1px solid #c8d6f5; border-radius: 7px; padding: 5px 11px; font-size: 12.5px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .tb-btn:hover { background: #eaf1fe; }
  .tb-btn:disabled { color: #b6bec9; border-color: #e3e7ee; cursor: default; background: #fff; }
  /* The ONE stand-out button in the bar: Market ASINs (everything else in the
     row is white with blue text — user decision 2026-07-30). */
  .tb-btn.primary { background: #2563eb; color: #fff; border-color: #2563eb; }
  .tb-btn.primary:hover { background: #1e4fd1; }
  .filters-bar .tnote { font-size: 12px; color: #98a1b0; }

  /* ── The BSR-curves tab's own little bars ────────────────────────────────
     `.timebar` / `.tlabel` used to be the page's FILTER bar; that bar is the
     shell's `.filters-bar` now (above). These two class names stayed behind on
     the curves tab's day walkers and chip rows (curves.js), which are NOT
     filter bars — they are strips inside a card, so they keep their own inline
     look rather than borrowing the house filter bar's. Kept here, narrowed to
     what still uses them, so deleting the page filter bar could not silently
     un-style the curves tab. */
  .timebar { display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
             background: #fff; padding: 10px 18px; }
  .timebar select { border: 1px solid #d7dbe2; border-radius: 7px; padding: 5px 8px;
                    font-size: 12.5px; font-family: inherit; color: #2d3436; background: #fff; cursor: pointer; }
  .tlabel { font-size: 11px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .04em; color: #98a1b0; }
  /* The curves table's own day walker (owner 2026-08-18). It sits INSIDE the
     card, under its title, so it drops the free-floating bar's own card
     chrome — otherwise it reads as a second card wedged into the first. The
     detail view's walker one level down did this with four inline styles; this
     is the same thing as a class, so both can be changed in one place. */
  .curve-daybar { margin: 0; border-radius: 0; box-shadow: none;
                  border-bottom: 1px solid #eef0f3; padding: 9px 18px; }
  /* Rewound is a STATE, and a state you cannot see is a bug waiting to be
     reported as one: the note goes amber so nobody reads a week-old table as
     this morning's. */
  .curve-daybar .daybar-warn { color: #9a6b0f; }
  .curve-daybar .daybar-warn b { color: #7c5408; }

  /* Per-niche pie charts (Revenue / Units share) — house style: Sales pies */
  .pies { display: flex; flex-wrap: wrap; border-bottom: 1px solid #eef0f3; }
  .pie-box { flex: 1 1 320px; min-width: 0; padding: 12px 18px 6px; }
  .pie-box h3 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #5b6472; margin-bottom: 6px; }
  .pie-wrap { position: relative; height: 190px; }
  .pie-empty { height: 190px; display: flex; align-items: center; justify-content: center; color: #98a1b0; font-size: 12.5px; }

  /* The niche (market) dropdown lives first in the Showing row. */
  #nicheSelMain { font-weight: 700; color: #1a1d23; max-width: 320px; }
  .niche-card h2 .nname { font-size: 17px; }

  /* In-place editing in the Market ASINs table */
  .edit-input { border: 1px solid transparent; border-radius: 6px; padding: 4px 7px; font-size: 12.5px; font-family: inherit; color: #2d3436; background: transparent; width: 140px; }
  .edit-input:hover { border-color: #d7dbe2; background: #fff; }
  .edit-input:focus { border-color: #2563eb; background: #fff; outline: none; }
  .rename-btn { background: none; border: 0; color: #2563eb; font-size: 10.5px; font-weight: 700; cursor: pointer; font-family: inherit; text-transform: none; letter-spacing: 0; margin-left: 8px; }
  .rename-btn:hover { text-decoration: underline; }

  /* WHAT KIND OF MARKET THIS IS (owner 2026-08-19). A word, in the card that
     holds the market's own settings — not something you infer from which tab
     you happen to be standing on. The chip STATES it; the link beside it
     changes it, and asks first. */
  .mkt-kind { font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
    border-radius: 20px; padding: 2px 9px; margin-left: 10px; border: 1px solid; }
  .mkt-kind.ours { color: #1e7a45; border-color: #b7e0c8; background: #eefaf2; }
  .mkt-kind.research { color: #7a5a12; border-color: #ecd9a8; background: #fdf7e8; }
  .kind-btn { background: none; border: 0; color: #2563eb; font-size: 10.5px; font-weight: 700;
    cursor: pointer; font-family: inherit; text-transform: none; letter-spacing: 0; margin-left: 8px; }
  .kind-btn:hover { text-decoration: underline; }

  /* ── Market-share summary (the headline row at the top) ──────────────────
     It is the SHELL's KPI row now (`.kpis` > `.kpi` > .label/.value/.sub,
     shell.css "HOUSE" block) — this page declares NONE of its padding, type
     sizes or flex behaviour any more (RULEBOOK Rule 6 §2: no page-local `.kpi`
     padding, `.value` font-size or `.label` margins; those copies are exactly
     what drifted apart). What is left below is the two things the shell does
     not own: the divider between tiles, and the one MEANING colour. */
  .kpis .kpi + .kpi { border-left: 1px solid #eef0f3; }
  /* Blue = "this is OUR share of the market", the page's own accent carrying a
     meaning, which Rule 6 §5a leaves to the page. */
  .kpis .kpi .value.blue { color: #2563eb; }
  .summary-range { font-size: 18px; color: #1a1d23; }
  /* Sales-dashboard charts row: big graph left (2fr), two pies right (1fr) */
  .charts-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 18px; margin-bottom: 18px; }
  .chart-card { background: #fff; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,.06); padding: 16px 18px; }
  .chart-card h3 { font-size: 15px; font-weight: 600; color: #2d3436; margin-bottom: 10px; }
  .pie-col { display: flex; flex-direction: column; gap: 18px; }
  .pie-col .chart-card { flex: 1; }
  /* Pies opened WITHOUT the share line get the whole width (applyPanels), and
     stacked circles in a page-wide box look broken — so alone they sit side by
     side and fill it. Set by `.pies-solo` on the grid, never by media query:
     what decides it is which panels are open, not how wide the window is. */
  .charts-grid.pies-solo .pie-col { flex-direction: row; }
  .charts-grid.pies-solo .pie-col .chart-card { flex: 1 1 0; min-width: 0; }
  @media (max-width: 1100px) {
    .charts-grid { grid-template-columns: 1fr; }
    .charts-grid.pies-solo .pie-col { flex-direction: column; }
  }

  /* Collapsible "Market ASINs" setup card */
  h2.clickable { cursor: pointer; user-select: none; }
  h2.clickable:hover { background: #fafbfd; }
  /* Collapse carets use the shared .cg-expand from shell.js (the Sales-style
     orange triangle) — no page-local chevron style (RULEBOOK Rule 6). */

  /* Per-ASIN trend chart (click rows to plot — same pattern as the Keywords page) */
  .trend-sec { border-top: 1px solid #eef0f3; }
  .trend-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 12px 18px 2px; }
  .trend-head h3 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #5b6472; margin-right: auto; }
  .metric-chip { background: #fff; color: #5b6472; border: 1px solid #d7dbe2; border-radius: 20px; padding: 3px 11px; font-size: 11.5px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .metric-chip:hover { border-color: #c8d6f5; color: #2563eb; }
  .metric-chip.on { background: #2563eb; border-color: #2563eb; color: #fff; }
  .trend-wrap { position: relative; height: 360px; padding: 8px 18px 14px; }
  .trend-empty { padding: 14px 18px 16px; color: #98a1b0; font-size: 12.5px; }
  /* .chart-dot / tr.trend-row.charted were DELETED 2026-08-27 with the
     click-a-row-to-chart system they belonged to. The tick box is now the one
     selection and the chart follows it, so a second read-out on the row would
     be a second answer to the same question. Do not re-add them. */
  tr.trend-row { cursor: pointer; }
  .deal-chip { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .03em; background: #fff3d6; color: #b45309; border-radius: 20px; padding: 2px 8px; margin-left: 6px; vertical-align: 1px; white-space: nowrap; }

  /* Recently deleted (60-day restore window, Inventory-style) */
  .restore-btn { background: #fff; color: #2563eb; border: 1px solid #c8d6f5; border-radius: 6px; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; font-family: inherit; }
  .restore-btn:hover { background: #eaf1fe; }
  .days-left-warn { color: #bf360c; }

  /* Niche cards */
  .niche-card h2 .ncount { font-size: 11.5px; font-weight: 400; color: #98a1b0; }
  tr.totals td { border-top: 2px solid var(--cg-total-line); font-weight: 700; color: #1a1d23; background: var(--cg-total-bg); }
  tr.totals td .sharepill { display: inline-block; background: #eaf1fe; color: #2563eb; border-radius: 20px; padding: 2px 10px; font-size: 11.5px; font-weight: 700; }

  /* ── BSR Curves tab ───────────────────────────────────────────────────── */
  /* THE ANSWER, first. The tab used to open with a formula and an R²; a reader
     who is not a statistician had to assemble the point themselves. This says it
     in one sentence, in the same words anyone would use out loud. */
  .curve-answer { padding: 16px 18px 12px; background: #f7faff; border-bottom: 1px solid #e6edfa; }
  .curve-answer .ca-line { font-size: 17px; line-height: 1.45; color: #1a1d23; }
  .curve-answer .ca-line b { color: #1a45a8; }
  .curve-answer .ca-sub { margin-top: 5px; font-size: 12px; color: #5b6472; }
  /* The maths, demoted to a footnote for whoever wants to check it. */
  .curve-fine { padding: 9px 18px; background: #fff; border-bottom: 1px solid #eef0f3;
                font-size: 11.5px; color: #8a93a2; line-height: 1.6; }
  .curve-fine b { color: #5b6472; }
  .curve-fine span[title] { cursor: help; }
  /* The scoreboard: one row per size, so "how many, in which size" is answered
     before the reader scrolls through thirteen separate blocks. */
  .bk-score { width: auto; min-width: 560px; margin: 4px 18px 14px; font-size: 12px; }
  /* the curve tab's gate table sizes to its CONTENT — the page-wide
     `table { width:100% }` stretched its 6 columns across the whole card
     with silly gaps around tiny figures (user 2026-08-03: no forced
     minimum either; snug columns, single-line rows, compact verdict text) */
  .curve-col-l .bk-score { width: auto !important; max-width: 100%; margin: 4px 0 6px; }
  .curve-col-l .bk-score th, .curve-col-l .bk-score td { padding: 4px 9px; white-space: nowrap; }
  .bk-score td.bk-ref, .bk-score tr.bk-score-tot td.bk-ref { font-size: 11.5px; white-space: nowrap; }
  .bk-score th { text-align: right; font-weight: 700; color: #5b6472; padding: 5px 12px;
                 border-bottom: 1px solid #e4e8ee; white-space: nowrap; }
  .bk-score th:first-child, .bk-score td:first-child { text-align: left; }
  .bk-score td { text-align: right; padding: 4px 12px; border-bottom: 1px solid #f2f4f7; }
  .bk-score tr.bk-row-short td { background: #fff8f0; }
  .bk-score tr.bk-score-tot td { border-top: 2px solid #e4e8ee; border-bottom: 0;
                                 background: #f7f9fc; font-weight: 600; }
  .curve-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(255px, 1fr)); gap: 1px; background: #eef0f3; border-bottom: 1px solid #eef0f3; }
  .curve-tile { background: #fff; padding: 14px 18px; }
  .ct-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #98a1b0; }
  .ct-value { font-size: 20px; font-weight: 700; color: #1a1d23; margin: 5px 0 4px; white-space: nowrap; }
  .ct-value sup { font-size: 12px; }
  /* the formula is the longest value — it must stay on ONE line, so it runs a
     size smaller than the plain numbers next to it. */
  .ct-value .formula { font-size: 16px; }
  .ct-note { font-size: 11.5px; color: #5b6472; line-height: 1.5; }
  .curve-calc { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 12px 18px; background: #fafbfd; border-bottom: 1px solid #eef0f3; }
  .curve-calc label { font-size: 12px; color: #5b6472; }
  .curve-calc input { width: 110px; border: 1px solid #d7dde6; border-radius: 7px; padding: 5px 8px; font-size: 13px; font-family: inherit; margin-left: 5px; }
  .curve-calc input:focus { border-color: #2563eb; outline: none; }
  /* "Rules of thumb" — the audit sheet above the curve view. Plain boxes in a
     responsive grid; short blocks read faster than one long wall of text. */
  .rule-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; align-items: start; }
  .rule-box { background: #fafbfd; border: 1px solid #eceff4; border-radius: 9px; padding: 12px 14px; }
  /* The WHEN tag on the three timed steps — setup / daily / weekly — so the
     chronological order is readable at a glance. */
  .rule-when { display: inline-block; float: right; font-size: 10px; font-weight: 700; text-transform: none; letter-spacing: 0; color: #2f7d52; background: #e3f3e9; border-radius: 20px; padding: 1px 8px; }
  .rule-box h3 { font-size: 12px; font-weight: 800; color: #2563eb; text-transform: uppercase; letter-spacing: .04em; margin: 0 0 7px; }
  .rule-box p { font-size: 12.5px; line-height: 1.55; color: #3f4653; margin: 0 0 7px; }
  .rule-box p:last-child { margin-bottom: 0; }
  .rule-box b { color: #1a1d23; }
  /* Coverage chips — the audit trail behind "is this curve allowed to speak?".
     A band with enough points goes green; a short one stays gray. */
  .curve-bands { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; padding: 10px 18px; background: #fafbfd; border-bottom: 1px solid #eef0f3; }
  .curve-bands .cb-lbl { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #5b6472; margin-right: 3px; }
  .cb-chip { font-size: 11.5px; color: #7b8494; background: #eef1f6; border: 1px solid #e2e6ee; border-radius: 20px; padding: 3px 10px; white-space: nowrap; cursor: help; }
  .cb-chip b { color: #5b6472; }
  .cb-chip.full { color: #2f7d52; background: #e3f3e9; border-color: #bfe3cd; }
  .cb-chip.full b { color: #2f7d52; }
  .curve-bands .tnote { flex-basis: 100%; margin-top: 2px; font-size: 11.5px; line-height: 1.5; color: #8a93a2; }
  tr.curve-row { cursor: pointer; }
  tr.curve-row:hover td { background: #f4f7fd; }
  tr.dot-out td { opacity: .5; }
  /* The two CHECK columns in the market table, either side of Amazon's own
     badge: what the CURVE says, and what we REALLY sold. Both are marked by a
     soft cell BACKGROUND (not a coloured font — that shouted) so the eye finds
     them without the numbers looking like a warning. Neither feeds revenue.
     These sit after the row-colour block above on purpose: a highlighted
     column stays highlighted on ours/hover/parent rows too. */
  /* Curve column went violet→TEAL (2026-08-04): the violet sat next to the
     Helium 10 purple columns and the two read as one family. */
  /* X-Ray look: a comparison column is a WHISPER of its source colour, not a
     block of it. The colour that does the telling is on the HEADER (label +
     underline, below) — the body just needs to read as "not our number". */
  /* ONE TINT PER SOURCE, and the HEADER wears the same tint as the cells
     under it (owners 2026-09-07: "badge + curve avg is good, because its
     header colour and cells background match — the other added hidden
     columns have only header font colour, match their background"). Before
     this, four different sources shared one blue-grey body and one blue
     header, so the eye could not tell where a column started or which header
     belonged to which stripe. Each tint is the palest possible version of
     that source's own label colour, listed at the block below. */
  .niche-card tbody > tr > td.real-col   { background: #f5f8fd; }
  .niche-card tbody > tr:hover > td.real-col   { background: #e9f0fa; }
  .niche-card tbody > tr > td.curve-col  { background: #f4faf8; }
  .niche-card tbody > tr:hover > td.curve-col  { background: #e6f4f1; }
  /* OUR figure is the bold one; a comparison column is a CHECK on it, so it
     wears the tint but not the weight (owner 2026-08-12 — three bold columns
     side by side made it impossible to see which number the page is about). */
  /* .units-col is NOT bold — only Parent rev. (.col-primary) is (owner 2026-08-12). */

/* ── The bucket behind a curve (BSR Curves tab) ────────────────────────────
   The fixed roster a curve is read from, per unit step, with a green tick per
   product read today. It is the proof that flipping between days shows the
   SAME products being fetched, not a fresh sample each time. */
.curve-bucket { border-top: 1px solid #d3e0f7; }
.bucket-head { padding: 10px 18px; font-size: 13px; color: #2c3f5c; display: flex;
  align-items: center; gap: 6px; flex-wrap: wrap; }
.bucket-head:hover { background: #f4f8ff; }
.bk-steps { margin-left: auto; font-size: 11px; color: #2f7d52; background: #e3f3e9;
  border-radius: 20px; padding: 2px 10px; }
.bk-body { padding: 0 18px 12px; }
.bk-step { margin-top: 12px; }
.bk-step-head { display: flex; align-items: center; gap: 8px; font-size: 12px;
  color: #2c3f5c; padding: 6px 0; flex-wrap: wrap; }
.bk-counts { margin-left: auto; font-size: 11px; color: #6b7c93; }
.bk-flag { font-size: 13px; }
.bk-flag.full { color: #2f7d52; }
.bk-flag.thin { color: #c98a1b; }
.bk-ok   { color: #2f7d52; font-weight: 700; }
.bk-miss { color: #c98a1b; font-weight: 700; }
.bk-out  { color: #b23b3b; font-weight: 700; }

/* The curve tables carry hundreds of rows — keep them scannable, not roomy. */
.curve-bucket table th, .curve-bucket table td,
#curveWrap > .table-scroll table th, #curveWrap > .table-scroll table td {
  padding: 3px 8px; font-size: 11.5px; line-height: 1.35;
}
#curveWrap .name-col, .curve-bucket .name-col { max-width: 220px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

/* Bucket filters + a header that stays put while you scroll a long list. */
.bk-filters { display: flex; align-items: center; gap: 6px; padding: 8px 0 2px; flex-wrap: wrap; }
.bk-filter { border: 1px solid #d3e0f7; background: #fff; color: #2c3f5c; border-radius: 20px;
  padding: 3px 11px; font-size: 11px; cursor: pointer; }
.bk-filter:hover { background: #f4f8ff; }
.bk-filter.on { background: #2563eb; border-color: #2563eb; color: #fff; }
.curve-bucket .table-scroll, #curveWrap > .table-scroll { max-height: 460px; overflow-y: auto; }
.curve-bucket table thead th, #curveWrap > .table-scroll table thead th {
  position: sticky; top: 0; z-index: 2; background: var(--cg-th-bg);
  box-shadow: inset 0 -1px 0 var(--cg-th-line);
}

/* ── The rules card's FLOW MAP ─────────────────────────────────────────────
   A pile of boxes is not a logic map. This is the pipe, left to right, one
   lane per stage, each block naming the rule that governs it — so the shape
   of the thing can be followed before reading a word of detail. */
.rule-flow { padding: 4px 0 16px; }
.rf-lane { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap; padding: 7px 0;
  border-bottom: 1px dashed #e1eaf8; }
.rf-lane:last-child { border-bottom: 0; }
.rf-lane-lbl { flex: 0 0 130px; align-self: center; font-size: 10px; font-weight: 700;
  letter-spacing: .06em; color: #6b7c93; }
.rf-box { flex: 1 1 150px; min-width: 130px; background: #fff; border: 1px solid #d3e0f7;
  border-radius: 7px; padding: 7px 10px; font-size: 11.5px; color: #2c3f5c; line-height: 1.35; }
.rf-box span { display: block; margin-top: 3px; font-size: 10px; color: #6b7c93; }
.rf-keep { background: #eef7f1; border-color: #bfe0cd; }
.rf-drop { background: #fdf0f0; border-color: #eec9c9; }
.rf-gate { background: #eef3fd; border-color: #b9cef1; font-weight: 600; }
.rf-arr, .rf-plus { align-self: center; color: #93a6c0; font-size: 14px; flex: 0 0 auto; }
.rule-zero { border-color: #2563eb !important; background: #f4f8ff; }
@media (max-width: 760px) { .rf-lane-lbl { flex-basis: 100%; } .rf-arr, .rf-plus { display: none; } }
.bk-count { margin-left: auto; font-size: 11.5px; color: #2c3f5c; }
.bk-count b { font-size: 13px; }

/* ── BSR Curves tab — 2 Aug 2026 restructure: three separate cards ──────────
   Card 1: category + day + the one-sentence answer. Card 2: the coverage
   table (left) beside the GRAPH of every point vs the fitted line (right),
   with the maths + calculator living next to the graph. Card 3: one flat,
   filterable product table. The cards get real gaps between them. */
#curveWrap .curve-gap { margin-top: 18px; }
/* STACKED, not side-by-side (2 Aug 2026 redesign after the two verdict
   columns made the table too wide for half a card): the gate table takes the
   card's FULL width — every column visible, nothing scrolls, nothing clips —
   and the graph sits full-width underneath with room to breathe. */
.curve-cols { display: block; padding: 10px 18px 6px; }
.curve-col-l { width: 100%; }
/* The graph is its OWN section under the table: a rule + air between them
   and a matching section title (user 2026-08-03 — they sat glued together
   with no headers). */
.curve-col-r { width: 100%; margin-top: 20px; padding-top: 14px; border-top: 1px solid #eef0f3; }
.curve-col-r .curve-calc, .curve-col-r .curve-fine { border-bottom: 0; padding-left: 2px; padding-right: 2px; }
.curve-chart-wrap { position: relative; height: 430px; }

/* Section titles inside the curve card — the gate table and the graph each
   get one, same size, so the two halves read as named sections. */
.bk-score-title { font-size: 13.5px; font-weight: 700; color: #2c3f5c; margin: 2px 0 8px; }
.bk-score-title .tnote { display: block; font-weight: 400; margin-top: 2px; }
.bk-score.compact { min-width: 0; width: 100%; margin: 0; font-size: 12px; }
.bk-score.compact th { padding: 4px 8px; white-space: normal; line-height: 1.25; vertical-align: bottom; }
.bk-score.compact td { padding: 3px 8px; }
.bk-cell-ok { background: #e8f6ee; }
.bk-cell-ok b { color: #166534; }
.bk-cell-short { background: #fdecec; }
.bk-cell-short b { color: #b91c1c; }
.bk-size-link { cursor: pointer; color: #2563eb; }
.bk-size-link:hover { text-decoration: underline; }
.bk-size-link.on { font-weight: 700; text-decoration: underline; }

/* "Every size covered?" — the explanation folds away behind its button. */
.curve-bands .cb-sum { font-size: 12px; color: #5b6472; }
.curve-bands .cb-why { font-size: 11px; padding: 2px 8px; }
.curve-bands .cb-note { display: none; }
.curve-bands .cb-note.open { display: block; }

/* Curves tab polish (2 Aug 2026 round 2): breathing room over the product
   table, two-line wrapped headers so columns stay narrow, chart tool row. */
.curve-bucket .bk-filters { margin: 12px 18px 14px; }
.curve-bucket table thead th { white-space: normal; line-height: 1.3; vertical-align: bottom; }
.curve-chart-tools { display: flex; align-items: center; gap: 10px; padding: 8px 2px 0; }

/* Curves round 3: tight centered coverage table, prominent maths line. */
.bk-score.compact th, .bk-score.compact td { text-align: center; padding: 3px 7px; }
.bk-score.compact { font-size: 11.5px; }
.curve-col-l { flex: 0 1 340px; min-width: 300px; }
.curve-fine { font-size: 14px; }
.curve-fine .formula { font-size: 15px; }

/* Curves round 4: back to slim single-line rows; headers centered vertically. */
.bk-score.compact th { vertical-align: middle; padding: 3px 6px; }
.bk-score.compact td { padding: 2px 6px; line-height: 1.35; }

.bk-cell-mid { background: #fff7e0; }
.bk-cell-mid b { color: #92400e; }
/* Curve-vs-badge referee cells: green = the curve wins, red = badge+⅓ wins,
   and the colour STRENGTHENS with the number of our products confirming it
   (1 referee = pale hint, 3+ = confident). All clickable for the breakdown. */
.bk-ref { cursor: pointer; }
.bk-w-c1 { background: #f2faf5; } .bk-w-c1 b { color: #4d7c62; }
.bk-w-c2 { background: #dff2e7; } .bk-w-c2 b { color: #2a6547; }
.bk-w-c3 { background: #c4e8d3; } .bk-w-c3 b { color: #14532d; }
.bk-w-b1 { background: #fdf4f4; } .bk-w-b1 b { color: #a05252; }
/* Helium 10 comparison columns (migration 158) — their own purple so they can
   never be mistaken for our figures; each sits NEXT TO our equivalent white
   column; hidden until the toolbar's Helium 10 button is on. */
/* ALL comparison columns share ONE style (2026-08-04): same selector strength
   (the column tint always wins over row fills — ours-green included — so a
   column reads as one continuous stripe), same hover darkening, same tinted
   header. ONE COLOUR PER SOURCE, and it means the same thing everywhere it
   appears (owner 2026-08-12):
       BLUE   #real-col   what we REALLY sold — the yardstick (units + revenue)
       TEAL   #curve-col  our own BSR→units curve
       PURPLE #h10-col    Helium 10's X-Ray file
       AMBER  #js-col     Jungle Scout's export (added 2026-09-03) — a fourth
                          outside opinion, so a fourth colour. Chosen away from
                          Helium 10's purple AND from the bronze below, which
                          are the two it sits next to.
       ROSE   #avg-col    the average of the badge and the curve (owners
                          2026-09-07). A MIXED column like the bronze one
                          below, so it must not wear either parent's colour:
                          teal would read as "the curve says", and this is
                          half the badge. Hidden by default.
       (A bronze "H10 x ours" column lived here too — Helium 10's units x OUR
       price maths. Removed 2026-09-08 at the owners' request: it answered
       "whose units, whose price" and nobody was asking.)
   A source keeps its colour in the units block, the revenue block and the BSR
   block alike, so the reader learns three colours once instead of per column. */
.niche-card tbody > tr > td.h10-col { background: #f8f6fd; }
.niche-card tbody > tr:hover > td.h10-col { background: #efeafa; }
.niche-card td.h10-col b { color: inherit; font-weight: 400; }   /* a figure is a figure — never a coloured one */
.niche-card tbody > tr > td.js-col { background: #fdfaf5; }
.niche-card tbody > tr:hover > td.js-col { background: #f7efe2; }
.niche-card td.js-col b { color: inherit; font-weight: 400; }
/* The HEADERS carry the same three colours — !important because the page-wide
   `.niche-card thead th { background: #eef1f6 !important }` (which exists to
   stop the frozen columns going white) outranked these and left every
   comparison header the same grey as our own. That is why the tints looked
   like they applied to the wrong columns: the body was striped and the header
   said nothing (owner 2026-08-12, "double-check they appear in the right
   place"). */
/* EACH header takes its OWN column's tint, not one shared blue (owners
   2026-09-07). The coloured word under the measure (.src-real, .src-curve …)
   names the source; the background says how far the stripe reaches. */
.niche-card thead th.real-col  { background: #f5f8fd !important; color: var(--cg-th-fg); }
.niche-card thead th.curve-col { background: #f4faf8 !important; color: var(--cg-th-fg); }
.niche-card thead th.h10-col   { background: #f8f6fd !important; color: var(--cg-th-fg); }
.niche-card thead th.js-col    { background: #fdfaf5 !important; color: var(--cg-th-fg); }
/* The mixed column, body and header: a warm tint under a bronze label, so it
   reads as its own thing at a glance without shouting. Declared AFTER the
   .h10-col rules above (same specificity) so it wins for the cells that carry
   both classes. */
/* The average column: its own rose tint, body and header, like the other
   mixed column below it. */
.niche-card tbody > tr > td.avg-col { background: #fdf6fa; }
.niche-card tbody > tr:hover > td.avg-col { background: #f7e9f1; }
.niche-card thead th.avg-col { background: #fdf6fa !important; }
/* The one place colour is allowed: the word naming the source, on its own line
   under the measure. Muted, normal weight — it labels, it does not shout. */
.th-src { font-weight: 600; }
.src-real  { color: #3b6fb5; }
.src-curve { color: #2f8378; }
.src-h10   { color: #7256b5; }
.src-js    { color: #b06d18; }
.src-avg   { color: #a8447a; }
/* Where a run of comparison columns STARTS, a divider separates it from our
   own number — so "ours | the checks" is one glance, not a colour hunt. */
.niche-card thead th.cmp-first, .niche-card tbody > tr > td.cmp-first { border-left: 1px solid #e4e7ec; }
.h10-btn { color: #6d28d9; border-color: #d8c9f5; font-weight: 600; }
.h10-btn.on { background: #6d28d9; border-color: #6d28d9; color: #fff; }
/* ── ONE BUTTON, NOT SEVEN (owners 2026-09-08) ─────────────────────────────
   "all the additional columns should be 1 button not many different ones,
   it's a mess on the eye at the moment."
   Five coloured chips plus two import buttons became one menu, built from the
   shell's .reports-wrap / .reports-menu — the same one Select ▾ and Bulk
   actions ▾ use — so the toolbar is three buttons that look alike instead of
   ten that do not. What survives from the chips is the COLOUR: each row wears
   a dot in the colour of the columns it turns on, so the switch and its result
   are obviously the same thing and there is no key to read.
   (The old .src-chip rules were deleted with the chips. Do not bring back a
   row of coloured buttons here.) */
.src-btn { font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  padding: 5px 11px; border-radius: 8px; border: 1px solid #d7dde6; background: #fff;
  color: #3f4653; display: inline-flex; align-items: center; gap: 5px; }
.src-btn:hover { background: #f7f9fc; }
.src-btn.on { border-color: #bcd3fa; color: #1d4ed8; }
.src-n { display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px;
  background: #2563eb; color: #fff; font-size: 10.5px; font-weight: 700; }
.src-menu { min-width: 300px; }
.src-item { cursor: pointer; }
.src-item .ri-main, .src-all .ri-main { display: inline-flex; align-items: center; gap: 7px; }
/* The tick keeps its own fixed width so the five names line up whether they
   are on or off — a name that shifts sideways as you tick it reads as a
   different row. */
.src-tick { display: inline-block; width: 11px; color: #2563eb; font-weight: 700; }
.src-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid rgba(0,0,0,.12); flex: none; }
.src-item.real-col  .src-dot { background: #3b6fb5; }
.src-item.curve-col .src-dot { background: #2f8378; }
.src-item.h10-col   .src-dot { background: #7256b5; }
.src-item.js-col    .src-dot { background: #b06d18; }
.src-item.avg-col   .src-dot { background: #a8447a; }
.src-item.on .ri-main { font-weight: 700; }
/* The All / None row: the same shape as the five under it (so the tick column
   lines up) but no colour dot — it is not a source, it is a shortcut — and a
   rule under it so the five read as its list. */
.src-all { border-bottom: 1px solid #eef1f5; cursor: pointer; }
.src-all .ri-main { font-weight: 700; color: #3f4653; }
/* The curve row keeps its freshness signal on the right — green = every
   category's curve is from today, amber = some are older. Worth knowing
   BEFORE you switch it on, which is why it shows whether the row is on. */
.src-item.curve-fresh-ok  .ri-sub { color: #15803d; }
.src-item.curve-fresh-old .ri-sub { color: #b45309; }
.src-menu-sep { padding: 7px 12px 3px; font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: #98a1b0;
  border-top: 1px solid #eef1f5; margin-top: 4px; }
.src-import { cursor: pointer; }
/* Header/click cards on this page carry structured multi-line explanations
   (examples per column, 2026-08-04) — keep their line breaks. */
.sv2-tipcard .tip-text { white-space: pre-line; }
/* Every figure in the niche tables sits dead-centre of its cell, both axes
   (user decision 2 Aug 2026) — the Product/Title/Model text columns stay left. */
.niche-card .table-scroll td { vertical-align: middle; }
.niche-card .table-scroll td.num, .niche-card .table-scroll th.num { text-align: center; }
.bk-w-b2 { background: #fbe3e3; } .bk-w-b2 b { color: #9f2f2f; }
.bk-w-b3 { background: #f6cccc; } .bk-w-b3 b { color: #7f1d1d; }
.curve-fine .cf-sub { margin-top: 4px; font-size: 13px; }

  /* ── Normalised-year tile + window (seasonality.js) ──────────────────────
     The window reuses .cmp-overlay / .cmp-card / .cmp-head from the Compare
     Products viewer above — only what is genuinely new lives here. */
  /* THE REASON, WHERE THE FIGURE WOULD BE (owner 2026-08-30: "articulate it in
     very few words, and write it instead of the figure, instead of —").
     Smaller and grey than a figure, so it reads as a status at a glance and
     can never be mistaken for money. The counts stay on the line below. */
  .stat-why { font-size: 13.5px; font-weight: 600; color: #6b7683; letter-spacing: .01em; }

  .kpi.seas-tile { cursor: pointer; }
  .kpi.seas-tile:hover { background: #f7f9fc; }

  /* ── The two tiny buttons in each yearly square (owner 2026-08-30) ───────
     A switch (is this market auto-filled?) and ↻ (read it now). They sit in
     the top-right CORNER, out of the text flow, so they can never push the
     label onto another line — the same corner rule the table headers follow
     (House Standard §5.4). The square reserves the width they take, so the
     label wraps before it reaches them instead of running underneath.
     They live inside a clickable tile, so every press stops there: the click
     handler in seasonality.js ignores anything inside [data-yr-tools]. */
  .kpi.yr-host { position: relative; padding-right: 52px; }
  .yr-tools { position: absolute; top: 7px; right: 10px; display: flex; align-items: center; gap: 6px; }
  /* In the slim one-line tile (owners 2026-09-06, "smaller like the PPC
     dashboard") the pair sits on the line's middle, not 7px from the top. */
  .kpis.cg-kpis-slim .kpi.yr-host { padding-right: 12px; }
  .kpis.cg-kpis-slim .kpi.yr-host .yr-tools { position: static; order: 9; margin-left: auto; }
  /* ── The light on the "Year — average" square (owners 2026-09-08) ───────
     "an indicator light showing green for 3/3 value points, or orange for
     2/3 …, and red for 1/3". It sits at the head of the square's own line, so
     the count and its colour are read together. A ring, not a flat dot: a
     6px flat dot at this size reads as a full stop. The hover on it says what
     the colour means in words — colour is never the only carrier. */
  .yr-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    vertical-align: middle; margin-right: 1px; flex: none; }
  .yr-dot-ok   { background: #16a34a; box-shadow: 0 0 0 2px #dcfce7; }
  .yr-dot-warn { background: #ea9a12; box-shadow: 0 0 0 2px #fdf0d8; }
  .yr-dot-bad  { background: #dc2626; box-shadow: 0 0 0 2px #fee2e2; }
  .yr-dot-wait { background: #b6bec9; box-shadow: 0 0 0 2px #eef1f5; }

  /* The switch: a 22×12 pill with a knob. Blue = in the nightly rotation. */
  .yr-sw { width: 22px; height: 12px; padding: 0; border: 0; border-radius: 7px; background: #d3d9e2;
    cursor: pointer; position: relative; transition: background .15s; flex: none; }
  .yr-sw:hover { background: #c3cbd7; }
  .yr-sw.on { background: #2563eb; }
  .yr-sw.on:hover { background: #1d4ed8; }
  .yr-knob { position: absolute; top: 2px; left: 2px; width: 8px; height: 8px; border-radius: 50%;
    background: #fff; transition: transform .15s; }
  .yr-sw.on .yr-knob { transform: translateX(10px); }
  /* Read it now. */
  .yr-go { width: 17px; height: 17px; padding: 0; border: 1px solid #e0e3e8; border-radius: 5px;
    background: #fff; color: #98a1b0; font-size: 11px; line-height: 1; cursor: pointer; flex: none;
    display: flex; align-items: center; justify-content: center; font-family: inherit; }
  .yr-go:hover { color: #2563eb; border-color: #bcd3fa; }
  .yr-go.busy, .yr-go:disabled { cursor: default; color: #2563eb; border-color: #bcd3fa; }
  .yr-spin { width: 9px; height: 9px; border: 1.5px solid #bcd3fa; border-top-color: #2563eb;
    border-radius: 50%; animation: yr-turn .8s linear infinite; }
  @keyframes yr-turn { to { transform: rotate(360deg); } }
  @media (prefers-reduced-motion: reduce) { .yr-spin { animation-duration: 3s; } }
  .seas-card { width: 1080px; }
  /* ── THE YEAR AHEAD, under the three squares (owners 2026-09-08) ─────────
     The forward graph lives in this window because the three figures it draws
     ARE the three squares directly above it. The page's own chart is the
     BACKWARD one, and keeping the two apart is the whole point (charts.js). */
  .yr-fc { margin-top: 16px; padding-top: 14px; border-top: 1px solid #eef0f3; }
  /* The heading, the zoom hint and Reset zoom on ONE line — the hint must not
     cost the height the paragraph under the chart just gave back. */
  .yr-fc-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
  .yr-fc h3 { margin: 0; font-size: 13px; font-weight: 700; color: #2c3340; }
  .yr-fc-head .tnote { margin-left: auto; font-size: 11.5px; color: #8a93a2; }
  .yr-fc-head .tb-btn { flex: none; }
  /* TALLER, because the paragraph under it is gone (owners 2026-09-08: "the
     graph itself can be higher, right now it's too short and narrow. Once you
     remove the text at the bottom, you have this space to go to"). 260 -> 430:
     the window is 1080 wide, so at 430 the plot is close to a 2:1 box and a
     dozen thin lines can be told apart. */
  .yr-fc-wrap { position: relative; height: 430px; }
  /* The hover card — a picture cannot go in a canvas tooltip, so this is an
     ordinary div placed by yrFcTooltip(). pointer-events:none or it would
     steal the hover it exists to describe. */
  .yr-fc-tip { position: absolute; display: none; pointer-events: none; z-index: 5;
    min-width: 190px; max-width: 260px; background: #fff; border: 1px solid #d7dde6;
    border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,.14); padding: 8px 10px;
    font-size: 12px; color: #2c3340; }
  .yr-tip-h { font-weight: 700; margin-bottom: 10px; }
  /* The whole year sits UNDER the month's own figures (owners 2026-09-08:
     "the yearly revenue should be below the monthly one, not at the top"),
     with a rule and some air above it — it is the sum of the twelve, not
     another row of the month. */
  .yr-tip-yr { display: flex; justify-content: space-between; gap: 14px;
    margin-top: 6px; padding-top: 6px; border-top: 1px solid #eef1f5; }
  .yr-tip-yr span { color: #6b7480; }
  .yr-tip-yr b { font-weight: 700; }
  .yr-tip-p { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
  .yr-tip-p img { width: 40px; height: 40px; object-fit: contain; border-radius: 4px;
    background: #f5f6fa; flex: none; }
  .yr-tip-p b { display: block; font-weight: 600; line-height: 1.25; }
  .yr-tip-asin { display: block; color: #8a93a2; font-size: 11px; margin-top: 1px; }
  .yr-tip-r { display: flex; justify-content: space-between; gap: 14px; padding: 1px 0; }
  .yr-tip-r span { color: #6b7480; }
  .yr-tip-f { margin-top: 5px; padding-top: 5px; border-top: 1px solid #eef1f5;
    color: #8a93a2; font-size: 11px; line-height: 1.3; }
  .seas-body { padding: 16px 20px 20px; }
  .seas-note { font-size: 12px; color: #3d4552; }
  .seas-note > div { margin-bottom: 4px; line-height: 1.5; }
  .seas-note b { color: #1a1d23; }
  .seas-warn { margin-top: 8px; padding: 8px 10px; background: #fff8e6;
               border: 1px solid #f0e0b0; border-radius: 8px; }
  .seas-chart { position: relative; height: 320px; width: 100%; margin-top: 12px; }
  .seas-controls { display: flex; align-items: center; gap: 14px; margin-top: 10px;
                   font-size: 12px; color: #5b6472; }
  .seas-toggle { display: flex; align-items: center; gap: 6px; cursor: pointer; }
  .seas-hint { color: #8b95a3; }
  .seas-bsr { margin-top: 10px; border-top: 1px solid #edf1f7; padding-top: 10px; }
  .seas-bsr-note { font-size: 12px; color: #5b6472; }
  .seas-detail { margin-top: 12px; }
  .seas-detail-hint { font-size: 12px; color: #8b95a3; }
  .seas-detail-card { border: 1px solid #e6eaf2; border-radius: 10px; padding: 12px 14px;
                      background: #fbfcfe; }
  .seas-detail-head { font-weight: 600; color: #1a1d23; margin-bottom: 8px; font-size: 13px; }
  .seas-kv { display: flex; justify-content: space-between; gap: 20px;
             font-size: 12px; padding: 3px 0; border-bottom: 1px solid #f0f3f8; }
  .seas-kv span { color: #5b6472; }
  .seas-detail-how { margin-top: 10px; font-size: 12px; color: #5b6472; }
  .seas-detail-how > div { margin-bottom: 3px; line-height: 1.5; }
  .seas-cap { margin-top: 6px; color: #8a6d1f; }
  .seas-loading, .seas-empty { padding: 28px 8px; font-size: 13px; color: #5b6472; }
  .seas-why { margin-top: 8px; }
  .seas-why > div { margin-bottom: 3px; line-height: 1.5; }

  /* The last-resort rank-drop mark: visibly different from the family \u2248. */
  .approx-floor { color: #b45309; font-weight: 600; }

/* ── ⚙ Settings: what runs behind this page (owner 2026-08-14) ──────────────
   The BUTTON and its menu are styled with the topbar block above (.set-btn /
   .set-menu — the PPC page's, verbatim). The window itself reuses
   .cmp-overlay / .cmp-card / .seas-note, so there is one popup style on this
   page, not a second one (RULEBOOK Rule 6 — reuse first).

   ONE PROCESS PER WINDOW since 2026-08-14 (second pass). The in-window tab
   strip is gone: its tabs were dead (a JSON string in an inline onclick closed
   the attribute early, so only the default tab ever opened), and the owner
   asked for the PPC menu instead. This row at the foot of each window is how
   you reach the other three without going back to the ⚙. */
.ms-more { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 18px; padding-top: 12px; border-top: 1px solid var(--cg-line, #e2e8f0); }
.ms-more > span { font-size: 12px; color: #64748b; margin-right: 2px; }
.ms-more-link { background: #fff; border: 1px solid var(--cg-line, #e2e8f0); border-radius: 7px;
  padding: 5px 11px; font-size: 12px; font-weight: 600; color: #2563eb; cursor: pointer;
  font-family: inherit; white-space: nowrap; }
.ms-more-link:hover { background: #f4f7fb; border-color: #c8d6f5; }

.mkt-jobs { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.mkt-job {
  border: 1px solid var(--cg-line, #e2e8f0); border-left: 3px solid #2563eb;
  border-radius: 8px; padding: 10px 12px; background: #fff;
}
.mkt-job.off  { border-left-color: #94a3b8; opacity: .72; }
.mkt-job.warn { border-left-color: #dc2626; background: #fffafa; }
.mkt-job-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.mkt-job-head b { font-size: 13.5px; }
.mkt-job-when { font-size: 11.5px; color: #64748b; flex: 1 1 auto; }
.mkt-job-sw { font-size: 11.5px; color: #475569; cursor: pointer; white-space: nowrap; }
.mkt-job-what { font-size: 12.5px; color: #334155; margin-top: 3px; }
.mkt-job-cost { font-size: 12px; color: #334155; margin-top: 5px; }
.mkt-job-note { font-size: 11.5px; color: #64748b; margin-top: 5px; font-style: italic; }
.mkt-job-bar {
  height: 6px; border-radius: 3px; background: #eef2f7; margin-top: 8px; overflow: hidden;
}
.mkt-job-bar > span { display: block; height: 100%; background: #2563eb; }
.mkt-job.warn .mkt-job-bar > span { background: #dc2626; }
.mkt-job-prog { font-size: 11.5px; color: #475569; margin-top: 3px; }

/* ── ⚙ Settings window body (owner 2026-08-14) ─────────────────────────────
   ONE background process per window, each drawing its own decision tree with
   the shared optflow engine. The card + overlay are the page's existing .cmp-*
   ones and the drawing is styled by shell.css's .fl-* block — this adds only
   the status line, the save row and the .ms-more footer. */
.ms-pane { padding-bottom: 4px; }

/* the live status line for the job a tab is about */
.ms-strip {
  display: flex; gap: 14px; align-items: baseline; flex-wrap: wrap;
  border: 1px solid var(--cg-line, #e2e8f0); border-left: 3px solid #2563eb;
  border-radius: 8px; padding: 8px 12px; margin-bottom: 10px; font-size: 11.5px; color: #64748b;
}
.ms-strip.off { border-left-color: #94a3b8; }
.ms-strip b { font-size: 13px; color: #1e293b; }
.ms-strip-sw { margin-left: auto; font-weight: 600; }
.ms-strip.off .ms-strip-sw { color: #b45309; }

/* the save row — sticky at the card's bottom, like the PPC diagrams' */
.ms-save {
  position: sticky; bottom: 0; background: #fff; border-top: 1px solid var(--cg-line, #e2e8f0);
  margin-top: 14px; padding: 10px 2px 2px; display: flex; align-items: center; gap: 12px;
}
.ms-saved { font-size: 12px; color: #1e7a45; }
.ms-hint { font-size: 11.5px; color: #94a3b8; margin-left: auto; }

/* the plain-text fallback when a diagram cannot be drawn */
.ms-flow-text { border: 1px solid var(--cg-line, #e2e8f0); border-radius: 10px; padding: 12px 16px; background: #fbfcfe; }
.ms-flow-text-note { font-size: 11.5px; color: #b45309; margin-bottom: 8px; }
.ms-flow-text ol { margin: 0; padding-left: 20px; }
.ms-flow-text li { font-size: 12.5px; color: #334155; margin-bottom: 9px; line-height: 1.55; }
.ms-flow-text li > div { font-size: 11.5px; color: #64748b; margin-top: 2px; }
.ms-flow-when { font-size: 11px; color: #2563eb; font-weight: 600; }

/* ── ⚙ Settings: the Keepa timetable (2026-08-14) ──────────────────────────
   Four jobs share one account. Every diagram now carries a strip saying WHEN
   its job runs and how much it may spend, and there is a window showing the
   whole day — the screen whose absence let the account run dry. */
.ms-when { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  border: 1px solid var(--cg-line, #e2e8f0); border-left: 3px solid #94a3b8;
  border-radius: 8px; padding: 8px 12px; margin: 0 0 10px; font-size: 12.5px; color: #334155; }
.ms-when.on { border-left-color: #16a34a; background: #f6fdf8; }
.ms-when-k { font-weight: 700; font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: #64748b; margin-right: 2px; }
.ms-when.on .ms-when-k { color: #15803d; }
.ms-when-x { flex: 1 1 100%; font-size: 11.5px; color: #64748b; line-height: 1.5; }

/* The 24-hour strip: who owns the day, as a picture. */
.ms-day { display: flex; gap: 2px; margin: 12px 0 14px; }
.ms-hr { flex: 1 1 0; height: 30px; border-radius: 4px; background: #eef2f7; color: #64748b;
  font-size: 10px; display: flex; align-items: center; justify-content: center; cursor: default; }
.ms-hr.free { background: repeating-linear-gradient(45deg, #f4f7fb, #f4f7fb 4px, #eaeff6 4px, #eaeff6 8px); }
.ms-hr.j-ratings      { background: #c7d7f7; color: #1e3a8a; }
.ms-hr.j-market_table { background: #bfe3d0; color: #14532d; }
.ms-hr.j-curve        { background: #f8d9b0; color: #7c2d12; }
.ms-hr.j-yearly       { background: #ddd0f0; color: #4c1d95; }

.ms-slots { display: flex; flex-direction: column; gap: 6px; margin-bottom: 4px; }
.ms-slot { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; font-size: 12.5px;
  border: 1px solid var(--cg-line, #e2e8f0); border-radius: 8px; padding: 8px 12px; }
.ms-slot.on { border-color: #86efac; background: #f6fdf8; }
.ms-slot > b { min-width: 104px; }
.ms-slot-j { font-weight: 600; padding: 1px 8px; border-radius: 20px; }
.ms-slot-j.j-ratings      { background: #c7d7f7; color: #1e3a8a; }
.ms-slot-j.j-market_table { background: #bfe3d0; color: #14532d; }
.ms-slot-j.j-curve        { background: #f8d9b0; color: #7c2d12; }
.ms-slot-j.j-yearly       { background: #ddd0f0; color: #4c1d95; }
.ms-slot-c, .ms-slot-b { color: #64748b; font-size: 12px; }
.ms-slot-b { margin-left: auto; }
.ms-slot-now { font-weight: 700; color: #15803d; font-size: 11.5px; }

/* ── "Is this diagram still true?" (owner 2026-08-15) ──────────────────────
   The diagrams are prose about behaviour, and prose rots silently when the
   code moves. tests/diagram-drift.mjs hashes the functions each diagram names
   and parks its verdict in diagram-truth.json; this is how that verdict looks.
   RED MEANS "GO AND LOOK", never "this is wrong" — a changed function may
   still behave exactly as described. */
.ms-truth { display: block; border-radius: 8px; padding: 9px 12px; margin: 0 0 12px;
  font-size: 12.5px; line-height: 1.55; border: 1px solid; }
.ms-truth .ms-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 8px; vertical-align: 1px; }
.ms-truth.ok      { background: #f4fbf6; border-color: #cbe9d6; color: #14532d; }
.ms-truth.ok .ms-dot      { background: #16a34a; }
.ms-truth.bad     { background: #fdf6f6; border-color: #f0cccc; color: #7f1d1d; }
.ms-truth.bad .ms-dot     { background: #dc2626; }
.ms-truth.unknown { background: #f7f9fc; border-color: #e2e8f0; color: #64748b; }
.ms-truth.unknown .ms-dot { background: #cbd5e1; }
.ms-truth-d { color: #64748b; font-size: 11.5px; }
.ms-truth-l { margin: 7px 0 0; padding-left: 20px; }
.ms-truth-l li { margin-bottom: 3px; }
.ms-truth-x { display: block; margin-top: 7px; font-size: 11.5px; color: #9a6a6a; }
.ms-truth-x code { background: #fff; border: 1px solid #f0cccc; border-radius: 4px; padding: 0 4px; }

/* the dot on each ⚙ menu row, and on the button when anything is red */
#mktSetMenu .set-item { position: relative; padding-left: 30px; }
#mktSetMenu .set-item::before { content: ''; position: absolute; left: 14px; top: 15px;
  width: 7px; height: 7px; border-radius: 50%; background: #cbd5e1; }
#mktSetMenu .set-item.t-green::before { background: #16a34a; }
#mktSetMenu .set-item.t-red::before   { background: #dc2626; }
  /* A DIAGRAM OF SOMETHING NOT BUILT — hollow, not green. Green on this menu
     means "checked against the live code"; a plan has no code to check, and a
     green dot beside it read as "built and working" (owner 2026-08-18). */
  #mktSetMenu .set-item.t-plan::before  { background: #fff; border: 1.5px dashed #b6bec9; }

  /* The curve chip in the Comparison-columns key answers "are we on the latest
     curve?" at a glance — green when every category's curve is today's, amber
     when one is not (owner 2026-08-18). */
  /* the curve row's freshness note now lives with .src-item above */
.set-btn.has-red::after { content: ''; display: inline-block; width: 7px; height: 7px;
  border-radius: 50%; background: #dc2626; margin-left: 7px; vertical-align: 1px;
  box-shadow: 0 0 0 2px rgba(255,255,255,.9); }

/* ── "Cost / dot" on the BSR curves table (owner 2026-08-15) ───────────────
   Tokens spent ÷ usable points bought, last 7 days. Complete and CHEAP are
   different questions: two categories can both read "complete ✓" while one
   spends 17 tokens a point and the other 4. Coloured so the expensive ones
   are findable at a glance — that is the whole reason the column exists. */
.cost-ok  { color: #15803d; font-weight: 600; }
.cost-mid { color: #b45309; font-weight: 600; }
.cost-bad { color: #b91c1c; font-weight: 700; }
.cost-u   { color: #94a3b8; font-weight: 400; font-size: 11px; }

/* ── Roster popup (owner 2026-08-15) ───────────────────────────────────────
   The ASINs behind one category's curve. House COMPACT table: 40px rows like
   the market tables, one-line identity cell, figures centred. Same .cmp-*
   overlay every other popup on this page uses — no second popup style. */
.rost-card { max-width: 1080px; }
/* it was flush against the card frame — an obvious ugliness (owner). */
.rost-sum { font-size: 12.5px; color: #475569; padding: 12px 2px 10px; }
.rost-tbl { width: 100%; }
.rost-tbl th, .rost-tbl td { padding: 5px 8px; font-size: 12px; }
.rost-tbl tbody tr { height: 34px; }
.rost-tbl .name-col { min-width: 260px; }
.rost-tbl td.cg-ident a { font-weight: 600; font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; }
.rost-t { display: block; color: #8a93a0; font-size: 11px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
/* the section headers inside the list — used vs not used */
.rost-sec td { background: #f1f5f9; font-weight: 700; font-size: 11px; color: #475569;
  text-transform: uppercase; letter-spacing: .04em; padding: 4px 8px; }
.rost-miss td { background: #fdfdfe; color: #64748b; }
/* THE FRACTION IS THE HEADLINE, the percentage the footnote (owner
   2026-08-15: "the how-many-out-of-how-many should be bigger; the percentage
   is screaming out but the number below doesn't"). */
.rost-frac { display: block; font-size: 13px; font-weight: 700; color: #1a1d23;
  font-family: 'IBM Plex Mono', monospace; line-height: 1.15; }
.rost-pct  { display: block; font-size: 10.5px; font-weight: 600; line-height: 1.2; }
/* short, classified reasons — the family case is the one worth spotting */
.why { display: inline-block; font-size: 11.5px; }
.why-used   { color: #15803d; font-weight: 600; }
.why-family { color: #7c3aed; font-weight: 600; }
.why-nobadge{ color: #b45309; }
.why-dropped{ color: #94a3b8; }
.why-skipped{ color: #94a3b8; }
/* the button in the main table's Roster column */
.roster-link { background: #fff; border: 1px solid #d7dde6; border-radius: 6px;
  padding: 2px 9px; font-size: 11.5px; font-weight: 600; color: #2563eb; cursor: pointer;
  font-family: inherit; white-space: nowrap; }
.roster-link:hover { background: #f4f8ff; border-color: #c8d6f5; }

/* ── Curve status switch on the BSR curves table (owner 2026-08-15) ────────
   Enabled = harvested daily inside the curve job's hours. Disabled = left
   alone and costs nothing. Seeded from the categories we sell in, so nothing
   changed the day it shipped — but it is a CHOICE now, not a computed fact,
   because a wasteful category can be worth pausing whatever we sell in it. */
.cst-sw { border: 1px solid #d7dde6; background: #f7f9fc; color: #64748b;
  border-radius: 20px; padding: 2px 11px; font-size: 11px; font-weight: 700;
  letter-spacing: .02em; cursor: pointer; font-family: inherit; white-space: nowrap; }
.cst-sw:hover:not(:disabled) { border-color: #c3ccd8; color: #1a1d23; }
.cst-sw.on { background: #e6f7ed; border-color: #bfe8cf; color: #15803d; }
.cst-sw:disabled { opacity: .5; cursor: default; }

/* ── The BSR curves table, made compact (owner 2026-08-15) ─────────────────
   "the header is not one row, it should be two rows with wrapped text aligned
   to the centre; Times complete could be much narrower because it's just a
   digit". The house rule already says a column is sized by its FIGURES and the
   header wraps to fit (shell.css, HOUSE TABLE STANDARD) — this table was not
   obeying it because its headers were one long unwrappable string. .th-label
   is the span the shell's two-line clamp works on.
   Header PADDING is deliberately not set here: the shell owns it
   (html[data-shell="v2"] thead th — 5px 15px 5px 7px, the right side reserved
   for the sort arrow) and wins on specificity anyway. So every width below is
   the FIGURE's width PLUS that 22px, not the figure's width. 58px left the word
   "complete" 42px to live in and it was silently chopped in half. */
.curve-tbl th { text-align: center; vertical-align: middle; }
.curve-tbl th .th-label {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; white-space: normal; line-height: 1.25; font-size: 10.5px;
  font-weight: 600; text-align: center;
}
/* Column order, so these numbers can be checked by eye against curves.js:
   1 category · 2 market · 3 curve status · 4 newest usable curve ·
   5 usable/covered/tried · 6 days tried · 7 today's status · 8 retry ·
   9 token cost · 10 roster · 11 extra scanned · 12 fit
   the plain-count columns are a digit or two — stop them taking a label's width */
.curve-tbl th:nth-child(6),  .curve-tbl td:nth-child(6),   /* days tried */
.curve-tbl th:nth-child(12), .curve-tbl td:nth-child(12) { /* fit */
  width: 72px; max-width: 72px;
}
.curve-tbl th:nth-child(2), .curve-tbl td:nth-child(2) { width: 66px; }   /* market */
.curve-tbl th:nth-child(3), .curve-tbl td:nth-child(3) { width: 82px; }   /* curve status */
.curve-tbl th:nth-child(8), .curve-tbl td:nth-child(8) { width: 68px; }   /* retry */
/* Three figures and a three-word header, so wider than the plain-digit columns
   above — still far under a label column.
   MIN-width, not width: this table is wider than the window and the browser
   shrinks every column proportionally to fit, which turned a 118px `width`
   into 92px and chopped the header's third word. A min-width cannot be
   shrunk; the table scrolls sideways inside its own strip instead, which is
   what .table-scroll is for. */
.curve-tbl th:nth-child(5), .curve-tbl td:nth-child(5) { min-width: 112px; }
.curve-tbl td { padding: 5px 6px; font-size: 12px; }
.curve-tbl tbody tr { height: 38px; }

/* The "why?" button in the Retry column. Amber rather than blue: it belongs to
   a row that did NOT finish, and it is the one control on this table that can
   spend tokens. It shipped for an hour with no rule at all and rendered as a
   raw grey browser button — caught in a screenshot, not by a measurement. */
.retry-btn { background: #fffaf0; border: 1px solid #f0d9a8; border-radius: 6px;
  padding: 2px 9px; font-size: 11.5px; font-weight: 600; color: #92400e; cursor: pointer;
  font-family: inherit; white-space: nowrap; }
.retry-btn:hover { background: #fdf2d8; border-color: #e5c37f; }

/* ── the "why didn't it complete" card ─────────────────────────────────── */
.retry-card { max-width: 640px; }
.rt-row { display: flex; gap: 10px; align-items: baseline; font-size: 12.5px;
  padding: 7px 2px; border-bottom: 1px solid var(--cg-line, #e2e8f0); }
.rt-k { min-width: 122px; color: #64748b; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; }
.rt-why { color: #334155; }
.rt-adv { margin: 12px 0; padding: 10px 12px; border-radius: 8px; font-size: 12.5px; line-height: 1.55; }
.rt-adv.ok { background: #f4fbf6; border: 1px solid #cbe9d6; color: #14532d; }
.rt-adv.no { background: #f7f9fc; border: 1px solid #e2e8f0; color: #475569; }
/* The three-part record in the curves table: usable / covered / tried.
   Colour is the FIRST number's story — green if it has ever produced a usable
   curve, amber if it collects the products but never fits a line (the case
   worth acting on), grey if it has never even collected enough. */
.hist-link { background: none; border: 0; padding: 2px 4px; cursor: pointer;
  font: 600 12px/1.2 inherit; color: #475569; border-radius: 5px; white-space: nowrap; }
.hist-link:hover { background: #f1f5f9; }
.hist-link b { font-size: 13px; }
.hist-ok b   { color: #15803d; }
.hist-mid b  { color: #b45309; }
.hist-none b { color: #94a3b8; }
.rt-gap { margin: 12px 0; padding: 10px 12px; border-radius: 8px; background: #f7f9fc;
  border: 1px solid #e2e8f0; font-size: 12.5px; line-height: 1.7; color: #334155; }
.rt-sub { color: #64748b; font-size: 11.5px; }

.rt-plan { font-size: 12.5px; line-height: 1.55; color: #334155; margin: 0 0 12px; }
.rost-sum { padding-left: 0; }
.rt-act { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-bottom: 4px; }
.rt-lbl { font-size: 11px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: #64748b; }
/* A number box, not a text field: it holds a token count and nothing else. */
.rt-tok { width: 92px; padding: 5px 8px; font: 600 13px/1.2 inherit; text-align: right;
  border: 1px solid #d7dde6; border-radius: 6px; color: #0f172a; background: #fff; }
.rt-tok:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.rt-unit { font-size: 12px; color: #64748b; margin-right: 4px; }
.rt-note { font-size: 11.5px; color: #64748b; flex: 1 1 100%; line-height: 1.55; margin-top: 8px; }

/* ── WHY A PRODUCT LEFT THE MARKET (2026-08-16) ─────────────────────────────
   Two reasons, two behaviours, so two clearly different colours — and both
   are CLICKABLE, because the guess is only a starting point. Amber = it is
   being watched and may come back; grey = it is settled and never will.     */
.rsn { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 11px;
       font-weight: 600; cursor: pointer; border: 1px solid transparent; white-space: nowrap; }
.rsn:hover { filter: brightness(0.94); text-decoration: underline; }
.rsn-small   { background: #fef3c7; color: #92400e; border-color: #fde68a; }
.rsn-notcomp { background: #f1f5f9; color: #475569; border-color: #e2e8f0; }
.rsn-none    { background: #fff; color: #94a3b8; border-color: #e2e8f0; font-style: italic; }
/* Deliberately quiet next to Restore: deleting for good is the rarer, heavier
   action, and the only one that cannot be undone. */
.forget-btn { background: #fff; color: #b91c1c; border: 1px solid #fecaca; border-radius: 6px;
              padding: 2px 8px; font-size: 11px; cursor: pointer; }
.forget-btn:hover { background: #fef2f2; }

/* ── "IT GREW BACK" (2026-08-16) — news, so it sits ABOVE the removed list ──
   Green rather than red: a product you removed selling well again is an
   opportunity, not a fault. Quiet enough to ignore on a day you are doing
   something else, loud enough that you never have to go looking for it.      */
.grew-card { border: 1px solid #bbf7d0; background: #f0fdf4; border-radius: 10px;
             padding: 12px 14px; margin: 0 0 var(--cg-row, 14px); }
.grew-head b { display: block; font-size: 13.5px; color: #14532d; }
.grew-head span { display: block; font-size: 11.5px; color: #4b7c5b; margin-top: 2px; }
.grew-tbl { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 12px; }
.grew-tbl th { text-align: center; font-size: 10.5px; font-weight: 600; color: #4b7c5b;
               padding: 4px 6px; border-bottom: 1px solid #bbf7d0; }
.grew-tbl th:first-child { text-align: left; }
.grew-tbl td { padding: 5px 6px; border-bottom: 1px solid #dcfce7; text-align: center; }
.grew-tbl td.name-col { text-align: left; }
.grew-no { background: #fff; color: #475569; border: 1px solid #cbd5e1; border-radius: 6px;
           padding: 2px 8px; font-size: 11px; cursor: pointer; }
.grew-no:hover { background: #f8fafc; }
.grew-foot { font-size: 11px; color: #4b7c5b; margin-top: 8px; }

  /* ═══════════════════════════════════════════════════════════════════════
     THE AI MARKET BUILDER (2026-08-18)
     The create window's mode strip, and the build card that shows a run's
     progress and then its draft. Nothing here re-declares table geometry —
     the shell owns that (RULEBOOK Rule 6); these are only the pieces the
     shell has no opinion about.
     ═══════════════════════════════════════════════════════════════════════ */
  .nm-modes { display: flex; gap: 6px; margin: 2px 0 12px; }
  .nm-mode { flex: 1; background: #fff; border: 1px solid #d7dbe2; border-radius: 8px;
             padding: 8px 10px; font: inherit; font-size: 13px; font-weight: 600;
             color: #5b6572; cursor: pointer; }
  .nm-mode:hover { background: #f6f8fb; }
  .nm-mode.on { border-color: #2563eb; color: #2563eb; background: #eef4ff; }
  .nm-opt { font-weight: 400; font-size: 11.5px; color: #98a1b0; }

  .bld-card { background: #fff; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,.06);
              margin: 0 var(--cg-gutter, 28px) var(--cg-row, 14px); overflow: hidden;
              border-left: 3px solid #2563eb; }
  .bld-card.failed { border-left-color: #dc2626; }
  .bld-card.split  { border-left-color: #d97706; }
  .bld-card.ready  { border-left-color: #16a34a; }
  .bld-head { display: flex; justify-content: space-between; align-items: baseline;
              gap: 12px; padding: 11px 16px; border-bottom: 1px solid #eef0f3; }
  .bld-head b { font-size: 14px; }
  .bld-head span { font-size: 12px; color: #98a1b0; }
  /* The stages, as a row you can read at a glance — a 40-minute job needs to
     say WHERE it is, not just that it is working. */
  .bld-steps { display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
               padding: 10px 16px 4px; font-size: 12px; }
  .bld-step { color: #b6bec9; }
  .bld-step.done { color: #16a34a; }
  .bld-step.now { color: #2563eb; font-weight: 700; }
  .bld-arrow { color: #dfe3ea; }
  .bld-note { padding: 6px 16px 10px; font-size: 12.5px; color: #5b6572; line-height: 1.55; }
  /* OUT OF CREDIT — the one failure that is a bill, not a fault, and the one
     the owner asked to be unmissable. Loud on purpose: it replaces the small
     grey reason line rather than sitting beside it. */
  .bld-credit { margin: 8px 16px 12px; padding: 14px 16px; border-radius: 10px;
    background: #fff1f2; border: 1px solid #fca5a5; border-left: 5px solid #dc2626; }
  .bld-credit-t { font-size: 15px; font-weight: 800; color: #b91c1c; margin-bottom: 5px; }
  .bld-credit-b { font-size: 13px; color: #7f1d1d; line-height: 1.6; }
  /* Figures, not adjectives: this is what proves a build is alive. */
  .bld-figs { display: flex; flex-wrap: wrap; gap: 14px; padding: 0 16px 11px;
              font-size: 12px; color: #5b6572; }
  .bld-foot { padding: 8px 16px 12px; font-size: 11.5px; color: #98a1b0; }
  /* A cap that stopped the search is never quiet — a silent truncation reads
     as "we covered everything" when we did not. */
  .bld-cap { margin: 0; padding: 8px 16px; background: #fff8ec; color: #8a6410;
             font-size: 12.5px; border-top: 1px solid #f3e6cd; border-bottom: 1px solid #f3e6cd; }
  /* ── "How it went" — the whole run at a glance ─────────────────────────
     A lamp, one row per search, one dot per page. It is the first thing on a
     draft because it says whether the list underneath is the whole market or
     only the part Amazon let us see. Open by default: a summary you have to
     click for is a summary nobody reads. */
  /* ── THE GRADE — one word on the card, everything else behind it ────────
     Owner 2026-08-23: "how it went should be 1 button saying Perfect … all the
     way to poor." A row of dots is something you have to read; a grade is
     something you glance at and then decide whether to open. */
  /* Other finished drafts — never only reachable by being the newest thing
     that happened. */

  .bld-grade-row { border-bottom: 1px solid #eef0f3; background: #fbfcfe; padding: 8px 16px; }
  .bld-grade { display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
    border: 1px solid var(--cg-line, #e2e8f0); background: #fff; border-radius: 999px;
    padding: 6px 14px 6px 11px; font: inherit; font-size: 12.5px; color: #475569; }
  .bld-grade:hover { background: #f5f8ff; border-color: #c7dbff; }
  .bld-grade b { color: #1e293b; }
  .bld-grade i { font-style: normal; color: #94a3b8; font-size: 11px; margin-left: 4px; }
  .bld-grade.ok    b { color: #1e7a45; }
  .bld-grade.warn  b { color: #a8631a; }
  .bld-grade.bad   b { color: #a8322a; }
  .bld-g-ok { color: #1e7a45; } .bld-g-warn { color: #a8631a; } .bld-g-bad { color: #a8322a; }

  /* The window it opens. Same overlay layer as the process map (400) — under
     nothing, over the sidebar. */
  .bld-win { position: fixed; inset: 0; background: rgba(15,23,42,.45); z-index: 400;
    display: flex; align-items: center; justify-content: center; padding: 24px; }
  .bld-win-card { background: #fff; border-radius: 14px; width: min(1180px, 96vw);
    max-height: 92vh; display: flex; flex-direction: column; overflow: hidden;
    box-shadow: 0 24px 60px rgba(15,23,42,.28); }
  .bld-win-body { overflow: auto; padding: 14px 18px 20px; }
  .bld-h3 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    font-size: 13px; color: #1e293b; margin: 18px 0 8px; }
  .bld-filters { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
  .bld-f { border: 1px solid var(--cg-line, #e2e8f0); background: #fff; border-radius: 999px;
    padding: 3px 10px; font: inherit; font-size: 11px; font-weight: 600; color: #64748b;
    cursor: pointer; }
  .bld-f:hover { background: #f5f8ff; }
  .bld-f.on { background: #2563eb; border-color: #2563eb; color: #fff; }
  .bld-grade-t { background: #eef2f9; color: #475569; border-radius: 999px;
    padding: 1px 8px; font-size: 11px; font-weight: 700; }
  /* Where the time went — bars, because the question is proportion ("was it
     Amazon or the AI?"), not arithmetic. Blue is us talking to Amazon, purple
     is the AI, grey is everything between the phases. */
  .bld-t-total { margin-left: auto; font-weight: 700; color: #1e293b; font-size: 12px; }
  .bld-times { display: grid; gap: 5px; }
  .bld-t-row { display: flex; align-items: center; gap: 10px; font-size: 11.5px; color: #475569; }
  .bld-t-n { flex: 0 0 210px; max-width: 210px; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  .bld-t-bar { flex: 1 1 auto; background: #f1f4f8; border-radius: 5px; height: 12px;
    overflow: hidden; }
  .bld-t-bar i { display: block; height: 100%; border-radius: 5px; background: #94a3b8; }
  .bld-t-bar i.net   { background: #5b8def; }
  .bld-t-bar i.ai    { background: #a78bfa; }
  .bld-t-bar i.other { background: #cbd5e1; }
  .bld-t-s { flex: 0 0 62px; text-align: right; font-weight: 700; color: #1e293b; }

  .bld-prod { max-height: 46vh; }
  .bld-img.sm { width: 46px; height: 46px; object-fit: contain; }
  .bld-v { display: inline-block; border-radius: 6px; padding: 2px 8px;
    font-size: 11px; font-weight: 700; }
  .bld-v.in     { background: #e7f4ec; color: #1e7a45; }
  .bld-v.out    { background: #fbe6e3; color: #a8322a; }
  .bld-v.unsure { background: #eef2f9; color: #475569; }
  .bld-v.none   { background: #fdf0dd; color: #a8631a; }

  .bld-run { border-bottom: 1px solid #eef0f3; background: #fbfcfe; padding: 9px 16px 11px; }
  .bld-run > summary { cursor: pointer; font-size: 12.5px; color: #475569;
                       display: flex; align-items: center; gap: 8px; list-style: none; }
  .bld-run > summary::-webkit-details-marker { display: none; }
  .bld-run > summary b { color: #1e293b; }
  .bld-run-lamp { width: 9px; height: 9px; border-radius: 50%; flex: none;
                  box-shadow: 0 0 0 3px rgba(0,0,0,.04); }
  .bld-run-lamp.ok   { background: #1e7a45; }
  .bld-run-lamp.warn { background: #d98324; }
  .bld-run-lamp.bad  { background: #c0392b; }
  .bld-run-sub  { font-size: 11.5px; color: #64748b; line-height: 1.55; margin: 5px 0 8px 17px; }
  .bld-run-rows { display: grid; gap: 3px; margin-left: 17px; }
  .bld-run-row  { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
                  font-size: 11.5px; color: #475569; }
  /* The terms line up, so a glance down the dots is a glance down the run. */
  .bld-run-w    { flex: 0 0 250px; max-width: 250px; overflow: hidden;
                  text-overflow: ellipsis; white-space: nowrap; }
  .bld-run-w i  { font-style: normal; color: #94a3b8; font-size: 10.5px; }
  .bld-st       { display: inline-flex; align-items: center; gap: 3px; color: #94a3b8;
                  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; }
  .bld-st + .bld-st { margin-left: 8px; }
  /* One dot = one page. A number instead of a dot IS the retry count — no key
     to memorise, the dot says how many goes it took. */
  .bld-dot-ok, .bld-dot-warn, .bld-dot-bad {
    display: inline-flex; align-items: center; justify-content: center; cursor: help;
    min-width: 15px; height: 15px; padding: 0 4px; border-radius: 4px;
    font-size: 9.5px; font-weight: 800; letter-spacing: 0; }
  /* WHICH PAGE A DOT IS. p1 and p2 are different facts about a market — page 2
     is the smaller sellers — so the page rides on the dot instead of hiding in
     a hover. The label is deliberately quiet: the colour is still the signal. */
  /* ── The charts row head (owners 2026-09-06) ──
     ONE line, the Sales Charts row's shape: the orange house caret + the
     title, the five panels as HOUSE chips (.filter-chip — never a page-local
     pill, House Standard §4), the range at the far end. The old .cw-btn pill,
     its ▸ caret and the uppercase CHARTS label are gone. */
  .cw-bar   { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px;
              padding: 11px 18px; }
  .cw-head  { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 14px;
              font-weight: 600; color: #2d3436; cursor: pointer; user-select: none; white-space: nowrap; }
  .cw-chips { flex: 1 1 auto; }
  /* The range control is pushed to the far end: the chips say WHAT to show,
     this says OVER WHAT — two different questions, so they are not interleaved. */
  .cw-range { margin-left: auto; display: flex; align-items: center; gap: 8px; }
  .cw-range label { font-size: 11.5px; font-weight: 600; color: #8a94a6; cursor: help; white-space: nowrap; }
  .cw-range select { border: 1px solid #d7dbe2; border-radius: 7px; padding: 4px 8px; font-size: 12px;
                     font-family: inherit; color: #2d3436; background: #fff; cursor: pointer; }
  /* The open panels sit INSIDE the card like the Sales row's: flat, no second
     shadowed box inside a box, a hairline above each. */
  #chartsCard .charts-grid, #chartsCard .rev-grid { padding: 0 18px var(--cg-row, 14px); margin: 0; }
  #chartsCard .chart-card { box-shadow: none; border: 1px solid #eef0f3; border-radius: 10px; }

  /* The line, edited where its work is shown. */
  .sup-line-box { display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
                  padding: 10px 18px 12px; border-bottom: 1px solid #eef0f3; background: #fbfcfe; }
  .sup-line     { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
                  color: #2d3436; font-weight: 600; }
  .sup-line-in  { display: inline-flex; align-items: center; gap: 2px; }
  .sup-line-in > i { font-style: normal; color: #8a93a0; font-size: 12.5px; }
  .sup-line input { width: 92px; padding: 5px 8px; font: inherit; font-size: 13px;
                    border: 1px solid #d7dde6; border-radius: 6px; text-align: right; }
  .sup-line input:focus { outline: 0; border-color: #2563eb; box-shadow: 0 0 0 2px #dbeafe; }
  .sup-line .gray { font-weight: 400; }
  .sup-line-said { font-size: 12px; font-weight: 600; }
  .sup-line-said.ok  { color: #1e7a45; }
  .sup-line-said.bad { color: #b02020; }
  .sup-line-note { font-size: 11.5px; color: #8a93a0; margin-left: auto; max-width: 380px;
                   line-height: 1.45; }

  /* ── ONE ROW FOR EVERY BUILD — running and finished, same shape ── */
  .bld-w-hint   { font-size: 11.5px; color: #98a1b0; margin-right: 2px; }
  .bld-w-open.on i,
  /* A build still running gets a live dot — the one pill whose figures are
     going to change while you look at it. */
  @keyframes bldPulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }

  /* ── NOT IN THE TABLE — the same table, its own selection ──
     A clear band above it so the two tables never read as one long one. */
  .trend-capnote { font-size: 12px; color: #6b7481; padding: 6px 2px 0; }
  /* The search box takes the house .cg-search look from shell.css and only
     says how wide it is here — the bulk bar is a flex row and an input with no
     width in one grows to fill it. */
  .mkt-search   { width: 210px; max-width: 30vw; }
  .mkt-search-n { font-size: 12px; color: #6b7481; white-space: nowrap; }
  .mkt-search-n a { color: #2563eb; cursor: pointer; text-decoration: underline; margin-left: 4px; }
  .rem-sec      { border-top: 12px solid #f2f5f9; padding-top: 2px; }
  /* CLOSED IS THE DEFAULT (owner 2026-08-27): the heading is the whole section
     until it is opened, so it costs one row. ONE wrapper carries the hiding —
     each child keeps whatever display it was written with. */
  .rem-body           { display: none; }
  .rem-sec.open .rem-body { display: block; }
  .rem-head     { cursor: pointer; }
  .rem-head .sup-slot { cursor: auto; }
  .rem-head     { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
                  padding: 12px 18px 2px; }
  .rem-head h3  { margin: 0; font-size: 14px; font-weight: 700; color: #1a1d23;
                  display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
  .rem-n        { display: inline-flex; align-items: center; justify-content: center;
                  min-width: 22px; height: 20px; padding: 0 7px; border-radius: 999px;
                  background: #eef2f7; color: #55606f; font-size: 11.5px; font-weight: 800; }
  /* .rem-sub (the "held out of X — same columns, same actions" sentence) was
     deleted 2026-08-27 at the owner's request. The heading names the list; the
     bulk bar inside it names the actions. */
  .rem-bar      { border-bottom: 0; }
  .bulk-item.bulk-good .ri-main { color: #1e7a45; }

  /* The line, edited beside the products it took. */
  .sup-line-box { display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
                  margin-left: auto; }
  .sup-why      { font-size: 12px; color: #6b7481; display: inline-flex; align-items: center; gap: 6px; }
  .sup-why b    { color: #2d3436; font-weight: 700; }
  .sup-why i    { font-style: normal; color: #cbd2dc; }
  .sup-alert    { color: #b45309; font-weight: 700; cursor: help; }
  .sup-line     { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
                  color: #2d3436; font-weight: 600; }
  .sup-line-in  { display: inline-flex; align-items: center; gap: 2px; }
  .sup-line-in > i { font-style: normal; color: #8a93a0; font-size: 12.5px; }
  .sup-line input { width: 88px; padding: 5px 8px; font: inherit; font-size: 13px;
                    border: 1px solid #d7dde6; border-radius: 6px; text-align: right; }
  .sup-line input:focus { outline: 0; border-color: #2563eb; box-shadow: 0 0 0 2px #dbeafe; }
  .sup-line .gray { font-weight: 400; }
  .sup-line-said { font-size: 12px; font-weight: 600; }
  .sup-line-said.ok  { color: #1e7a45; }
  .sup-line-said.bad { color: #b02020; }

  /* The totals row's share pills sit UNDER their number instead of after it —
     the cell is sized for a figure, and an inline pill was being cut off. */
  .totals .tot-share { display: block; margin-top: 2px; font-weight: 400; }
  .totals .tot-share .sharepill { white-space: nowrap; }
  .totals .tot-ours  { display: inline-block; white-space: nowrap; }

  .bld-pg       { display: inline-flex; align-items: center; gap: 2px; }
  .bld-pg + .bld-pg { margin-left: 5px; }
  .bld-pg > i   { font-style: normal; font-size: 9.5px; font-weight: 700; color: #9aa4b2;
                  letter-spacing: -.02em; }

  /* ONE COLOUR PER SEARCH, the same chip in the run report and on the draft, so
     "do the products that matter all come from one search?" is a glance down a
     column rather than forty phrases read end to end. 1 is always your market
     name. v0 is the unknown-search grey — never a borrowed colour. */
  .bld-via      { display: inline-flex; align-items: center; justify-content: center;
                  min-width: 19px; height: 19px; padding: 0 5px; border-radius: 5px;
                  font-size: 11px; font-weight: 800; line-height: 1; cursor: help;
                  border: 1px solid transparent; }
  .bld-via-h    { width: 52px; }
  .bld-via.v1   { background: #e3edfd; border-color: #bcd4f7; color: #1b4f9c; }
  .bld-via.v2   { background: #e6f6ec; border-color: #bfe4cd; color: #1c6f42; }
  .bld-via.v3   { background: #fdeee0; border-color: #f3d4b2; color: #9a5716; }
  .bld-via.v4   { background: #f0e8fb; border-color: #d8c7f2; color: #5b3496; }
  .bld-via.v5   { background: #fde8ef; border-color: #f5c6d6; color: #9c2b52; }
  .bld-via.v0,
  .bld-via.none { background: #f1f4f8; border-color: #e0e6ee; color: #97a1b0; font-weight: 700; }
  .bld-via.seed { background: #fff5d8; border-color: #ecd79a; color: #8a6100; font-size: 10px; }

  /* ── "Already found in" (migration 274) ────────────────────────────────
     Same chips as Found, so the two columns read as one thought: this search
     returned it · these earlier searches already had another size or colour of
     it. `new` is the answer people scan for, so it is the one with colour in
     it; "not checked" is deliberately grey and wordy — it must never be
     mistaken for an answer. */
  .bld-alr-h    { width: 96px; }
  .bld-already  { white-space: nowrap; }
  .bld-new      { display: inline-flex; align-items: center; height: 19px; padding: 0 7px;
                  border-radius: 5px; font-size: 11px; font-weight: 800; line-height: 1;
                  background: #e6f7ed; border: 1px solid #bfe8cf; color: #1e7a45; cursor: help; }

  /* ── "AI right?" and "Why — in your words" (migration 274) ─────────────
     The judgement about the AI, kept visibly apart from the tick at the far
     left — they are two different decisions and the width between them is part
     of saying so. The select is as narrow as its longest word; the reason box
     is the wide one, because that is the column that carries the teaching. */
  .bld-right-h  { width: 86px; }
  .bld-right    { width: 82px; font: inherit; font-size: 11.5px; padding: 2px 4px;
                  border: 1px solid #dbe3ee; border-radius: 6px; background: #fff; color: #3a4553; }
  .bld-right:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 2px rgba(37,99,235,.15); }
  /* A row somebody has judged is worth seeing from across the table. */
  .bld-right[data-set="wrong"]   { background: #fdecec; border-color: #e79a9a; color: #b02020; font-weight: 700; }
  .bld-right[data-set="correct"] { background: #e6f7ed; border-color: #bfe8cf; color: #1e7a45; font-weight: 700; }
  .bld-right[data-set="unsure"]  { background: #fff3e0; border-color: #ffddb0; color: #b36b00; }
  .bld-whyme-h  { width: 220px; }
  .bld-whyme    { min-width: 200px; }
  .bld-rightwhy { width: 100%; box-sizing: border-box; font: inherit; font-size: 11.5px;
                  padding: 3px 6px; border: 1px solid #dbe3ee; border-radius: 6px;
                  background: #fff; color: #3a4553; }
  .bld-rightwhy:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 2px rgba(37,99,235,.15); }
  .bld-rightwhy::placeholder { color: #b7c0cc; }

  /* ── THE PROMPT WINDOW, and the drafts-list picker (migration 276) ──────
     Both buttons end here: the prompt as it is on the left, the prompt as it
     WOULD be on the right — and the right side is a real textarea, because the
     owners' whole condition for letting a prompt change is being able to edit
     it first. */
  .bld-pw-card   { width: min(1180px, 96vw); max-height: 92vh; display: flex; flex-direction: column; }
  .bld-pw-body   { padding: 12px 16px; overflow: auto; flex: 1 1 auto; }
  .bld-pw-why    { font-size: 12.5px; line-height: 1.55; color: #8a6100; background: #fff8e6;
                   border: 1px solid #e8cf95; border-radius: 8px; padding: 9px 12px; margin-bottom: 10px; }
  .bld-pw-same   { font-size: 12.5px; color: #4a5568; background: #f2f6fb; border: 1px solid #dbe3ee;
                   border-radius: 8px; padding: 9px 12px; margin-bottom: 10px; }
  .bld-pw-cols   { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
  .bld-pw-col h4 { margin: 0 0 6px; font-size: 12.5px; color: #4a5568; font-weight: 700; }
  .bld-pw-pre,
  .bld-pw-new    { width: 100%; box-sizing: border-box; height: 46vh; overflow: auto;
                   font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px;
                   line-height: 1.55; white-space: pre-wrap; word-break: break-word;
                   border: 1px solid #dbe3ee; border-radius: 8px; padding: 10px 12px; margin: 0; }
  .bld-pw-pre    { background: #f7fafd; color: #4a6a8a; }
  .bld-pw-new    { background: #fff; color: #232f3e; resize: vertical; }
  .bld-pw-new:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 2px rgba(37,99,235,.15); }
  .bld-pw-note   { margin-top: 10px; font-size: 12px; line-height: 1.6; color: #6b7787; }
  .bld-pw-acts   { display: flex; justify-content: flex-end; gap: 10px; padding: 12px 16px;
                   border-top: 1px solid #e6e8ec; }
  @media (max-width: 900px) { .bld-pw-cols { grid-template-columns: 1fr; } }

  /* One tick per draft on the list, for choosing what button 3b analyses. */
  /* The pick box is a column of its own on the left, so the name and the ✕ keep
     the row they have always had. `float` is what the ✕ already uses here. */
  .ri-pick       { float: left; margin: 1px 8px 0 0; display: inline-flex; align-items: center;
                   cursor: pointer; }
  .ri-pick input { cursor: pointer; }
  .drafts-item   { overflow: hidden; }          /* contains the floated pick box */
  .drafts-foot   { display: flex; align-items: center; gap: 10px; padding: 9px 12px;
                   border-top: 1px solid #e6e8ec; background: #f7fafd; }
  .drafts-foot-n { font-size: 11.5px; color: #8a93a0; }

  /* ── THE EXAM'S CARD in ⚙ → AI market builder (migration 275) ──────────
     One number, big enough to read from the doorway, and the caveat under it
     in the house's short-lines style — `unsure` counting as neither is the
     thing a reader must not have to work out for themselves. */
  .ms-score      { border: 1px solid #d8e4f1; background: #f7fafd; border-radius: 10px;
                   padding: 12px 14px; margin: var(--cg-row, 14px) 0 0; }
  .ms-score-h    { display: flex; align-items: center; gap: 10px; font-size: 14px; color: #1a3f66; }
  .ms-score-h b  { flex: 0 0 auto; }
  .ms-score-h .tb-btn { margin-left: auto; }
  .ms-score-body { margin-top: 8px; }
  .ms-score-line { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
                   font-size: 12.5px; color: #4a6a8a; }
  .ms-score-line.bad { color: #b02020; }
  .ms-score-n    { font-size: 26px; font-weight: 800; color: #1e7a45; line-height: 1; }
  .ms-score-sub  { flex: 1 1 100%; font-size: 11.5px; color: #8a93a0; }
  .ms-score-note { margin-top: 8px; font-size: 11.5px; line-height: 1.55; color: #6b7787; }

  .bld-dot-ok   { background: #e7f4ec; color: #1e7a45; }
  .bld-dot-warn { background: #fdf0dd; color: #a8631a; }
  .bld-dot-bad  { background: #fbe6e3; color: #a8322a; }
  .bld-run-figs { margin: 9px 0 0 17px; font-size: 11.5px; color: #475569;
                  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
  .bld-run-figs i { color: #cbd5e1; font-style: normal; }
  .bld-fig-warn { color: #a8631a; font-weight: 700; cursor: help; }
  .bld-run-key  { margin: 8px 0 0 17px; font-size: 10.5px; color: #94a3b8;
                  display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
  .bld-run-key span { cursor: default; }

  /* The constraints the sorter answered, as chips — the key to the "why"
     column, so they have to be scannable, not a sentence. */
  /* ── THE ONE ACTION BAR (owner 2026-08-27) ────────────────────────────
     It reads left to right the way the job runs: what is chosen · ways to
     change it · what to do with it. The chips are the HOUSE chips from
     shell.css (Rule 6 §4) — this file only says how the bar is laid out and
     what is page-specific about it. The old .bld-b pill and the .bld-acts bar
     at the bottom of the card are gone with it. */
  .bld-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 9px 16px; border-bottom: 1px solid #eef0f3; font-size: 11.5px; color: #64748b; }
  /* THE COUNT IS THE ANSWER TO THE WHOLE PAGE — "what will Create the market
     save?" — so it is the one bold thing on the bar and it reads as a figure,
     not as a label. It turns grey when the answer is "nothing". */
  .bld-picked { font-size: 12.5px; font-weight: 700; color: #1a1d23;
    background: #eef4ff; border: 1px solid #dae5f8; border-radius: 999px;
    padding: 3px 11px; white-space: nowrap; }
  .bld-picked.none { color: #98a1b0; background: #f5f6f8; border-color: #e6e8ec; }
  /* A count that changed should be SEEN to change: one chip click can move it
     by two hundred, and a number that quietly swaps is a number nobody trusts. */
  .bld-picked.bump { animation: bldBump .32s ease-out; }
  @keyframes bldBump { 0% { transform: scale(1); } 35% { transform: scale(1.09); } 100% { transform: scale(1); } }
  .bld-bar-lbl { color: #98a1b0; margin-left: 4px; }
  .bld-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
  .bld-chips .filter-chip b { font-weight: 700; margin-left: 3px; }
  /* The AI's three verdicts, then the two extremes. Same control, different
     question — the divider is what stops "All" reading as a fourth verdict. */
  .bld-chip-sep { width: 1px; height: 16px; background: #dfe3ea; margin: 0 3px; }
  /* Pinned right: two quiet actions and the one that finishes the job. */
  .bld-bar-acts { display: flex; align-items: center; gap: 8px; margin-left: auto; }
  .bld-bar-acts .tb-btn:disabled, .bld-bar-acts .add-btn:disabled {
    opacity: .45; cursor: not-allowed; }
  /* Discard is the only irreversible thing on the row. It is not painted red —
     it is not dangerous, it is just final — but it must not read as a peer of
     Copy either, so it takes the quiet warning tone. */
  .bld-discard { color: #b45309; border-color: #f0d9b5; }
  .bld-discard:hover { background: #fdf6ec; border-color: #e0b878; }


  .bld-con { display: inline-block; background: #eef2f9; color: #334155; border-radius: 6px;
             padding: 2px 8px; margin: 2px 4px 2px 0; font-size: 11.5px; font-weight: 600; }

  /* Loosely defined is not a warning about the machinery, it is a fact about
     the market — so it is a heavier band than a capped run, and it sits above
     everything else on the draft. */
  .bld-cap.bld-loose { background: #fff3d9; color: #7a5600; border-color: #eddaae;
                       line-height: 1.5; padding: 10px 16px; }
  /* ── THE BUILDER PAGE'S BODY WHEN NO DRAFT IS OPEN ────────────────────
     Before the split this space was full of market cards, so it was allowed to
     be empty. It is the whole page now: it says what is waiting, or how to
     start, and never nothing. */
  .bld-idle { padding: 0; }
  .bld-idle-in { padding: 18px 20px 20px; }
  .bld-idle-t { font-size: 15px; font-weight: 700; color: #1e293b; margin-bottom: 10px; }
  .bld-idle-p { margin: 10px 0 0; font-size: 13px; line-height: 1.6; color: #5b6572; max-width: 720px; }
  .bld-idle-q { color: #7b8492; font-size: 12.5px; }
  .bld-idle-p a, .bld-idle-q a { color: #2563eb; font-weight: 600; text-decoration: none; }
  .bld-idle-p a:hover, .bld-idle-q a:hover { text-decoration: underline; }
  .bld-idle-row { display: flex; align-items: center; gap: 12px; width: 100%;
    text-align: left; background: #f8fafc; border: 1px solid #e7ebf1; border-radius: 9px;
    padding: 11px 14px; margin-bottom: 8px; cursor: pointer; font: inherit; }
  .bld-idle-row:hover { background: #eef4ff; border-color: #c7d7f5; }
  .bld-idle-name { font-weight: 700; color: #1e293b; font-size: 13.5px; flex: 1 1 auto; min-width: 0; }
  .bld-idle-state { font-size: 12px; color: #475569; background: #eef2f9;
    border-radius: 999px; padding: 3px 10px; font-weight: 600; white-space: nowrap; }
  .bld-idle-state.running { color: #1d4ed8; background: #e6efff; }
  .bld-idle-when { font-size: 11.5px; color: #98a1b0; white-space: nowrap; }

  /* ── APPROVED BUILDS — the record that used to have no door (2026-09-07) ──
     A quiet list under the drafts: the builds that became markets, so their
     score, searches, time and cost stay reachable. The rows reuse the draft
     row's look; the heading is smaller and greyer than "drafts waiting" so it
     never competes with the work in front of the reader, and the list scrolls
     rather than running down the page. */
  .bld-approved { margin-top: 4px; padding-top: 14px; border-top: 1px solid #eef0f3; }
  .bld-approved-t { font-size: 12.5px; font-weight: 700; color: #7b8492;
    text-transform: uppercase; letter-spacing: .03em; margin-bottom: 9px; }
  .bld-approved-list { max-height: 260px; overflow-y: auto; }
  .bld-idle-row.bld-approved-row { background: #fff; }
  .bld-idle-row.bld-approved-row:hover { background: #f4f8ff; }
  .bld-idle-score { font-size: 11.5px; color: #64748b; background: #f1f5fb;
    border-radius: 999px; padding: 3px 9px; font-weight: 600; white-space: nowrap; }
  .bld-idle-score.g-bad  { color: #9f1239; background: #fdeaee; }
  .bld-idle-score.g-warn { color: #92600a; background: #fbf1dc; }
  .bld-idle-score.g-ok   { color: #1d6b3a; background: #e7f5ec; }

  /* ── AN APPROVED BUILD'S READ-ONLY REPORT ─────────────────────────────── */
  .bld-approved-card { padding: 0; }
  .bld-appr-note { padding: 12px 16px 13px; border-bottom: 1px solid #eef0f3;
    font-size: 13px; line-height: 1.6; color: #475569; }
  .bld-appr-note b { color: #1e293b; }
  .bld-appr-terms { padding: 11px 16px; border-bottom: 1px solid #eef0f3; font-size: 12.5px;
    color: #475569; line-height: 1.7; }
  .bld-appr-terms .bld-con { margin: 2px 4px 2px 0; }
  .bld-appr-acts { display: flex; gap: 8px; padding: 12px 16px; align-items: center; }


  /* ── WHAT THE BUILD WAS ASKED FOR (owner 2026-09-02) ──────────────────
     Replaces four stacked bands — an amber description, a grey private note,
     a constraints line and a separate name row — each with its own colour and
     its own sentence. The owner's word for that was "a mess".

     ONE label column, so name / description / ASINs / checked-against line up
     and can be read down. The label column is fixed, not min-content: with
     min-content the widest label set the width and the block jumped as soon as
     a build carried a private note. */
  .bld-inputs { padding: 10px 16px 11px; border-bottom: 1px solid #eef0f3;
                display: flex; flex-direction: column; gap: 6px; }
  .bld-in-row { display: grid; grid-template-columns: 168px minmax(0, 1fr);
                align-items: start; gap: 12px; }
  .bld-in-lbl { font-size: 10.5px; font-weight: 700; text-transform: uppercase;
                letter-spacing: .045em; color: #98a1b0; padding-top: 7px; }
  .bld-in-val { min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
  /* THE READ-ONLY SLOT. It is a box, not plain text, because the point being
     made is "this is what was submitted" — the same shape as the name's input
     beside it, minus the ability to type. */
  /* Capped for READING, not for room: a description run out to 1,600px is one
     long line the eye loses its place on. The slot still fills a narrow screen. */
  .bld-in-box { width: 100%; max-width: 1080px; box-sizing: border-box; min-height: 28px;
                border: 1px solid #e7ebf1; border-radius: 7px; background: #f8fafc;
                padding: 7px 10px; font-size: 12.5px; line-height: 1.5; color: #3f4653;
                white-space: pre-wrap; word-break: break-word; }
  /* AN EMPTY SLOT IS DRAWN, NOT SKIPPED. "Nothing was given here" is read off
     the empty box instantly; a missing row would just look like a shorter page. */
  .bld-in-box.empty { background: #fcfdfe; border-style: dashed; min-height: 32px; }
  .bld-inputs input#bldName { border: 1px solid #d7dbe2; border-radius: 7px;
                              padding: 6px 10px; font: inherit; font-size: 13px;
                              min-width: 260px; max-width: 420px; flex: 0 1 320px; }
  .bld-inputs input#bldName:focus { outline: none; border-color: #2563eb;
                                    box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
  /* Only ever shown once the name really differs from the build's own record. */
  .bld-was { font-size: 11.5px; color: #b45309; background: #fff8ec;
             border: 1px solid #f0dcbb; border-radius: 6px; padding: 3px 8px; }
  .bld-was b { color: #92400e; }
  /* One wrapping ROW of ASINs. pre-wrap was putting one per line, which turned
     three ASINs into a three-line block for no reason (owner 2026-09-03). */
  .bld-chips { display: flex; flex-wrap: wrap; gap: 5px 6px; align-items: center; }
  .bld-in-note { display: block; font-size: 11px; color: #94a3b8; margin-bottom: 6px; }
  .bld-in-note b { color: #64748b; }
  .bld-seed-chip { display: inline-block; margin: 0; padding: 2px 8px;
                   border-radius: 6px; background: #eef2f9; color: #334155;
                   font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
                   text-decoration: none; }
  .bld-seed-chip:hover { background: #e2e9f5; color: #1d4ed8; }
  .bld-in-row.is-checked .bld-in-lbl { color: #64748b; }
  .bld-in-row.is-checked { margin-top: 2px; padding-top: 9px; border-top: 1px dashed #eef0f3; }

  /* ── Bulk actions: one menu instead of three near-equal buttons ────────── */
  .bld-bulk-wrap { position: relative; }
  .bld-bulk-menu { min-width: 320px; right: 0; }
  .bld-bulk-menu .set-item.is-off { opacity: .45; cursor: default; }
  .bld-bulk-menu .set-item.is-off:hover { background: none; }
  /* Discard is final, so it is the only coloured line in the menu — and it is
     LAST, with a rule above it, so it can never be hit on the way to Copy. */
  .bld-menu-danger { color: #b45309; border-top: 2px solid #f4f7fb !important; }
  .bld-menu-danger:hover { background: #fdf6ec; }
  /* ── A TICK IS A CELL, NOT A 13px BOX ──────────────────────────────────
     "Those checkboxes are tiny and if you click next to them nothing happens."
     The label fills the cell, so the whole column is the target; the box itself
     is bigger too. cursor:pointer says so before the click proves it. */
  /* ⚠ min-height LEFT A DEAD STRIP. The label was 38px tall in a 45px cell, so
     the top and bottom few pixels of the column did nothing — measured, not
     guessed: cell 105×45, label 105×38. A click target that is *nearly* the
     cell is the same complaint in a smaller size.
     A table cell has no usable height for a child to inherit, so the label is
     absolutely positioned to the cell's own box: inset:0 fills it exactly,
     whatever the row height turns out to be. */
  /* (The tick cell's own looks — the whole-cell hit area, the 17px box, the
     hover — moved into Shared Data/shell.css as .cg-tick-cell / .cg-tick-hit /
     .cg-tick on 2026-09-03, when the Leads table needed the same thing. Rule 6:
     the house version lives in the shell, not copied into a second page. The
     markup here wears BOTH class names, so this table is visibly the same
     component. Only the width pinning below is this page's own.) */

  /* ── COMPACT (owner 2026-09-03: "make the draft table more compact") ──────
     The row height was set by a 72px picture and 6px of padding on every cell,
     so a 200-product draft was a very long scroll. The picture is the only
     thing that has to be big enough to judge by, so it shrinks least: 72 → 52,
     which is still far past the 28px favicon it used to be, and hovering
     enlarges it anyway. Everything else gives up a pixel or two. Net row
     height ~86px → ~62px, about nine more products per screen. */
  .bld-tbl { width: 100%; border-collapse: collapse; font-size: 12px; }
  .bld-tbl th { font-size: 10px; font-weight: 600; color: var(--cg-th-fg); text-align: center;
                padding: 5px 5px; border-bottom: 1px solid var(--cg-th-line); white-space: normal; }
  .bld-tbl td { padding: 4px 5px; border-bottom: 1px solid #f4f6f9; vertical-align: middle;
                text-align: center; }
  .bld-tbl td.name-col, .bld-tbl td.bld-why { text-align: left; }
  /* HALF THE WIDTH IT HAD (owner 2026-09-02: "too wide for no reason"). The
     column has no natural size — the title is long, so an auto table gave it
     every spare pixel and squeezed the nine columns that carry the numbers.
     Capped here; the title already clamps to two lines, so nothing is lost.
     ⚠ THE TICK COLUMN IS PINNED IN THE SAME BREATH. Capping Product alone just
     moved the problem: an auto table hands the freed pixels to whichever column
     will take them, and that was the 17px checkbox — 140px of dead space
     between the box and the first word. Both ends fixed, so the slack goes to
     the two REASON columns, which are the ones that can use it. */
  .bld-tbl th.bld-keep-th, .bld-tbl td.bld-tick-cell { width: 44px; max-width: 44px; }
  .bld-tbl th:nth-child(2), .bld-tbl td.name-col { width: 340px; max-width: 340px; }
  /* BIG ENOUGH TO JUDGE BY (owner 2026-08-22: "the pictures need to be much
     bigger, so a user could quickly identify if it's a competitor or not").
     28px was a favicon — you could tell there WAS a photo, not what of. This
     is the one column that answers "is this the same kind of thing as mine?"
     faster than any title can, so it gets the room. Hovering enlarges further,
     because a thumbnail is a shortlist and the full picture settles it. */
  .bld-img { width: 52px; height: 52px; object-fit: contain; max-width: 100%;
             vertical-align: middle; margin-right: 8px; border-radius: 6px;
             background: #fff; border: 1px solid #eef0f3; padding: 2px;
             transition: transform .12s ease, box-shadow .12s ease;
             transform-origin: left center; }
  /* ⚠ NO transform: scale() HERE ANY MORE. It used to be scale(2.4), and a
     scaled element is still laid out inside its parent — so the part that grew
     past the draft's own scrolling table was CLIPPED by that table, which is
     exactly the cropping the owner reported. Enlarging is now the shell's
     shared viewport-fixed preview (shell.js, .cg-zoom), which is not inside
     any table and therefore cannot be cropped by one. */
  /* The picture and the words sit side by side, so the row stays one line tall
     per product instead of the title wrapping under a floated image. */
  /* The flex lives on a DIV inside the cell. On the <td> it took the cell out
     of table layout, and a table whose columns cannot be sized from their
     content re-resolves its width on any recalculation — the tick flicker. */
  .bld-tbl td.name-col > .bld-cell { display: flex; align-items: center; gap: 2px; }
  .bld-tbl td.name-col > a, .bld-tbl td.name-col .fnote { display: block; }
  .bld-name-txt { min-width: 0; }
  .bld-tbl .fnote { font-size: 11px; color: #98a1b0; }
  /* The NAME is what a person judges by, so it reads first, dark, and clamps
     to two lines; the ASIN and its flags sit under it as the reference. */
  .bld-ttl { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
             overflow: hidden; font-size: 12px; color: #1e293b; line-height: 1.3;
             font-weight: 600; }
  .bld-sub { display: block; margin-top: 2px; font-size: 10.5px; color: #98a1b0; }
  .bld-sub a { font-size: 11px; }
  .bld-why { color: #5b6572; max-width: 380px; }
  .bld-seed { font-size: 10.5px; color: #2563eb; }
  /* The amber dot on a seed the AI disowned. It stays IN the list, because it
     is user input and the owner is the authority — the dot is advice. */
  .bld-dot { color: #d97706; cursor: pointer; font-size: 15px; line-height: 1; }
  .bld-flagged { background: #fffaf0; }
  .bld-sep td { background: #f6f8fb; color: #5b6572; font-size: 11.5px;
                text-align: left; font-weight: 600; }
  /* .bld-acts / .bld-count were the second bar at the BOTTOM of the card —
     past 200 rows and the left-out drawer, so the thing you came to do was the
     thing furthest from the thing you were doing. Merged into .bld-bar at the
     top on 2026-08-27. Do not re-add a second action bar. */

/* ── ⚙ Settings: the prompt behind an AI step (owner 2026-08-18) ───────────
   "We aren't sure what prompt it's using." The Leads page answers that with
   two extra tabs; here the prompt opens ON the step, because the question is
   raised BY the drawing and an answer that makes you leave the drawing is a
   worse answer. Only boxes that really have a prompt behind them look
   clickable — a hover state on a box that does nothing teaches distrust of
   every other box. */
.ms-pk {
  display: block; margin-top: 7px; font-size: 11px; font-weight: 600;
  color: #2563eb; letter-spacing: .01em;
}
.ms-pk b { font-weight: 700; }
.fl-node:has(.ms-pk) { cursor: pointer; }
.fl-node:has(.ms-pk):hover { box-shadow: 0 0 0 2px #bfdbfe; }
.fl-node.ms-pk-on { box-shadow: 0 0 0 2px #2563eb; }
.fl-node.ms-pk-on .ms-pk b { display: inline-block; transform: rotate(180deg); }
.ms-pk-li { cursor: pointer; }              /* the plain-text fallback's line */

.ms-prompts:empty { display: none; }
.ms-prompt {
  border: 1px solid #bfdbfe; border-left: 3px solid #2563eb; border-radius: 10px;
  background: #f8fbff; padding: 12px 16px; margin: 12px 0 4px;
}
.ms-prompt.warn { border-color: #fcd9b6; border-left-color: #b45309; background: #fffaf3; }
.ms-prompt-h {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 700; color: #1e293b;
}
.ms-prompt-x {
  margin-left: auto; border: 0; background: none; cursor: pointer;
  font-size: 13px; color: #94a3b8; line-height: 1; padding: 2px 4px;
}
.ms-prompt-x:hover { color: #1e293b; }
.ms-prompt-when { font-size: 11.5px; color: #475569; margin-top: 5px; line-height: 1.5; }
.ms-prompt-load { font-size: 12px; color: #64748b; margin-top: 8px; }
.ms-prompt-meta {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 9px 0 2px;
  font-size: 11px; color: #64748b;
}
.ms-prompt-meta b { color: #1e293b; font-weight: 600; }
.ms-prompt-meta i { font-style: normal; color: #94a3b8; }
/* The words themselves, exactly as sent: pre-wrap, never reflowed — the model
   reads the line breaks, so a paragraph shown as one run is not what it gets. */
.ms-prompt-body {
  margin: 8px 0 0; padding: 11px 13px; max-height: 340px; overflow: auto;
  border: 1px solid var(--cg-line, #e2e8f0); border-radius: 8px; background: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.6; color: #334155;
  white-space: pre-wrap; word-break: break-word;
}
.ms-prompt-foot { font-size: 11px; color: #64748b; margin-top: 8px; line-height: 1.55; }

/* ── The draft's "left out" section (owner 2026-08-19: "yes") ──────────────
   It used to be a number in the header and nothing else — a claim you could
   not open. Closed by default because the reader's job is the kept list; this
   is for checking the AI was right, and its ticks are live so a wrongly
   rejected competitor can be put straight back in. */
.bld-outs { margin: 10px 0 2px; border: 1px solid var(--cg-line, #e2e8f0);
  border-radius: 10px; background: #fcfcfd; }
.bld-outs > summary { cursor: pointer; padding: 9px 14px; font-size: 12px;
  font-weight: 700; color: #475569; list-style: none; }
.bld-outs > summary::-webkit-details-marker { display: none; }
.bld-outs > summary::before { content: '▸ '; color: #94a3b8; }
.bld-outs[open] > summary::before { content: '▾ '; }
.bld-outs > summary:hover { color: #1e293b; }
.bld-outs-note { padding: 0 14px 8px; font-size: 11.5px; color: #64748b; line-height: 1.55; }
.bld-outs .table-scroll { margin: 0 10px 10px; }
/* A seed the SEARCH guessed, not one you pasted (migration 236). It reads
   differently on purpose: a wrong guess must not look like your own mistake. */
.bld-seed.guess { background: #fdf7e8; border-color: #ecd9a8; color: #7a5a12; }

/* .bld-waiting / .bld-w-open / .bld-w-car were the drafts STRIP in the page
   body — one or two rows of pills above every market, all day. Deleted with it
   on 2026-08-27; the list is the header drop-down below. Do not re-add a strip. */
/* ── DRAFTS IN THE HEADER (owner 2026-08-27) ───────────────────────────────
   One button, and it is not there at all when nothing is waiting. Deliberately
   NOT the look of the two main tabs — "we don't want it to be visually similar
   to those two tabs, these are the actual main tabs" — so it wears the amber
   the drafts have always used, which also says at a glance that something is
   waiting for a person. */
.drafts-btn { display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid #f0d9b5; background: #fffdf7; color: #b45309;
  border-radius: 8px; padding: 6px 11px; font: inherit; font-size: 12.5px;
  font-weight: 600; cursor: pointer; white-space: nowrap; }
/* IT SITS FLUSH AGAINST THE BLUE ACTION WITHOUT THIS — 0px, measured on the
   live page 2026-08-31, which is the one spacing the header-fit test could not
   see until it started measuring the drafts chip too. */
#draftsWrap { margin-left: 10px; }
.drafts-btn:hover { background: #fdf6ec; border-color: #e0b878; }
.drafts-btn.active { background: #b45309; border-color: #b45309; color: #fff; }
.drafts-btn b { font-weight: 800; }
.drafts-car { font-size: 10px; opacity: .75; }
/* A STOPPED BUILD IS NOT A DRAFT and must not be counted as one — it wears its
   own quiet red count on the button, and its own line in the list (migration
   265: before this, a failure vanished from the page the moment a newer build
   started, and the owner had to ask twice where one had gone). */
/* The one number on the run's fact line that is money rather than counting. */
.bld-fig-cost { font-weight: 700; color: #b45309; }
.drafts-stop { margin-left: 6px; padding-left: 7px; border-left: 1px solid #f0d9b5;
  color: #b42318; font-weight: 700; }
.drafts-item.stopped .ri-sub { color: #b42318; }
/* An earlier attempt at a market that failed again — folded away by default,
   never dropped: it is a different set of words, and that is what somebody
   comes back for. */
.drafts-item.folded { display: none; }
.ri-more { margin-left: 8px; padding: 1px 7px; border-radius: 20px; border: 1px solid #e6d4b8;
  background: #fffaf1; color: #b45309; font: inherit; font-size: 10.5px; font-weight: 700;
  cursor: pointer; vertical-align: 1px; }
.ri-more:hover { background: #fdf0dc; }
/* Delete for good — quiet until the row is under the pointer, so a list you are
   reading never looks like a row of delete buttons. */
.ri-del { float: right; margin-left: 8px; padding: 0 5px; border: 0; background: none;
  color: #c3ccd8; font: inherit; font-size: 12px; line-height: 1.2; cursor: pointer;
  visibility: hidden; }
.drafts-item:hover .ri-del { visibility: visible; }
.ri-del:hover { color: #b42318; }
.drafts-head { padding: 9px 16px 5px; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: #8a93a0; background: #fafbfd; border-top: 1px solid #edf2f7; }
/* TWENTY ROWS DO NOT FIT ON A LAPTOP — the last ones were cut off by the
   bottom of the menu with no way to reach them (seen live 2026-08-31). */
.drafts-menu { max-height: 70vh; overflow-y: auto; }
/* A build still running gets the same pulse the old pills used. */
.drafts-live { width: 7px; height: 7px; border-radius: 50%; background: #b45309;
  animation: draftsPulse 1.5s ease-in-out infinite; }
.drafts-btn.active .drafts-live { background: #fff; }
@keyframes draftsPulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
.drafts-menu { min-width: 300px; max-height: 380px; overflow: auto; }
.drafts-item.on   { background: #fffdf7; }
.drafts-item.live .ri-main::after { content: ' · building…'; color: #b45309; font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .drafts-live { animation: none; } }

/* ═══ HOW A MARKET IS MADE — the process row + the map (owner 2026-08-22) ═══
   The Leads page's shape, this page's pipeline. Seven cards on one line at
   1920, wrapping cleanly below that. A card, not a chip: a chip can only say
   its own name, and the live state is the whole reason the row exists. */
.mkt-process { margin: 0 0 var(--cg-row, 14px); }
.mp-cap { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: #64748b; margin-bottom: 5px; display: flex; align-items: baseline; gap: 10px;
  flex-wrap: wrap; }
.mp-cap i { font-style: normal; font-weight: 500; font-size: 11px; letter-spacing: 0;
  text-transform: none; color: #94a3b8; }
/* EIGHT STEPS SINCE 2026-08-22 (the build searches twice), and the row still
   has to fit on one line at a normal screen: at 168px basis the eighth wrapped
   onto a line of its own, behind a dangling arrow. Narrower basis, and the
   arrows collapse to nothing before the cards do — an arrow between two cards
   on different lines points at the margin. */
.mp-flow { display: flex; align-items: stretch; gap: 0; flex-wrap: wrap; }
/* ── SHORT, NOT TALL (owner 2026-08-27) ────────────────────────────────────
   "The process of those squares is unnecessarily high… all the white space
   should be removed by making them shorter."
   Every number below is height. A WIDER basis is part of it and not a
   contradiction: at 138px the two-word labels wrapped onto a second and third
   line, and a row is as tall as its tallest card — so giving each card more
   width takes height OFF the row. */
/* ⚠ FLEXBOX WRAPS ON flex-basis, NOT ON min-width. Eight cards at a 152px
   basis need 1,216px before a single one is allowed to shrink, so the row broke
   onto two lines at 1440 even though the cards would have fitted at their
   minimum. A SMALL basis with flex-grow is what actually fits: the cards ask
   for little, take one line, and then grow into whatever the window has —
   measured at 196px on a 1920 screen and 169px at 1600. */
.mp-step { flex: 1 1 124px; min-width: 118px; max-width: 210px;
  display: flex; flex-direction: column;
  border: 1px solid var(--cg-line, #e2e8f0); border-radius: 10px; background: #fff;
  overflow: hidden; }
/* An AI step is the one a person comes here to change, so it is marked. */
.mp-step.ai { border-color: #c7dbff; }
.mp-step.hot { border-color: #f4c98a; background: #fffdf7; }
.mp-open { display: flex; flex-direction: column; gap: 2px; align-items: stretch;
  text-align: left; width: 100%; border: 0; background: none; cursor: pointer;
  font: inherit; padding: 7px 10px 6px; }
.mp-who { display: flex; align-items: center; gap: 7px; }
.mp-open:hover { background: #f7f9fd; }
.mp-n { display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%; background: #eef2f9; color: #64748b;
  font-size: 10.5px; font-weight: 800; }
.mp-step.ai .mp-n { background: #e6efff; color: #2563eb; }
.mp-step.hot .mp-n { background: #fdebd2; color: #b45309; }
.mp-t { font-size: 12.5px; font-weight: 700; color: #1e293b; line-height: 1.25; }
.mp-who i { font-style: normal; font-weight: 700; font-size: 9.5px; color: #94a3b8;
  text-transform: uppercase; letter-spacing: .07em; white-space: nowrap; }
.mp-step.ai .mp-who i { color: #2563eb; }
/* The state line is ONE line. It is a glance, not a sentence — and a card that
   wraps here sets the height of all eight. */
.mp-l { font-size: 11px; color: #64748b; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* No border, no strip of its own — the button belongs to the card it acts on.
   The border-top plus its two paddings was a whole line of height per card. */
.mp-a { padding: 0 10px 7px; display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; }
.mp-b { border: 1px solid var(--cg-line, #e2e8f0); background: #fff; border-radius: 6px;
  padding: 3px 8px; font: inherit; font-size: 10.5px; font-weight: 600; color: #2563eb;
  cursor: pointer; white-space: nowrap; }
.mp-b:hover { background: #eef4ff; }
/* Blue fill marks the one control that SPENDS something the moment it is
   pressed — the same convention the Leads row uses. */
.mp-b.mp-do { background: #2563eb; border-color: #2563eb; color: #fff; }
.mp-b.mp-do:hover { background: #1d4fd7; }
/* The arrows are punctuation. At 15px with 5px either side they were costing
   about 175px of the row — a whole card's width — which is what pushed the
   eighth step onto a line of its own, and a lone card on its own line stretched
   to the full width (hence the max-width above: a wrapped card must not become
   a banner). */
.mp-arrow { align-self: center; color: #cbd5e1; font-size: 11px; padding: 0 2px;
  font-weight: 700; flex: 0 1 auto; min-width: 0; overflow: hidden; }
/* The arrows are the first thing to go when the row is tight — they are
   punctuation, and a row that wraps costs a whole second line of cards.
   Measured: with them gone the eight cards still fit one line at 1280. */
@media (max-width: 1500px) { .mp-arrow { display: none; } }

/* ── the map window ─────────────────────────────────────────────────────── */
.mp-win { position: fixed; inset: 0; background: rgba(15,23,42,.45); z-index: 400;
  display: flex; align-items: center; justify-content: center; padding: 24px; }
.mp-card { background: #fff; border-radius: 14px; width: min(1360px, 96vw);
  height: min(88vh, 940px); display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 24px 60px rgba(15,23,42,.28); }
.mp-head { display: flex; align-items: baseline; gap: 12px; padding: 14px 18px;
  border-bottom: 1px solid var(--cg-line, #e2e8f0); }
.mp-head h2 { margin: 0; font-size: 16px; color: #1e293b; }
.mp-sub { font-size: 11.5px; color: #94a3b8; }
.mp-head .cmp-close { margin-left: auto; }
.mp-body { display: flex; min-height: 0; flex: 1; }
.mp-spine { width: 288px; flex: none; overflow: auto; padding: 12px;
  border-right: 1px solid var(--cg-line, #e2e8f0); background: #fbfcfe; }
.mp-s { display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  width: 100%; text-align: left; border: 1px solid transparent; background: none;
  border-radius: 9px; padding: 8px 10px; font: inherit; cursor: pointer; }
.mp-s:hover { background: #f1f5fb; }
.mp-s.on { background: #fff; border-color: #bfdbfe; box-shadow: 0 1px 3px rgba(37,99,235,.12); }
.mp-st { font-size: 12.5px; font-weight: 700; color: #1e293b; }
.mp-st i { font-style: normal; font-weight: 600; font-size: 10px; color: #94a3b8;
  text-transform: uppercase; letter-spacing: .06em; }
.mp-sl { font-size: 11px; color: #64748b; line-height: 1.4; }
.mp-sc { font-size: 10.5px; color: #94a3b8; }
.mp-sarrow { display: block; text-align: center; color: #cbd5e1; font-size: 11px;
  line-height: 1; margin: 1px 0; }
.mp-n.on { background: #2563eb; color: #fff; }

.mp-stage { flex: 1; min-width: 0; overflow: auto; padding: 16px 18px 20px;
  display: flex; flex-direction: column; }
.mp-stage-h { display: flex; align-items: center; gap: 10px; font-size: 15px;
  font-weight: 700; color: #1e293b; }
.mp-stage-c { margin-left: auto; font-style: normal; font-size: 11px; color: #94a3b8; }
.mp-stage-l { font-size: 12px; color: #64748b; margin: 5px 0 12px; }
/* A capped MEASURE. At 1050px a paragraph runs ~150 characters a line and the
   eye loses its place returning to the left edge; ~75 is the readable band. */
.mp-panel, .mp-p-b { font-size: 12.5px; color: #334155; line-height: 1.7; max-width: 72ch; }
/* Bullets, not paragraphs — a panel opened mid-task is read standing up. */
.mp-li { margin: 0; padding: 0; list-style: none; display: grid; gap: 7px; }
.mp-li li { position: relative; padding-left: 15px; }
.mp-li li::before { content: '·'; position: absolute; left: 3px; top: -1px;
  color: #94a3b8; font-weight: 800; }
.mp-acts { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

/* ── the prompt editor, beside what the run adds to it ──────────────────── */
/* ⚠ NOT `flex: 1`. It was, back when these two columns were the only thing in
   the stage — and once "How to make this step better" was added below them, a
   stretched grid whose textarea has a 260px minimum pushed the model box and
   the Save button straight out of the bottom of the grid, where they overlapped
   the panel underneath. The stage scrolls; this block is its natural height. */
.mp-prompt { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 16px; align-items: stretch; flex: 0 0 auto; }
.mp-prompt > .mp-col:first-child { display: flex; flex-direction: column; min-height: 0; }
@media (max-width: 1180px) { .mp-prompt { grid-template-columns: 1fr; } }
.mp-col { min-width: 0; }
.mp-col-h { display: flex; align-items: baseline; gap: 10px; font-size: 12px;
  font-weight: 700; color: #1e293b; margin-bottom: 8px; }
.mp-model { margin-left: auto; font-size: 11px; font-weight: 600; color: #2563eb;
  background: #eef4ff; border-radius: 20px; padding: 2px 9px; }
.mp-row { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
.mp-row-end { justify-content: flex-end; }
.mp-row label { font-size: 11px; font-weight: 700; color: #64748b; }
.mp-row select, .mp-row input { border: 1px solid var(--cg-line, #e2e8f0); border-radius: 8px;
  padding: 5px 8px; font: inherit; font-size: 12px; background: #fff; }
.mp-row input { flex: 1 1 140px; min-width: 0; }
.mp-vnote { font-size: 11px; color: #94a3b8; }
/* Monospace and generous, because this is the one box on the page where every
   line break is meaningful — the model reads them. */
.mp-ta { width: 100%; flex: 1; min-height: 260px; resize: vertical; border-radius: 10px;
  border: 1px solid var(--cg-line, #e2e8f0); padding: 11px 13px; background: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; line-height: 1.6; color: #1e293b; }
.mp-ta:focus { border-color: #2563eb; outline: none; }
.mp-saved { font-size: 11.5px; color: #1e7a45; margin-right: auto; }
.mp-warn { font-size: 11px; color: #94a3b8; line-height: 1.5; margin-top: 6px; }
.mp-col-add { background: #fbfcfe; border: 1px solid var(--cg-line, #e2e8f0);
  border-radius: 12px; padding: 13px 15px; overflow: auto; max-height: 520px; }
.mp-add-note { font-size: 11.5px; color: #64748b; line-height: 1.6; margin-bottom: 10px; }
.mp-blk { border-left: 3px solid #dbe4f0; padding: 3px 0 3px 11px; margin: 9px 0; }
.mp-blk > b { display: block; font-size: 12px; color: #1e293b; }
.mp-blk > span { display: block; font-size: 11.5px; color: #5b6572; line-height: 1.55; margin-top: 2px; }
.mp-blk > span b { color: #1e293b; }   /* emphasis INSIDE the sentence stays inline */
/* Three blocks are worth telling apart at a glance: the one that is YOURS, the
   one that is the LEARNING loop, and the one the page cannot read back without. */
.mp-blk.yours { border-left-color: #f0b429; }
.mp-blk.learn { border-left-color: #1e7a45; }
.mp-blk.contract { border-left-color: #94a3b8; }
/* ── "How to make this step better" — the panel a stranger reads first ──────
   It runs the full width UNDER the two columns, because it is about both of
   them: the prompt on the left and the data on the right are the two things it
   tells you how to change. Numbered rows, each with a wrong/right example
   directly under it — a rule with no example is a rule nobody can apply. */
.mp-t-where { margin-top: 14px; font-size: 11.5px; line-height: 1.6; color: #5b6572;
  background: #f6f8fb; border: 1px solid var(--cg-line, #e2e8f0); border-radius: 10px;
  padding: 9px 13px; }
.mp-t-where b { color: #1e293b; }
.mp-teach { margin-top: 12px; border: 1px solid var(--cg-line, #e2e8f0); border-radius: 12px;
  padding: 13px 15px; background: #fff; }
.mp-teach .mp-col-h { margin-bottom: 4px; }
.mp-t-row { font-size: 12px; line-height: 1.6; color: #5b6572; padding: 9px 0;
  border-bottom: 1px solid #f1f4f8; }
.mp-t-row:last-child { border-bottom: 0; }
.mp-t-row > b { color: #1e293b; }
.mp-t-learn { border-left: 3px solid #1e7a45; padding-left: 11px; }
.mp-t-safe { color: #94a3b8; font-size: 11.5px; }
.mp-t-note { display: block; margin-top: 6px; font-size: 11px; color: #94a3b8; line-height: 1.55; }
/* The examples. Two lines, wrong then right, so the difference is the only
   thing on screen between them. */
.mp-ex { display: grid; gap: 3px; margin: 7px 0 2px; font-size: 11.5px; line-height: 1.5; }
.mp-ex span { border-radius: 7px; padding: 5px 9px; }
.mp-ex-b { background: #fdf2f2; color: #9b3b3b; }
.mp-ex-g { background: #f1f8f3; color: #1e5f38; }

/* The way out to the full decision tree. It sits in the stage heading rather
   than the spine: it is about the step you are reading, not the list. */
.mp-draw { margin-left: 12px; font-weight: 600; }
.mp-stage-h .mp-stage-c { margin-left: auto; }

/* ── MARKET REVENUE, FOUR WAYS (owner 2026-08-27) ──────────────────────────
   Four charts rather than four lines: two are dollars per 30 days and two are
   dollars per year, about forty times larger, and one axis cannot carry both
   without flattening the smaller pair into the baseline. Two per row on a wide
   screen, one per row when there is no room for two readable ones. */
/* Two per row on a normal screen: at 420px three fitted and the fourth hung
   alone on a line of its own. */
.rev-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(480px, 1fr));
  gap: var(--cg-row, 14px); padding: 0 var(--cg-gutter, 28px) var(--cg-row, 14px); }
.rev-grid .chart-card { margin: 0; }
.rev-wrap { position: relative; height: 260px; width: 100%; }
/* The source, said on the heading in the colour the table already uses for it,
   so a reader who knows the comparison columns knows these without a legend. */
.rev-src { font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; margin-left: 8px; padding: 2px 7px; border-radius: 999px; }
.rev-src.src-est   { color: #2563eb; background: #eef4ff; }
.rev-src.src-curve { color: #2f8378; background: #f1f8f6; }
.rev-src.src-h10   { color: #7256b5; background: #f5f3fb; }
/* Why a line is short, or missing entirely. A chart that is empty for a reason
   has to say the reason — an empty box says "broken". */
.rev-note { margin: 6px 2px 0; font-size: 11.5px; color: #94a3b8; line-height: 1.45; }
.rev-note.none { color: #b45309; }
/* The little colour square in front of a note's line, naming which line it is
   about. It was written by drawRevenuePanel from the day that panel shipped and
   NEVER HAD A RULE HERE — an inline `background` on a bare <span> with no size
   paints nothing, so every one of those notes has been keyless. Found while
   adding the yearly panel, fixed for both (RULEBOOK Rule 5a: a stale or missing
   half of a feature is a bug, fixed on sight, not left for the next reader). */
.rev-key { display: inline-block; width: 10px; height: 10px; border-radius: 2px;
  margin-right: 6px; vertical-align: -1px; }
/* The yearly panel's key for a BOLD dot — drawn as the dot itself (a filled
   circle with its own ring) rather than as a square, so the legend and the mark
   on the chart are the same shape. */
.rev-key-dot { border-radius: 50%; background: #475569; box-shadow: 0 0 0 2px #fff, 0 0 0 3px #475569; }
/* The 12-month total is drawn as diamonds, not a line (it can only land on a
   few days), so its key is a diamond too — the key and the mark on the chart
   have to be the same shape or the reader has to guess which is which. */
.rev-key-dia { transform: rotate(45deg); border-radius: 1px; }

  /* ── Market keywords (keywords.js, 2026-09-06) — the folded row under the charts ── */
  /* Its own card (#keywordsCard) under the charts card, the same one-line
     head shape as the charts row (.cw-bar) so it reads as "another collapsed row". */
  .mk-card { padding: 11px 18px; }
  .mk-card > .mk-sec > h3.mk-head { display: flex; align-items: center; gap: 6px; margin: 0; cursor: pointer; user-select: none; font-size: 14px; }
  .mk-head .mk-meta { font-size: 12px; font-weight: 500; color: #636e72; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mk-tools { display: inline-flex; gap: 8px; align-items: center; margin-left: auto; }
  .mk-btn { font: inherit; font-size: 12px; font-weight: 600; padding: 4px 10px; border: 1px solid #d7dbe2; border-radius: 8px; background: #fff; color: #5b6472; cursor: pointer; }
  .mk-btn:hover { background: #e9f0fb; border-color: #c9d9f0; }
  .mk-btn.on { background: #2563eb; border-color: #2563eb; color: #fff; }
  .mk-btn:disabled { opacity: .5; cursor: default; }
  .mk-host { padding: 12px 0 4px; }
  .mk-scroll { border: 1px solid #eef0f3; border-radius: 8px; }
  .mk-table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 12.5px; }
  .mk-table th { position: sticky; top: 0; z-index: 3; background: #fff; border-bottom: 2px solid #d7dbe2; padding: 6px 8px; font-size: 11px; font-weight: 600; color: #636e72; text-align: center; white-space: nowrap; cursor: pointer; user-select: none; vertical-align: bottom; }
  .mk-table th.sorted { color: #2d3436; }
  .mk-table th.sorted::after { content: ' ▾'; font-size: 9px; }
  .mk-table th.sorted.asc::after { content: ' ▴'; }
  .mk-table td { padding: 5px 8px; border-bottom: 1px solid #eef0f3; text-align: center; font-family: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .mk-table th.mk-kw, .mk-table td.mk-kw { text-align: left; font-family: inherit; position: sticky; left: 34px; background: #fff; z-index: 2; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }
  .mk-table th.mk-tick, .mk-table td.mk-tick { position: sticky; left: 0; width: 34px; min-width: 34px; background: #fff; z-index: 2; cursor: default; }
  .mk-table th.mk-kw { z-index: 4; } .mk-table th.mk-tick { z-index: 4; }
  .mk-table td.mk-kw .mk-term { font-weight: 500; }
  .mk-table td.mk-cap { font-weight: 700; }
  .mk-table tbody tr:hover td { background: #f3f6fb; }
  .mk-table .mk-tech { display: none; }
  .mk-table.tech .mk-tech { display: table-cell; border-left: 1px solid #eef0f3; }
  .mk-table th.mk-ours-col, .mk-table td.mk-ours-col { border-left: 1px solid #eef0f3; }
  .mk-sub { display: block; font-size: 10px; color: #98a1b0; line-height: 1; margin-top: 2px; }
  .mk-click { cursor: pointer; border-bottom: 1px dashed #b8c0cc; }
  .mk-click:hover { border-bottom-color: #2563eb; color: #2563eb; }
  /* one family = one column: picture, market rank, ASIN, brand. No coloured rule over the
     picture (owners 2026-09-06: "weird color bar above the products images"); ours are told
     apart by the market table's blue tint on the whole column, nothing else. */
  .mk-table th.mk-fam { min-width: 100px; padding: 6px 4px 4px; }
  .mk-table th.mk-fam.ours, .mk-table td.mk-fam-td.ours { background: color-mix(in srgb, var(--fam) 9%, #fff); }
  .mk-fam-pic { display: block; width: 34px; height: 34px; margin: 0 auto 2px; cursor: pointer; }
  .mk-fam-pic img { width: 34px; height: 34px; object-fit: contain; border-radius: 4px; background: #f5f6fa; display: block; }
  .mk-fam-pic .pic-ph { display: block; width: 34px; height: 34px; border-radius: 4px; background: #f1f3f7; }
  .mk-fam-rank { display: block; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 12px; font-weight: 700; color: #2d3436; }
  .mk-fam-asin { display: block; font-family: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace; font-size: 10.5px; font-weight: 600; color: #2d3436; letter-spacing: .01em; }
  .mk-fam-asin small { font-size: 9px; font-weight: 500; color: #8a94a6; margin-left: 2px; }
  .mk-fam-lbl { display: block; font-size: 10px; font-weight: 500; color: #98a1b0; max-width: 100px; overflow: hidden; text-overflow: ellipsis; margin: 0 auto; }
  /* the place cell: 1st → 3rd among Amazon's most-clicked, coloured by mkPlaceColor */
  .mk-place { display: inline-block; min-width: 34px; padding: 1px 6px; border-radius: 6px; color: #2d3436; font-weight: 500; }
  .mk-place.mk-click { border-bottom: 0; }
  .mk-place.mk-click:hover { color: #2563eb; }
  .mk-pop { position: fixed; z-index: 240; background: #fff; border: 1px solid #d7dbe2; border-radius: 10px; box-shadow: 0 10px 30px rgba(20,30,50,.18); padding: 12px 14px; width: min(460px, 92vw); font-size: 12.5px; color: #2d3436; }
  .mk-pop h4 { margin: 0 0 4px; font-size: 13px; font-weight: 700; padding-right: 20px; }
  .mk-pop .mk-pop-sub { color: #636e72; font-size: 12px; margin-bottom: 8px; }
  .mk-pop .mk-pop-x { position: absolute; top: 6px; right: 10px; border: 0; background: none; font: inherit; font-size: 16px; color: #98a1b0; cursor: pointer; }
  .mk-pop-t { border-collapse: collapse; width: 100%; font-size: 12px; max-height: 300px; }
  .mk-pop-t th { text-align: center; font-weight: 600; color: #636e72; padding: 4px 6px; border-bottom: 1px solid #d7dbe2; white-space: nowrap; }
  .mk-pop-t td { text-align: center; padding: 4px 6px; border-bottom: 1px solid #eef0f3; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; }
  .mk-pop-t th.l, .mk-pop-t td.l { text-align: left; font-family: inherit; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .mk-pop-t tr.tot td { font-weight: 700; border-top: 2px solid #d7dbe2; }
  .mk-pop-note { font-size: 11px; color: #98a1b0; margin-top: 8px; line-height: 1.4; }

/* How the BSR line was drawn — three short lines under the one-sentence
   answer at the top of the BSR curves tab (owners 2026-09-07: explain the
   method "SHORTLY and clearly" on the page itself). Quiet, because it is the
   footnote to the answer above it, not a second headline. */
.curve-answer .ca-how { margin-top: 6px; font-size: 12px; line-height: 1.5; color: #4b5563; }
.curve-answer .ca-how b { color: #1a1d23; font-weight: 600; }

/* The little table inside a Rules-of-thumb card (rule 24's three kinds of
   reading). Same quiet look as the prose around it — it is there because
   three things with four properties each read as a table, not a paragraph. */
.rule-box .rule-tbl { width: 100%; border-collapse: collapse; margin: 8px 0 10px; font-size: 12px; }
.rule-box .rule-tbl th { text-align: left; font-weight: 600; color: #4b5563; padding: 4px 8px 4px 0;
                         border-bottom: 1px solid #e5e7eb; }
.rule-box .rule-tbl td { padding: 5px 8px 5px 0; border-bottom: 1px solid #f1f3f5; vertical-align: top;
                         text-align: left; }
.rule-box .rule-tbl tr td:nth-child(3), .rule-box .rule-tbl tr th:nth-child(3),
.rule-box .rule-tbl tr td:last-child, .rule-box .rule-tbl tr th:last-child { text-align: center; }
