/* HAND-WRITTEN, NOT generated — deliberately kept separate from
   styles.scoped.css (scripts/scope-web-demo-css.mjs). That file's entire
   contract is "mechanical @scope rewrite, zero content change"; this file
   exists precisely to make a content change (suppressing UI Phase 1's
   do-not-ship list forbids), so mixing the two would blur what the
   generator's own drift-guard test is allowed to assume about its output.

   Loaded AFTER styles.scoped.css (see WebInstall.tsx) so these rules win the
   cascade at equal specificity.

   recon/16-adversarial-review-phase1.md, L4-1: renderShellExtras() ends with
   an UNCONDITIONAL renderDemoBar() (public/web/app.js:3637), on every branch
   of render() including the guest homepage's first paint. It is not just
   cosmetic — its "Signed in" control flips the public site into "Signed in
   as @blake" for any visitor, which is also the trigger for the
   MIN_LISTINGS_TO_INSTALL brick guard in floorTransport.ts. Blake's files
   stay byte-identical; this suppresses it visually and functionally
   (display:none removes it from hit-testing, so its buttons cannot be
   clicked) without touching app.js. */
.blake-install-scope .demo-bar {
  display: none !important;
}

/* R24 — Nick's ruling: a category with zero listings gets no tile at all
   (mirrors the mobile app). demoTextFixups.ts's fixEmptyCategoryTiles
   removes the tile control itself; these two rules only handle the layout
   fallout of removing items from Blake's two FIXED-count grids so no empty
   cell/trailing gap is left behind. Both classes (MOSAIC_REFLOW_CLASS /
   MEGA_REFLOW_CLASS in demoTextFixups.ts — pinned against these exact
   literals in demoTextFixups.test.ts, see that file) are toggled by the
   fixup only when fewer than the full slate of tiles survives — an
   untouched page (every category has listings) keeps Blake's original
   layout byte-for-byte.

   .mosaic is a named-area grid (styles.css:431-443) — grid-area pins each
   tile to its own cell regardless of whether it exists, so a removed tile
   leaves its area blank rather than being backfilled by a neighbor.
   .mega-grid has no named areas, but a fixed repeat(9, 1fr) template
   (styles.css:256) — fewer tiles auto-place left-to-right with nothing
   pinning a hole in the middle, but leave a TRAILING gap on the right at a
   fixed 9-column width.

   🔴 F1 (adversarial review of #671, 2026-08-26) — TWO PRIOR ATTEMPTS, both
   measured broken:
     1. Reused Blake's own :1024px dense auto-flow fallback
        (grid-template-areas:none + grid-auto-flow:dense) with "featured"
        tiles at grid-column:span 2. A short final row still left a large
        blank strip trailing it — dense packing only prevents a hole INSIDE
        a row, not a short LAST row.
     2. repeat(auto-fit, minmax(Npx, 1fr)). auto-fit only collapses a track
        that is empty in EVERY row it spans — once the surviving tile count
        exceeds however many columns fit at the viewport's width, the grid
        wraps to a second row, and whichever columns that row doesn't fill
        stay reserved (occupied in row 1), leaving the same trailing blank
        strip. Measured LIVE on staging with this exact CSS injected: 1024px
        viewport → 717.7px blank (75.9% of the last row); 768px → 233.6px;
        534px → 247.5px. The harness's own earlier "5/9 and 9/9, zero
        trailing gap" measurement was real but was the one case (single row,
        no wrap) where this approach happens to work — never re-checked
        across 1-8 survivors × the real breakpoints, which is what caught it.

   🔴 L1 (adversarial re-review of #671, 2026-08-26) — THE --gbz-tile-cols FIX
   ABOVE WAS ALSO WRONG. Pinning column count 1:1 to tile count guarantees no
   WRAP, but it does nothing about how narrow each column gets: at high
   survivor counts on a phone it produces sliver tiles with clipped labels —
   measured 8 survivors @375px = 31.9×165px tiles, 82.6px of a 114px label
   clipped, starting at just 3 survivors on a phone; staging's real 5-survivor
   case clips 56.3px TODAY. A column CAP (stop increasing columns past some
   max) was considered and rejected — it reintroduces the exact partial-last-
   row problem F1 already fixed.

   FIX: flex-wrap. `display:flex; flex-wrap:wrap` on the container,
   `flex: 1 1 <basis>` on each tile. Flexbox's own `flex-grow` stretches
   whichever tiles land in the FINAL row to fill it exactly — no leftover
   gap, unlike a grid track that stays whatever width the template says
   regardless of what's actually in it — and `flex-shrink`/the basis floor
   keeps every tile above a sane minimum width instead of dividing the full
   row by however many tiles happen to survive. Measured across the same
   70-combination matrix (1-8 survivors × the real breakpoints): 0px gap AND
   0px label clipping at every one, minimum tile width never below 182px
   desktop / 339px @375px. `display:flex` makes every grid-* property on the
   old rules inert, so they're deleted rather than left dead. The container's
   own `gap` declaration (styles.css — mosaic and mega-grid both already set
   it) is unaffected by the display change and keeps applying between flex
   items exactly as it did between grid items.

   `align-items: flex-start` on the mega-grid rule (not the mosaic one) is
   load-bearing: .mega-tile is `aspect-ratio: 1` (styles.css:257) with no
   explicit height, so a flex container's default `align-items: stretch`
   would stretch each tile to match the tallest item in its row and break
   the square aspect ratio; flex-start lets each tile size itself normally
   instead. The mosaic's own `.tile` gets an explicit `height: 165px`
   instead (matching styles.css:435's original row height), so it has no
   equivalent stretch problem to guard against. */
.blake-install-scope #categories .mosaic.gbz-mosaic-reflow {
  display: flex;
  flex-wrap: wrap;
}
.blake-install-scope #categories .mosaic.gbz-mosaic-reflow .tile {
  flex: 1 1 180px;
  height: 165px;
}

.blake-install-scope #mega .mega-grid.gbz-mega-reflow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
}
.blake-install-scope #mega .mega-grid.gbz-mega-reflow .mega-tile {
  flex: 1 1 100px;
}

/* R25 + R26 RETIRED 2026-08-31 (Blake's auth pop-up restore). Both centered
   text inside <a> elements that linkFixups used to create: R25 for the
   #btn-signin button→anchor swap (fixSigninButton), R26 for the two injected
   Create-account links (addCreateAccount). All three fixups are retired —
   #btn-signin is a real <button> again (the UA centers button content
   natively, which was R25's own root-cause finding), it opens the in-page
   auth modal, and the injected links no longer exist. Rules for elements
   that cannot exist are not kept "just in case" — a resurrected anchor
   should LOOK broken so the regression is seen, not quietly styled. */

/* R27 RETIRED 2026-08-31 (Blake's auth pop-up restore). The Create-account
   pill and its mobile banner row are gone — account creation moved into the
   in-page auth pop-up (Start Trading opens register directly; the wall offers
   both doors), so the guest nav is back to Blake's original single row and
   the marker-scoped rules lost their subject. R28 (font boosting) and R29
   (signed-in nav fit) below are separate concerns and stay. */

/* ═══ Mobile layout, reported from Tyler's iPhone 2026-08-27 (Safari/iOS) ═══
   Three separate defects, all on the demo surface, all fixed here rather than
   in Blake's byte-sacred files. Read the note on each — the first one does
   NOT reproduce in a Chromium engine, which changes how it had to be fixed. */

/* 1 · Collection-highlight titles printed on top of each other (screenshots 1
   and 2 — the same .collector-card on Collections AND the home feed, which is
   why one rule closes both).

   styles.css:1435 sets `grid-template-columns: repeat(4, 1fr)`. A `1fr` track's
   automatic minimum is min-content, and `.cc-hl .t` is `white-space: nowrap`
   with titles like "Rolex Oyster Perpetual 36" — so the track's min-content is
   the FULL title width. `.cc-hl` carries `min-width: 0` (styles.css:1436),
   which is enough for Chromium to keep each cell at 68px and let the title's
   own `overflow: hidden` clip it; measured on this tree, scrollWidth 298 vs
   clientWidth 68, clipping correctly. iOS Safari evidently resolves the track
   minimum the other way, so the cell takes the title's width, the title fills
   it, `overflow: hidden` then has nothing to clip, and four 298px-wide titles
   render across each other exactly as the screenshots show.

   `minmax(0, 1fr)` states the zero minimum on the TRACK instead of relying on
   the item's `min-width` to propagate outward — the canonical fix for this
   class, and a no-op anywhere it already worked. The other two rules are the
   belt to that braces: the title cannot exceed its cell, and the cell clips
   whatever is left. Deliberately not inside a media query — the track minimum
   is wrong at every width; it only becomes VISIBLE when the cell is narrow. */
.blake-install-scope .cc-highlights {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.blake-install-scope .cc-hl {
  overflow: hidden;
}
.blake-install-scope .cc-hl .t,
.blake-install-scope .cc-hl .p {
  min-width: 0;
  max-width: 100%;
}

@media (max-width: 720px) {
  /* 2 · "Browse the Floor" category chips read as a waterfall (screenshot 3).
     Ten chips wrap to FIVE rows at a 339px content width — measured on this
     tree, total chip width 1153px. The width is not mostly padding: styles.css
     :783 sets `text-transform: uppercase` AND `letter-spacing: 0.1em`, so
     "MUSICAL INSTRUMENTS" alone runs 176px. Tightening the tracking is
     therefore the biggest lever and the least destructive one — the chips stay
     uppercase and keep Blake's pill shape, they just stop being spaced like a
     display heading at thumb size. Padding and font come down a step with it,
     and `min-height` 40 → 32 shortens every row it doesn't remove.

     Wrapping is kept on purpose. A single horizontally-scrolling strip would
     collapse this to one row, but it hides categories behind a swipe on the
     surface whose whole job is browsing them; the ask was smaller and better
     organised, not fewer. */
  .blake-install-scope .cat-tabs {
    gap: 6px;
  }
  .blake-install-scope .cat-tab {
    padding: 7px 11px;
    font-size: 11px;
    letter-spacing: 0.04em;
    min-height: 32px;
  }

  /* 3 · Message thread runs off the right edge (screenshot 4 — the "MESSAGE"
     button is sheared off and the bubbles continue past the screen).

     `.thread-view` (styles.css:1179) is a flex column, so its width is set by
     its widest child, and `.thread-head` (:1185) is a flex row of back arrow +
     avatar + name + trade count + action button with `gap: 12px` and nothing
     permitted to shrink — flex children default to `min-width: auto`, i.e. they
     refuse to go below their content width. Their sum exceeds a phone
     viewport, so the whole card is laid out wider than the screen and every
     later row (bubbles included) inherits that width.

     Letting the head's children shrink and wrap is the fix; the `overflow-x`
     on the card is a backstop so no future wide child can shear the surface
     again. `overflow-wrap: anywhere` on the bubble is for the shared-listing
     UUIDs that appear in these threads — a 36-character unbreakable token sets
     a min-content width all on its own.

     ⚠️ Reasoned from source, NOT observed: this thread needs a signed-in
     session, so it could not be reproduced here. Verify on the device that
     reported it. */
  .blake-install-scope .thread-view {
    max-width: 100%;
    overflow-x: hidden;
  }
  .blake-install-scope .thread-head {
    flex-wrap: wrap;
    row-gap: 6px;
  }
  .blake-install-scope .thread-head > * {
    min-width: 0;
  }
  .blake-install-scope .msgs {
    min-width: 0;
  }
  .blake-install-scope .bubble {
    max-width: 85%;
    overflow-wrap: anywhere;
  }
}

/* ═══ Feed card internals overflow their OWN box at 2-up (Tyler, 2026-08-27) ══
   "the cards don't sit natively inside their frame — it doesn't show all the
   engagement metrics, title, and unfair price votes."

   NOT the .rail. That one also runs past the viewport and is a red herring:
   it is `overflow-x:auto` with a 1528px scrollWidth, i.e. a horizontal
   scroller doing exactly what it was built to do. The real defect is inside
   the BROWSE grid, where the content overflows the card rather than the
   viewport.

   MEASURED at 375px on staging. styles.css:3774 (already inside this same
   720px query) forces `.grid-cards` to `repeat(2, 1fr) !important` with a
   12px gap, so each card is 163.5px and its padded inner box is 134px. Two
   rows need more than that and both are `flex-wrap: nowrap`:

     .lcard-userrow   needs 216px in 134  (avatar 26 · uname 69 · social 68 ·
                                           pm-wrap 28, gap 7)
     .lcard-priceline needs 196px in 134  (price 61 · cvotes 127, gap 8)

   So `.social` (the ♡318 metrics) is clipped 29px out, `.cvotes` (↑FAIR /
   ↓OVER) 47px out, and `.pm-wrap` 68px out — precisely the three things the
   report named.

   Blake DID adapt this grid for mobile in the same block — he hides
   `.social-block` and shrinks `.cvote` — so the intent is clearly that the
   card adapts; these two rows were simply missed.

   FIX IS `flex-wrap`, NOT hiding. The complaint is that the metrics and votes
   are MISSING, so suppressing them would answer the wrong question. Wrapping
   keeps every control visible and costs only a little card height:
     userrow   -> line 1 avatar+uname (102px), line 2 social+pm-wrap (103px)
     priceline -> line 1 price (61px),         line 2 cvotes (127px)
   Both lines land inside 134px. `margin-left:auto` on `.social`/`.cvotes` is
   left alone deliberately — once wrapped it right-aligns them on their own
   line, which is the same visual weighting they had before.

   `.uname` gets the truncation it never had: it is the one child that can grow
   without bound (a long handle), and without `min-width:0` a flex item refuses
   to shrink below its content, which would push the row wide again no matter
   how the rest wraps.

   Scoped to `.grid-cards` so the same card markup used at full width — where
   the box is ~222px and both rows already fit — is untouched. */
/* RETIRED 2026-09-10. The measurements above describe a two-up phone grid that no
   longer exists. Both halves of this fix now live in styles.css, for EVERY card:
   the priceline wraps only when the price and its pills don't fit (.lcard-priceline),
   and the user row never wraps — the handle truncates, as it always did on rail
   cards. Scoping either rule to .grid-cards made the same card look different by
   where it lived (Blake 2026-09-10). */

/* ──────────────────────────────────────────────────────────────────────────
   THE "ADD YOUR TAKE" SEND BUTTON'S TOUCH TARGET

   Reported by the owner 2026-08-28 as "the hitslop just doesn't work". Two
   separate problems were behind that one symptom: the control was DEADENED by
   writeGuard (fixed in commentPost.ts, it now posts for real), and the target
   itself is genuinely too small to hit with a thumb.

   Blake's box: `.take-composer .send` is a 12px glyph, and `.take-composer.live
   .send` adds `padding: 6px 9px` (styles.css:601, :2162). That is roughly
   30x26 CSS px. Fine with a mouse. Under the 44x44 that WCAG 2.5.5 and both
   platform guidelines ask for, and it is a one-glyph arrow, so there is nothing
   around it to catch a near miss.

   📌 GROWS THE TARGET, NOT THE GLYPH. font-size is deliberately untouched: the
   arrow is Blake's and the composer's proportions are his. min-width/min-height
   plus centring expand only the hit area, so the control looks the same and
   catches the thumb. `flex: none` keeps the flex parent from shrinking it back
   below the minimum on a narrow card, which is exactly where the miss happens.

   Scoped to .take-composer so the modal's "Post" (a text label, already a wide
   target) and every other .send in the file are left alone.
   ────────────────────────────────────────────────────────────────────────── */
.blake-install-scope .take-composer .send {
  min-width: 44px;
  min-height: 44px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* R28 — Safari must not inflate the demo's text (iOS font boosting opt-out).

   Tyler's iPhone screenshot, staging 2026-08-30 ~20:49: the nav's SIGN IN and
   CREATE ACCOUNT pills rendered at roughly half-again the intended size, each
   wrapping to two lines, shoving the row off the right edge — while a Chromium
   engine at the identical 375px viewport renders them one-line at 63px/110px.
   The engine gap is the diagnosis: iOS Safari "font boosting" inflates text it
   judges undersized unless the page opts out, and NOTHING in the demo, the
   overrides, or the SPA sets text-size-adjust (grepped, absent everywhere).
   The 08-27 mobile section above already records one "does NOT reproduce in a
   Chromium engine" defect on this surface — this is that class again.

   100%, scoped to the install root and inherited from there: the standard
   opt-out, no visual change in any engine that was already honest about
   size. Cannot be verified in Chromium BY DEFINITION — Tyler's phone is the
   instrument for this one, which is exactly how it was found. */
.blake-install-scope {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* R29 — the SIGNED-IN mobile nav fits the viewport. This is NOT an R27
   regression; it is a defect we spent three PRs standing next to.

   Tyler's phone, staging 2026-08-30, signed in as casey: the nav runs off the
   right edge, Categories flush to the screen edge, bell and avatar gone.
   MEASURED on the real build at 375px, signed in (not injected, not reasoned):

     .brand          x10   w90
     #btn-openapp    x106  w132   <- authed ONLY (app.js:18)
     .nav-actions    x244  w262   -> right edge 506 in a 375px viewport

   The bell landed at x412 and the avatar at x466, both entirely off-screen and
   INVISIBLE rather than reachable: .blake-install-scope sets overflow-x:clip
   (R-scope above) and documentElement.scrollWidth stays 375, so nothing about
   the page hints the controls exist.

   🔑 WHY EVERY EARLIER MEASUREMENT MISSED IT. Blake renders "Open in App" only
   when authed — guests get .store-badges, which are only-desktop and so render
   nothing on a phone (app.js:18). The signed-in nav therefore carries 132px +
   a gap that the guest nav never has. Every measurement in the R27 saga, v1 and
   v2 both, was taken on the GUEST nav, where that pill does not exist. One
   template, two DOMs, and we only ever instrumented one. R27 v1's unconditional
   wrap did not cause this — it made an already-broken nav VISIBLE as a ragged
   stack; v2's marker class then scoped the wrap away and reverted signed-in to
   the original silent clipping. Neither touched the actual overflow, because
   the overflow predates both (the pill landed 2026-08-28).

   THE FIX, and why these two elements:
   · #btn-openapp drops its label and keeps its icon. 132px -> 44px. The button
     has no aria-label; font-size:0 (not display:none) leaves the text in the
     accessibility tree, so the accessible name stays "Open in App" — VERIFIED,
     along with the 15px SVG surviving at its explicit size (styles.css:1939).
   · #btn-me is the only genuinely redundant control on a phone: the avatar chip
     opens the profile, and the mobile tab bar already carries a PROFILE tab in
     the same viewport. The bell has no such duplicate, so it stays.

   Guest-inert BY CONSTRUCTION, and this time the claim is checked: both ids are
   rendered only in the authed branch (app.js:18 and :36), so for a signed-out
   visitor these selectors match nothing at all. That is a stronger guarantee
   than R27 v2's marker class, which needs JS to have run.

   VERIFIED LIVE at 375px, signed in as casey on the served staging build with
   these exact rules injected and the row re-measured: openapp 44 at x106, bell
   fully on-screen at x324–368, Categories keeping its text at w104, nav right
   edge 368 with 7px to spare, scrollWidth 375. 480px matches R27's breakpoint.

   ⚠️ Chromium at 375px is not Tyler's iPhone. R28's note is the standing lesson
   here, and the GUEST banner overlapping the logo in his 2026-08-30 screenshot
   does NOT reproduce in this engine (measured: zero vertical overlap, logo
   y16–60, banner y72–116). That one is still unexplained and is NOT addressed
   by this rule. */
/* PRE-SHOW 6 #14 (2026-10-01): the #btn-openapp half of this rule is retired.
   The button is now a 44px icon circle at every width it shows (.app-open in
   styles.css), so there is no label left to drop here. */
@media (max-width: 480px) {
  .blake-install-scope #btn-me {
    display: none;
  }
}

/* Google and Apple sign-in on the auth cards (app.js authOauthButtons). Google
   draws its own button, a 40px iframe, into this slot (src/web/oauthWeb.ts);
   the slot centers it and holds its height so the cards below do not jump
   when it lands. The terms box is the Google or Apple sign-up's step 1. */
.blake-install-scope .auth-oauth-google {
  display: flex;
  justify-content: center;
  min-height: 44px;
}
.blake-install-scope .auth-agree {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-muted);
  cursor: pointer;
}
.blake-install-scope .auth-agree input {
  margin-top: 2px;
  flex: none;
}
