/* ============================================================================
   showroom.html — page-scoped styles.

   New styling for this page lands here, never in the page's <style> block.
   The two inline blocks already in showroom.html are pending extraction
   (see changes/0045_2026-08-06_storefront-next-to-do.md, Task 1).
   ============================================================================ */

/* --- Showroom Products › the On checkbox on a child row -------------------
   Child blocks and bundles are indented in the Product column — 22px on the
   media block, with the tree stem drawn at 14px — but their On checkbox stayed
   at the parent's left edge, so BLK-142's control sat directly under Cristallo's
   and the tree read in the second column only.

   Indented by moving the cell's padding rather than widening the column. The On
   column is pinned at exactly one 26px checkbox plus 12px either side, so there
   is no slack inside it: 24/0 shifts the box 12px right within the width it
   already has, Product gives up nothing, and the gap on the right is covered by
   Product's own left padding. Half a checkbox — enough to read as a level down
   without competing with the 22px step in the column beside it. */
#sfItemsTable tr.sf-childrow td.sf-oncell { padding-left: 24px; padding-right: 0; }

/* A child's checkbox is 30% off the parent's — 26 → 18px, its tick 16 → 11px, and
   the corner scaled with the box so a smaller square does not read as a rounder
   one. Size is the second thing saying "level down", after the indent, and it says
   it on the control itself rather than on the space around it: a material and one
   of its blocks are no longer the same weight of decision at a glance. The 2px
   stroke is deliberately NOT scaled — it is what makes an empty box visible, and
   at 1.4px the unchecked children would go faint.

   The column is untouched: a child cell now measures 24 + 18 = 42px against the
   50px pin, so the box centres in the slack and sits 16px right of the parent's. */
#sfItemsTable tr.sf-childrow .sf-check,
#sfItemsTable tr.sf-childrow .sf-check .box { width: 18px; height: 18px; }
#sfItemsTable tr.sf-childrow .sf-check .box { border-radius: 4px; }
#sfItemsTable tr.sf-childrow .sf-check .box svg { width: 11px; height: 11px; }

/* --- Showroom Products › Show Price / Show Qty ----------------------------
   A per-item override of the two switches in Settings › Showroom Display —
   Show Pricing and Show Quantities. Two states, not three: only the override
   that DISAGREES with the default carries information. While the showroom
   shows every price, a row marked "Show" says exactly what Default says, so the
   chip toggles Default ⇄ the opposite of the switch and the redundant word is
   never reachable. Flip the switch and the available override flips with it.

   One column per chip. They were a single "Buyer Sees" column holding both, on
   the reading that the pair is one decision about what a row exposes — but they
   are two independent fields resolving against two separate switches, and a
   header that names neither made the reader decode the `$` and `#` icons to tell
   which chip was which. Each column now says what its chip does. */
#sfItemsTable th.col-vis-price, #sfItemsTable td.col-vis-price,
#sfItemsTable th.col-vis-qty,   #sfItemsTable td.col-vis-qty { text-align: center; }
/* Both pinned to one width so the two chips sit in an even pair, like Price and
   Featured either side of them — neither column ever grows. 104px is the wider
   header, "SHOW PRICE" at the thead's 11px uppercase, plus the table's 12px cell
   padding either side; it also clears the 72px chip with room to spare. The
   header does not wrap: at this width "SHOW PRICE" would break to two lines and
   take the whole header row down with it. */
#sfItemsTable thead th.col-vis-price,
#sfItemsTable thead th.col-vis-qty { width: 104px; min-width: 104px; max-width: 104px; white-space: nowrap; }

/* Browse & Filtering used to be the third card in a two-column grid and spanned both
   columns to fill the dead half-row, laying its two settings out side by side. It is
   a 520px dialog now: there is no grid to span and no second column to reach, so the
   rules that did it are gone and the two rows stack, which is what that width wants. */

/* --- Showroom Products › Price cell ---------------------------------------
   The price this product actually shows at, over an empty box that overrides it.
   The old placeholder said "Default" without ever saying what the default was;
   the number above is that answer.

   Moved here verbatim from the page's inline <style> in order to change it —
   styles belong in CSS files, and this page's blocks are pending extraction
   anyway (0045, Task 1). Only the vertical centring below is new. */
.sf-pricecell {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-end; justify-content: center;
  /* 21px base line + 5px gap + 30px field. Reserved in every state, so the row
     is the same height whether the field is showing or not — including rows that
     already carry an override, which used to be 3px shorter than the rest. */
  min-height: 56px;
  transition: padding-bottom 120ms;
}
.sf-pricecell__base { font-size: 14px; font-weight: 500; color: var(--color-text); white-space: nowrap; }
/* Show Price set to Hide — the column stops quoting a figure and says what the buyer
   gets instead. A word, not a price, so it drops to 10px — the floor, memory.md §4 —
   and subtle ink, and stops being read as a number down the column. Never struck: a
   row can carry a custom price AND be hidden at once (Taj Mahal ships that way), and
   the strikethrough below would then read as the override having replaced the word.
   The id lifts this over that rule's `:has()` specificity. */
#sfItemsTable .sf-pricecell__base.is-hidden {
  font-size: 10px; font-weight: 500; color: var(--color-text-subtle); text-decoration: none;
}
/* An override supersedes the tier price, so the tier price is struck and drops two points.
   14 → 12px, not 13 → 11px: 12px is the project's font floor. */
.sf-pricecell:has(input:not(:placeholder-shown)) .sf-pricecell__base { font-size: 12px; text-decoration: line-through; color: var(--color-text-subtle); }

/* A hidden price has nothing to override, so hovering the row must not offer the
   box. `display: none`, not `opacity: 0` — the field also stops being focusable,
   which closes the :focus-within path that would otherwise reveal it to the
   keyboard while the mouse could not reach it.

   The reserved 35px goes with it, unconditionally rather than on hover: a row can
   be hidden AND already carry an override (Taj Mahal), and that rule holds the
   padding open at rest, which would leave "Hidden" floating 18px above the centre
   line of an empty cell. Set Show Price back to Default and both return. */
#sfItemsTable tbody tr .sf-pricecell:has(.sf-pricecell__base.is-hidden) { padding-bottom: 0; }
#sfItemsTable tbody tr .sf-pricecell:has(.sf-pricecell__base.is-hidden) .sf-cprice { display: none; }

/* The override box is out of the way until you reach for it. opacity, not
   visibility or display: the box stays focusable, so :focus-within can still
   reveal it for the keyboard.

   It is also out of flow, pinned to the bottom of that reserved height. In flow
   it held its row open on every product, which pushed the price 18px above the
   cell's centre line — on the 38 rows that have no override and never show the
   box, that read as a price sitting crooked in its cell for no visible reason.
   Out of flow the price sits on the centre line at rest and moves up only when
   the field actually appears, and the reserved height means the row does not
   move when it does. */
.sf-cprice {
  position: absolute; right: 0; bottom: 0;
  display: inline-flex; align-items: center; gap: 5px; flex-direction: row-reverse;
  opacity: 0; transition: opacity 120ms;
}
#sfItemsTable tbody tr:hover .sf-cprice,
.sf-pricecell:focus-within .sf-cprice,
.sf-pricecell:has(input:not(:placeholder-shown)) .sf-cprice { opacity: 1; }
/* Revealing the field re-centres the price in what is left above it — 30px of
   field plus the 5px gap. Same 120ms as the fade, so the price rising and the
   field arriving read as one movement rather than two. */
#sfItemsTable tbody tr:hover .sf-pricecell,
.sf-pricecell:focus-within,
.sf-pricecell:has(input:not(:placeholder-shown)) { padding-bottom: 35px; }
/* Right-aligned so the override lines up under the price it replaces. */
.sf-cprice input { width: 95px; padding: 5px 8px; font-size: 12px; text-align: right; }
/* Save is a bare icon — no button chrome, no resting or hover border. It appears only
   while there is an unsaved edit: typing sets .is-dirty, saving clears it. A saved
   override is a settled value, so nothing hovers over it asking to be saved again. */
.sf-cprice__save { visibility: hidden; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0; background: none; color: var(--color-text-subtle); cursor: pointer; transition: color 120ms; }
.sf-cprice__save:hover { color: var(--color-primary-700); }
/* The one ring kept: a keyboard user has to see where focus is. */
.sf-cprice__save:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; border-radius: 5px; }
.sf-cprice.is-dirty .sf-cprice__save { visibility: visible; }
.sf-cprice__save svg { width: 15px; height: 15px; }

/* Custom domain field — right-aligned so the address ends on the same edge as the
   subdomain field beside it, where the .vava-store.com addon puts it. */
.sf-domainrow input[data-domain-panel="custom"] { text-align: right; }

/* ==========================================================================
   COLLECTIONS — the named rows a buyer reads on the showroom
   --------------------------------------------------------------------------
   Merchandising was cut from this console in change 0043 for one reason: hand-
   curated lists decay the moment slabs sell. It returns here because a collection
   now names how it fills — a rule keeps itself true, and only the collections a
   supplier really does curate by hand carry that cost. The table says which is
   which on every row, so the decay risk is visible rather than discovered.
   ========================================================================== */

/* Bounded-fluid columns over table-layout:fixed — the table resizes with the
   browser, never with the data. Order is a single grip, so it is the one column
   pinned to its content.
   The floor and the fixed layout belong together, and they belong here: an inline
   `style="min-width:706px"` on the table was an ADR-018 / memory.md §14 violation shipped inside
   this feature's own surface. 706px was the sum of FIVE columns' floors; Shown is gone — its
   switch moved onto the Collection cell — so the floor comes down with it. Below 604px the
   table scrolls inside .table-wrap rather than crushing the Collection name. */
#sfCollectionsTable { table-layout: fixed; min-width: 604px; }
#sfCollectionsTable th.col-ord   { width: 78px; min-width: 78px; max-width: 78px; }   /* fits the uppercase header on one line */
#sfCollectionsTable th.col-coll  { width: 46%; min-width: 24%; max-width: 100%; }
#sfCollectionsTable th.col-fills { width: 36%; min-width: 18%; max-width: 75%; }
#sfCollectionsTable th.col-count { width: 18%; min-width: 9%; max-width: 35%; }

/* THE SWITCH LEADS THE NAME. It used to end the row as a status column; it reads
   better as the first thing on the row it governs — switch then label, as
   everywhere else on the platform — and a shown/hidden state is not something an
   operator should have to track back across three columns to set.
   The flex lives on an inner span, never on the `<td>`: a cell that stops being a
   table-cell also stops obeying the fixed column widths above. */
#sfCollectionsTable td.col-coll .sf-collcell { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* A bare `.switch` span is inline, so its 34×20 box collapses outside the flex
   `.switch-field` it normally sits in. */
#sfCollectionsTable td.col-coll .switch { flex: none; display: inline-flex; cursor: pointer; }
#sfCollectionsTable td.col-coll .main { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Order — a grip, dragged. It was an up/down pair, which had to grey itself out at
   each end of the list to stop being a button that does nothing; one grip says the
   rows are yours to arrange and has no ends to defend. Grab and grabbing are the
   two cursors that promise it. */
.sf-ord { display: inline-flex; }
.sf-drag {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-control); color: var(--color-text-muted); cursor: grab;
  transition: color 120ms, border-color 120ms;
}
.sf-drag:hover { color: var(--color-text); border-color: var(--color-border-strong); }
.sf-drag:active { cursor: grabbing; }
.sf-drag svg { width: 14px; height: 14px; }
/* The row being carried, and the gap it is about to fall into. */
#sfCollectionsTable tr.is-dragging td { opacity: .45; }

/* How a collection fills, said on the row. By hand carries the re-curation cost
   0043 objected to; by rule does not — so the two never wear the same chip. */
.sf-fillchip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--radius-sm);
  font-size: 12px; font-weight: 500; white-space: nowrap;
}
.sf-fillchip svg { width: 12px; height: 12px; }
/* Neither kind is a warning, so neither gets a warning colour — the icon carries
   the difference and the ground stays quiet. */
.sf-fillchip { background: var(--color-control); color: var(--color-text-muted); }
.sf-fillchip--hand { color: var(--color-text); }
/* The rule itself, under the chip — a rule you cannot read is a rule you cannot trust. */
.sf-fillsub { display: block; margin-top: 3px; font-size: 11px; color: var(--color-text-subtle); }

/* ---- New / Edit Collection dialog ---- */

/* The fill choice opens as a list with nothing chosen — the dialog will not save
   until one is picked, because there is no sensible default between "I curate
   this" and "a rule curates this". */
.sf-fillopts { display: flex; flex-direction: column; gap: 8px; }
/* These option rows are <label>s nested inside a .field, so app.css's uppercase
   12px field-label style reaches them and shouts every sentence. Reading matter
   is not a field label — reset the whole inherited set on the rows and on the
   material picker below, which has the same problem. */
.sf-fillopt, .sf-fillopt *, .sf-pickrow, .sf-pickrow * {
  text-transform: none; letter-spacing: normal;
  font-family: inherit; font-weight: 400;
}
.sf-fillopt { display: block; cursor: pointer; }
/* Only the radio is hidden — a bare `input` selector here also swallows the number
   box inside a rule row, which then reads "Added in the last __ days" with the number
   invisible and untypeable. */
.sf-fillopt > input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.sf-fillopt__box {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 12px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-control);
  transition: border-color 120ms, background 120ms;
}
.sf-fillopt:hover .sf-fillopt__box { border-color: var(--color-border-strong); }
.sf-fillopt input:checked + .sf-fillopt__box {
  border-color: var(--color-primary); background: var(--color-primary-50);
}
.sf-fillopt input:focus-visible + .sf-fillopt__box { outline: 2px solid var(--color-primary); outline-offset: 2px; }
/* The dot is drawn, not native — a native radio cannot be sized to the row. */
.sf-fillopt__dot {
  flex: none; width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid var(--color-control-border); background: var(--color-surface);
}
.sf-fillopt input:checked + .sf-fillopt__box .sf-fillopt__dot {
  border: 4px solid var(--color-primary); background: var(--color-surface);
}
.sf-fillopt__t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sf-fillopt__t .m { font-size: 13px; font-weight: 500; color: var(--color-text); }
.sf-fillopt__t .s { font-size: 11px; color: var(--color-text-subtle); }
/* The number a rule needs sits inside the rule's own row, so the sentence reads
   straight through: "Added in the last [30] days". */
.sf-fillopt__n {
  width: 52px; padding: 4px 7px; text-align: right;
  font-size: 12px;
  border: 1px solid var(--color-control-border); border-radius: var(--radius-sm);
  background: var(--color-surface); color: var(--color-text);
}
.sf-fillopt input:not(:checked) + .sf-fillopt__box .sf-fillopt__n { opacity: .45; }
.sf-fillopt__tail { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; flex: none; font-size: 12px; color: var(--color-text-muted); }

/* The hand-picked list appears only once "I pick the materials" is chosen. */
.sf-pickwrap { margin-top: 14px; display: flex; flex-direction: column; gap: 6px; }
.sf-picklist {
  max-height: 232px; overflow-y: auto;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-control);
}
.sf-pickrow {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 11px; cursor: pointer;
  border-bottom: 1px solid var(--color-border);
}
.sf-pickrow:last-child { border-bottom: 0; }
.sf-pickrow:hover { background: var(--color-surface-alt); }
.sf-pickrow__n { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sf-pickrow__n .m { font-size: 13px; color: var(--color-text); }
.sf-pickrow__n .s { font-size: 11px; color: var(--color-text-subtle); }
.sf-pickrow__c { margin-left: auto; flex: none; font-size: 11px; color: var(--color-text-subtle); }

/* The picker's own find row. The page search narrows the open tab's tables and a dialog is not
   a tab, so the list carries chips and a box of its own; .search caps its width for the page
   toolbar, and inside a dialog field it takes the full column. */
.sf-pickwrap .fchips { margin-bottom: 2px; }
.sf-picksearch { max-width: none; }
.sf-pickempty {
  padding: 12px 11px; font-size: 12px; color: var(--color-text-subtle);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-control);
}

/* Phone — the grip and the fill chip need the row to breathe. */
@media (max-width: 768px) {
  /* 44×44 is the floor for anything tappable. One grip fits the 78px column the
     header already needs, so unlike the pair it replaced it costs the row nothing. */
  .sf-drag { width: 44px; height: 44px; }
  .sf-drag svg { width: 18px; height: 18px; }
  .sf-fillopt__box { padding: 13px 12px; }
  .sf-fillopt__n { width: 64px; min-height: 44px; padding: 7px; }
  .sf-pickrow { min-height: 48px; }
}

/* The line under a field that says what the field means for a buyer. No shared hint
   class exists in app.css, so this stays page-local rather than minting a global one
   off a single dialog. */
.sf-collhint { font-size: 11px; color: var(--color-text-subtle); }

/* -------------------------------------------------------------------------
   Collections slide-over

   It is a table, not a form. Five columns whose narrowest honest width is 706px,
   and the last of them is the switch that takes a row off the showroom — on the
   standard 500px panel you would scroll sideways to reach the control you opened
   the panel for. Sized to the table plus the body's own padding, and it still
   yields to a narrow window.
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   Product-type selectors

   They sat in a band of their own between the card header and the table, then in
   the card's toolbar once that header went, then on the page's own row above the
   tabs, beside the search. They are back in the Products card's toolbar (user,
   2026-10-11): above the tabs they read as page-wide and came and went with the
   tab. The request states and the account stages moved into their own tabs with
   them. `.subtabs--inline` drops the 8px bottom margin `.subtabs` keeps for a band
   of its own; in a toolbar the toolbar's own padding is the space.
   ------------------------------------------------------------------------- */

/* The two showroom-wide switches bank right on the Products toolbar, the fixed
   corner, opposite the types. 12px non-bold label to the RIGHT of the switch
   (memory.md rules 4 and 5); muted, so it does not compete with the chosen type. */
.sf-tabdefs { margin-left: auto; display: flex; align-items: center; gap: 18px; flex: none; }
.sf-tabdef { display: inline-flex; align-items: center; gap: 8px; margin: 0; cursor: pointer; }
.sf-tabdef__t { font-size: 12px; font-weight: 400; color: var(--color-text-muted); white-space: nowrap; }
.sf-tabdef .switch { flex: none; }
/* Off, the label stops claiming something is shown. */
.sf-tabdef .switch[aria-checked="false"] + .sf-tabdef__t { color: var(--color-text-subtle); text-decoration: line-through; text-decoration-thickness: 1px; }
/* Under 900px a tab's filter row scrolls sideways, the way the tab strip above it
   does, rather than running off the card's edge with its last options out of reach. */
@media (max-width: 900px) {
  [data-tab-panel] > .card > .toolbar > .subtabs--inline { min-width: 0; max-width: 100%; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  [data-tab-panel] > .card > .toolbar > .subtabs--inline::-webkit-scrollbar { display: none; }
  [data-tab-panel] > .card > .toolbar > .subtabs--inline > * { flex: none; white-space: nowrap; }
}

/* ---- Product information panel ---------------------------------------------
   Opened from a product name in the items table (#so-sf-product). Label and value
   sit tight against the middle rather than at opposite edges of the panel: spread
   apart, the eye has to travel a hand's width to join a word to its answer, and
   the pairs stop reading as pairs. */
.sfp-h {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 600;
}
.sfp-h + .sfp-facts { margin-bottom: 22px; }
.sfp-facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  column-gap: 14px;
  row-gap: 9px;
  margin: 0;
  font-size: 13px;
}
.sfp-facts dt {
  text-align: right;
  color: var(--color-text-muted);
}
.sfp-facts dd {
  margin: 0;
  color: var(--color-text);
}

/* ── The Requests tab's Confirmed / Unconfirmed swap (the abandonment view) ─────
   The swap rides the find row beside the state chips; the note sits over the
   unconfirmed table and says why those rows count for nothing. */
.req-views { display: flex; align-items: center; gap: 6px; }
.req-views__label { font-size: 12px; }
.req-views__note { margin: 0 0 8px; font-size: 12px; }
/* ACTIONS, sized for its widest content rather than a share: two small buttons
   and the gap between them, plus the cell's own padding. A share would hand it
   a third of a wide screen to hold two words. The reminded stamp drops to its
   own line under the buttons. */
.req-queue th.rq-actions { width: 184px; }
.req-queue td.rq-actions { white-space: nowrap; }
.req-queue td.rq-actions .sf-reminded { display: block; margin-top: 4px; font-size: 11px; white-space: normal; }
