/* ============================================================
   Legend's Best — the shop in the same dress as the console (2026-10-02)

   The admin console was taken through an iOS pass: twenty-pixel corners,
   hairline edges with a light catch along the top, soft layered shadows,
   pill buttons with a press you can feel, and frosted chrome over the page.
   The shop, which is where the customers actually are, never had it. This
   carries the same vocabulary across, reading its values from
   css/admin-ios.css rather than inventing a second set.

   WHAT THIS FILE DOES NOT DO
   It changes no colour. The brand sky blue, the tinted states and every
   status colour stay exactly as styles.css sets them. Only the geometry,
   the edges, the shadows and the press change.

   HOW THE FROST IS DONE, AND WHY IT MATTERS
   backdrop-filter makes the element a containing block, which re-parents
   every position:fixed thing inside it. That is what broke the console the
   first time glass was tried. So the frost is painted on a ::before layer
   behind the content, which has no children of its own to re-parent, and
   never on a panel that holds other furniture.

   Loaded last on the shop pages. Reversible: drop the file and the link.
   ============================================================ */

/* ---- geometry: one token move, and everything that reads it follows ---- */
/* styles.css hands these out to cards, panels, fields and sheets alike, so
   raising them here lifts the whole shop at once rather than needing a rule
   per component. The pill stays a pill. */
html body {
  --radius-lg: 20px;
  --radius-md: 16px;
  --radius-sm: 12px;
}

/* ---- motion: one curve and one set of speeds, taken from the console ---
   The shop had ten different easing curves and two hundred and twenty-four
   plain `ease` and `linear` transitions, even though styles.css has defined
   a single --ease token since the beginning. The same button could settle
   differently on two pages. The console does not have that problem: nearly
   all of its motion runs on one curve at a handful of speeds, so this takes
   those values rather than inventing a third set.

   Retuning the token is most of the work on its own, because everything
   already written as `var(--ease)` follows it. The rules under it reach the
   interactive things that were written with hardcoded values instead.

   Nothing new moves. The same things move, together. */
html body {
  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur-fast: 150ms;
  --dur: 220ms;
  --dur-slow: 320ms;
}

/* The things a person touches, and the things that answer a touch. Written
   as the two long-hand properties rather than `transition`, so a rule that
   set its own list of properties keeps that list and changes only how fast
   and how it settles. */
a,
button,
.btn, .btn-solid, .btn-outline, .icon-btn,
.quick-cat, .chip, .tab,
.product-card, .product-card__like,
.card, .pay-method, .community-card, .dash-quick__item,
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select, textarea,
.nav-menu__item, .cust-nav__item, .main-nav__link {
  transition-timing-function: var(--ease);
}

/* A hover or a press answers at once. Anything slower than about a fifth of
   a second on these reads as lag rather than smoothness, and the shop had
   several at two and a half times that. */
a,
button,
.btn, .btn-solid, .btn-outline, .icon-btn,
.quick-cat, .chip,
.product-card__like,
.nav-menu__item, .cust-nav__item, .main-nav__link {
  transition-duration: var(--dur-fast);
}

/* A card settling, a field taking focus: a touch slower, because something
   larger is moving. */
.product-card,
.card, .pay-method, .community-card, .dash-quick__item,
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select, textarea {
  transition-duration: var(--dur);
}

/* Someone who asked for less movement gets none of it, including this. */
@media (prefers-reduced-motion: reduce) {
  a, button, .btn, .btn-solid, .btn-outline, .icon-btn, .quick-cat, .chip, .tab,
  .product-card, .product-card__like, .card, .pay-method, .community-card,
  .dash-quick__item, input, select, textarea,
  .nav-menu__item, .cust-nav__item, .main-nav__link {
    transition-duration: .01ms;
  }
}

/* ---- surfaces: a hairline edge, a light catch, a shadow that sits -----
   The same three-part shadow the console uses: a tight contact shadow, a
   wide soft one well below, and a highlight along the top edge that reads
   as light falling on a raised surface. */
/* .stg-card and .pay-method are deliberately left out of the border half of
   this rule and handled below: the first draft set them to 1px and quietly
   took away the 2px edge the review stage card uses and the 1.5px one that
   marks a chosen payment method. */
.card,
.product-card,
.panel,
.community-card,
.legal-content,
.dash-quick__item {
  border: 1px solid color-mix(in srgb, var(--border) 78%, transparent);
  box-shadow:
    0 1px 2px rgba(9, 30, 74, .05),
    0 10px 28px -20px rgba(9, 30, 74, .45),
    inset 0 1px 0 rgba(255, 255, 255, .6);
}

/* The track order form is NOT a card. It is a row of fields sitting on the
   dark track-order panel, and the card kit's hairline border plus its pale
   inset highlight drew a white rectangle around the inputs on that dark
   background: three boxes inside a box. It keeps the field styling the
   panel gives it and nothing else. */
.track-order__form {
  border: 0;
  box-shadow: none;
  background: none;
}

/* A card lifts a little further when pointed at, and not at all on a touch
   screen, where there is no pointing and the shadow only costs paint. */
@media (hover: hover) and (pointer: fine) {
  .product-card:hover {
    box-shadow:
      0 1px 2px rgba(9, 30, 74, .06),
      0 18px 40px -22px rgba(9, 30, 74, .55),
      inset 0 1px 0 rgba(255, 255, 255, .7);
  }
}

/* A payment method keeps its thicker edge, which is what marks the chosen
   one, and takes only the shadow. The review stage card takes neither: its
   clip-path cuts the corners off, and a clip-path crops a box-shadow away,
   so one here would be paint for nothing. */
.pay-method {
  box-shadow:
    0 1px 2px rgba(9, 30, 74, .05),
    0 10px 28px -20px rgba(9, 30, 74, .45),
    inset 0 1px 0 rgba(255, 255, 255, .6);
}

/* A browser without color-mix keeps the solid edge it had. */
@supports not (border-color: color-mix(in srgb, red 50%, transparent)) {
  .card, .product-card, .panel, .community-card {
    border-color: var(--border);
  }
}

/* ---- controls: a press you can feel ----------------------------------- */
/* The console's own press. It is the one piece of motion added here, it is
   under a tenth of a second, and it is the answer to a tap rather than
   decoration, so it stays on a phone where the drifting layers do not. */
.btn:active:not(:disabled),
.btn-solid:active:not(:disabled),
.btn-outline:active:not(:disabled),
.icon-btn:active:not(:disabled),
.quick-cat:active {
  transform: scale(.97);
}
.btn, .btn-solid, .btn-outline, .icon-btn, .quick-cat {
  transition: transform .09s var(--ease), background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), color var(--dur) var(--ease);
}

/* A filled button carries the same top highlight the cards do, so the two
   read as the same material. */
.btn-solid,
.btn--primary {
  box-shadow:
    0 1px 2px rgba(9, 30, 74, .18),
    0 10px 24px -16px rgba(1, 100, 206, .75),
    inset 0 1px 0 rgba(255, 255, 255, .22);
}

/* ---- fields: the console's corner, and a ring you can see ------------- */
/* The 16px minimum from styles.css is untouched: it is the one rule that
   stops an iPhone zooming into a field, and nothing here goes near size. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select,
textarea {
  border-radius: var(--radius-sm);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  border-color: var(--blue-600);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue-600) 18%, transparent);
}

/* ---- sheets and panels that sit over the page ------------------------- */
/* A sheet rises from the bottom edge, so only its top corners are round,
   and they are rounder than a card's: that difference is what makes it read
   as a sheet rather than a tall card. */
.product-card__picker--sheet,
.mobile-menu__panel,
.notif-panel {
  border-radius: 24px 24px 0 0;
}
.support-fab__panel {
  border-radius: 24px;
}

/* The frost, as a layer rather than a filter on the panel, so nothing
   fixed inside these loses the window as its frame. */
.notif-panel::before,
.support-fab__panel::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background: color-mix(in srgb, #fff 82%, transparent);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
  backdrop-filter: blur(26px) saturate(180%);
}
.notif-panel > *,
.support-fab__panel > * { position: relative; z-index: 1; }

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .notif-panel::before, .support-fab__panel::before { background: #fff; }
}

/* ---- the region a gift card is for ------------------------------------
   Sits above the value cards and reads as the first question, the way a
   shop asks where you are before showing what it can sell you. Full width
   rather than a small inline control: it changes what is on offer below it,
   so it should not look like an afterthought. */
.region-select {
  width: 100%;
  height: 46px;
  padding: 0 40px 0 14px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background-color: #fff;
  /* The chevron is drawn here rather than left to the browser, which paints
     a different one on every platform. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a687d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  background-size: 18px 18px;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  color: var(--ink-900);
  cursor: pointer;
}
.region-select:focus-visible {
  outline: none;
  border-color: var(--blue-600);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue-600) 18%, transparent);
}

/* ---- the shop hero starts with the brand picture ----------------------
   The hero is the biggest thing on the page, so whatever fills it is what
   the browser times the page by. It used to fill with a YouTube thumbnail,
   whose address is not known until /categories answers, so the largest
   paint could not happen until an API round trip had finished: measured at
   4.1 seconds, against a heading that was readable at 2.2.

   This picture is ours, it is on our own domain, and the stylesheet asks
   for it during parse. The clip still arrives and covers it later. A
   category with its own colour sets `background` inline from script, and an
   inline shorthand beats this, so a category hero is left exactly as it was.
   ---------------------------------------------------------------------- */
.shop-hero--poster {
  /* Root-absolute: a url() in a stylesheet resolves against the stylesheet,
     so a plain "assets/..." here asks for css/assets/... and finds nothing. */
  background-image: url("/assets/hero-default.jpg");
  background-size: cover;
  background-position: center;
  position: relative;
}

/* Same veil as the video hero, for the same reason: white writing over a
   photograph needs a floor under it. 66% of this navy keeps it at 5.5:1
   against the brightest frame. */
.shop-hero--poster::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(4, 28, 74, .72) 0%, rgba(4, 28, 74, .66) 70%, rgba(4, 28, 74, .58) 100%);
}
.shop-hero--poster > .container { position: relative; z-index: 2; }

/* ---- a hero with a picture behind the writing ------------------------- */
/* The shop hero runs a video under its heading. On a bright frame the white
   title was reading against near-white, which is a legibility problem
   before it is a taste one. A scrim under the text fixes it without dimming
   the picture everywhere. */
/* Only the video hero, and only between the clip and the writing. The clip
   sits at z-index 0 and the container at 2, so the scrim takes 1 and no
   child needs its position changed: setting `position: relative` on every
   child here would have taken the absolute positioning off .hero-bg and
   dropped the clip out of the hero altogether. */
.shop-hero--video::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* The writing sits a little under halfway down, so the veil has to be at
     its strongest there rather than thinning out across the middle, which
     is where the first draft put its weakest point. Against the worst case,
     a pure white frame, 66% of this navy leaves white text at 5.5:1, which
     clears the small-text bar and not merely the large-text one. */
  background: linear-gradient(180deg, rgba(4, 28, 74, .72) 0%, rgba(4, 28, 74, .66) 70%, rgba(4, 28, 74, .58) 100%);
}

/* ---- a phone: the frost costs more than it gives on a small screen ---- */
/* Same call as the console, and the same reason the site keeps no drifting
   layers on a phone: a full-width blur is the most expensive paint on the
   page and the least visible on the smallest one. */
@media (max-width: 720px) {
  .notif-panel::before,
  .support-fab__panel::before {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: #fff;
  }
}

/* ---- someone who asked for less movement gets none of it -------------- */
@media (prefers-reduced-motion: reduce) {
  .btn:active:not(:disabled),
  .btn-solid:active:not(:disabled),
  .btn-outline:active:not(:disabled),
  .icon-btn:active:not(:disabled),
  .quick-cat:active {
    transform: none;
  }
}
