/* ============================================================================
   storefront.html — page-scoped styles.

   New styling for this page lands here, never in the page's <style> block.
   The two inline blocks already in storefront.html are pending extraction
   (see changes/0045_2026-08-06_storefront-next-to-do.md, Task 1).
   ============================================================================ */

/* --- Storefront 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; }

/* --- Storefront Products › Show Price / Show Qty ----------------------------
   A per-item override of the two switches in Settings › Storefront Display —
   Show Pricing and Show Quantities. Two states, not three: only the override
   that DISAGREES with the default carries information. While the storefront
   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; }

/* --- Storefront Products › toolbar: the storefront-wide default -------------
   Every Default chip in the table defers to these two switches, so they sit in
   the toolbar of the table that inherits them rather than behind the page-
   settings gear — a column full of "Default" that never says what a buyer sees
   is the reason a read-only mirror used to stand here.

   The gap is wide enough that the two read as two settings, not one label split
   in half; `flex: none` keeps them off the row the search box stretches. */
.sf-visdefs { display: inline-flex; align-items: center; gap: 18px; flex: none; }
.sf-visdefs .switch-field { 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. */

/* --- Storefront 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 12px 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: 12px; 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 storefront
   --------------------------------------------------------------------------
   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 two-button stack, 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, so it is this run's to fix rather than adjacent code to leave alone.
   706px is the sum of the five columns' own floors; below it the table scrolls inside .table-wrap
   rather than crushing the Collection name. */
#sfCollectionsTable { table-layout: fixed; min-width: 706px; }
#sfCollectionsTable th.col-ord   { width: 78px; min-width: 78px; max-width: 78px; }   /* fits the uppercase header on one line */
#sfCollectionsTable th.col-coll  { width: 40%; min-width: 20%; max-width: 100%; }
#sfCollectionsTable th.col-fills { width: 30%; min-width: 15%; max-width: 75%; }
#sfCollectionsTable th.col-count { width: 14%; min-width: 7%; max-width: 35%; }
#sfCollectionsTable th.col-shown { width: 16%; min-width: 8%; max-width: 40%; }

/* Shown is the status column, so it ends the row and its right padding answers
   the first cell's left padding. */
#sfCollectionsTable th.col-shown,
#sfCollectionsTable td.col-shown { text-align: right; }
/* A bare `.switch` span is inline, so its 34×20 box collapses outside the flex
   `.switch-field` it normally sits in. Inline-flex blockifies it without turning the
   cell into a flex container — a `<td>` that stops being a table-cell also stops
   obeying the fixed column widths above. */
#sfCollectionsTable td.col-shown .switch { display: inline-flex; cursor: pointer; }

/* Order — up/down rather than a drag grip. The order is short and rarely
   changed, and two buttons work on a phone where a grip does not. */
.sf-ord { display: inline-flex; flex-direction: column; gap: 2px; }
.sf-ord button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 16px; padding: 0;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-control); color: var(--color-text-muted); cursor: pointer;
  transition: color 120ms, border-color 120ms;
}
.sf-ord button:hover { color: var(--color-text); border-color: var(--color-border-strong); }
.sf-ord button:disabled { opacity: .4; cursor: default; }
.sf-ord svg { width: 12px; height: 12px; }

/* 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); }

/* Phone — the order buttons and the fill chip need the row to breathe. */
@media (max-width: 768px) {
  /* 44×44 is the floor for anything tappable, and two of those stacked would make a
     108px-tall row. The table already scrolls sideways inside .table-wrap on a phone, so
     the pair turns to sit side by side — width is the cheap axis here, height is not. */
  #sfCollectionsTable th.col-ord { width: 104px; min-width: 104px; max-width: 104px; }
  .sf-ord { flex-direction: row; gap: 4px; }
  .sf-ord button { width: 44px; height: 44px; }
  .sf-ord 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 storefront — 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.
   ------------------------------------------------------------------------- */
.slideover--collections { width: min(760px, 100%); }

/* -------------------------------------------------------------------------
   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, and they now ride the page's own row
   at the trailing edge — beside the search that filters the same list, and level
   with the request states and the account stages, which are the same question
   asked of the other two tabs.

   `.subtabs` carries an 8px bottom margin for the band it no longer sits in; in
   a toolbar the toolbar's own padding is the space. The selector is on `.toolbar`
   rather than on `.toolbar--page` so it holds wherever the group is put next.
   ------------------------------------------------------------------------- */
.toolbar > .sf-typefilter { margin-bottom: 0; flex-wrap: wrap; }

/* -------------------------------------------------------------------------
   A column header with something at each end

   The Product header carries the add button and the name at its leading edge and
   the on-storefront count at its trailing one. A flex wrapper INSIDE the cell, not
   `display: flex` on the `th`: a flexed header cell stops being a table cell, and
   under `table-layout: fixed` it is the header cells that carry the column widths.
   ------------------------------------------------------------------------- */
.th-split { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* The header is 11px uppercase and tracked; a badge inside it keeps its own case
   and tracking, or it reads as a second heading rather than as a count. */
.th-split .badge { text-transform: none; letter-spacing: 0; font-weight: 500; }

/* The two storefront-wide switches ride the tab strip, so they sit against tabs that
   are taller than they are and must not stretch to match. */
.tabs > .sf-visdefs { align-self: center; }

/* ---- 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);
}
