/* ==========================================================================
   Fashion Pedon — Storefront layer
   Everything here is new markup the design-system demo files never needed
   (they're static, this is database-driven) — the homepage builder's
   section types, the shop filter rail, and the product gallery. Every
   value is still a design-system token.
   ========================================================================== */

/* ---------- [hidden] must always win -----------------------------------------
   Several design-system components (.fp-alert, .fp-drawer's inner bits) set
   their own `display` unconditionally, which — being an author rule — beats
   the browser's own [hidden] default despite matching specificity. The admin
   layer hit this exact bug (a quick-add row that stayed visible); JS here
   toggles visibility by setting the `hidden` property in a few places too
   (the pincode result box), so the same guarantee needs to hold here. */
[hidden] { display: none !important; }

/* ---------- Homepage section visibility (show_on_mobile/show_on_desktop) -- */

.fp-section--desktop-only { display: none; }
.fp-section--mobile-only { display: block; }
@media (min-width: 750px) {
  .fp-section--desktop-only { display: block; }
  .fp-section--mobile-only { display: none; }
}

/* ---------- Category grid (index.php: category_grid section) --------------
   noon-style: two rows, side-scrolling, tiles sit directly on the section's
   plain white background (no card border/fill — see category_grid.php).
   grid-auto-flow:column + a fixed row count is what makes a flat list of
   categories lay out as two rows instead of wrapping to a third: each
   column gets exactly 2 slots (top then bottom) before the grid starts a
   new column, which is also what creates the intentional "next tile peeks
   at the edge" cue — the strip's total width is never a clean multiple of
   the viewport width. */
.cats {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(2, auto);
  grid-auto-columns: 76px;
  gap: var(--fp-space-5) var(--fp-space-3);
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: var(--fp-space-2);
}
.cats::-webkit-scrollbar { display: none; }
@media (min-width: 750px) {
  .cats { grid-auto-columns: 108px; gap: var(--fp-space-6) var(--fp-space-4); }
}
.cat { display: block; text-align: center; scroll-snap-align: start; }
.cat:hover { text-decoration: none; }
.cat__media {
  aspect-ratio: 1 / 1;
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  border: var(--fp-border-hair);
  background: var(--fp-paper-0);
}
.cat__media img,
.cat__media .fp-ph { width: 100%; height: 100%; object-fit: cover; transition: transform var(--fp-duration-slow) var(--fp-ease-out); }
.cat:hover .cat__media img,
.cat:hover .cat__media .fp-ph { transform: scale(1.04); }
.cat__label {
  display: block;
  margin-top: var(--fp-space-2);
  font-size: var(--fp-text-xs);
  font-weight: var(--fp-weight-medium);
  color: var(--fp-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Brand tiles (shop.php: category view only) --------------------
   Single row (a category typically stocks far fewer brands than the full
   category list needs two rows for) — same tile anatomy as .cat so the two
   read as one visual language, just scrolling one row instead of two. */
.brand-strip {
  display: flex;
  gap: var(--fp-space-4);
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: var(--fp-space-2);
}
.brand-strip::-webkit-scrollbar { display: none; }
.brand-tile { flex: 0 0 72px; display: block; text-align: center; scroll-snap-align: start; }
.brand-tile:hover { text-decoration: none; }
.brand-tile__media {
  aspect-ratio: 1 / 1;
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  border: var(--fp-border-w-thick) solid var(--fp-border-hair);
  background: var(--fp-paper-0);
}
.brand-tile__media img,
.brand-tile__media .fp-ph { width: 100%; height: 100%; object-fit: cover; }
.brand-tile.is-active .brand-tile__media { border-color: var(--fp-action-primary); }
.brand-tile__label {
  display: block;
  margin-top: var(--fp-space-2);
  font-size: var(--fp-text-xs);
  color: var(--fp-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.brand-tile.is-active .brand-tile__label { color: var(--fp-text-brand); font-weight: var(--fp-weight-semibold); }

/* ---------- Categories drawer grid (bottom-nav "Categories" tab) ----------
   The #menu drawer is shared with the header hamburger, but the bottom-nav
   button is explicitly labelled "Categories" — so unlike .cats' side-
   scrolling strip (built for a homepage teaser, a handful of tiles peeking
   off-screen), this needs to show every top-level category at once, at a
   fixed 2 columns, in the drawer's ~320px-wide panel. */
.fp-drawer-catgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--fp-space-3); }
.fp-drawer-cat {
  display: flex; flex-direction: column;
  border: var(--fp-border-hair); border-radius: var(--fp-radius-lg);
  overflow: hidden; text-align: center;
  background: var(--fp-paper-0);
}
.fp-drawer-cat:hover { text-decoration: none; border-color: var(--fp-action-primary); }
.fp-drawer-cat__media { aspect-ratio: 1 / 1; background: var(--fp-bg-sunken); }
.fp-drawer-cat__media img,
.fp-drawer-cat__media .fp-ph { width: 100%; height: 100%; object-fit: cover; }
.fp-drawer-cat__label {
  padding: var(--fp-space-2) var(--fp-space-2);
  font-size: var(--fp-text-xs);
  font-weight: var(--fp-weight-medium);
  color: var(--fp-text-primary);
}

/* ---------- Categories page (categories.php: bottom-nav "Categories") -----
   Own classes, deliberately not shared with the #menu drawer's
   .fp-drawer-catgrid (footer.php) — same visual idea, but a full page has
   room to grow past 2 columns on wider screens where the drawer never will,
   and keeping them separate means a future change to one can't silently
   reshape the other. */
.category-page-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--fp-space-4); }
@media (min-width: 560px) {
  .category-page-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
}
.category-page-tile {
  display: flex;
  flex-direction: column;
  border: var(--fp-border-hair);
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  text-align: center;
  background: var(--fp-paper-0);
}
.category-page-tile:hover { text-decoration: none; border-color: var(--fp-action-primary); }
.category-page-tile__media { aspect-ratio: 1 / 1; background: var(--fp-bg-sunken); }
.category-page-tile__media img,
.category-page-tile__media .fp-ph { width: 100%; height: 100%; object-fit: cover; }
.category-page-tile__label {
  padding: var(--fp-space-3);
  font-size: var(--fp-text-sm);
  font-weight: var(--fp-weight-medium);
  color: var(--fp-text-primary);
}

/* ---------- Hero slider (index.php: hero_slider section) ------------------ */

/* Owner specifically wants this to match the header search row's own
   vertical rhythm — same padding-block value as .fp-header__search-row
   (assets/css/storefront.css), not the generic --fp-section-y used by every
   other homepage section. Left/right stays on .fp-container as normal. */
.fp-section--hero { padding-block: var(--fp-space-3); }

/* noon-style hero: a rounded-corner image card, no coloured section
   background (the wrapping <section> is a plain .fp-section, same as every
   other homepage section — transparent, page background shows through).
   .fp-hero-slider itself carries no visual chrome — the rounding/clipping
   live on the viewport so the rounded corners crop the images, not just an
   outer box with square photos peeking past them. */
.fp-hero-slider__viewport {
  position: relative;
  aspect-ratio: 2 / 1;
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  touch-action: pan-y;
  cursor: grab;
}
.fp-hero-slider__viewport:active { cursor: grabbing; }
.fp-hero-slider__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fp-duration-slow) var(--fp-ease-standard);
}
.fp-hero-slider__slide.is-active { opacity: 1; visibility: visible; }
.fp-hero-slider__link { display: block; position: relative; width: 100%; height: 100%; color: inherit; }
.fp-hero-slider__link:hover { text-decoration: none; }
.fp-hero-slider__img { width: 100%; height: 100%; object-fit: cover; }
/* No slide image (none uploaded yet, or one failed to load) — a dark
   brand-toned gradient rather than the generic light-grey .fp-ph used for
   product/category placeholders, since the hero's own heading/subtitle
   text overlays in white and needs a dark backdrop to stay readable. */
.fp-hero-slider__img.fp-ph {
  background: linear-gradient(135deg, var(--fp-amber-700), var(--fp-paper-900));
}
.fp-hero-slider__img.fp-ph::before { display: none; }

/* width: min(...) + box-sizing guarantees this never overflows the slide's
   right edge — max-width alone (the old rule) could compute wider than the
   viewport at large heading font sizes on narrow screens, which is exactly
   what was clipping the heading on mobile.
   inset:0 + flex/justify-end (rather than the old left:0;bottom:0, which
   sized the box to exactly its own content and grew it UPWARD from that
   bottom anchor) is what fixes the top-clipping: the box now spans the
   viewport's full height from the start, so flexbox lays the text out
   within that whole space and bottom-aligns it, instead of the text being
   free to grow past the top of a box that was only ever as tall as it
   happened to need — on the short end of the 2:1 ratio, at real heading
   lengths, that "happened to need" routinely exceeded the image's own
   height, and .fp-hero-slider__viewport's overflow:hidden clipped whatever
   poked out the top. */
.fp-hero-slider__copy {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  width: min(46ch, 100%);
  box-sizing: border-box;
  padding: var(--fp-space-6);
  /* Stopped at 55% (not the old plain "to transparent", which faded across
     the box's FULL height) — this box now spans the whole image (inset:0,
     needed so flex can bottom-align the text without ever clipping it), so
     an unstopped gradient darkened top-to-bottom over the entire photo
     instead of just the strip behind the text, which is what was making
     the whole image read as dull/grey. Only the bottom ~55%, where the
     text actually sits, gets the legibility wash now; the rest of the
     photo is untouched. */
  background: linear-gradient(to top, var(--fp-bg-overlay) 0%, transparent 55%);
}
.fp-hero-slider__title {
  font-family: var(--fp-font-display);
  font-size: clamp(var(--fp-text-lg), 5vw, var(--fp-text-2xl));
  font-weight: var(--fp-weight-extrabold);
  line-height: 1.2;
  color: var(--fp-paper-0);
  overflow-wrap: break-word;
}
.fp-hero-slider__subtitle { color: var(--fp-paper-200); margin-top: var(--fp-space-2); overflow-wrap: break-word; }

@media (max-width: 480px) {
  .fp-hero-slider__copy { padding: var(--fp-space-5) var(--fp-space-4) var(--fp-space-8); }
}

/* Dots sit BELOW the rounded card, in normal flow — not overlaid on the
   image — so they're never lost against a busy photo. No arrow buttons,
   ever (this is a touch/drag-first carousel). */
.fp-hero-slider__dots {
  display: flex;
  justify-content: center;
  gap: var(--fp-space-2);
  margin-top: var(--fp-space-4);
}
.fp-hero-slider__dot {
  width: 8px; height: 8px;
  padding: 0;
  border: 0;
  border-radius: var(--fp-radius-pill);
  background: var(--fp-border-strong);
  transition: width var(--fp-duration-fast) var(--fp-ease-standard),
              background-color var(--fp-duration-fast) var(--fp-ease-standard);
}
.fp-hero-slider__dot.is-active { background: var(--fp-action-primary); width: 20px; }

/* ---------- Banner strip (index.php: banner_strip section) ---------------- */

.fp-banner-strip {
  display: grid;
  gap: var(--fp-grid-gap);
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .fp-banner-strip { grid-template-columns: repeat(var(--fp-strip-cols, 1), 1fr); }
}
.fp-banner-strip__item {
  position: relative;
  display: block;
  aspect-ratio: 21 / 9;
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  background: var(--fp-bg-inverse);
}
.fp-banner-strip__item:hover { text-decoration: none; }
.fp-banner-strip__item img,
.fp-banner-strip__item .fp-ph { width: 100%; height: 100%; object-fit: cover; }
.fp-banner-strip__copy {
  position: absolute;
  left: 0; bottom: 0; right: 0;
  box-sizing: border-box;
  padding: var(--fp-space-5);
  background: linear-gradient(to top, var(--fp-bg-overlay), transparent);
}
.fp-banner-strip__copy p { overflow-wrap: break-word; }

/* ---------- Image grid / lookbook (index.php: image_grid section) --------- */

.fp-image-grid {
  display: grid;
  gap: var(--fp-space-3);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 700px) {
  .fp-image-grid { grid-template-columns: repeat(var(--fp-image-grid-cols, 3), 1fr); }
}
.fp-image-grid__item { position: relative; display: block; aspect-ratio: 3 / 4; border-radius: var(--fp-radius-md); overflow: hidden; }
.fp-image-grid__item:hover { text-decoration: none; }
.fp-image-grid__item img,
.fp-image-grid__item .fp-ph { width: 100%; height: 100%; object-fit: cover; }
.fp-image-grid__caption {
  position: absolute;
  left: var(--fp-space-3); bottom: var(--fp-space-3);
  padding: var(--fp-space-1) var(--fp-space-3);
  border-radius: var(--fp-radius-pill);
  background: var(--fp-bg-overlay);
  color: var(--fp-paper-0);
  font-size: var(--fp-text-xs);
}

/* ---------- Video (index.php: video section) ------------------------------ */

.fp-video { position: relative; aspect-ratio: 16 / 9; border-radius: var(--fp-radius-lg); overflow: hidden; background: var(--fp-bg-inverse); }
.fp-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------- Countdown deal (index.php: countdown_deal section) ------------ */

.fp-countdown { display: flex; gap: var(--fp-space-2); }
.fp-countdown__unit {
  display: grid;
  justify-items: center;
  min-width: 52px;
  padding: var(--fp-space-2) var(--fp-space-1);
  border-radius: var(--fp-radius-sm);
  background: var(--fp-bg-inverse);
  color: var(--fp-paper-0);
}
.fp-countdown__unit span { font-family: var(--fp-font-mono); font-size: var(--fp-text-lg); font-weight: var(--fp-weight-bold); }
.fp-countdown__unit small { font-size: var(--fp-text-2xs); text-transform: uppercase; letter-spacing: var(--fp-tracking-wide); color: var(--fp-paper-400); }

/* ---------- Rich text / CMS pages ------------------------------------------ */

.fp-prose { font-size: var(--fp-text-base); line-height: var(--fp-leading-relaxed); color: var(--fp-text-primary); }
.fp-prose > * + * { margin-top: var(--fp-space-4); }
.fp-prose h2 { font-family: var(--fp-font-display); font-size: var(--fp-text-xl); font-weight: var(--fp-weight-bold); margin-top: var(--fp-space-8); }
.fp-prose h3 { font-weight: var(--fp-weight-semibold); margin-top: var(--fp-space-6); }
.fp-prose ul, .fp-prose ol { padding-left: 1.4em; }
.fp-prose li + li { margin-top: var(--fp-space-2); }
.fp-prose a { color: var(--fp-text-brand); text-decoration: underline; }

/* ---------- Shop: filter rail, results, chips ------------------------------ */

.filter-group + .filter-group { margin-top: var(--fp-space-6); padding-top: var(--fp-space-6); border-top: var(--fp-border-subtle-line); }
.rail-filters { display: none; }
@media (min-width: 1000px) {
  .rail-filters { display: block; position: sticky; top: calc(var(--fp-header-h-full) + var(--fp-space-4)); }
  .filter-trigger { display: none !important; }
}
.range { width: 100%; accent-color: var(--fp-action-primary); }

.fp-shop-skeleton { display: grid; gap: var(--fp-grid-gap); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.fp-shop-skeleton__card { border-radius: var(--fp-radius-lg); overflow: hidden; border: var(--fp-border-hair); }
.fp-shop-skeleton__media { aspect-ratio: 3 / 4; }
.fp-shop-skeleton__line { height: 14px; margin: var(--fp-space-3) var(--fp-space-4) 0; }
.fp-shop-skeleton__line:last-child { margin-bottom: var(--fp-space-4); width: 60%; }

.fp-results[data-loading] { opacity: 0.5; pointer-events: none; }

/* ---------- Product gallery (product.php) ----------------------------------
   The whole point of this block: nothing here can ever grow wider than its
   parent. .gallery is the sizing boundary (max-width:100%, no intrinsic
   width from its content); .gallery__viewport is a fixed-ratio window with
   overflow:hidden; .gallery__track is the ONLY thing that scrolls, and it
   scrolls inside the viewport (overflow-x:auto), never the page. A raw
   4000x3000 upload can't push the body sideways here — every image is
   width:100%/height:100% inside its own slide, capped by the viewport. */

.pdp { display: grid; gap: var(--fp-space-8); min-width: 0; }
@media (min-width: 950px) { .pdp { grid-template-columns: 1fr 1fr; gap: var(--fp-space-16); align-items: start; } }

/* min-width:0 here is load-bearing, not decoration: .pdp__buy is a grid
   item, and a grid item's default min-width is auto (its content's
   intrinsic minimum), not 0. Without this, one wide child (a non-wrapping
   row with a width:100% button plus another element) sets the intrinsic
   minimum for the WHOLE column — which then makes .pdp__buy itself, and
   every sibling inside it (price row, delivery text, tabs), render wider
   than the viewport. That single missing property was the actual cause of
   several unrelated-looking elements all clipping on the right at once. */
.pdp__buy { min-width: 0; }

.gallery { max-width: 100%; min-width: 0; }
.gallery__viewport {
  position: relative;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  max-height: 42vh;
  margin-inline: auto;
  border-radius: var(--fp-radius-lg);
  overflow: hidden;
  background: var(--fp-paper-0);
  /* Root cause of "swipe does nothing on the image itself": .gallery__track
     below used to carry touch-action:pan-x, which tells the browser it may
     go ahead and drive horizontal scrolling NATIVELY, with no need to ask
     product.js first. product.js *also* drags track.scrollLeft by hand on
     every touchmove (needed so a touch that starts ON the <img> — not just
     beside it — reliably moves the gallery on every mobile browser). Both
     of those were fighting over the same scrollLeft on the same touch at
     once: the browser's own native pan-x handling and this script's manual
     write. Two owners of one property don't average out to "it moves twice
     as far" — they cancel out to "it barely moves at all," which reads
     exactly like the touch was dead on arrival. pan-y here (repeated on
     .gallery__track below) tells the browser to keep handling VERTICAL
     panning itself — so the page still scrolls normally — while explicitly
     giving up horizontal handling, leaving product.js as the single,
     uncontested driver of every horizontal swipe, no matter where inside
     this box it starts. */
  touch-action: pan-y;
}
.gallery__track {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-width: none;
}
.gallery__track::-webkit-scrollbar { display: none; }
.gallery__slide {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.gallery__slide img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
  /* Stops iOS Safari's own long-press "save/copy image" handling from
     grabbing a touch that starts on the image before product.js's swipe
     handler (.gallery__viewport touchstart/touchmove) ever sees it. */
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  user-select: none;
}
/* .fp-ph's own display:grid;place-items:center (the base rule) is what
   actually centers the "No image" icon+label both ways — a same-specificity
   "display:block" override here (matching the <img> rule above) would win
   by source order and silently flatten that centering back to plain
   top-left inline flow, which is exactly what was happening before. */
.gallery__slide .fp-ph {
  width: 100%;
  height: 100%;
  max-width: 100%;
}

.gallery__dots { display: flex; justify-content: center; gap: var(--fp-space-2); margin-top: var(--fp-space-3); }
.gallery__dot {
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: var(--fp-radius-pill);
  background: var(--fp-border-strong); flex: none;
}
.gallery__dot.is-active { background: var(--fp-action-primary); width: 20px; transition: var(--fp-transition-control); }

.gallery__thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--fp-space-3); margin-top: var(--fp-space-3); }
.gallery__thumb {
  aspect-ratio: 1 / 1; border-radius: var(--fp-radius-sm); overflow: hidden;
  border: var(--fp-border-w-thick) solid transparent; padding: 0; background: none;
  transition: var(--fp-transition-control); min-width: 0;
}
.gallery__thumb img { display: block; width: 100%; height: 100%; max-width: 100%; object-fit: cover; }
.gallery__thumb .fp-ph { width: 100%; height: 100%; max-width: 100%; }
.gallery__thumb.is-active { border-color: var(--fp-action-primary); }

/* ---------- Product tabs — a bordered box that fits its active panel ------
   Only one .pdp-tabs__panel is ever un-hidden at a time (assets/js/
   product.js) — since [hidden] is display:none, .pdp-tabs__body's height is
   already just the visible panel's height with nothing extra to constrain;
   the "oversized empty box" this replaces came from nothing sizing the
   container to content in the first place, not from any fixed height set
   here — so there's deliberately no min-height/height anywhere below. */
.pdp-tabs {
  border: var(--fp-border-hair);
  border-radius: var(--fp-radius-md);
  overflow: hidden;
}
.pdp-tabs__head {
  margin: 0;
  padding-inline: var(--fp-space-4);
  background: var(--fp-bg-sunken);
  border-bottom: var(--fp-border-hair);
}
.pdp-tabs__body { padding: var(--fp-space-5); }
.pdp-tabs__panel[hidden] { display: none; }
.pdp-tabs__panel { animation: fp-fade-in 0.15s ease; }

@media (min-width: 950px) { .pdp__buy { position: sticky; top: calc(var(--fp-header-h-full) + var(--fp-space-4)); min-width: 0; } }

/* Sticky "Add to bag" / "Buy it now" bar (Flipkart-style) — fixed on every
   screen size, not just mobile, since these two buttons don't exist
   anywhere else on the page any more (they used to sit inline in
   .pdp__buy). footer.php hides the global bottom nav on product pages, so
   this is the only fixed bottom bar present there; see the body:has() rules
   further down for the matching #main padding-bottom / WhatsApp offset,
   which apply at ALL widths (not just mobile) since this bar isn't
   mobile-only the way the bottom nav is. */
:root { --fp-actionbar-h: 68px; }

.pdp-actionbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--fp-z-header);
  display: flex;
  gap: var(--fp-space-3);
  box-sizing: border-box;
  width: 100%;
  padding: 8px var(--fp-gutter);
  padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  background: var(--fp-bg-surface);
  border-top: var(--fp-border-hair);
  box-shadow: 0 -2px 12px rgba(16, 18, 43, 0.08);
}
.pdp-actionbar .fp-btn {
  flex: 1 1 0;
  min-width: 0;
  padding-inline: var(--fp-space-4);
}

/* Sticky "Place Order" bar on cart.php (Flipkart-style) — mobile-only,
   UNLIKE .pdp-actionbar above: this one stacks ABOVE the bottom nav rather
   than replacing it (the cart page keeps Home/Categories/Account/Cart
   reachable), and desktop already shows Checkout in the always-visible
   summary card next to the line items, so there's nothing for this bar to
   add there. bottom is the bottom nav's own height, not 0 — that's what
   puts this bar directly above the nav instead of on top of it. */
:root { --fp-cart-bar-h: 64px; }

.cart-checkout-bar { display: none; }

@media (max-width: 899px) {
  .cart-checkout-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fp-space-4);
    position: fixed;
    left: 0; right: 0;
    bottom: calc(var(--fp-bottomnav-h) + env(safe-area-inset-bottom, 0px));
    z-index: var(--fp-z-header);
    box-sizing: border-box;
    width: 100%;
    height: var(--fp-cart-bar-h);
    padding-inline: var(--fp-gutter);
    background: var(--fp-bg-surface);
    border-top: var(--fp-border-hair);
    box-shadow: 0 -2px 12px rgba(16, 18, 43, 0.08);
  }
}
/* cart.js toggles this via an IntersectionObserver on the inline Checkout
   button (data-cart-checkout-inline) — never show both at once. Two classes
   beats the single-class .cart-checkout-bar rule above regardless of the
   media query it's nested in, so this wins whenever it's applied. */
.cart-checkout-bar.is-hidden { display: none; }
.cart-checkout-bar__total { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.cart-checkout-bar__label { font-size: var(--fp-text-xs); color: var(--fp-text-secondary); }
.cart-checkout-bar__amount { font-size: var(--fp-text-lg); font-weight: var(--fp-weight-bold); color: var(--fp-text-primary); }
.cart-checkout-bar .fp-btn { flex: none; padding-inline: var(--fp-space-6); }

.care { display: flex; flex-wrap: wrap; gap: var(--fp-space-6); }
.care figure { display: grid; justify-items: center; gap: var(--fp-space-2); width: 76px; }
.care figcaption { font-family: var(--fp-font-mono); font-size: var(--fp-text-2xs); text-transform: uppercase; letter-spacing: var(--fp-tracking-wide); color: var(--fp-text-muted); text-align: center; line-height: 1.4; }

.sizetable { width: 100%; }
.sizetable th, .sizetable td { padding: var(--fp-space-3) var(--fp-space-2); text-align: left; border-bottom: var(--fp-border-subtle-line); }
.sizetable td { font-family: var(--fp-font-mono); font-size: var(--fp-text-xs); }
.sizetable th { font-size: var(--fp-text-xs); font-weight: 600; }

/* ---------- Header search (always-open, noon-style) ------------------------
   Its own row under the logo row rather than an icon-triggered panel — on
   every screen size, not just mobile, so there's one layout to reason about
   instead of a fragile inline-vs-stacked breakpoint switch. header.php
   leaves this whole row out on pages that pass $hideHeaderSearch = true
   (checkout, where address + payment live on one page). */
.fp-header__search-row {
  border-top: var(--fp-border-hair);
  padding-block: var(--fp-space-3);
}
.fp-header__search { position: relative; max-width: 640px; margin-inline: auto; }
.fp-header__search form { position: relative; }
.fp-header__search svg {
  position: absolute; left: var(--fp-space-4); top: 50%; transform: translateY(-50%);
  color: var(--fp-text-muted); pointer-events: none;
}
.fp-header__search-input { padding-left: var(--fp-space-10); }
.fp-search-results {
  position: absolute;
  top: calc(100% + var(--fp-space-2));
  left: 0;
  right: 0;
  z-index: var(--fp-z-sticky);
  background: var(--fp-bg-surface);
  border: var(--fp-border-hair);
  border-radius: var(--fp-radius-md);
  box-shadow: var(--fp-shadow-md);
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--fp-space-2);
}
.fp-search-results__item {
  display: flex;
  align-items: center;
  gap: var(--fp-space-3);
  padding: var(--fp-space-2);
  border-radius: var(--fp-radius-sm);
  color: var(--fp-text-primary);
}
.fp-search-results__item:hover { background: var(--fp-bg-sunken); text-decoration: none; }
.fp-search-results__thumb { width: 40px; height: 40px; flex: none; border-radius: var(--fp-radius-sm); object-fit: cover; background: var(--fp-bg-sunken); }
.fp-search-results__name { font-size: var(--fp-text-sm); }
.fp-search-results__price { font-family: var(--fp-font-mono); font-size: var(--fp-text-xs); color: var(--fp-text-muted); margin-left: auto; }

/* ---------- Desktop/laptop only: search moves inside the header bar -------
   Everything above this block is untouched and still governs every width
   below 900px — mobile's always-open search stays byte-for-byte the same
   row it's always been, same DOM, same CSS path, nothing here overrides it.

   At 900px+, .fp-header__bar and .fp-header__search-row (plus its inner
   .fp-container) switch to display:contents: they stop generating their own
   box, so their children — the hamburger button, logo, nav, the search box,
   and the actions icon — become direct flex children of <header> itself,
   all in one row. That's what makes `order` able to slot the search box
   between the nav and the account icon, which isn't reachable while it
   lived in a separate wrapping element one level up. Since .fp-header__bar
   can no longer carry the page's usual .fp-container max-width/gutter once
   it's display:contents, <header> takes that over directly via the
   padding-inline calc (full-bleed background, content still capped to
   --fp-container-max — the same effect .fp-container normally gives). */
@media (min-width: 900px) {
  .fp-header {
    display: flex;
    align-items: center;
    gap: var(--fp-space-4);
    min-height: var(--fp-header-h);
    padding-inline: max(var(--fp-gutter), calc((100% - var(--fp-container-max)) / 2));
  }
  .fp-header__bar,
  .fp-header__search-row,
  .fp-header__search-row > .fp-container {
    display: contents;
  }
  .fp-header__bar > .fp-icon-btn { order: 1; }
  .fp-header__bar > .fp-logo { order: 2; }
  .fp-header__nav { order: 3; }
  .fp-header__search {
    order: 4;
    flex: 1 1 240px;
    min-width: 0;
    max-width: 360px;
    margin-inline: 0;
  }
  .fp-header__actions { order: 5; }
}

/* ---------- Recently viewed ------------------------------------------------- */

.scroller { display: flex; gap: var(--fp-grid-gap); overflow-x: auto; padding-bottom: var(--fp-space-4); scroll-snap-type: x mandatory; }
.scroller > * { flex: 0 0 clamp(180px, 44vw, 240px); scroll-snap-align: start; }

/* ---------- Checkout / order-success / track-order (Phase 8) -------------- */
/* Ported verbatim from the design system's checkout.html page-local <style>
   block — these three pages never had a shared home, so it lives here now. */

.pair { display: grid; gap: var(--fp-space-5); }
@media (min-width: 620px) { .pair { grid-template-columns: 1fr 1fr; } .pair .fp-field + .fp-field { margin-top: 0; } }

.stepbar { display: flex; align-items: center; gap: var(--fp-space-3); flex-wrap: wrap; }
.stepbar__item { display: flex; align-items: center; gap: var(--fp-space-2); font-size: var(--fp-text-xs); color: var(--fp-text-muted); }
.stepbar__item.is-done { color: var(--fp-text-secondary); }
.stepbar__item.is-current { color: var(--fp-text-brand); font-weight: var(--fp-weight-semibold); }
.stepbar__n {
  width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: var(--fp-radius-pill); border: var(--fp-border-w-hair) solid currentColor;
  font-family: var(--fp-font-mono); font-size: 10px;
}
.stepbar__item.is-done .stepbar__n { background: var(--fp-action-primary); border-color: var(--fp-action-primary); color: var(--fp-text-on-brand); }
.stepbar__item.is-current .stepbar__n { border-color: var(--fp-action-primary); border-width: 2px; }

.receipt { max-width: 460px; margin-inline: auto; }

/* ---------- Checkout wizard (3 steps, one form, JS shows/hides panels) ----- */
/* .checkout-page keeps the whole flow single-column and narrow even on
   desktop — a stepped wizard reads oddly stretched across a wide two-column
   layout the old single-scroll page used; each step is a short, focused
   task, not a long page to lay out side by side with anything. */
.checkout-page { max-width: 640px; margin-inline: auto; }
.checkout-step { animation: fp-fade-in 0.15s ease; }
@keyframes fp-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.location-capture { padding: var(--fp-space-4); border: var(--fp-border-hair); border-radius: var(--fp-radius-md); background: var(--fp-bg-sunken); }
.location-capture.is-invalid { border-color: var(--fp-danger-border); background: var(--fp-danger-bg); }
.location-capture__status { display: flex; align-items: center; gap: var(--fp-space-2); font-size: var(--fp-text-sm); }
.location-capture__status[data-ok] { color: var(--fp-success-fg); }
.location-capture__status[data-error] { color: var(--fp-danger-fg); }
.location-capture [data-location-spinner][hidden] { display: none; }

@media (max-width: 619px) {
  .checkout-page { padding-inline: 0; }
  .stepbar { font-size: var(--fp-text-2xs); gap: var(--fp-space-2); }
  .stepbar__label { display: none; } /* numbers only on narrow screens, so the bar never wraps or overflows */
}

/* ---------- Whole product card clickable (storefront only) ----------------- */
/* Cursor affordance only — the actual click-anywhere behaviour is JS
   (assets/js/product-cards.js), delegated from <body> so it covers every
   render_product_card() card on every page without a per-page <script> tag.
   (An earlier ::after "stretched link" CSS-only attempt had a bug — putting
   position:relative on the name's own <a> made the pseudo-element stretch
   to that tiny inline box instead of the whole .fp-product card, so only
   the name text was ever clickable. JS avoids that whole class of mistake.) */
.fp-product { cursor: pointer; }
.fp-product__wish, .fp-product__name a { cursor: pointer; }

/* ---------- Account pages (Phase 10) ---------------------------------------- */

.account-layout { display: grid; grid-template-columns: 220px 1fr; gap: var(--fp-space-8); align-items: start; }
/* Grid items default to min-width:auto (their content's own intrinsic
   minimum), not 0 — same bug already fixed once for .pdp__buy. Here it means
   any single unbreakable thing inside either column (a long order number, a
   status badge sitting next to a price, the account-nav pill strip's own
   overflow-x:auto content) can set the minimum width for its ENTIRE column,
   which on the >820px two-column layout pushes .account-layout wider than
   the page, and on the collapsed single-column mobile layout pushes the
   whole page into horizontal scroll — exactly the "cut off on mobile"
   symptom every account/*.php page built on this grid was hitting. */
.account-layout > * { min-width: 0; }
.account-nav { position: sticky; top: var(--fp-space-4); }
.account-nav__link {
  display: flex; align-items: center; gap: var(--fp-space-3);
  padding: var(--fp-space-3) var(--fp-space-2);
  border-radius: var(--fp-radius-sm);
  font-size: var(--fp-text-sm); color: var(--fp-text-secondary);
}
.account-nav__link svg { flex: none; color: var(--fp-text-muted); }
.account-nav__link:hover { background: var(--fp-bg-sunken); color: var(--fp-text-primary); text-decoration: none; }
.account-nav__link.is-active { background: var(--fp-bg-brand-soft); color: var(--fp-text-brand); font-weight: var(--fp-weight-semibold); }
.account-nav__link.is-active svg { color: var(--fp-text-brand); }

@media (max-width: 820px) {
  .account-layout { grid-template-columns: 1fr; }
  .account-nav { position: static; }
  .account-nav nav { display: flex; overflow-x: auto; gap: var(--fp-space-2); }
  .account-nav__link { white-space: nowrap; }
}

/* Dashboard quick-links: fixed 2 columns at every width (not just mobile) —
   4 boxes read as a natural top row / bottom row pair either way, and the
   labels ("Orders", "Wishlist", "Coupons", "Help Center") never need more
   than half the row even on a wide desktop screen. */
.account-quicklinks { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--fp-space-4); }
.account-quicklink {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--fp-space-2);
  text-align: center;
  padding: var(--fp-space-5);
  color: var(--fp-text-primary);
}
.account-quicklink:hover { text-decoration: none; border-color: var(--fp-action-primary); }
.account-quicklink svg { color: var(--fp-text-brand); }
.account-quicklink span { font-size: var(--fp-text-sm); font-weight: var(--fp-weight-semibold); }

/* Activity history: a plain timestamped list, one row per event — reuses
   .fp-row/.fp-body-sm rather than inventing a new row component. */
.account-activity__row { display: flex; align-items: flex-start; gap: var(--fp-space-3); padding-block: var(--fp-space-3); border-bottom: var(--fp-border-hair); }
.account-activity__row:last-child { border-bottom: none; }
.account-activity__icon {
  flex: none;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: var(--fp-radius-pill);
  background: var(--fp-bg-sunken);
  color: var(--fp-text-brand);
}

/* Account settings / Feedback & info: tap-to-open rows — icon (optional),
   label, trailing chevron. Reuses .account-activity__icon for the same
   circular icon badge so the two list styles on the dashboard match. */
.account-settings__row {
  display: flex; align-items: center; gap: var(--fp-space-3);
  padding-block: var(--fp-space-4);
  border-bottom: var(--fp-border-hair);
  color: var(--fp-text-primary);
}
.account-settings__row:last-child { border-bottom: none; }
.account-settings__row:hover { text-decoration: none; background: var(--fp-bg-sunken); }
.account-settings__row .account-activity__icon { width: 32px; height: 32px; }
.account-settings__label { flex: 1; font-size: var(--fp-text-sm); }
.account-settings__row > svg:last-child { flex: none; color: var(--fp-text-muted); }

/* Logout: one centered, rounded box — a little breathing room either side
   on mobile instead of running full-width edge to edge like every other
   card on the page, so it visually reads as a deliberate, separate,
   final action rather than just another settings card. */
.account-logout { max-width: 420px; margin-inline: auto; text-align: center; }

/* ---------- Mobile bottom tab bar (noon-style) ------------------------------
   Four items only, fixed under everything else, mobile only (same 900px
   cutoff .fp-header__nav uses to switch to the desktop nav). Lives in
   footer.php but AFTER </footer> closes — position:fixed pulls it out of
   document flow entirely regardless, it is not part of the footer's box.
   #main gets a matching padding-bottom so the last bit of every page's
   content is never hidden behind it, and the WhatsApp float moves up to
   sit above it. !important on the box model/positioning properties here is
   deliberate: this exact component was reported rendering as unstyled
   stacked content (i.e. the CSS not applying) more than once, so the
   properties that make it a fixed horizontal bar are pinned hard rather
   than left to lose a cascade fight with anything else. */
:root { --fp-bottomnav-h: 60px; }

.fp-bottomnav { display: none !important; }

@media (max-width: 899px) {
  #main { padding-bottom: calc(var(--fp-bottomnav-h) + env(safe-area-inset-bottom, 0px)) !important; }

  .fp-float-wa { bottom: calc(var(--fp-bottomnav-h) + var(--fp-space-4) + env(safe-area-inset-bottom, 0px)) !important; }

  .fp-bottomnav {
    display: flex !important;
    flex-direction: row !important;
    align-items: stretch !important;
    justify-content: space-between !important;
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    width: 100% !important;
    z-index: var(--fp-z-header);
    background: var(--fp-bg-surface);
    border-top: var(--fp-border-hair);
    box-shadow: 0 -2px 12px rgba(16, 18, 43, 0.08);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    margin: 0;
  }
  .fp-bottomnav__item {
    flex: 1 1 0 !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 2px;
    min-height: var(--fp-tap-min);
    padding: var(--fp-space-2) var(--fp-space-1);
    background: none;
    border: 0;
    font-family: inherit;
    font-size: var(--fp-text-2xs);
    color: var(--fp-text-muted);
    text-decoration: none;
    position: relative;
  }
  .fp-bottomnav__item:hover { text-decoration: none; }
  .fp-bottomnav__item svg { width: 22px; height: 22px; }
  .fp-bottomnav__item.is-active { color: var(--fp-action-primary); }
  .fp-bottomnav__badge {
    position: absolute;
    top: 2px;
    left: calc(50% + 6px);
    min-width: 16px;
    height: 16px;
    padding-inline: 3px;
    border-radius: var(--fp-radius-pill);
    background: var(--fp-danger-solid);
    color: #fff;
    font-size: 10px;
    font-weight: var(--fp-weight-semibold);
    line-height: 16px;
    text-align: center;
  }
}

/* Product pages swap the bottom nav for .pdp-actionbar (see product.php /
   footer.php's $hideBottomNav flag) — and unlike the bottom nav, this bar
   isn't mobile-only, so its #main/WhatsApp clearance can't live inside the
   max-width:899px block above. body:has() targets exactly the pages where
   the bar exists, at every viewport width; placed after the bottom-nav
   block so it wins the (otherwise equal-specificity, both !important)
   cascade on mobile too. */
body:has(.pdp-actionbar) #main {
  padding-bottom: calc(var(--fp-actionbar-h) + env(safe-area-inset-bottom, 0px)) !important;
}
body:has(.pdp-actionbar) .fp-float-wa {
  bottom: calc(var(--fp-actionbar-h) + var(--fp-space-4) + env(safe-area-inset-bottom, 0px)) !important;
}

/* cart.php's sticky "Place Order" bar STACKS above the bottom nav instead of
   replacing it, so — unlike .pdp-actionbar above — this one only needs the
   extra clearance on the same mobile widths the bottom nav itself is on;
   still has to come after the bottom-nav block above for the same
   equal-specificity/!important cascade reason. :has([data-cart-filled]:not(
   [hidden])) tracks the cart's actual empty/full state live: cart.js flips
   that [hidden] attribute via AJAX (removing the last line) with no page
   reload, and this reacts the same way, so the extra space never lingers
   once the bar itself is gone. */
@media (max-width: 899px) {
  body:has([data-cart-filled]:not([hidden])) #main {
    padding-bottom: calc(var(--fp-bottomnav-h) + var(--fp-cart-bar-h) + env(safe-area-inset-bottom, 0px)) !important;
  }
  body:has([data-cart-filled]:not([hidden])) .fp-float-wa {
    bottom: calc(var(--fp-bottomnav-h) + var(--fp-cart-bar-h) + var(--fp-space-4) + env(safe-area-inset-bottom, 0px)) !important;
  }
}
