/* ==========================================================================
   Air Market - v9 mobile layer, FOUNDATION sheet (V9-MOBILE-SPEC.md).

   v9 is what none of v0-v8 ever shipped: a phone layout. The store's shell
   has a hard, measured floor - #topbar's nowrap tier-2 row forces 826px of
   minimum width onto .window, so a 390px phone can see 390 of the app's
   826 and the rest is clipped, not reflowed (V9-MOBILE-SPEC.md section 1
   has the full trace, read off the code and a 320-frame capture, not
   invented). v9 is the additive layer that removes that floor and reflows
   everything above it, in the same pattern this repo has shipped four
   times before it (v3 over v2, v5 over v4, v6 over v5): a LAST-loaded set
   of sheets, every rule gated behind a media query, so at desktop widths
   the layer is provably inert rather than merely "not visibly different".

   SEVEN SHEETS, ONE PER WORKSTREAM (the v6 precedent, not the spec's own
   plan). V9-MOBILE-SPEC.md section 4 describes five Phase-2 tasks sharing
   one fenced sheet; that does not survive five agents editing the same
   file at once, and it would survive it exactly as well as v6's single
   shared file would have - which is why v6 shipped seven files instead of
   one (store-v6-core.css's own header). This build follows v6's precedent
   rather than the spec's: one sheet per workstream, all seven created and
   linked to index.html up front by this task (T0.2), so no later agent
   ever has to open index.html or fight another agent for the same file.

     store-v9-mobile.css     this file - the foundation every other sheet
                             depends on. Breakpoint literals, the gutter
                             step-down, the v9-rail primitive.
     store-v9-nav.css        T1  - topbar collapse to the 56px mobile bar,
                             the menu sheet, the search row, the docked
                             Stack pill (spec 3.1). This is the sheet that
                             actually releases the 826px floor.
     store-v9-detail.css     T2.1 - listing detail: hero stack, stats rail,
                             gallery rail, table scroll wrappers (spec 3.2).
     store-v9-editorial.css  T2.2 - Discover and editorial rails, hero type
                             scale, card aspect cap (spec 3.3).
     store-v9-browse.css     T2.3 - browse facet collapse to a disclosure
                             panel (spec 3.4).
     store-v9-grids.css      T2.4 - the long tail of fixed-column grids
                             across catalogue, search, reports, studio,
                             creator and collections (spec 3.5).
     store-v9-taps.css       T2.5 - the >= 44px tap-target floor and the
                             16px body-text floor (spec 3.6).

   BYTE-IDENTITY, STRUCTURALLY. Every rule in every one of the seven sheets
   above MUST live inside `@media (max-width: 720px)` or `@media
   (max-width: 480px)` - no bare rule, ever, in any of the seven files.
   That is what turns the >= 861px byte-identity bar (V6-SPEC.md section
   17, amendment A1; carried forward here as v9's AC2) into a structural
   guarantee instead of something QA merely failed to find a counterexample
   to. A sheet that paints nothing above 721px cannot be the reason a
   desktop pixel moved - there is no rule left to audit for "did the media
   query get this one wrong", because there is no rule outside one.

   SCOPING AND SPECIFICITY, for the six sheets that follow this one. The
   shipped document is always `<html data-ui="v5" data-v6="on">`
   (index.html's own header comment explains why there is no longer a
   design switch to worry about). Media queries add NO specificity of
   their own - wrapping a rule in one changes WHEN it applies, never how
   hard it competes with another rule that also applies at that width. To
   beat an existing declaration you must match or exceed ITS selector
   specificity and let this layer's later position in source order break
   the tie - exactly the mechanism v6 already uses against v0-v5
   (store-v6-core.css's header spells out the identical trick one layer
   down). Concretely, for the six sheets after this one:
     - overriding a v2/v3/v4/v5-era rule: mirror whichever subset of
       `:root:is([data-ui="v2"],[data-ui="v3"],[data-ui="v4"],[data-ui="v5"])`
       the rule you are overriding actually uses - check the source file
       first. The four v3-era feature sheets do not all use the full list;
       store-v3-core.css's own --v3-gutter, for instance, is scoped to
       v3/v4/v5 only, no v2, and this file's gutter override below mirrors
       that exact subset rather than the wider one.
     - overriding a v5-only rule (store-v5.css): mirror `:root[data-ui="v5"]`.
     - overriding a v6 rule (any store-v6-*.css): mirror `:root[data-v6="on"]`.
     - a BRAND NEW class this layer introduces, that nothing above already
       defines, needs no prefix at all - there is nothing to tie-break
       against. The v9-rail utility below is written this way on purpose.
   Never reach for !important as a substitute for matching specificity. The
   one !important in the whole v6 stack (store-v6-browse.css's [hidden]
   guard) is defending a rule against the user agent's own stylesheet, a
   different problem from losing a tie-break against another author rule -
   it is not precedent for using !important here.

   WHAT THIS FILE OWNS AND NOTHING ELSE. "Foundation" means only things
   every other sheet depends on:
     1. the two breakpoint literals, documented once here because a custom
        property cannot appear inside a media query's condition;
     2. the --v3-gutter step-down from 40px to a 16px-class token, and the
        .page rule that makes the step-down visible in this file without
        tracing a variable through a second sheet to see the effect;
     3. a paragraph proving the 826px shell floor needs NO rule in this
        file - measured, not assumed, and entirely T1's fix to make;
     4. the v9-rail scroll-rail primitive that spec sections 3.2, 3.3 and
        3.5 all need, written once so three sheets do not each invent a
        slightly different scroll-snap implementation.
   Nothing else belongs here. No detail-page, editorial, browse, grid or
   tap-target rule - those are the six sheets above, each owned by one
   task, each free to edit its own file without ever touching this one
   again.
   ========================================================================== */

/* --------------------------------------------------------------------------
   BREAKPOINTS - literals, not custom properties.

   --bp-mobile: 720px   the app's existing collapse point, reused rather
                        than invented. store-v5.css:329 already wraps
                        .detail-head's CTA column to full width here;
                        store-v6-browse.css:107 already collapses the
                        facet-rail grid to one column here. Every v9 rule
                        that means "phone-and-small-tablet" keys off this
                        same number, so the app gets one collapse seam
                        instead of six sheets drifting to six different
                        ones over time.
   --bp-phone: 480px    fine-tuning only: type scale, single-column where
                        two columns still clips, the gutter's last step.

   These are NOT declared as CSS custom properties, on purpose. A custom
   property cannot appear inside a media query's condition -
   `@media (max-width: var(--bp-mobile))` is invalid, and the query is
   simply dropped with no rule ever applying and no error visible anywhere
   you would think to look - so declaring one here would be a foot-gun with
   no upside. The two numbers are written as literals at every use site in
   this sheet and its six siblings; this comment is the one place that
   explains what they mean and why there are two of them, not five. The
   repo already has precedent for exactly this tradeoff: V3.CONDENSE_AT is
   a JS literal (assets/js/v3/core.js:694) cross-referenced from a CSS
   comment (store-v3-core.css:41) rather than synced through a custom
   property, for the identical reason - the value needs to cross a boundary
   custom properties cannot cross.

   WHY TWO, NOT A LADDER. store-v3-topnav.css already steps the desktop bar
   at 1180 / 940 / 860px to stop it overlapping itself on the way down
   (section 4 of that file), and that ladder is untouched here - it is not
   what this spec fixes, and nothing below 861px inherits any rhythm from
   it. Below 720px the shell has never had ANY layout at all, so there is
   no existing cadence to slot a third, fourth and fifth step into; a
   five-step ladder here would be five seams for six sheets and six
   independent agents to keep synchronised, for a device class (roughly
   320-430px wide phones) that the capture behind this spec shows
   clustering into exactly two behaviours - "the shell layout changes
   shape" and "the type scale and column count need one more turn of the
   screw". Two numbers both sheets can hold in their head beats five that
   nobody will remember to update together.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   THE GUTTER STEP-DOWN (spec section 2, "the gutter comes down").

   --v3-gutter is declared once, on
   :root:is([data-ui="v3"],[data-ui="v4"],[data-ui="v5"]), in
   store-v3-core.css:91, as var(--space-40) (40px). Its consumers already
   read the variable rather than repeating the number: the bar's own tier
   padding (store-v3-topnav.css:50, store-v3-filters.css:31,
   store-v3-mega.css:93 and :297) and .page's left/right padding
   (store-v3-core.css:233-234, `padding-left/padding-right: var(--v3-gutter)`).
   Because every consumer already reads the variable, redefining
   --v3-gutter at <= 720px is sufficient BY ITSELF to shrink all of them in
   lockstep - the bar's internal insets included, which matters because
   T1's single-row mobile bar (3.1) inherits this same padding.

   The .page rule immediately below does not change that cascade - .page
   would already be 16px either way, since it too reads var(--v3-gutter) -
   it is written anyway so the next reader sees ".page's gutter comes down
   at mobile widths" stated in this file, rather than having to trace a
   custom property through a second sheet to notice the effect.

   The reduced value is --space-16 (tokens.css), not an invented number.
   Picked over the smaller tokens (--space-4/8/12) because at 390px the
   surfaces sitting in this gutter - the mobile bar's icon row, the nav
   list inside the menu sheet, .page's own content - still need a margin
   that reads as deliberate rather than cramped; half of 40 is 20, which is
   not a token this scale has, and --space-16 is the largest sub-24 step
   available.
   -------------------------------------------------------------------------- */

@media (max-width: 720px) {
  :root:is([data-ui="v3"],[data-ui="v4"],[data-ui="v5"]) {
    --v3-gutter: var(--space-16);
  }
  :root:is([data-ui="v3"],[data-ui="v4"],[data-ui="v5"]) .page {
    padding-left: var(--v3-gutter);
    padding-right: var(--v3-gutter);
  }
}

/* --------------------------------------------------------------------------
   THE SHELL FLOOR - MEASURED, NOT GUESSED.

   V9-MOBILE-SPEC.md section 1.1 traces the 826px floor to #topbar's own
   .v3-row (tier 2's content row: flex-wrap: nowrap, six children that
   cannot shrink) forcing its min-content width onto #topbar, which
   .window's overflow-x: hidden then clips instead of reflowing. The
   candidate fix at THIS layer would have been `min-width: 0` on .window,
   .content and .page, in case any of the three was independently floored
   the same way a flex item with the browser's automatic minimum size can
   be - the exact bug the topbar has, one level up.

   Measured instead of assumed, chromium, 390x844, before this sheet was
   linked into index.html: .window and #topbar both report
   `scrollWidth: 826, clientWidth: 390`. Injecting
   `.window, .content, .page { min-width: 0 !important; }` and re-measuring
   produces IDENTICAL numbers - 826/390, unchanged to the pixel. Neither is
   a flex item of a container that would honour a min-width override
   anyway: .window is not itself a flex item of anything above it, and
   .content's cross-axis stretch under #topbar's/window's column flow does
   not enforce an automatic minimum the way a nowrap ROW does - only the
   row inside #topbar has that problem.

   Conclusion: no min-width rule belongs in this file for the shell floor.
   Collapsing the nowrap row itself into the 56px mobile bar is entirely
   T1's fix (spec 3.1) - this file does not touch #topbar's markup, its
   flex-wrap, or any of its children.

   ONE HONEST SIDE EFFECT TO FLAG FOR T1, found by measuring again after
   linking this sheet: #topbar's .v3-row reads the SAME --v3-gutter this
   file redefines above (store-v3-topnav.css:50, `padding: 0
   var(--v3-gutter)`), because tier 1 and tier 2 share one row class. That
   is intentional reuse, not an oversight - it is what "redefining the
   existing custom property... NOT re-padding every surface" (spec section
   2) means in practice, and it is a real head start for T1's own 56px row,
   which wants this same reduced gutter. But it means the floor's exact
   NUMBER moves as a side effect of a padding change alone, with no wrap
   logic touched: measured post-link, 390x844, .window and #topbar both now
   report `scrollWidth: 802, clientWidth: 390` (not 826). The floor is not
   fixed - 802 is still more than double the 390px viewport, every reachability
   problem section 1 describes is still exactly as broken - it is simply
   measured 24px narrower because the row's own padding shrank along with
   .page's. T1 should treat 802/390 as the accurate starting number, not
   826; 826 was the pre-v9 baseline and stops being the live number the
   moment this sheet is linked.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   v9-rail - THE SHARED SCROLL-RAIL PRIMITIVE.

   Spec sections 3.2, 3.3 and 3.5 each turn a fixed grid into a horizontal
   swipe rail at <= 720px (the App Store idiom this mock already imitates
   elsewhere - store.css:425 .hero-carousel and store-v6-rec.css:64
   .v6-rec-cards both hand-roll the same handful of properties today). This
   is the one contract, so three sheets do not each write a slightly
   different scroll-snap implementation that then drifts. Two ways to use
   it, because 3.2/3.3/3.5 are CSS-only tasks against existing markup - none
   of them may add a class through JS:

   1. If the surface's markup is JS-rendered and CAN carry a new class
      (none of the current v9 tasks are, but a future one might be), add
      "v9-rail" alongside the existing container class and set
      --v9-rail-item as an inline custom property on the same element:
        <div class="ed-grid-5 v9-rail" style="--v9-rail-item: 78vw">

   2. The common case: apply the same four declarations directly to your
      own selector instead of the .v9-rail class, at the specificity you
      need to win (see SCOPING at the top of this file), and set
      --v9-rail-item in that same rule:

        :root[data-v6="on"] .ed-grid-5 {
          --v9-rail-item: 78vw;
          display: flex;
          flex-wrap: nowrap;
          overflow-x: auto;
          overflow-y: hidden;
          scroll-snap-type: x proximity;
          -webkit-overflow-scrolling: touch;
          scrollbar-width: none;
        }
        :root[data-v6="on"] .ed-grid-5::-webkit-scrollbar { display: none; }
        :root[data-v6="on"] .ed-grid-5 > * {
          flex: 0 0 var(--v9-rail-item);
          min-width: 0;
          scroll-snap-align: start;
        }

   Either way, --v9-rail-item is a percentage-of-viewport length: 78vw for
   a 3-4up editorial rail (spec 3.3), 85vw for the wider detail gallery
   (spec 3.2, "one tile = 85vw"). Pick the number that leaves a sliver of
   the next card visible at the right edge - that sliver is what tells a
   thumb there is more to scroll, and its absence is why a plain
   `overflow-x: auto` grid reads as "the layout broke" instead of "swipe".
   Rails are deliberately exempt from the capture's overflow probe (spec
   3.3) - `overflow-x: auto` here is the fix, not the bug.

   The class form below carries no [data-ui]/[data-v6] prefix. Nothing
   above this layer defines `.v9-rail`, so there is no existing rule to
   tie-break against and no specificity to mirror - see SCOPING's third
   bullet at the top of this file.
   -------------------------------------------------------------------------- */

@media (max-width: 720px) {
  .v9-rail {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .v9-rail::-webkit-scrollbar { display: none; }
  .v9-rail > * {
    flex: 0 0 var(--v9-rail-item, 78vw);
    min-width: 0;
    scroll-snap-align: start;
  }
}
