/*
 * components.css — the shared EBAN pieces, ported from the iOS app.
 *
 * Every number here is traceable to the audited spec. Where a value looks
 * oddly precise (4.68px radius, 2.34px bars, −3px lockup spacing) it IS the
 * iOS value and must stay — those are the details that make the site read as
 * the same product as the apps.
 */

/* ============================================================
   Header wash — the peach gradient behind the logo/tabs/search.
   iOS: vertical headerWashTop → headerWashBottom, ignoring the top safe area
   so it bleeds behind the status bar.
   ============================================================ */

.header-wash {
  background: linear-gradient(
    to bottom,
    var(--header-wash-top),
    var(--header-wash-bottom)
  );
}

/* ============================================================
   Brand lockup — "EBAN" / "SHOPPING"
   iOS: VStack(alignment: .leading, spacing: -3); both lines brand orange,
   weight .black, tracking 3. 24px over 17px. NOT translated in Arabic.
   ============================================================ */

.lockup {
  display: flex;
  flex-direction: column;
  line-height: 1;
  /* The −3 spacing: iOS tightens the two lines until they nearly touch. */
  gap: -3px;
  user-select: none;
}

.lockup__eban,
.lockup__shopping {
  color: var(--brand);
  font-weight: 900;
  letter-spacing: 3px;
  line-height: 1;
}

.lockup__eban {
  font-size: 24px;
}

.lockup__shopping {
  font-size: 17px;
  /* CSS has no negative flex gap, so the −3 is taken here instead. */
  margin-top: -3px;
}

/* ============================================================
   Feed tabs — Recommended · 🔥Trending · Discounts · New arrivals
   iOS: selected 17 heavy textPrimary; unselected 15 semibold textPrimary@65%.
   Underline is a 20×3 brand capsule 3px below, always occupying space
   (opacity toggles, so labels never shift).
   ============================================================ */

.feedtabs {
  display: flex;
  align-items: flex-end;
  width: 100%;
  /* iOS uses Spacer(minLength: 8) between items inside a full-width row. */
  gap: 8px;
  /* The same gutter as the header, the grids and every other page block. This
     used to live ONLY inside `@media (min-width: 640px)`, so on a phone the
     tabs had no padding at all and sat hard against the left edge while
     everything above and below them started 16px in (Adam, 2026-08-20). */
  padding: 6px var(--gutter) 10px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.feedtabs::-webkit-scrollbar {
  display: none;
}

.feedtab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  flex: 0 0 auto;
  white-space: nowrap;
}

.feedtab__label {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 15px;
  font-weight: 600;
  color: rgba(13, 27, 62, 0.65);
  transition: color 0.18s ease, font-size 0.18s ease;
}

.feedtab[aria-selected='true'] .feedtab__label {
  font-size: 17px;
  font-weight: 800;
  color: var(--text-primary);
}

/* Trending ONLY gets the flame, and it is the RED one (#E0342C), 13px bold,
   3px before the label. The offers-bar flame is white — different icon fill. */
.feedtab__flame {
  width: 13px;
  height: 13px;
  color: var(--red-trending);
  flex: 0 0 auto;
}

.feedtab__rule {
  width: 20px;
  height: 3px;
  border-radius: 999px;
  background: var(--brand);
  opacity: 0;
  transition: opacity 0.18s ease;
}

.feedtab[aria-selected='true'] .feedtab__rule {
  opacity: 1;
}

/* ============================================================
   Search bar — squarish, NOT a pill. Radius 10, 2px brand border, white fill.
   Children: magnifier · rotating hint · camera (OUTLINE) · "Search" pill.
   ============================================================ */

.searchbar {
  display: flex;
  align-items: center;
  gap: 0;
  height: 38px;
  padding: 4px 4px 4px 12px;
  background: var(--surface-card);
  border: 2px solid var(--brand);
  border-radius: var(--r-search);
  width: 100%;
  cursor: text;
}

.searchbar__icon {
  width: 15px;
  height: 15px;
  color: var(--text-tertiary);
  flex: 0 0 auto;
}

.searchbar__hintwrap {
  /* "greedy": the hint takes all remaining width. Clipped to a 20px line so a
     rotating string never pushes the camera or the pill around. */
  position: relative;
  flex: 1 1 auto;
  height: 20px;
  overflow: hidden;
  margin-left: 8px;
  min-width: 0;
}

.searchbar__hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Rotation: old text slides UP and out of the top, new text rises FROM the
   bottom, both cross-fading. 0.45s easeInOut, fired every 2.6s by ui.js. */
.searchbar__hint--out {
  animation: hint-out 0.45s cubic-bezier(0.42, 0, 0.58, 1) forwards;
}

.searchbar__hint--in {
  animation: hint-in 0.45s cubic-bezier(0.42, 0, 0.58, 1) forwards;
}

@keyframes hint-out {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-20px); opacity: 0; }
}

@keyframes hint-in {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* iOS uses the OUTLINE camera here, not .fill — 16px semibold textTertiary. */
.searchbar__camera {
  width: 16px;
  height: 16px;
  color: var(--text-tertiary);
  flex: 0 0 auto;
  margin-inline: 2px;
  padding: 0;
}

.searchbar__go {
  flex: 0 0 auto;
  background: var(--brand);
  color: #fff;
  font-size: 13px;
  font-weight: 800;
  padding: 7px 16px;
  border-radius: var(--r-sm);
  line-height: 1;
}

/* ============================================================
   ⭐ LiveBarsBadge — the animated 3-bar equalizer.
   iOS box = 18: radius box*0.26, bars box*0.13 wide, box*0.11 gap,
   bottom inset box*0.2. Bars are BOTTOM-ANCHORED: the baseline is fixed and
   only the tops move. Heights and durations are per-bar and deliberately
   uneven so the loop never looks synchronised.
   ============================================================ */

.livebars {
  width: 18px;
  height: 18px;
  border-radius: 4.68px;
  background: var(--red-live);
  display: flex;
  align-items: flex-end; /* bottom-anchored */
  justify-content: center;
  gap: 1.98px;
  padding-bottom: 3.6px;
  flex: 0 0 auto;
}

.livebars__bar {
  width: 2.34px;
  border-radius: 999px;
  background: #fff;
  animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1); /* easeInOut */
  animation-iteration-count: infinite;
  animation-direction: alternate; /* autoreverses */
}

.livebars__bar:nth-child(1) {
  animation-name: livebar-1;
  animation-duration: 0.46s;
}
.livebars__bar:nth-child(2) {
  animation-name: livebar-2;
  animation-duration: 0.6s;
}
.livebars__bar:nth-child(3) {
  animation-name: livebar-3;
  animation-duration: 0.52s;
}

@keyframes livebar-1 { from { height: 4.32px; } to { height: 9.36px; } }
@keyframes livebar-2 { from { height: 6.48px; } to { height: 11.52px; } }
@keyframes livebar-3 { from { height: 5.04px; } to { height: 10.44px; } }

/* ============================================================
   Suggestion cards — "Best sellers" + "From <store>" / "New in"
   Only rendered when BOTH cards have exactly 2 products (iOS gate).
   ============================================================ */

.sugg {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: start;
}

.sugg__card {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 10px 6px;
  border-radius: var(--r-tile);
  background: linear-gradient(
    to bottom,
    var(--card-wash-top),
    var(--card-wash-bottom)
  );
  box-shadow: var(--shadow-card);
  min-width: 0;
}

.sugg__head {
  display: flex;
  align-items: center;
  gap: 5px;
  padding-inline: 4px;
  min-width: 0;
}

.sugg__title {
  font-size: 17px;
  font-weight: 800;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.sugg__chev {
  width: 11px;
  height: 11px;
  color: var(--text-tertiary);
  flex: 0 0 auto;
  margin-left: auto;
}

.sugg__tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5px;
}

.sugg__tile {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.sugg__photo {
  /* iOS aspectRatio 0.86 — TALLER than square. */
  aspect-ratio: 0.86;
  width: 100%;
  background: #fff;
  border-radius: var(--r-photo);
  overflow: hidden;
}

.sugg__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sugg__price {
  font-size: 14px;
  font-weight: 800;
  color: var(--brand);
  text-align: center;
}

/* ============================================================
   Offers bar — red strip with a never-pausing marquee.
   ============================================================ */

.offerbar {
  display: flex;
  align-items: center;
  /* iOS uses HStack(spacing: 10) — SuggestedStrip.swift OfferBar. */
  gap: 10px;
  background: var(--red-live);
  border-radius: 6px;
  padding: 7px 6px 7px 12px;
  overflow: hidden;
}

/* The offers-bar flame is WHITE. The tab flame is #E0342C. Not the same. */
.offerbar__flame {
  width: 13px;
  height: 13px;
  color: #fff;
  flex: 0 0 auto;
}

.offerbar__go {
  flex: 0 0 auto;
  background: #fff;
  color: var(--red-live);
  font-size: 12px;
  font-weight: 800;
  padding: 6px 12px;
  border-radius: 5px;
  line-height: 1;
  white-space: nowrap;
}

/* ---- MarqueeText: two identical copies, 48px apart, sliding left at 35px/s.
   `--cycle` (textWidth + 48) and `--dur` (cycle / 35) are set by ui.js after
   measuring. A CSS keyframe loop is driven by the compositor clock, so it
   cannot silently park off-screen the way iOS's state-animation version did
   (see the warning in SuggestedStrip.swift:257-262). ---- */

.marquee {
  position: relative;
  flex: 1 1 auto;
  height: 18px;
  overflow: hidden;
  min-width: 0;
}

.marquee__track {
  display: flex;
  gap: 48px;
  width: max-content;
  height: 100%;
  align-items: center;
  animation: marquee-slide var(--dur, 12s) linear infinite;
  will-change: transform;
}

.marquee__copy {
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}

@keyframes marquee-slide {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-1 * var(--cycle, 400px))); }
}

/* ============================================================
   Section header — 4×22 brand accent bar + 22px black title.
   ============================================================ */

.sechead {
  display: flex;
  align-items: center;
  gap: 10px;
}

.sechead__bar {
  width: 4px;
  height: 22px;
  border-radius: 3px;
  background: var(--brand);
  flex: 0 0 auto;
}

.sechead__title {
  font-size: 22px;
  font-weight: 900;
  color: var(--text-primary);
}

.sechead__sub {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-tertiary);
}

.sechead__all {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 3px;
  color: var(--brand);
  font-size: 13px;
  font-weight: 600;
}

.sechead__all svg {
  width: 11px;
  height: 11px;
}

/* ============================================================
   Stores & brands rail — 78px logo tiles.
   ============================================================ */

.storesrail {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}

.storesrail::-webkit-scrollbar {
  display: none;
}

.storetile {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 84px;
}

.storetile__logo {
  width: 78px;
  height: 78px;
  border-radius: 10px;
  background: var(--surface-soft);
  border: 0.5px solid var(--border-hair);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.storetile__logo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.storetile__logo svg {
  width: 26px;
  height: 26px;
  color: var(--text-tertiary);
}

.storetile__name {
  width: 84px;
  height: 30px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-secondary);
  text-align: center;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ============================================================
   Product card — the waterfall tile.
   ============================================================ */

.pgrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.pcard {
  display: flex;
  flex-direction: column;
  background: var(--surface-card);
  border-radius: var(--r-tile);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  min-width: 0;
}

.pcard__media {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  background: var(--surface-soft);
  overflow: hidden;
}

.pcard__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.35s var(--ease-press);
}

@media (hover: hover) {
  .pcard:hover .pcard__media img {
    transform: scale(1.045);
  }
}

.pcard__fav {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-primary);
}

.pcard__fav svg {
  width: 15px;
  height: 15px;
}

.pcard__fav[aria-pressed='true'] {
  color: var(--accent-star);
}

.pcard__body {
  padding: 8px 10px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.pcard__title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  /* Two lines, like the app cards. A one-line clamp here was the Android bug. */
  min-height: 2.6em;
}

.pcard__price {
  font-size: 15px;
  font-weight: 800;
  color: var(--brand);
}

.pcard__was {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  text-decoration: line-through;
  margin-left: 6px;
}

/* Flat per-item shipping under the price — 10px semibold tertiary, the same
   weight the app cards give it, so it reads as a footnote to the price rather
   than a second price. */
.pcard__ship {
  font-size: 10px;
  font-weight: 600;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================
   Buttons
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--r-btn);
  font-weight: 800;
  line-height: 1;
  padding: 0 20px;
  min-height: 44px;
  transition: transform var(--dur-press) var(--ease-press),
    filter 0.18s ease;
}

.btn:active {
  transform: scale(var(--press-scale));
}

/* iOS gradient CTA: brand → brandBright, leading → trailing. */
.btn--primary {
  background: linear-gradient(to right, var(--brand), var(--brand-bright));
  color: #fff;
}

.btn--solid {
  background: var(--brand);
  color: #fff;
}

.btn--ghost {
  background: var(--surface-card);
  color: var(--text-secondary);
  border: 1px solid var(--border-hair);
}

.btn--danger {
  background: #fff;
  color: #dc2626;
  border: 1px solid #fecaca;
}

.btn[disabled] {
  opacity: 0.45;
  pointer-events: none;
}

.btn--block {
  width: 100%;
}

/* Chips are the ONE pill in the system — everything else stays squareish. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: var(--r-chip);
  background: var(--surface-chip);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 600;
  padding: 7px 14px;
  white-space: nowrap;
}

.chip[aria-pressed='true'] {
  background: var(--brand);
  color: #fff;
}

/* ============================================================
   Cards / panels
   ============================================================ */

.card {
  background: var(--surface-card);
  border-radius: var(--r-card);
  border: 0.5px solid var(--border-hair);
}

.card--pad {
  padding: 14px;
}

/* ============================================================
   Empty states — ONE skeleton for Cart / Notifications / Wishlist.
   iOS: 92px brand@10% circle, 40px REGULAR icon, 18px heavy title,
   14px body, and a DOUBLE trailing spacer so the block sits ~1/3 down
   rather than dead centre.
   ============================================================ */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  min-height: 60vh;
  padding-inline: 20px;
}

.empty__top {
  flex: 1 1 0;
}

/* Twice the weight below the block — this is the double Spacer. */
.empty__bottom {
  flex: 2 2 0;
}

.empty__icon {
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255, 100, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--brand);
  flex: 0 0 auto;
}

.empty__icon svg {
  width: 40px;
  height: 40px;
  /* iOS uses the REGULAR weight glyph here, not bold. */
  stroke-width: 1.5;
}

.empty__title {
  font-size: 18px;
  font-weight: 800;
  color: var(--text-primary);
}

.empty__body {
  font-size: 14px;
  color: var(--text-tertiary);
  max-width: 320px;
  line-height: 1.45;
}

/* ============================================================
   Badges
   ============================================================ */

.badge {
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  background: #ef4444;
  color: #fff;
  font-size: 9px;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.badge--tier {
  background: linear-gradient(to right, var(--brand), var(--brand-bright));
  height: 18px;
  font-size: 10px;
  padding: 0 8px;
}

/* ============================================================
   Toast
   ============================================================ */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--tabbar-h) + 20px);
  transform: translateX(-50%) translateY(12px);
  background: var(--text-primary);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  padding: 11px 18px;
  border-radius: 10px;
  box-shadow: var(--shadow-pop);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.22s var(--ease-press);
  z-index: 90;
  max-width: calc(100vw - 40px);
  text-align: center;
}

.toast--on {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}


/* ============================================================
   Icon chips — the coloured rounded square in a settings row.

   These used to size only the SPAN and let the inline <svg> stretch to fill
   the flex box. Chromium does that; SAFARI DOES NOT — an SVG with no width or
   height of its own collapses inside a flex parent, so every icon on the You
   page rendered as an empty coloured square (Adam, 2026-08-10). Every other
   icon on the site is sized by a class that targets the svg directly; these
   are now too.

   Background and tint stay inline because they are per-row.
   ============================================================ */

.iconchip {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
/* iOS YouView settingsRow: a 30x30 chip filled with iconColor at 15%, and the
   glyph inside at 14pt semibold — NOT 18. Drawing it at 18 filled the chip
   corner to corner and made the whole menu look heavy and cramped
   (Adam, 2026-08-16). */
.iconchip svg { width: 14px; height: 14px; }

.iconchip--lg { width: 34px; height: 34px; }
.iconchip--lg svg { width: 16px; height: 16px; }

/* Small trailing chevron in a row. */
.iconmini { flex: 0 0 auto; display: flex; align-items: center; }
.iconmini svg { width: 11px; height: 11px; }

/* ============================================================
   Category page header — the SHEIN one the apps use
   (search bar + sibling strip + sort row). Sticky, so it holds
   its place while the product grid moves under it.
   ============================================================ */

.cathead {
  position: sticky;
  /* Sits UNDER the site header, which is itself sticky at top:0 with z-index
     50. Offsetting by its measured height (set on :root by category.js, since
     the header is a different height at each breakpoint) is what keeps the
     search bar and sibling strip visible instead of sliding behind it. */
  top: var(--apphead-h, 68px);
  z-index: 20;
  background: var(--page-bg);
  padding: 6px 0 4px;
}

.cathead__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
}

.cathead__back {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 32px;
  flex: 0 0 auto;
  color: var(--text-primary);
}
.cathead__back svg { width: 18px; height: 18px; }

/* The category name in the back-bar. Replaces the search-styled pill that used
   to live here — see the note in category.js. Deliberately NOT bordered: it is
   a heading, not a second search field. */
.cathead__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15px;
  font-weight: 800;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cathead__search {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 4px 4px 12px;
  border-radius: 10px;
  border: 2px solid var(--brand);
  background: var(--surface-card);
  color: var(--text-tertiary);
}
.cathead__search > svg { width: 16px; height: 16px; flex: 0 0 auto; }

.cathead__q {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cathead__cam {
  flex: 0 0 auto;
  display: flex;
  padding: 2px;
  cursor: pointer;
}
.cathead__cam svg { width: 17px; height: 17px; }

.cathead__go {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 800;
  color: #fff;
  background: var(--brand);
  border-radius: 8px;
  padding: 7px 16px;
}

/* Sibling categories. Two fixed heights, so the strip never changes size
   mid-transition: a one-line name and a two-line name must occupy the same box
   or the row grows and shrinks as you scroll and the photos visibly jump. */
/* 98px is the iOS `stripTall`, and it is exactly the tile: 62 photo + 5 gap +
   30 name box + 1. Any padding on top of that pushes the names into the sort
   row, so the breathing room goes ABOVE the strip, not inside it. */
.sibstrip {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  height: 98px;
  margin-top: 10px;
  padding: 0 12px;
  overflow-x: auto;
  scrollbar-width: none;
}
.sibstrip::-webkit-scrollbar { display: none; }

.sibtile {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  width: 72px;
  color: var(--text-primary);
}

.sibtile__img {
  width: 62px;
  height: 62px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface-soft);
  display: block;
  flex: 0 0 auto;
}
.sibtile__img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.sibtile__name {
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  line-height: 1.25;
  height: 30px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* Collapsed: one short line of small rounded squares with the name beside
   them — NOT circles, so the strip reads as the same thing at both sizes. */
.cathead.is-scrolled .sibstrip {
  height: 34px;
  gap: 14px;
  align-items: center;
  margin-top: 4px;
}
.cathead.is-scrolled .sibtile {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  width: auto;
}
.cathead.is-scrolled .sibtile__img { width: 30px; height: 30px; border-radius: 6px; }
.cathead.is-scrolled .sibtile__name {
  height: auto;
  font-size: 12px;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  white-space: nowrap;
}

/* Sort. Three equal columns rather than springy gaps: the labels are different
   widths, so a flex-gap row read as unevenly spaced. Every label is
   text-primary and bold — these are controls, and the inactive ones were
   washed out. */
.catsort {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  padding: 6px 14px 2px;
}

.catsort__btn {
  display: flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: 0;
  padding: 0;
  font-size: 14px;
  font-weight: 800;
  color: var(--text-primary);
  cursor: pointer;
}
.catsort__btn svg { width: 12px; height: 12px; }
.catsort__btn--mid { justify-content: center; }
.catsort__btn--end { justify-content: flex-end; }
.catsort__btn.is-on { color: var(--brand); }

.catsort__menu { background: var(--surface-card); }

.catsort__opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border-hair);
  padding: 13px 16px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.catsort__opt:last-child { border-bottom: 0; }
.catsort__opt.is-on { font-weight: 800; }
.catsort__opt svg { width: 14px; height: 14px; }

/* The category page prints its own title under the sticky header, so this copy
   drops the back arrow the standalone pagehead carries. */
.pagehead--slim { padding-left: 0; padding-right: 0; }

/* ============================================================
   Stores & brands — the brand LIST (stores.js) and the same row
   dropped into a category grid as a promo (category.js).

   A 1:1 port of iOS BrandRow / Android BrandRow: identity on top,
   a swipeable strip of the brand's own stock underneath. Full-bleed
   bands separated by the page background, so the page reads as a
   list rather than a wall of cards.
   ============================================================ */

.brandrow {
  background: var(--surface-card);
  padding: 14px 0;
  margin: 0 0 10px;
}

.brandrow__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 var(--gutter, 16px);
  text-decoration: none;
  color: inherit;
}

.brandrow__logo {
  flex: 0 0 auto;
  width: 62px;
  height: 62px;
  border-radius: 10px;
  background: var(--surface-soft);
  border: 0.5px solid var(--border-hair);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.brandrow__logo img { width: 100%; height: 100%; object-fit: cover; }
.brandrow__logo svg { width: 26px; height: 26px; color: var(--text-tertiary); }

.brandrow__id {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1 1 auto;
}

.brandrow__name {
  font-size: 15px;
  font-weight: 800;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.brandrow__count { font-size: 11px; font-weight: 600; color: var(--text-tertiary); }

.brandrow__all {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: 12px;
  font-weight: 800;
  color: var(--brand);
}

.brandrow__all svg { width: 12px; height: 12px; }

/* The strip scrolls horizontally and bleeds off the right edge — the same
   "swipe me" signal the apps give. Cards keep their normal grid width. */
.brandrow__strip {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 12px var(--gutter, 16px) 2px;
}

.brandrow__strip::-webkit-scrollbar { display: none; }
.brandrow__strip > .pcard { flex: 0 0 152px; width: 152px; }

.brandrow__empty {
  margin: 10px 0 0;
  padding: 0 var(--gutter, 16px);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-tertiary);
}

/* Inside a category grid the row must span every column, or it would sit in
   one cell and squash. */
.brandrow--inline {
  grid-column: 1 / -1;
  margin: 4px 0;
}

/* Jump bar — with five sections and eighty shops the page is long, so tapping
   a heading scrolls straight to it. */
.jumpbar {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0 0 12px;
}

.jumpbar::-webkit-scrollbar { display: none; }

.jumpbar__chip {
  flex: 0 0 auto;
  padding: 8px 14px;
  border-radius: 6px;
  border: 0.5px solid var(--border-hair);
  background: var(--surface-card);
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

.jumpbar__chip.is-on { background: var(--brand); color: #fff; border-color: var(--brand); }

.secthead {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 18px 0 8px;
  font-size: 17px;
  font-weight: 800;
  color: var(--text-primary);
}

.secthead__bar { width: 3px; height: 16px; background: var(--brand); }

/* ---- one brand's page (store.js) ---- */

.storehead { margin-bottom: 14px; }

.storehead__banner {
  height: 132px;
  border-radius: 4px;
  overflow: hidden;
  background: linear-gradient(135deg, var(--brand-bright), var(--brand-deep));
}

.storehead__banner img { width: 100%; height: 100%; object-fit: cover; }

.storehead__id {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: -26px;
  padding: 0 4px;
}

.storehead__logo {
  width: 72px;
  height: 72px;
  border-radius: 10px;
  background: var(--surface-card);
  border: 2px solid var(--surface-card);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

.storehead__logo img { width: 100%; height: 100%; object-fit: cover; }
.storehead__logo svg { width: 28px; height: 28px; color: var(--text-tertiary); }

.storehead__name { display: block; font-size: 19px; font-weight: 800; color: var(--text-primary); }
.storehead__count { display: block; font-size: 12px; font-weight: 600; color: var(--text-tertiary); }

/* ============================================================
   Product page — joined CTA pair + SKU sheet
   A port of iOS ProductDetailView: the two CTAs are ONE squarish block joined
   in the middle (Add to cart = yellow-orange, Buy Now = deep orange), and the
   colour/size/quantity choices live in the sheet either one opens — never
   inline under the title.
   ============================================================ */

.buypair {
  display: flex;
  flex: 1 1 auto;
  max-width: 300px;
  border-radius: 6px;
  overflow: hidden;
}

.buypair__add,
.buypair__buy {
  flex: 1 1 0;
  min-width: 0;
  min-height: 46px;
  padding: 0 10px;
  font-size: 14px;
  font-weight: 900;
  color: #fff;
  white-space: nowrap;
}

.buypair__add { background: linear-gradient(135deg, #ffc64b, #ffa200); }
.buypair__buy { background: linear-gradient(135deg, var(--brand), var(--brand-deep, #e05500)); }

/* ---- SKU sheet ---- */

.sku {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.42);
}

.sku__panel {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px var(--gutter) calc(16px + env(safe-area-inset-bottom, 0px));
  background: var(--surface-card);
  border-radius: 14px 14px 0 0;
}

.sku__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--surface-soft);
  color: var(--text-secondary);
}

.sku__head { display: flex; gap: 12px; align-items: flex-start; padding-right: 34px; }
.sku__img { width: 84px; height: 84px; border-radius: 8px; object-fit: cover; flex: 0 0 auto; }
.sku__price { font-size: 19px; font-weight: 900; color: var(--brand); }

.sku__body { overflow-y: auto; display: flex; flex-direction: column; gap: 16px; }
.sku__group { display: flex; flex-direction: column; gap: 8px; }

.sku__swatches { display: flex; flex-wrap: wrap; gap: 10px; }

/* iOS ColorSwatchButton: the colour's own photo, name underneath, brand ring
   when selected. The old web chips were text-only. */
.swatch { display: flex; flex-direction: column; align-items: center; gap: 6px; width: 76px; }

.swatch__img {
  width: 76px;
  height: 76px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-soft);
  border: 0.5px solid var(--border-hair);
  display: block;
}

.swatch__img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.swatch[aria-pressed='true'] .swatch__img { border: 2.5px solid var(--brand); }

.swatch__name {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  max-width: 88px;
  text-align: center;
  line-height: 1.25;
}

.swatch[aria-pressed='true'] .swatch__name { color: var(--brand); font-weight: 800; }

.sku__confirm {
  min-height: 48px;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 900;
  color: #fff;
  background: linear-gradient(135deg, var(--brand), var(--brand-deep, #e05500));
}
