/* site/app/screens/proshop.css — the pro shop.
 * Depends on tokens.css + ui.css + shell.css. Nothing here defines a colour, a duration or an
 * easing curve of its own; a hex code in this file is a bug, because it will not follow the
 * palette into dark mode and the app is used courtside at night.
 *
 * The shape is a conventional storefront on purpose (Syd: "a dupe of a shopify store... JUST
 * so i can give me comments"). What is NOT conventional is the payment gate: the cart is
 * styled as a cart the whole way to the pay button, and only the paid order gets the navy
 * card treatment that the rest of the app reserves for a thing that is real.
 */

/* ── View push ────────────────────────────────────────────────────────────── */
/* ⚠ GATED ON [data-ready]. boot.js stamps that after the first frame; without the gate the
   whole shop slides into place on load as its initial styles resolve, which reads as jank on
   the slow phones that are actually at the venue. */
.shop{ container: shop-screen / inline-size; }

.shop .shop-view{ opacity: 1; transform: translate3d(0, 0, 0); }
[data-ready] .shop .shop-view{
  transition: transform var(--t-menu) var(--ease-out),
              opacity var(--t-menu) var(--ease-out);
}
/* ⚠ THE RESTING STATE IS ABOVE, THE OFFSET IS THE STARTING STYLE — not the other way round.
   The first version set the offset inline in JS and cleared it in requestAnimationFrame,
   which makes the screen's correct layout conditional on a callback of ours running; rAF is
   suspended in a backgrounded tab, so a view painted while the app was in the background
   measured 12px across and transparent until the tab came back. Same pattern as .enter in
   tokens.css, and a transition can still be interrupted and retargeted where a @keyframes
   would restart from zero. */
@starting-style{ .shop .shop-view.from-right{ opacity: 0; transform: translate3d(12px, 0, 0); } }
@starting-style{ .shop .shop-view.from-left{ opacity: 0; transform: translate3d(-12px, 0, 0); } }

/* ── Top bar: title plus the cart ─────────────────────────────────────────── */
.shop .shop-topbar{
  display: flex; align-items: flex-start; gap: var(--s-3);
  /* 20px puts the cart's right edge on the search field's, and on the grid's. */
  padding-right: 20px;
}
.shop .shop-topbar .screen-head{ flex: 1; min-width: 0; }

.shop .shop-backbar{
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: 4px 20px 2px;
}
/* ⚠ NOT ORANGE, AND cafe.css ALREADY SAYS WHY IN ITS OWN WORDS. Going back is navigation,
   not the action — and the action colour is already on this view, worn by Add to cart or Pay.
   It also could not be read: 15px orange on the cream page is the lowest-contrast text on the
   screen, so the two shops disagreed and the pro shop was the one that was wrong. */
.shop .shop-back{
  display: inline-flex; align-items: center; gap: 3px;
  border: 0; background: transparent; cursor: pointer;
  padding: 8px 10px 8px 4px; margin-left: -4px; border-radius: var(--r-full);
  color: var(--ink-secondary);
  font: 600 15px/1 var(--font-ui); letter-spacing: -.008em;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  min-height: var(--tap-min);
}
.shop .shop-back svg{ width: 18px; height: 18px; }

/* The cart lives in the top-right of every view. ⚠ It cannot live at the bottom: the floating
   nav already owns that band, and two floating things fighting for the same thumb is how a
   customer taps Book when they meant to check out. */
.shop .shop-cartbtn{
  position: relative; flex: none;
  display: grid; place-items: center;
  width: var(--tap-min); height: var(--tap-min); margin-top: 2px;
  border: 0; border-radius: var(--r-full);
  background: var(--bg-raised); box-shadow: var(--shadow-1);
  color: var(--ink); cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.shop .shop-cartbtn svg{ width: 21px; height: 21px; }
.shop .shop-cartbtn-n{
  position: absolute; top: -3px; right: -3px;
  min-width: 19px; height: 19px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--action); color: var(--action-ink);
  font: 700 11px/1 var(--font-ui); font-variant-numeric: tabular-nums;
  border: 2px solid var(--bg);
}

/* ── Product art ──────────────────────────────────────────────────────────── */
/* ⚠ NO PHOTOGRAPHS. site/_headers has no img-src for anything off-origin, so a stock photo
   URL is a silently broken box. These are flat brand shapes drawn inline, and they inherit
   the theme instead of being a picture that is wrong in the dark. */
.shop .shop-art{ width: 78%; height: auto; display: block; }
.shop .shop-art .f-fig{ fill: var(--ink); }
.shop .shop-art .f-soft{ fill: var(--ink); opacity: .28; stroke: var(--ink); }
.shop .shop-art .f-cut{ fill: var(--bg-sunken); stroke: var(--bg-sunken); }
/* Chartreuse appears on exactly one object in this screen: the ball. DESIGN.md §2 —
   chartreuse is energy and the ball, never decoration and never "success". */
.shop .shop-art .f-live{ fill: var(--live); }

/* ── The grid ─────────────────────────────────────────────────────────────── */
/* ⚠⚠ 20px, LIKE EVERY OTHER GUTTER IN THE APP, AND IT WAS 16 — WHICH IS THE WHOLE OF SYD'S
   "margins not working" ON THIS TAB (2026-09-04). shell.css sets `.sec-head { padding: 0 20px }`
   and `.screen-head { padding: 6px 20px 12px }`, so the section heading "PADDLES" sat four
   pixels INSIDE the cards it was labelling, on every section, down the whole page. Four pixels
   is not a thing anybody can name on sight and it is exactly what makes a screen look slightly
   broken without anyone being able to say why. Every page-level block in this file is on 20
   now; the numbers INSIDE a card (its own padding) are unchanged and have nothing to do with
   the page's edge. */
.shop .shop-grid{
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px; padding: 0 20px;
}

/* ⚠ FLEX COLUMN, ART flex:none. As a plain block the card stretches to its row-mate's height
   and the square art stretches with it, so two paddles side by side came out at visibly
   different sizes whenever one name wrapped to a second line. */
.shop .pcard{
  display: flex; flex-direction: column;
  width: 100%; padding: 0; border: 0; text-align: left; cursor: pointer;
  background: var(--bg-raised); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1); overflow: hidden;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  font-family: var(--font-ui); color: var(--ink);
  transition: transform var(--t-press) var(--ease-out), color var(--t-press) var(--ease-out);
}
.shop .pcard-art{
  position: relative; flex: none; display: grid; place-items: center;
  aspect-ratio: 1 / 1; background: var(--bg-sunken);
}
/* Sold out dims the picture AND says the words. Colour alone would be invisible to a checker,
   to a colourblind player, and in direct sun on a court. */
.shop .pcard[data-out] .pcard-art .shop-art{ opacity: .34; }
.shop .pcard[data-out] .pcard-name{ color: var(--ink-tertiary); }
.shop .pcard-flag{ position: absolute; left: 8px; bottom: 8px; }

/* ⚠ "2 LEFT" AND "CART · NOT PAID" ARE STATUS, NOT THE ACTION — AND THEY WERE THE QUIETEST
   TEXT ON THE CHECKOUT SCREEN. shell.css paints .tag.due in --action, which is orange at 11px
   on a 16% orange tint: the lowest-contrast pair in the app, on the one badge the payment-first
   rule needs a customer to actually read. Amber is a different hue from the pay button, so the
   two can never be confused, and it survives being read in sunlight.
   ⚠ THE SCOPED OVERRIDE THAT USED TO LIVE HERE IS GONE. It guessed the palette would name
   the token --attention; it shipped as --attn, so `var(--attention, var(--warn))` never
   resolved and quietly fell through to plain --warn — the right idea rendered in the wrong
   role's colour, on every screen but this one still orange. The fix now lives on .tag.due in
   shell.css using --attn-bg/--attn-ink, so it applies to every unpaid-cart badge. Nothing
   .shop-specific is needed. */

.shop .pcard-body{ flex: 1; display: block; padding: 10px 12px 13px; }
.shop .pcard-brand{
  display: block; font: 600 10px/1 var(--font-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-tertiary);
}
.shop .pcard-name{
  display: block; margin-top: 5px;
  font: 500 14px/1.3 var(--font-ui); letter-spacing: -.006em; color: var(--ink);
}
.shop .pcard-price{
  display: block; margin-top: 6px;
  font: 600 15px/1 var(--font-ui); letter-spacing: -.01em; color: var(--ink);
}

.shop .shop-footnote{
  margin: 2px 20px 0; padding: 0;
  font: 400 13px/1.5 var(--font-ui); color: var(--ink-tertiary);
}

/* ── Product page ─────────────────────────────────────────────────────────── */
.shop .pdp-art{
  display: grid; place-items: center;
  margin: 6px 20px 16px; aspect-ratio: 4 / 3;
  background: var(--bg-sunken); border-radius: var(--r-lg);
}
.shop .pdp-art .shop-art{ width: 52%; }

.shop .pdp-head{ padding: 0 20px; }
.shop .pdp-brand{
  margin: 0; font: 600 11px/1 var(--font-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-tertiary);
}
.shop .pdp-name{
  margin: 8px 0 0; font-family: var(--font-display); font-weight: 600;
  font-size: 26px; line-height: 1.14; letter-spacing: -.016em; color: var(--ink);
}
.shop .pdp-priceline{ display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.shop .pdp-price{ font: 600 20px/1 var(--font-ui); letter-spacing: -.014em; }

.shop .pdp-blurb{
  margin: 14px 20px 0;
  font: 400 15px/1.55 var(--font-ui); color: var(--ink-secondary);
}

.shop .pdp-choosers{ padding: 18px 20px 0; display: grid; gap: 16px; }
.shop .chooser-label{
  margin: 0 0 8px;
  font: 600 12px/1 var(--font-ui); letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-tertiary);
}
.shop .chips{ display: flex; flex-wrap: wrap; gap: 8px; }

/* ⚠ CHIPS, NOT A NATIVE <select>. Syd's standing rule, and there is a hard reason as well as
   a stylistic one: an OS select wheel cannot show "Sold out" against a single option, so the
   customer picks US 10, taps through, and only then learns it does not exist. */
.shop .chip{
  display: inline-flex; align-items: center; gap: 7px;
  min-height: var(--tap-min); padding: 10px 15px;
  border: 1.5px solid var(--rule); border-radius: var(--r-full);
  background: var(--bg-raised); color: var(--ink); cursor: pointer;
  font: 500 15px/1 var(--font-ui); letter-spacing: -.006em;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out),
              background-color var(--t-press) var(--ease-out),
              border-color var(--t-press) var(--ease-out),
              color var(--t-press) var(--ease-out);
}
/* Selected is INK-filled, not orange. Orange is the one thing on the screen you are meant to
   press — here that is Add to cart, and a selected chip would be competing with it. */
.shop .chip[aria-checked="true"]{
  background: var(--ink); border-color: var(--ink); color: var(--bg-raised); font-weight: 600;
}
.shop .chip[aria-disabled="true"]{
  color: var(--ink-tertiary); border-style: dashed; cursor: default;
  background: transparent;
}
.shop .chip[aria-disabled="true"] > span:first-child{ text-decoration: line-through; }
.shop .chip-out{
  font: 600 10px/1 var(--font-ui); letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-tertiary);
}

.shop .pdp-buy{ padding: 22px 20px 0; }
/* A disabled primary button must stop looking like the one thing you are meant to press.
   Orange is the action colour; a sold-out button that keeps it is a lie the eye reads first
   and the word second. */
.shop .shop-view .btn[disabled]{ background: var(--bg-sunken); color: var(--ink-tertiary); cursor: default; }

/* The cart, frozen while a payment is in flight. The customer can still read every line —
   they just cannot change what has already been sent to the payment provider. */
.shop .is-locked{ pointer-events: none; opacity: .5; }
.shop .pdp-gate{
  margin: 10px 2px 0; text-align: center;
  font: 400 13px/1.45 var(--font-ui); color: var(--ink-tertiary);
}

.shop .pdp-spec{ margin: 22px 20px 0; }
.shop .pdp-spec-row{
  display: flex; gap: 16px; justify-content: space-between;
  padding: 11px 4px; border-bottom: 1px solid var(--rule);
  font: 400 13px/1.4 var(--font-ui); color: var(--ink-secondary);
}
.shop .pdp-spec-row:last-child{ border-bottom: 0; }
.shop .pdp-spec-row > span:first-child{
  flex: none; font-weight: 600; color: var(--ink-tertiary);
  letter-spacing: .04em; text-transform: uppercase; font-size: 11px; padding-top: 2px;
}
.shop .pdp-spec-row > span:last-child{ text-align: right; }

/* ── Cart ─────────────────────────────────────────────────────────────────── */
/* ⚠ ui.css's .row .title / .meta are block elements everywhere else in the app. Here they are
   spans — the row's contents sit inside a <button>-free span so the whole line can hold a
   stepper — and inline spans do not stack: the variant ran on straight after the product
   name as "Ridgeline CX-13 Power 8.1 oz · 4 in". Scoped to .shop-view so this does not reach
   into any other screen's rows. */
.shop .shop-view .row .title, .shop .shop-view .row .meta{ display: block; }

.shop .cart-row{ align-items: flex-start; }
.shop .cart-thumb{
  flex: none; width: 52px; height: 52px; border-radius: var(--r-sm);
  background: var(--bg-sunken); display: grid; place-items: center; overflow: hidden;
}
.shop .cart-thumb .shop-art{ width: 74%; }

.shop .cart-stepper{ display: flex; align-items: center; gap: 4px; margin-top: 9px; flex-wrap: wrap; }
.shop .step{
  width: 32px; height: 32px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--rule); border-radius: var(--r-full);
  background: var(--bg-raised); color: var(--ink); cursor: pointer;
  font: 500 17px/1 var(--font-ui);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out),
              background-color var(--t-press) var(--ease-out);
}
/* ⚠ 32px IS UNDER THE 44px FLOOR, so the hit area is grown past the drawn circle instead of
   the circle being grown. A stepper drawn at 44px sits next to a 52px thumbnail and squeezes
   the product name onto three lines on a narrow phone. The pseudo-element is the real target. */
.shop .step{ position: relative; }
.shop .step::before{ content: ""; position: absolute; inset: -7px; border-radius: inherit; }
.shop .step[disabled]{ color: var(--ink-tertiary); background: var(--bg-sunken); cursor: default; }
.shop .cart-qty{ min-width: 26px; text-align: center; font: 600 15px/1 var(--font-ui); }
.shop .cart-cap{
  font: 500 11px/1 var(--font-ui); color: var(--ink-tertiary); margin-left: 4px;
}

/* ⚠⚠ THE ITEMS LIST HAD NO PAGE GUTTER AT ALL. ui.css's `.list` supplies the card — a raised
   ground, a 16px radius and a shadow — and no margin, because it is used inside sections that
   provide their own. The cart and the paid receipt drop it straight onto the page, so at 375px
   it ran 0 → 375 with its rounded corners and its shadow sliced off at both screen edges,
   under a heading and above a totals card that were both inset 20. Every other page-level
   block in this file was moved to 20 on 2026-09-04; this one is rendered from `viewCart` and
   `viewPaid` rather than declared here, which is why it was missed. */
.shop .list { margin: 0 20px; }

/* ── Fulfilment choice ────────────────────────────────────────────────────── */
.shop .choices{ margin: 0 20px; display: grid; gap: 10px; }
.shop .choice{
  display: flex; align-items: flex-start; gap: 12px; text-align: left;
  width: 100%; padding: 14px 15px; cursor: pointer;
  border: 1.5px solid var(--rule); border-radius: var(--r-lg);
  background: var(--bg-raised); color: var(--ink);
  font-family: var(--font-ui);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out),
              border-color var(--t-press) var(--ease-out);
}
.shop .choice[aria-checked="true"]{ border-color: var(--ink); }
.shop .choice .grow{ flex: 1; min-width: 0; }
.shop .choice-tick{
  flex: none; width: 22px; height: 22px; margin-top: 1px;
  display: grid; place-items: center; border-radius: 50%;
  border: 1.5px solid var(--rule); color: transparent;
}
.shop .choice-tick svg{ width: 13px; height: 13px; }
.shop .choice[aria-checked="true"] .choice-tick{
  background: var(--ink); border-color: var(--ink); color: var(--bg-raised);
}
.shop .choice-title{ display: block; font: 600 15px/1.3 var(--font-ui); letter-spacing: -.008em; }
.shop .choice-meta{
  display: block; margin-top: 4px;
  font: 400 13px/1.45 var(--font-ui); color: var(--ink-tertiary);
}
.shop .choice-price{ flex: none; font: 600 14px/1 var(--font-ui); margin-top: 2px; }

.shop .addr{
  margin: 10px 20px 0; padding: 14px 15px;
  background: var(--bg-sunken); border-radius: var(--r-lg);
}
.shop .addr p{ margin: 0; }
.shop .addr-label{
  font: 600 11px/1 var(--font-ui); letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-tertiary);
}
.shop .addr-name{ margin-top: 8px !important; font: 600 15px/1.3 var(--font-ui); }
.shop .addr-line{ margin-top: 3px !important; font: 400 14px/1.45 var(--font-ui); color: var(--ink-secondary); }
/* Two problems in one control: it was the third orange thing on a screen whose one orange
   thing is Pay, and its box was 21px tall — half the 44px floor, inside a flow that takes
   money. Ink with an underline reads as a link without borrowing the action colour. */
.shop .addr-change{
  display: inline-flex; align-items: center;
  border: 0; background: none; padding: 8px 0 0; margin: 0; cursor: pointer;
  min-height: var(--tap-min);
  font: 600 13px/1 var(--font-ui); color: var(--ink); text-decoration: underline;
  text-underline-offset: 3px;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}

/* ── Totals and the pay button ────────────────────────────────────────────── */
.shop .totals{
  margin: 0 20px; padding: 15px 16px;
  background: var(--bg-raised); border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.shop .totals-row{
  display: flex; justify-content: space-between; gap: 16px; padding: 4px 0;
  font: 400 15px/1.4 var(--font-ui); color: var(--ink-secondary);
}
.shop .totals-row.is-total{
  font: 600 18px/1.3 var(--font-ui); letter-spacing: -.012em; color: var(--ink);
}

.shop .shop-actions{ padding: 18px 20px 0; }
.shop .shop-actions .btn + .btn{ margin-top: 10px; }
.shop .paynote{
  margin: 11px 2px 0; text-align: center;
  font: 400 13px/1.5 var(--font-ui); color: var(--ink-tertiary); text-wrap: pretty;
}

/* ── The paid order ───────────────────────────────────────────────────────── */
/* ⛔ THE NAVY CARD IS RESERVED FOR A THING THAT IS REAL. Everything before payment is drawn
   on cream, because navy is the app's identity surface — a ticket, a live board, a paid
   order. Styling a cart this way would tell the customer they own something they do not. */
/* ⚠ INK ON THIS CARD IS MIXED FROM --cream, NOT WRITTEN AS A HEX.
   These four values were #9FB3C6, #C9D6E2, rgba(246,248,237,.16) and #B9F2D0. The card is
   navy in BOTH themes, so the theme-aware --ink-secondary cannot be used here (in light mode
   it is a dark blue, i.e. invisible) — which is why the hexes went in. But a hex is a copy of
   the brand colour that stops tracking it: change --cream and this card keeps the old one,
   silently, on the one screen that says a customer's money arrived. bookings.css hit the same
   wall on its ticket and solved it this way; this is the same solution, so the two navy
   surfaces in the app cannot drift apart. */
.shop .paid-card{
  margin-top: 8px;
  --paid-dim:  color-mix(in srgb, var(--cream) 62%, transparent);
  --paid-soft: color-mix(in srgb, var(--cream) 80%, transparent);
  --paid-rule: color-mix(in srgb, var(--cream) 16%, transparent);
}
.shop .paid-top{ display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.shop .paid-date{ font: 500 13px/1 var(--font-ui); }
.shop .paid-kicker{ display: block; margin: 18px 0 0; color: var(--paid-dim); }
.shop .paid-no{
  margin: 4px 0 0;
  font-family: var(--font-display); font-weight: 600;
  font-size: 44px; line-height: 1; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; color: var(--cream);
}
.shop .paid-name{ margin: 8px 0 0; font: 500 15px/1.3 var(--font-ui); color: var(--paid-soft); }
.shop .paid-card .divider{ background: var(--paid-rule); }
.shop .paid-how{ margin: 0; font: 400 14px/1.5 var(--font-ui); color: var(--paid-soft); }

/* The paid tag has to hold its own on navy; the cream-ground version of .tag.paid is too
   quiet against it. */
.shop .paid-card .tag.paid{
  background: color-mix(in srgb, var(--ok) 26%, transparent);
  color: color-mix(in srgb, var(--ok) 45%, var(--cream));
}

/* ⚠ IN DARK, A NAVY CARD ON A NAVY GROUND IS NOT A CARD. Checked side by side: the receipt
   was floating on nothing but its shadow while the plain .list and .totals below it read
   perfectly, because those use --bg-raised. The navy treatment is a light-mode device for
   saying "this one is real"; in the dark the same job is done by the ground the whole app
   already sits on, plus the order number set in Fraunces at 44px. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .shop .paid-card{
    background: var(--bg-raised); border: 1px solid var(--rule);
  }
}
:root[data-theme="dark"] .shop .paid-card{
  background: var(--bg-raised); border: 1px solid var(--rule);
}

/* ── Hover, gated ─────────────────────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine){
  /* An underline, not orange: a hover tint on a 14px product name is unreadable orange text
     on white, and the card is not the action — Add to cart is. */
  .shop .pcard:hover .pcard-name{ text-decoration: underline; text-underline-offset: 2px; }
  .shop .chip:not([aria-disabled="true"]):hover{ border-color: var(--ink-secondary); }
  .shop .choice:hover{ border-color: var(--ink-secondary); }
  .shop .step:not([disabled]):hover{ background: var(--bg-sunken); }
  .shop .shop-cartbtn:hover{ background: var(--bg-sunken); }
}

/* ── Tablet: the grid gets a third column ─────────────────────────────────── */
/* ⚠ @container, NOT @media, AND THAT IS THE WHOLE BUG. This asked the BROWSER WINDOW how wide
   it was. The app is drawn inside a phone-width frame, so on a tablet the window cleared 620px
   while the frame was still 390 — the grid went to three columns of 111px cards and the
   "SOLD OUT" flag took up 70% of a card. A container query asks the box the grid is actually
   laid out in, which is the frame. Named `shop-screen`, declared on .shop at the top of this
   file, so a container some other stylesheet adds later cannot capture it. */
@container shop-screen (min-width: 620px){
  .shop .shop-grid{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .shop .pdp-art{ aspect-ratio: 16 / 9; }
}

/* ── Reduced motion / transparency / contrast ─────────────────────────────── */
/* Naming this file's own animations, per DESIGN.md §4.8: the view push (.shop-view), the
   press scale on cards, chips, choices and steppers. The push becomes a cross-fade — the
   information that the screen changed survives; the sideways movement does not. */
@media (prefers-reduced-motion: reduce){
  [data-ready] .shop .shop-view{ transition-property: opacity; }
  @starting-style{
    .shop .shop-view.from-right, .shop .shop-view.from-left{ opacity: 0; transform: none; }
  }
  .shop .chip, .shop .choice, .shop .step, .shop .pcard{ transition-property: background-color, border-color, color; }
}

@media (prefers-contrast: more){
  .shop .pcard, .shop .totals, .shop .choice, .shop .chip, .shop .step, .shop .shop-cartbtn{ border: 1px solid var(--ink); }
  .shop .pcard[data-out] .pcard-art .shop-art{ opacity: .5; }
}

/* ══ THE SHOP'S OWN BAR ═════════════════════════════════════════════════════
   Syd, 2026-09-03: "pro shop should have navigation bar of its own some how / search bar".

   ⚠ THE SAME COMPONENT AS THE CAFE'S RAIL, ON PURPOSE. Two long lists in one app that move
     in two different ways is the inconsistency Apple's familiarity principle is about — a
     control that looks the same must behave the same. Sticky, jumps to a section, lights the
     section you are in.
   ⚠ IT STICKS TO 0, WHICH IS UNDER THE CART BUTTON AND NOT UNDER THE APP HEADER. app.js hides
     the header avatar on this tab precisely so the cart can own the top-right corner; the bar
     scrolls up until it meets the top of the scrollport and then holds. */
.shop .shop-tools {
  position: sticky; top: 0; z-index: 5;
  display: grid; gap: 9px;
  margin: 0 0 14px; padding: 8px 0 9px;
  background: var(--bg);
  border-bottom: 1px solid var(--rule);
}

/* ⚠ A REAL <input type="search"> INSIDE A STYLED SHELL, NOT A DIV PRETENDING. Syd's standing
   rule is about custom DROPDOWNS — a native select is an OS wheel that covers the screen. A
   text field is the opposite case: the OS keyboard, autocorrect, dictation, the clear gesture
   and every assistive technology are all attached to the real element, and none of them can
   be re-implemented. So the element is native and only its chrome is ours. */
.shop .shop-search {
  display: flex; align-items: center; gap: 9px;
  margin: 0 20px; padding: 0 12px;
  min-height: 42px; border-radius: var(--r-full);
  background: var(--bg-sunken);
  border: 1px solid transparent;
  transition: border-color 160ms var(--ease-out), background-color 160ms var(--ease-out);
}
.shop .shop-search:focus-within { border-color: var(--focus); background: var(--bg); }
.shop .shop-search-i { display: grid; place-items: center; flex: none; color: var(--ink-tertiary); }
.shop .shop-search-i svg { width: 17px; height: 17px; display: block; }
.shop .shop-search-in {
  flex: 1 1 auto; min-width: 0;
  border: 0; background: transparent; outline: none; padding: 0;
  font: 500 15px/1.2 var(--font-ui); color: var(--ink);
}
.shop .shop-search-in::placeholder { color: var(--ink-tertiary); }
/* Safari draws its own clear button and a decoration on type="search"; both are the wrong
   shape here and the second one cannot be styled at all. */
.shop .shop-search-in::-webkit-search-decoration,
.shop .shop-search-in::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.shop .shop-search-x {
  flex: none; display: grid; place-items: center;
  width: 26px; height: 26px; margin-right: -4px;
  border: 0; border-radius: 50%; cursor: pointer;
  background: color-mix(in srgb, var(--ink) 12%, transparent); color: var(--ink-secondary);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.shop .shop-search-x svg { width: 13px; height: 13px; display: block; }
/* ⚠ THE UA'S `[hidden] { display: none }` IS A BARE TYPE-LESS SELECTOR AND LOSES TO ANY CLASS
   RULE THAT SETS display. `display: grid` above therefore un-hid the clear button, and it sat
   in an empty field offering to clear nothing — visible on the deployed build before anyone
   typed a character. This is why `el.hidden = true` silently fails so often. */
.shop .shop-search-x[hidden] { display: none; }
/* The visual button is 26px because a 44px circle inside a 42px field is the field. The TARGET
   is 44px, extended past the drawing — the same trick the cafe's + on a tile uses. */
.shop .shop-search-x::after { content: ""; position: absolute; inset: -9px; }
.shop .shop-search-x { position: relative; }

/* ⚠⚠ IT WRAPS. IT DOES NOT SCROLL SIDEWAYS, AND THAT IS THE SECOND HALF OF "elements
   clipping" (Syd, 2026-09-04). Three chips measure 424px against a 375px phone, so the last
   one — "Bags, shoes and kit" — was cut through the middle of a word at the screen edge with
   no fade, no arrow and nothing else to say it could be dragged. It read as a rendering fault,
   which is what a clipped word always reads as.
   ⚠ WRAPPING RATHER THAN SHRINKING THE WORDS, because the chip's label IS the section's
     heading further down the page — this file already warns against "a thing called
     'Overgrip 3-pack' in one place and 'Balls and grips' in another". Two lines of chips costs
     38px on the narrowest phone and nothing at all above about 430px, where all three fit.
   ⚠ AND IT MATCHES A DECISION SYD HAS ALREADY MADE ONCE. On the courts timetable: "i dont want
     to scroll, i want it all to be visible and selectable without needing to scroll at all
     horizontally." The same argument holds here — a control you cannot see is a control that
     does not exist. */
.shop .shop-railtrack {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 0 20px;
}
.shop .shop-railbtn {
  flex: 0 1 auto; min-width: 0;
  min-height: 38px; padding: 0 15px; border-radius: var(--r-full);
  border: 1px solid var(--rule); background: var(--bg); color: var(--ink-secondary);
  font: 600 13.5px/1 var(--font-ui); letter-spacing: -.004em; cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: background-color 160ms var(--ease-out), color 160ms var(--ease-out),
              border-color 160ms var(--ease-out);
}
/* Filled, not tinted — the section you are in gets a SHAPE, so it survives greyscale and
   sunlight. Same decision as the selected tab in the floating nav. */
.shop .shop-railbtn[aria-current="true"] {
  background: var(--ink); border-color: var(--ink); color: var(--bg);
}
