/* ==========================================================================
   layout.css, page shells, hero, navigation, containers, utilities
   ========================================================================== */

/* ==========================================================================
   Mobile app shell (customer + shopper)
   ========================================================================== */

.app {
  position: relative;
  width: 100%;
  max-width: var(--shell-max);
  min-height: 100dvh;
  margin: 0 auto;
  background: var(--paper);
  overflow-x: hidden;
}

/* Pages whose content sits on white rather than the paper tint
   (shopper requests feed, onboarding). */

/* Reserve room for the floating chrome so nothing hides behind it. */
.app--has-nav       { padding-bottom: calc(var(--nav-h) + var(--sp-18) + env(safe-area-inset-bottom)); }
.app--has-actionbar { padding-bottom: calc(var(--actionbar-h) + var(--sp-18) + env(safe-area-inset-bottom)); }

/* On a desktop viewport the shell is centred and framed so the mobile
   screens do not float in an ocean of white. */
@media (min-width: 760px) {
  body:not(.page-admin) { background: #EDEDF1; padding: var(--sp-15) 0; }
  body:not(.page-admin) .app {
    min-height: calc(100dvh - var(--sp-17));
    border-radius: var(--r-sheet);
    box-shadow: var(--shadow-raise);
    overflow: hidden;
  }
}

/* ==========================================================================
   Dark hero
   A plain rectangle on every screen. Only the customer home keeps the
   curve (.hero--lg), because its category rail rides along it. The curve
   was dropped elsewhere: it did no work there and cost header height.
   The curve itself is two bottom corner ellipses, with no SVG.
   ========================================================================== */

.hero {
  position: relative;
  z-index: var(--z-hero);
  padding: calc(var(--sp-17) + env(safe-area-inset-top)) var(--page-x) var(--sp-12);
  background: var(--ink);
}

/* Shorter hero: titles, chat, search. */
.hero--sm { padding-bottom: var(--sp-10); }

/* Taller, curved hero: the customer home only, where the category rail
   rides the curve. Frame 1 uses `Q 201 283 402 187`, depth 48. */
.hero--lg {
  --hero-curve: 48px;
  padding-bottom: var(--sp-18);
  border-bottom-left-radius: 50% var(--hero-curve);
  border-bottom-right-radius: 50% var(--hero-curve);
}

/* Kept for the profile screens, which have their own scalloped divider. */
.hero--flat { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

.hero__bar {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  min-height: var(--icon-btn);
}

.hero__back,
.hero__action {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--icon-btn);
  height: var(--icon-btn);
  border-radius: var(--r-full);
  background: var(--on-dark-fill);
  color: var(--on-dark);
  transition: background var(--dur-fast) var(--ease);
}
.hero__back:hover,
.hero__action:hover { background: var(--on-dark-fill-2); opacity: 1; }

.hero__titles { flex: 1; min-width: 0; }

.hero__title {
  color: var(--on-dark);
  font-size: var(--fs-h2);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-h2);
}

.hero__sub {
  margin-top: var(--sp-1);
  color: var(--on-dark-soft);
  font-size: var(--fs-chip);
}

.hero__link {
  flex-shrink: 0;
  color: var(--on-dark-mid);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
}

/* Content that overlaps the hero curve (search bar, filter chips). */
.hero__row { margin-top: var(--sp-9); }

/* A card that straddles the hero edge. */
.hero__float {
  position: relative;
  z-index: 4;
  margin: calc(var(--sp-9) * -1) var(--page-x) 0;
}

/* ==========================================================================
   Page body
   ========================================================================== */

.page {
  padding: var(--sp-9) var(--page-x) var(--sp-14);
}

.page--flush { padding-inline: 0; }
.page--tight { padding-top: var(--sp-4); }

.section { margin-top: var(--sp-15); }
.section:first-child { margin-top: 0; }

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-6);
  margin-bottom: var(--sp-7);
}

.section__title {
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  letter-spacing: -0.2px;
}

.section__title--lg { font-size: var(--fs-h2); letter-spacing: var(--ls-h2); }

.section__link { color: var(--violet); font-size: var(--fs-chip); font-weight: var(--fw-semi); }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.stack { display: flex; flex-direction: column; gap: var(--gap-stack); }
.stack--sm  { gap: var(--sp-6); }
.stack--xs  { gap: var(--sp-4); }
.stack--lg  { gap: var(--sp-15); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-inline);
}
.cluster--sm    { gap: var(--sp-4); }
.cluster--tight { flex-wrap: nowrap; }
.cluster--between { justify-content: space-between; flex-wrap: nowrap; }

.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-stack); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-stack); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-7); }

/* Horizontal rail, category carousel, chip rows, listing carousels.
   Bleeds to the screen edge and hides its scrollbar, as in the frames. */
.scroller {
  display: flex;
  gap: var(--sp-9);
  margin-inline: calc(var(--page-x) * -1);
  padding-inline: var(--page-x);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.scroller::-webkit-scrollbar { display: none; }
.scroller > * { flex-shrink: 0; scroll-snap-align: start; }

.scroller--wide { margin-inline: calc(var(--page-x-wide) * -1); padding-inline: var(--page-x-wide); }
.scroller--chips { gap: var(--sp-5); }

.spacer { flex: 1; }

/* ==========================================================================
   Floating bottom navigation (customer + shopper)
   ========================================================================== */

.bottom-nav {
  position: fixed;
  bottom: calc(var(--sp-15) + env(safe-area-inset-bottom));
  left: 50%;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  justify-content: space-around;
  width: min(340px, calc(100% - 40px));
  max-width: calc(var(--shell-max) - 40px);
  height: var(--nav-h);
  padding: 0 var(--sp-4);
  border-radius: var(--r-nav);
  background: var(--panel);
  box-shadow: var(--shadow-float);
  transform: translateX(-50%);
}

.bottom-nav__item {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  color: var(--text-disabled);
  transition: color var(--dur-fast) var(--ease);
}

.bottom-nav__item:hover { color: var(--text-body); opacity: 1; }

/* A count of what is waiting behind a tab, like the cart badge: pending
   jobs, quotes to answer, unread messages. Sits on the icon's top right. */
.bottom-nav__item { position: relative; }
.bottom-nav__badge {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: 6px;
  pointer-events: none;
}

.bottom-nav__item[aria-current='page'] { color: var(--text); }

/* The violet pill stays on the icon alone, so the label underneath reads
   as a caption rather than being swallowed by the active state. */
.bottom-nav__item .icon {
  width: 38px;
  height: 38px;
  padding: 8px;
  border-radius: var(--r-full);
  transition: background var(--dur-fast) var(--ease);
}

.bottom-nav__item[aria-current='page'] .icon { background: var(--violet-nav); }

.bottom-nav__label {
  font-size: 10px;
  font-weight: var(--fw-semi);
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.bottom-nav__badge {
  position: absolute;
  top: 8px;
  right: 8px;
}

/* ==========================================================================
   Floating action bar, the "label + primary button" pill
   ========================================================================== */

.actionbar {
  position: fixed;
  bottom: calc(var(--sp-13) + env(safe-area-inset-bottom));
  left: 50%;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  width: min(calc(100% - 40px), calc(var(--shell-max) - 40px));
  min-height: var(--actionbar-h);
  padding: 0 var(--sp-6) 0 var(--sp-13);
  border-radius: 35px;
  background: var(--panel);
  box-shadow: var(--shadow-float);
  transform: translateX(-50%);
}

.actionbar__meta { flex: 1; min-width: 0; }
.actionbar__label { color: var(--text-soft); font-size: var(--fs-meta); }
.actionbar__value { color: var(--text); font-size: var(--fs-body); font-weight: var(--fw-bold); }

.actionbar .btn { flex-shrink: 0; }

/* Composer variant, tighter padding for the chat input row. */
.actionbar--composer { min-height: 66px; padding: 0 var(--sp-4); }

/* Stacked variant, two full-width buttons (accept / decline). */
.actionbar--stack {
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-6);
  padding: var(--sp-8);
  border-radius: var(--r-sheet);
}

/* ==========================================================================
   Auth screens, no hero, centred content
   ========================================================================== */

.auth {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  padding: calc(var(--sp-18) + env(safe-area-inset-top)) var(--page-x-wide)
           calc(var(--sp-18) + env(safe-area-inset-bottom));
}

.auth__head { margin-bottom: var(--sp-15); }
.auth__title { font-size: var(--fs-display); font-weight: var(--fw-black); letter-spacing: var(--ls-display); }
.auth__sub { margin-top: var(--sp-3); color: var(--text-soft); font-size: var(--fs-body); line-height: var(--lh-normal); }
.auth__foot { margin-top: auto; padding-top: var(--sp-14); text-align: center; font-size: var(--fs-chip); color: var(--text-body); }

/* Onboarding slides */
.slides { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
.slides::-webkit-scrollbar { display: none; }
.slide { flex: 0 0 100%; scroll-snap-align: center; }

.dots { display: flex; justify-content: center; gap: var(--sp-3); }
.dots__dot {
  width: 7px; height: 7px;
  border-radius: var(--r-full);
  background: var(--line-input);
  transition: width var(--dur) var(--ease), background var(--dur) var(--ease);
}
.dots__dot.is-active { width: 22px; background: var(--violet); }
/* ==========================================================================
   Admin
   --------------------------------------------------------------------------
   Admin is mobile, like the rest of the app. The 2026-09-02 frame set labels
   it "Phase 1A, mobile first" and draws every admin screen at 402x874 with a
   five-item bottom nav, so it uses the same .app shell, .hero and
   .bottom-nav as customer and shopper. The desktop sidebar that used to live
   here is gone, along with components/admin-sidebar.html.
   ========================================================================== */

/* A count sitting against a queue heading, e.g. "Pending 5". */
.queue-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 var(--sp-3);
  margin-left: var(--sp-3);
  border-radius: var(--r-full);
  background: var(--violet);
  color: var(--on-dark);
  font-size: var(--fs-micro);
  font-weight: var(--fw-black);
}
