/* ==========================================================================
   Waraqat Shajar — global stylesheet
   Design tokens ported verbatim from src/styles/globals.css (Tailwind v4
   source). Semantic component classes translated from src/components/ui.tsx
   + src/lib/button-variants.ts Tailwind strings.
   ========================================================================== */

:root {
  color-scheme: light;
  --background: #ffffff;
  --foreground: #1a1a1a;
  --card: #ffffff;
  --card-foreground: #1a1a1a;
  --popover: #ffffff;
  --popover-foreground: #1a1a1a;
  --primary: #2e7d32;
  --primary-foreground: #ffffff;
  --secondary: #eaf3ea;
  --secondary-foreground: #1b5e20;
  --muted: #f7f9f5;
  --muted-foreground: #5b6b5e;
  --accent: #e8f5e9;
  --accent-foreground: #1b5e20;
  --destructive: oklch(0.577 0.245 27.325);
  --destructive-tint: rgba(220, 38, 38, 0.1);
  --border: #e3e8e1;
  --input: #e3e8e1;
  --ring: #2e7d32;

  --brand: #2e7d32;
  --brand-dark: #1b5e20;
  --brand-light: #66bb6a;
  --brand-tint: #f7f9f5;
  --rating: #f5a623;

  /* Categorical chart palette for the 4 account roles — validated for CVD
     separation, lightness band, and contrast (dataviz skill validator). */
  --chart-role-farmer: #2e7d32;
  --chart-role-trader: #1976d2;
  --chart-role-factory: #d97706;
  --chart-role-consumer: #7c3aed;

  --radius: 0.75rem;
  --radius-sm: calc(var(--radius) * 0.6);
  --radius-md: calc(var(--radius) * 0.8);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) * 1.4);
  --radius-2xl: calc(var(--radius) * 1.8);
  --radius-3xl: calc(var(--radius) * 2.2);
  --radius-4xl: calc(var(--radius) * 2.6);

  --font-cairo: "Cairo", sans-serif;
  --font-inter: "Inter", sans-serif;
  --font-sans: var(--font-cairo);
}

.dark {
  /* A <select>'s open options list (and other native chrome -- scrollbars,
     date pickers) is rendered by the OS/browser, not by our CSS -- without
     this, it stayed stark white with a generic blue highlight even in dark
     mode, clashing hard against every other themed element on the page.
     color-scheme tells the browser which palette to draw that native chrome
     in, so it approximately follows dark mode automatically -- no
     per-control styling of the open list is otherwise possible. */
  color-scheme: dark;
  --background: #10150f;
  --foreground: #eef2ec;
  --card: #171d15;
  --card-foreground: #eef2ec;
  --popover: #171d15;
  --popover-foreground: #eef2ec;
  --primary: #66bb6a;
  --primary-foreground: #10150f;
  --secondary: #1e2a1c;
  --secondary-foreground: #a5d6a7;
  --muted: #1e2a1c;
  --muted-foreground: #93a394;
  --accent: #24331f;
  --accent-foreground: #a5d6a7;
  --destructive: oklch(0.704 0.191 22.216);
  --destructive-tint: rgba(220, 38, 38, 0.2);
  --border: #2a362678;
  --input: #2a362678;
  --ring: #66bb6a;

  --brand: #66bb6a;
  --brand-dark: #2e7d32;
  --brand-light: #a5d6a7;
  --brand-tint: #171d15;
  --rating: #f5a623;

  --chart-role-farmer: #43a047;
  --chart-role-trader: #1e88e5;
  --chart-role-factory: #e65100;
  --chart-role-consumer: #7e57c2;
}

/* ---------------------------------------------------------------------- */
/* Reset & base                                                            */
/* ---------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  overflow-x: hidden;
}

body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  display: flex;
  min-height: 100%;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

h1,
h2,
h3,
h4,
p,
dl,
dd {
  margin: 0;
}

svg {
  display: block;
  width: 1.15em;
  height: 1.15em;
  flex-shrink: 0;
}

[dir="rtl"] .force-ltr,
.force-ltr {
  direction: ltr;
  unicode-bidi: isolate;
  text-align: end;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------- */
/* Layout primitives                                                       */
/* ---------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: 1280px;
  min-width: 0;
  margin-inline: auto;
  padding-inline: 1rem;
  box-sizing: border-box;
}

@media (min-width: 640px) {
  .container {
    padding-inline: 1.5rem;
  }
}

@media (min-width: 1024px) {
  .container {
    padding-inline: 2rem;
  }
}

main {
  flex: 1;
}

/* ---------------------------------------------------------------------- */
/* Typography                                                              */
/* ---------------------------------------------------------------------- */
.heading {
  font-family: var(--font-sans);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.text-muted {
  color: var(--muted-foreground);
}

.text-primary {
  color: var(--primary);
}

/* ---------------------------------------------------------------------- */
/* Buttons                                                                 */
/* ---------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: 2rem;
  padding-inline: 0.65rem;
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.15s, color 0.15s, border-color 0.15s, transform 0.1s;
  background: transparent;
  color: var(--foreground);
  text-decoration: none;
  user-select: none;
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled {
  pointer-events: none;
  opacity: 0.5;
}

.btn svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  pointer-events: none;
}

.btn-default,
.btn-primary {
  background: var(--primary);
  color: var(--primary-foreground);
}
.btn-default:hover,
.btn-primary:hover {
  background: color-mix(in srgb, var(--primary) 80%, transparent);
}

.btn-outline {
  border-color: var(--border);
  background: var(--background);
}
.btn-outline:hover {
  background: var(--muted);
}

.btn-secondary {
  background: var(--secondary);
  color: var(--secondary-foreground);
}
.btn-secondary:hover {
  background: color-mix(in srgb, var(--secondary) 90%, var(--foreground) 5%);
}

.btn-ghost:hover {
  background: var(--muted);
}

.btn-destructive {
  background: var(--destructive-tint);
  color: var(--destructive);
}
.btn-destructive:hover {
  background: color-mix(in srgb, var(--destructive) 20%, transparent);
}

.btn-link {
  color: var(--primary);
  text-underline-offset: 4px;
}
.btn-link:hover {
  text-decoration: underline;
}

.btn-sm {
  height: 1.75rem;
  padding-inline: 0.6rem;
  font-size: 0.8rem;
  border-radius: min(var(--radius-md), 12px);
}

.btn-lg {
  height: 2.25rem;
  padding-inline: 0.65rem;
}

.btn-icon {
  width: 2rem;
  height: 2rem;
  padding: 0;
}

/* Hidden by default (no flash of a button that most visitors never get to
   use) -- js/layout.js's wireThemeToggle only adds .is-visible once
   authState.isAdmin is confirmed true. Regular visitors are locked to
   light mode sitewide (see js/state.js's applyDarkMode); only an admin
   account keeps any control over it at all. */
#theme-toggle {
  display: none;
}

#theme-toggle.is-visible {
  display: inline-flex;
}

.btn-icon-sm {
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border-radius: min(var(--radius-md), 12px);
}

/* ---------------------------------------------------------------------- */
/* Inputs / Textarea / Select / Label / Checkbox / Radio                  */
/* ---------------------------------------------------------------------- */
.label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1;
  user-select: none;
  margin-bottom: 0.375rem;
}

.input,
.textarea,
.select {
  width: 100%;
  min-width: 0;
  height: 2rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--input);
  background: transparent;
  padding-inline: 0.65rem;
  padding-block: 0.25rem;
  font-size: 0.9rem;
  color: var(--foreground);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
  font-family: inherit;
}

.textarea {
  height: auto;
  min-height: 4rem;
  padding-block: 0.5rem;
  resize: vertical;
}

.select {
  cursor: pointer;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--muted-foreground);
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
  border-color: var(--ring);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 50%, transparent);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.field-error {
  color: var(--destructive);
  font-size: 0.8rem;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 400;
}

.checkbox-row input[type="checkbox"],
.checkbox-row input[type="radio"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
  cursor: pointer;
}

/* ---------------------------------------------------------------------- */
/* Badge                                                                   */
/* ---------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  height: 1.25rem;
  padding-inline: 0.5rem;
  border-radius: var(--radius-4xl);
  border: 1px solid transparent;
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
  background: var(--primary);
  color: var(--primary-foreground);
}

.badge-secondary {
  background: var(--secondary);
  color: var(--secondary-foreground);
}

.badge-outline {
  background: transparent;
  border-color: var(--border);
  color: var(--foreground);
}

.badge-destructive {
  background: var(--destructive-tint);
  color: var(--destructive);
}

/* ---------------------------------------------------------------------- */
/* Avatar                                                                  */
/* ---------------------------------------------------------------------- */
.avatar {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  overflow: hidden;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.875rem;
  font-weight: 600;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px var(--border);
}

.avatar-lg {
  width: 2.5rem;
  height: 2.5rem;
  font-size: 1rem;
}

.avatar-xl {
  width: 4.5rem;
  height: 4.5rem;
  font-size: 1.35rem;
}

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

/* ---------------------------------------------------------------------- */
/* Card                                                                    */
/* ---------------------------------------------------------------------- */
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--card);
  color: var(--card-foreground);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent);
  padding: 1rem;
}

.card-flush {
  padding: 0;
}

.card-header {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.card-title {
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
}

.card-description {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.card-footer {
  display: flex;
  align-items: center;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--muted) 50%, transparent);
  padding: 1rem;
  margin: 1rem -1rem -1rem;
  border-bottom-left-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xl);
}

/* ---------------------------------------------------------------------- */
/* Separator                                                               */
/* ---------------------------------------------------------------------- */
.separator {
  border: none;
  background: var(--border);
  height: 1px;
  width: 100%;
}

/* ---------------------------------------------------------------------- */
/* Dialog / Dropdown (hand-rolled, no headless UI library)                 */
/* ---------------------------------------------------------------------- */
.dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(0, 0, 0, 0.4);
  display: none;
}

.dialog-overlay.is-open {
  display: block;
}

.dialog-content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 51;
  width: calc(100% - 2rem);
  max-width: 26rem;
  max-height: 85vh;
  overflow-y: auto;
  display: none;
  flex-direction: column;
  gap: 1rem;
  border-radius: var(--radius-xl);
  background: var(--popover);
  color: var(--popover-foreground);
  padding: 1rem;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25), inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent);
}

.dialog-content.is-open {
  display: flex;
}

.dialog-close {
  position: absolute;
  top: 0.5rem;
  inset-inline-end: 0.5rem;
}

.dialog-header {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.dialog-title {
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 600;
}

.dialog-description {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.dialog-footer {
  display: flex;
  flex-direction: column-reverse;
  gap: 0.5rem;
  margin: 0 -1rem -1rem;
  padding: 1rem;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--muted) 50%, transparent);
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}

@media (min-width: 640px) {
  .dialog-footer {
    flex-direction: row;
    justify-content: flex-end;
  }
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  position: absolute;
  inset-inline-start: 0;
  top: calc(100% + 4px);
  z-index: 50;
  min-width: 12rem;
  max-width: calc(100vw - 2rem);
  border-radius: var(--radius-lg);
  background: var(--popover);
  color: var(--popover-foreground);
  padding: 0.25rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15), inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent);
  display: none;
}

/* On narrow viewports the account trigger sits at the very edge of the
   header cluster with no room to its inline-start side, so anchoring there
   (the desktop-safe default above) pushes most of the menu off-screen —
   anchor from the opposite edge instead so it opens back onto the page. */
@media (max-width: 639px) {
  .dropdown-content {
    inset-inline-start: auto;
    inset-inline-end: 0;
  }
}

.dropdown-content.is-open {
  display: block;
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  background: none;
  border: none;
  text-align: start;
  cursor: pointer;
  color: inherit;
}

.dropdown-item:hover {
  background: var(--muted);
}

.dropdown-item-destructive {
  color: var(--destructive);
}
.dropdown-item-destructive:hover {
  background: var(--destructive-tint);
}

.dropdown-separator {
  height: 1px;
  background: var(--border);
  margin: 0.25rem 0;
}

/* "Where do I go" menu (js/ui.js's locationMenuHTML) -- a plain .dropdown,
   just with its trigger allowed to wrap onto a second line (addresses run
   long) and its own items tinted green on hover instead of the generic
   neutral gray, so picking an actual navigation option reads as the
   brand-colored action it is. */
.location-menu .btn {
  white-space: normal;
  text-align: start;
  line-height: 1.3;
}
.location-menu .dropdown-item:hover {
  background: var(--accent);
  color: var(--accent-foreground);
}

/* ---------------------------------------------------------------------- */
/* Custom select popup (js/ui.js's enhanceSelect) -- a real <select>'s open
   options list is drawn by the OS/browser, not by this stylesheet, so it
   always renders as stark light-mode native chrome no matter the site's
   theme. This is a themed replacement popup shown instead; the real
   <select> underneath stays in the DOM (still what every page's own JS
   reads/writes) and still supplies its own closed-state appearance, which
   the .select rule above already themes correctly. */
.select-popup {
  position: fixed;
  z-index: 300;
  max-height: 16rem;
  overflow-y: auto;
  border-radius: var(--radius-lg);
  background: var(--popover);
  color: var(--popover-foreground);
  padding: 0.25rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15), inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent);
}

.select-popup-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  background: none;
  border: none;
  text-align: start;
  cursor: pointer;
  color: inherit;
}

.select-popup-option:hover,
.select-popup-option.is-active {
  background: var(--muted);
}

.select-popup-option.is-selected {
  background: var(--accent);
  color: var(--accent-foreground);
}

.select-popup-option svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  visibility: hidden;
}

.select-popup-option.is-selected svg {
  visibility: visible;
}

/* ---------------------------------------------------------------------- */
/* Header                                                                  */
/* ---------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--background) 95%, transparent);
  backdrop-filter: blur(8px);
}

.site-header-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: 0.75rem;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.logo img {
  height: 2rem;
  width: auto;
}

.logo-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.logo-wordmark {
  font-family: var(--font-sans);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.logo-tagline {
  display: none;
  font-size: 0.7rem;
  color: var(--muted-foreground);
}

@media (min-width: 480px) {
  .logo-tagline {
    display: block;
  }
}

.header-search {
  position: relative;
  flex: 1;
  display: block;
}

.header-search svg {
  position: absolute;
  inset-inline-start: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1rem;
  height: 1rem;
  color: var(--muted-foreground);
}

.header-search input {
  border-radius: 999px;
  padding-inline-start: 2.25rem;
}

/* Used to be display:none below 640px entirely (no way to search at all
   on a phone) -- collapses to a compact round icon button "on the side" of
   the header instead (matching the cart/wishlist/theme icons already
   there), per the user's own request, and expands into a real full-width
   input on tap rather than trying to cram flex:1 in among an already-tight
   mobile icon cluster. See wireHeaderSearch() in layout.js for the
   tap-to-expand toggle. */
@media (max-width: 639px) {
  .header-search {
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 999px;
  }
  .header-search:hover {
    background: var(--muted);
  }
  .header-search input {
    width: 2.25rem;
    height: 2.25rem;
    padding-inline-start: 2.25rem;
    padding-inline-end: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    transition: width 0.2s ease;
  }
  .header-search.is-expanded {
    position: absolute;
    top: 100%;
    inset-inline: 0.75rem;
    margin-top: 0.4rem;
    width: auto;
    height: auto;
    z-index: 30;
    background: var(--card);
    border-radius: var(--radius-lg);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
    padding: 0.35rem;
  }
  .header-search.is-expanded input {
    width: 100%;
    height: 2.25rem;
    background: var(--muted);
    cursor: text;
  }
}

.header-actions {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

/* On narrow phones the icon cluster (theme/lang/cart/wishlist) can need more
   room than the viewport has, so it scrolls internally rather than pushing
   off-screen. This wrapper is deliberately separate from #header-auth-area:
   overflow-x here forces overflow-y to auto too (CSS spec), which would
   clip the account dropdown menu if it lived in the same clipped box. */
.header-actions-scroll {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.header-actions-scroll::-webkit-scrollbar {
  display: none;
}

.header-login-link {
  display: none;
}

@media (min-width: 640px) {
  .header-login-link {
    display: inline-flex;
  }
}

.icon-badge {
  position: relative;
}

.icon-badge-count {
  position: absolute;
  top: -0.25rem;
  inset-inline-end: -0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1rem;
  min-width: 1rem;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 0.6rem;
  font-weight: 600;
  padding-inline: 0.2rem;
}

/* ---------------------------------------------------------------------- */
/* Footer                                                                  */
/* ---------------------------------------------------------------------- */
.site-footer {
  position: relative;
  background: #10150f;
  color: #eef2ec;
  overflow: hidden;
  flex-shrink: 0;
}

.site-footer::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("images/footer-wave.jpg");
  background-size: cover;
  background-position: center;
  opacity: 0.15;
}

.footer-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem;
  padding-block: 3rem;
}

@media (min-width: 768px) {
  .footer-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.footer-col-brand {
  grid-column: span 2;
}

@media (min-width: 768px) {
  .footer-col-brand {
    grid-column: span 1;
  }
}

.footer-heading {
  font-size: 0.875rem;
  font-weight: 600;
  color: #a5d6a7;
  margin-bottom: 0.75rem;
}

.footer-list li {
  font-size: 0.875rem;
  color: #c9d6c8;
  padding-block: 0.2rem;
}

.footer-phone {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.75rem;
  font-size: 0.875rem;
  color: #c9d6c8;
}

.footer-bottom {
  position: relative;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-block: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: space-between;
  font-size: 0.75rem;
  color: #93a394;
}

/* ---------------------------------------------------------------------- */
/* Splash screen                                                          */
/* ---------------------------------------------------------------------- */
.splash-screen {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  background: var(--background);
  opacity: 1;
  transition: opacity 400ms ease;
}

.splash-screen.is-fading {
  opacity: 0;
}

.splash-screen.is-hidden {
  display: none;
}

.splash-logo {
  height: 4rem;
  width: auto;
  animation: pulse 1.6s ease-in-out infinite;
}

.splash-wordmark {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 700;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

/* Deep-link landing (cart.html?order=.../dashboard-orders.html?order=...
   from a WhatsApp confirmation message -- see ui.js's
   scrollToAndHighlightOrder) -- a brief themed glow so the specific row
   the link promised to show is obviously the one that just got scrolled
   to, not just "somewhere in this list." */
@keyframes order-highlight {
  0%,
  100% {
    box-shadow: none;
  }
  15%,
  85% {
    box-shadow: 0 0 0 2px var(--ring), 0 0 24px color-mix(in srgb, var(--ring) 45%, transparent);
  }
}

.is-order-highlighted {
  animation: order-highlight 3s ease-in-out;
  border-radius: var(--radius-lg);
}

/* ---------------------------------------------------------------------- */
/* Hero / carousel                                                        */
/* ---------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  color: white;
}

.hero-slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  /* Not dead-center on purpose. This banner's own box is far wider than it
     is tall (full viewport width, but a height only as tall as the text
     content needs -- at a big desktop window this ratio gets extreme), so
     background-size:cover crops hard off the top and bottom of whatever
     photo is behind it. Every hero photo used here (admin-uploaded,
     js/pages/home.js's loadSiteImages) is a person shot with their face in
     the upper third to upper half of the frame, never the bottom -- a
     dead-center crop was cutting straight through the top of their head at
     wide/short viewport ratios (reported live, e.g. 1920x1080 at 100% page
     zoom). Biasing toward the top keeps the face in frame across every
     current hero photo and viewport width tested, at the cost of cropping
     a bit more off the bottom (background scenery, not a subject).
  */
  background-position: center 15%;
  opacity: 0;
  transition: opacity 1s ease;
}

.hero-slide.is-active {
  opacity: 1;
}

.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(27, 94, 32, 0.8), rgba(27, 94, 32, 0.3) 60%, transparent);
}

.hero-overlay-flat {
  position: absolute;
  inset: 0;
  background: rgba(27, 94, 32, 0.5);
}

.hero-content {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  text-align: center;
  padding-block: 3rem;
}

@media (min-width: 640px) {
  .hero-content {
    padding-block: 5rem;
  }
}

.hero-badge {
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.15);
  padding: 0.4rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  backdrop-filter: blur(4px);
}

.hero-headline {
  max-width: 48rem;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 1.9rem;
  line-height: 1.15;
}

@media (min-width: 640px) {
  .hero-headline {
    font-size: 2.5rem;
  }
}

@media (min-width: 1024px) {
  .hero-headline {
    font-size: 3rem;
  }
}

.hero-sub {
  max-width: 42rem;
  color: rgba(255, 255, 255, 0.9);
}

.hero-cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
}

.hero-roles {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.9);
}

.hero-role-pill {
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
}

.hero-stats {
  margin-top: 1rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

@media (min-width: 640px) {
  .hero-stats {
    gap: 2rem;
  }
}

.hero-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--radius-xl);
  background: rgba(255, 255, 255, 0.1);
  padding: 0.6rem 0.5rem;
  backdrop-filter: blur(4px);
}

@media (min-width: 640px) {
  .hero-stat {
    padding: 0.75rem 1.25rem;
  }
}

.hero-stat svg {
  width: 1.25rem;
  height: 1.25rem;
}

.hero-stat-value {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 1.15rem;
}

.hero-stat-label {
  font-size: 0.7rem;
  text-align: center;
  color: rgba(255, 255, 255, 0.8);
}

.hero-dots {
  position: absolute;
  z-index: 10;
  inset-inline: 0;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
}

.hero-dot {
  height: 0.375rem;
  width: 0.375rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.5);
  border: none;
  padding: 0;
  cursor: pointer;
}

.hero-dot.is-active {
  width: 1.5rem;
  background: white;
}

.hero-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  /* Resting state is a near-invisible chevron, not a persistent glass
     button -- per the user's own design reference, the arrows should read
     as "subtle, clean hover-state micro-indicators", only really
     announcing themselves once you're actually looking at the hero (the
     .hero:hover rule below), not sitting there as a constant UI element. */
  background: transparent;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  opacity: 0.5;
  transition: opacity 0.25s ease, background 0.25s ease;
}

.hero:hover .hero-arrow {
  opacity: 1;
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(4px);
}

.hero-arrow:hover {
  background: rgba(255, 255, 255, 0.3);
}

.hero-arrow svg {
  width: 1.1rem;
  height: 1.1rem;
}

.hero-arrow-prev {
  inset-inline-start: 0.75rem;
}

/* inset-inline-start/end flip sides in this RTL site (start = right,
   end = left) but these are spatial navigation arrows, not text -- the
   left-positioned arrow should always point left and the right-positioned
   one right, regardless of reading direction. So the rotation has to be
   the opposite of what the "prev"/"next" naming alone would suggest. */
.hero-arrow-prev svg {
  transform: rotate(-90deg);
}

.hero-arrow-next {
  inset-inline-end: 0.75rem;
}

.hero-arrow-next svg {
  transform: rotate(90deg);
}

@media (min-width: 640px) {
  .hero-arrow {
    width: 2.75rem;
    height: 2.75rem;
  }

  .hero-arrow-prev {
    inset-inline-start: 1.25rem;
  }

  .hero-arrow-next {
    inset-inline-end: 1.25rem;
  }
}

/* ---------------------------------------------------------------------- */
/* About page                                                              */
/* ---------------------------------------------------------------------- */
.about-hero {
  background-size: cover;
  background-position: center;
}

.about-logo-badge {
  width: 5rem;
  height: 5rem;
  border-radius: 999px;
  background: white;
  padding: 0.85rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  display: flex;
  align-items: center;
  justify-content: center;
}

.about-logo-badge img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.about-mission-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: center;
}

@media (min-width: 768px) {
  .about-mission-grid {
    grid-template-columns: 3fr 2fr;
  }
}

.about-mission-body {
  margin-top: 1rem;
  color: var(--muted-foreground);
  line-height: 1.8;
}

.about-mission-image {
  border-radius: var(--radius-xl);
  overflow: hidden;
  aspect-ratio: 4 / 3;
}

.about-mission-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about-steps-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 640px) {
  .about-steps-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .about-steps-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.about-step-card {
  position: relative;
  padding: 1.5rem 1.25rem;
}

.about-step-number {
  position: absolute;
  top: 1rem;
  inset-inline-end: 1.25rem;
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--border);
}

/* ---------------------------------------------------------------------- */
/* Ad slot                                                                 */
/* ---------------------------------------------------------------------- */
.ad-slot {
  display: block;
  margin-inline: auto;
  width: 100%;
  overflow: hidden;
  border-radius: var(--radius-lg);
}

.ad-slot-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--border);
  background: color-mix(in srgb, var(--muted) 50%, transparent);
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* Skyscraper ads flanking the main content on wide screens — no room for
   these on mobile, so they're hidden below the lg breakpoint entirely. */
.page-with-sidebars {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
  justify-content: center;
}

.page-main-content {
  flex: 1;
  min-width: 0;
  max-width: 1280px;
  padding-inline: 1rem;
}

@media (min-width: 640px) {
  .page-main-content {
    padding-inline: 1.5rem;
  }
}

.ad-skyscraper {
  display: none;
  flex-shrink: 0;
  position: sticky;
  top: 5rem;
}

@media (min-width: 1024px) {
  .ad-skyscraper {
    display: block;
    width: 160px;
  }
}

/* ---------------------------------------------------------------------- */
/* Section headers                                                        */
/* ---------------------------------------------------------------------- */
.section {
  padding-block: 3rem;
}

.section-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 1.5rem;
  gap: 1rem;
}

.section-title {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 700;
}

.section-subtitle {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

/* Used to be a bare text link, hidden entirely below 640px (no way to get
   to e.g. the full farmers directory from the homepage's own "Discover
   farmers" section on a phone at all) -- a real pill button now, visible
   on every viewport, per the user's own request for something clearly
   tappable rather than a subtle line of colored text easy to miss. */
.section-link {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--primary);
  border: 1px solid var(--primary);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  white-space: nowrap;
}

.section-link:hover {
  background: var(--accent);
}

/* ---------------------------------------------------------------------- */
/* Trust badges                                                           */
/* ---------------------------------------------------------------------- */
.trust-grid {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--border);
}

.trust-grid::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("images/leaf-pattern-bg.jpg");
  background-repeat: repeat;
  background-size: 420px;
  opacity: 0.05;
  pointer-events: none;
}

.trust-grid-inner {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
  padding-block: 2rem;
}

@media (min-width: 1024px) {
  .trust-grid-inner {
    grid-template-columns: repeat(4, 1fr);
  }
}

.trust-item {
  display: flex;
  align-items: center;
  /* Centered, not left stuck-to-the-grid-column-edge -- on a wide desktop
     viewport each of the 4 grid columns is easily 400-500px, and the
     icon+text pair here (compact, non-growing content) used to just sit at
     the flex-start end of that with the leftover few hundred px of empty
     column dumped entirely on one side -- read as a big awkward gap
     between items rather than one evenly laid-out row. */
  justify-content: center;
  gap: 0.75rem;
}

.trust-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
}

.trust-icon svg {
  width: 1.15rem;
  height: 1.15rem;
}

.trust-title {
  font-size: 0.875rem;
  font-weight: 600;
}

.trust-subtitle {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* ---------------------------------------------------------------------- */
/* Category grid                                                          */
/* ---------------------------------------------------------------------- */
.category-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}

@media (min-width: 640px) {
  .category-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1024px) {
  .category-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.category-card {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-xl);
  overflow: hidden;
}

.category-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.category-card:hover img {
  transform: scale(1.05);
}

.category-card-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(27, 94, 32, 0.8), transparent 60%);
}

.category-card-label {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: 0.75rem;
  color: white;
}

.category-card-name {
  font-family: var(--font-sans);
  font-weight: 600;
}

.category-card-hint {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.8);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.category-card:hover .category-card-hint {
  opacity: 1;
}

/* ---------------------------------------------------------------------- */
/* Product grid / card                                                    */
/* ---------------------------------------------------------------------- */
.product-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}

@media (min-width: 640px) {
  .product-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .product-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.product-card {
  display: block;
}

.product-card-media {
  position: relative;
  aspect-ratio: 4 / 3;
  width: 100%;
  background: var(--muted);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  overflow: hidden;
}

.product-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.product-card-body {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.75rem 1rem 1rem;
}

.product-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.product-card-title {
  font-family: var(--font-sans);
  font-weight: 600;
}

.product-card-rating {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.875rem;
}

.product-card-rating svg {
  width: 0.9rem;
  height: 0.9rem;
  fill: var(--rating);
  color: var(--rating);
}

/* admin-users.html's per-farmer "feature on homepage" toggle -- filled amber
   once a farmer is featured, matching the star-rating color language used
   everywhere else on the site rather than a second one-off color. */
.is-featured-star {
  fill: var(--rating);
  color: var(--rating);
}

.product-card-gov {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.product-card-price {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--primary);
}

.favorite-btn {
  position: absolute;
  top: 0.5rem;
  inset-inline-end: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--background) 90%, transparent);
  border: none;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

.favorite-btn svg {
  width: 1rem;
  height: 1rem;
  color: var(--foreground);
}

.favorite-btn.is-static {
  position: static;
  width: auto;
  height: auto;
  padding: 0.4rem 0.6rem;
  gap: 0.3rem;
}

.favorite-btn.is-active svg {
  fill: var(--destructive);
  color: var(--destructive);
}

.favorite-count {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--foreground);
}

/* ---------------------------------------------------------------------- */
/* CTA banner                                                              */
/* ---------------------------------------------------------------------- */
.cta-banner {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-2xl);
  background: var(--primary);
  padding: 2.5rem 1.5rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

@media (min-width: 768px) {
  .cta-banner {
    flex-direction: row;
    text-align: start;
    padding-inline: 2.5rem;
  }
}

.cta-banner-bg {
  position: absolute;
  inset: 0;
  background-image: url("images/cta-sunrise.jpg");
  background-size: cover;
  background-position: center;
  opacity: 0.25;
}

.cta-banner-gradient {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--primary), color-mix(in srgb, var(--primary) 85%, transparent) 60%, color-mix(in srgb, var(--primary) 70%, transparent));
}

.cta-banner-text {
  position: relative;
}

.cta-banner-title {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 700;
  color: white;
}

.cta-banner-subtitle {
  margin-top: 0.5rem;
  max-width: 36rem;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.9);
}

.cta-banner-actions {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  flex-shrink: 0;
}

.btn-on-brand {
  background: white;
  color: var(--primary);
}
.btn-on-brand:hover {
  background: rgba(255, 255, 255, 0.9);
}

.btn-outline-on-brand {
  border-color: rgba(255, 255, 255, 0.6);
  background: transparent;
  color: white;
}
.btn-outline-on-brand:hover {
  background: rgba(255, 255, 255, 0.1);
}

/* ---------------------------------------------------------------------- */
/* Role selector / checkbox grids / star rating                           */
/* ---------------------------------------------------------------------- */
.role-selector {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.role-pill {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.4rem 1rem;
  font-size: 0.875rem;
  background: var(--background);
  cursor: pointer;
}

.role-pill[aria-pressed="true"] {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: var(--primary);
}

.checkbox-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
  max-height: 16rem;
  overflow-y: auto;
  padding: 0.25rem;
}

@media (min-width: 640px) {
  .checkbox-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.checkbox-grid label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 400;
  cursor: pointer;
}

.star-input {
  display: inline-flex;
  gap: 0.25rem;
}

.star-input button {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  line-height: 0;
}

.star-input svg {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--muted-foreground);
}

.star-input svg.is-filled {
  fill: var(--rating);
  color: var(--rating);
}

.star-rating {
  display: inline-flex;
  gap: 0.125rem;
}

.star-rating svg {
  width: 1rem;
  height: 1rem;
  color: var(--muted-foreground);
}

.star-rating svg.is-filled {
  fill: var(--rating);
  color: var(--rating);
}

/* ---------------------------------------------------------------------- */
/* Auth / form pages                                                      */
/* ---------------------------------------------------------------------- */
.auth-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-block: 3rem;
  padding-inline: 1rem;
}

.auth-card {
  width: 100%;
  max-width: 26rem;
}

.form-title {
  font-family: var(--font-sans);
  font-size: 1.35rem;
  font-weight: 700;
  text-align: center;
  margin-bottom: 0.25rem;
}

.form-subtitle {
  text-align: center;
  font-size: 0.875rem;
  color: var(--muted-foreground);
  margin-bottom: 1.5rem;
}

/* Reusable 2-column layout that collapses to 1 column below 640px — several
   places build this inline instead of relying on a fixed 2-col grid, since a
   hardcoded inline grid-template-columns never responds to viewport width. */
.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 640px) {
  .grid-2 {
    grid-template-columns: repeat(2, 1fr);
  }
}

.form-stack {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.form-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  margin-block: 0.25rem;
}

.form-divider::before,
.form-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.form-footer-link {
  text-align: center;
  font-size: 0.875rem;
  color: var(--muted-foreground);
  margin-top: 1rem;
}

.error-text {
  color: var(--destructive);
  font-size: 0.875rem;
}

.success-text {
  color: var(--primary);
  font-size: 0.875rem;
}

/* ---------------------------------------------------------------------- */
/* Page (generic) layout                                                  */
/* ---------------------------------------------------------------------- */
.page-header {
  padding-block: 2rem;
}

.page-title {
  font-family: var(--font-sans);
  font-size: 1.75rem;
  font-weight: 700;
}

.filters-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

.filters-row .select {
  width: auto;
  min-width: 10rem;
}

.empty-state {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  padding-block: 2rem;
  text-align: center;
}

/* ---------------------------------------------------------------------- */
/* Product detail                                                         */
/* ---------------------------------------------------------------------- */
.product-detail {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  padding-block: 2rem;
}

@media (min-width: 1024px) {
  .product-detail {
    grid-template-columns: 3fr 2fr;
  }
}

.product-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
}

.product-gallery img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-lg);
}

.product-gallery-zoom-outer {
  position: relative;
  grid-column: span 3;
}

.product-gallery-zoom {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  cursor: zoom-in;
}

.product-gallery-zoom img {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
  display: block;
}

.gallery-zoom-lens {
  display: none;
  position: absolute;
  border: 2px solid var(--primary);
  background: rgba(255, 255, 255, 0.25);
  pointer-events: none;
}

.gallery-zoom-result {
  display: none;
  position: absolute;
  inset-inline-start: calc(100% + 1rem);
  top: 0;
  width: 320px;
  height: 240px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background-repeat: no-repeat;
  background-color: var(--card);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  z-index: 30;
}

@media (max-width: 1023px) {
  .gallery-zoom-lens,
  .gallery-zoom-result {
    display: none !important;
  }
}

#gallery-hero-img {
  transition: opacity 0.18s ease;
}

#gallery-hero-img.is-fading {
  opacity: 0;
}

.gallery-nav-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(4px);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  transition: background 0.2s ease;
}

.gallery-nav-arrow:hover {
  background: rgba(0, 0, 0, 0.55);
}

.gallery-nav-arrow svg {
  width: 1.1rem;
  height: 1.1rem;
}

.gallery-nav-prev {
  inset-inline-start: 0.6rem;
}

.gallery-nav-prev svg {
  transform: rotate(90deg);
}

.gallery-nav-next {
  inset-inline-end: 0.6rem;
}

.gallery-nav-next svg {
  transform: rotate(-90deg);
}

.product-gallery-thumbs {
  grid-column: span 3;
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding-block: 0.25rem;
}

.product-gallery-thumb {
  flex-shrink: 0;
  width: 4rem;
  height: 4rem;
  border-radius: var(--radius-md);
  overflow: hidden;
  padding: 0;
  border: 2px solid transparent;
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.2s ease, border-color 0.2s ease;
}

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

.product-gallery-thumb:hover {
  opacity: 0.9;
}

.product-gallery-thumb.is-active {
  opacity: 1;
  border-color: var(--primary);
}

.product-detail-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.75rem;
  padding: 1rem;
  background: var(--muted);
  border-radius: var(--radius-lg);
}

.product-detail-stat-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.product-detail-stat-value {
  font-weight: 600;
}

.product-detail-price {
  font-family: var(--font-sans);
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--primary);
}

/* ---------------------------------------------------------------------- */
/* Freshness (harvest-based quality) badge                                 */
/* ---------------------------------------------------------------------- */
.freshness-card {
  margin-top: 1rem;
}

.freshness-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.freshness-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 0.2rem 0.65rem;
  font-size: 0.75rem;
  font-weight: 600;
}

.freshness-bar-track {
  margin-top: 0.5rem;
  height: 0.375rem;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}

.freshness-bar-fill {
  height: 100%;
  border-radius: 999px;
  transition: width 0.6s ease;
}

.product-card-freshness {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.7rem;
  font-weight: 600;
  margin-top: 0.2rem;
}

.product-card-freshness::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 999px;
  background: currentColor;
}

.product-qty-calc-total {
  font-weight: 700;
  color: var(--primary);
}

.product-detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* ---------------------------------------------------------------------- */
/* Comments                                                                */
/* ---------------------------------------------------------------------- */
.comments-section {
  margin-top: 2.5rem;
  border-top: 1px solid var(--border);
  padding-top: 2rem;
}

.comment-row {
  display: flex;
  gap: 0.75rem;
  padding-block: 0.75rem;
}

.comment-body {
  flex: 1;
}

.comment-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
}

.comment-author {
  font-weight: 600;
}

.comment-date {
  color: var(--muted-foreground);
}

.comment-text {
  font-size: 0.9rem;
  margin-top: 0.15rem;
}

.comment-form {
  display: flex;
  gap: 0.5rem;
  margin-top: 1rem;
}

.comment-form textarea {
  flex: 1;
}

/* ---------------------------------------------------------------------- */
/* Dashboard / Admin shell                                                 */
/* ---------------------------------------------------------------------- */
.shell {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding-block: 2rem;
}

@media (min-width: 1024px) {
  .shell {
    flex-direction: row;
  }
}

.shell[data-auth-pending] {
  display: none;
}

.shell-sidebar {
  flex-shrink: 0;
  min-width: 0;
}

@media (min-width: 1024px) {
  .shell-sidebar {
    width: 14rem;
  }
}

.shell-nav {
  display: flex;
  flex-direction: row;
  gap: 0.25rem;
  overflow-x: auto;
}

@media (min-width: 1024px) {
  .shell-nav {
    flex-direction: column;
    overflow-x: visible;
  }
}

.shell-nav-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  color: var(--muted-foreground);
  white-space: nowrap;
}

.shell-nav-link:hover {
  background: var(--muted);
}

.shell-nav-link.is-active {
  background: var(--accent);
  color: var(--accent-foreground);
}

.shell-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.status-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  border: 1px solid color-mix(in srgb, var(--destructive) 30%, transparent);
  background: var(--destructive-tint);
  border-radius: var(--radius-xl);
  padding: 1rem;
}

.status-banner svg {
  width: 1.25rem;
  height: 1.25rem;
  color: var(--destructive);
  flex-shrink: 0;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.stat-card {
  padding: 1rem;
  animation: stat-card-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.sourcing-match-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
}

.sourcing-match-card {
  padding: 1rem;
}

.sourcing-match-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.sourcing-match-qty {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 1.05rem;
}

.sourcing-match-meta {
  font-size: 0.8rem;
  color: var(--muted-foreground);
}

.sourcing-match-govs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

@keyframes stat-card-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.stat-value {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.stat-label {
  font-size: 0.8rem;
  color: var(--muted-foreground);
}

/* ---------------------------------------------------------------------- */
/* Admin analytics — animated horizontal bar charts                        */
/* ---------------------------------------------------------------------- */
.chart-bars {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.chart-bar-row {
  display: grid;
  grid-template-columns: 7rem 1fr 3rem;
  align-items: center;
  gap: 0.75rem;
  animation: stat-card-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}

@media (max-width: 480px) {
  .chart-bar-row {
    grid-template-columns: 5rem 1fr 2.5rem;
  }
}

.chart-bar-label {
  display: flex;
  flex-direction: column;
  font-size: 0.8rem;
  font-weight: 600;
  overflow: hidden;
}

.chart-bar-label span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chart-bar-sublabel {
  font-size: 0.7rem;
  font-weight: 400;
  color: var(--muted-foreground);
}

.chart-bar-track {
  direction: ltr;
  height: 1.35rem;
  background: var(--muted);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.chart-bar-fill {
  height: 100%;
  width: var(--chart-bar-pct, 0%);
  background: var(--chart-bar-color, var(--primary));
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  transition: width 1s cubic-bezier(0.16, 1, 0.3, 1);
}

.chart-bar-value {
  font-size: 0.8rem;
  font-weight: 600;
  text-align: end;
  font-variant-numeric: tabular-nums;
}

.list-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}

.list-row:last-child {
  border-bottom: none;
}

.list-row-main {
  flex: 1;
  min-width: 12rem;
}

.list-row-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------------- */
/* Cart page                                                               */
/* ---------------------------------------------------------------------- */
.cart-list {
  padding-inline: 1.25rem;
  /* .card's own inset border stays; this adds real elevation on top of it
     -- the plain flat list (a thin divider between rows, nothing else) was
     part of what read as unpolished, especially right where a row's own
     dark, fully-opaque order-tracking widget sits directly against it. */
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent),
    0 8px 28px rgba(0, 0, 0, 0.06);
}

.cart-row {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  flex-wrap: wrap;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--border);
}

.cart-row:last-child {
  border-bottom: none;
}

.cart-row-media {
  flex-shrink: 0;
  width: 5rem;
  height: 5rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--muted);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 8%, transparent);
}

.cart-row-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cart-row-main {
  flex: 1;
  min-width: 12rem;
}

.cart-row-subtotal {
  font-weight: 600;
  color: var(--primary);
  font-size: 0.85rem;
}

.cart-total-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 1.25rem;
  padding: 1.1rem 1.4rem;
  /* A plain var(--muted) gray read as an afterthought for the one number
     on this page that actually matters most -- the brand-tinted --accent
     plus a soft primary-colored ring gives it real visual weight instead. */
  background: var(--accent);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 25%, transparent);
  font-weight: 600;
}

.cart-total-value {
  font-size: 1.35rem;
  color: var(--primary);
}

/* Delivery method choice -- was two bare native radio buttons with plain
   text labels, easy to miss and inconsistent with every other choice
   control on the site (role-pill, escrow-method-circle). Same
   hide-the-real-input-behind-a-styled-label trick as those. */
.delivery-method-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 0.8rem;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.delivery-method-pill input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.delivery-method-pill:has(input:checked) {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: var(--primary);
}

.delivery-method-pill:has(input:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Quantity +/- stepper -- a bare <input type="number"> relies on the
   browser's own tiny native spinner (or none at all on some platforms/
   input modes), which read as the most basic possible control on an
   otherwise polished page. */
.qty-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--input);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.qty-stepper .input {
  border: none;
  border-radius: 0;
  text-align: center;
  width: 3rem;
  height: 1.9rem;
  padding-inline: 0.25rem;
  -moz-appearance: textfield;
}

.qty-stepper .input::-webkit-inner-spin-button,
.qty-stepper .input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.qty-stepper-btn {
  width: 1.9rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  border: none;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  color: var(--foreground);
}

.qty-stepper-btn:hover {
  background: var(--accent);
}

.qty-stepper-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ---------------------------------------------------------------------- */
/* Admin sidebar (dark, gradient header)                                  */
/* ---------------------------------------------------------------------- */
.admin-sidebar {
  border-radius: var(--radius-xl);
  background: #171d15;
  color: #eef2ec;
  overflow: hidden;
}

.admin-sidebar-header {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--brand), var(--brand-dark));
  padding: 1rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.admin-sidebar-name {
  font-weight: 600;
  font-size: 0.9rem;
}

.admin-sidebar-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.9);
}

.admin-sidebar-nav {
  padding: 0.5rem;
  display: flex;
  flex-direction: row;
  gap: 0.25rem;
  overflow-x: auto;
}

@media (min-width: 1024px) {
  .admin-sidebar-nav {
    flex-direction: column;
    overflow-x: visible;
  }
}

.admin-nav-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.65rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
  white-space: nowrap;
}

.admin-nav-link:hover {
  background: rgba(255, 255, 255, 0.1);
  color: white;
}

.admin-nav-link.is-active {
  background: var(--primary);
  color: white;
}

.admin-nav-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.05);
  flex-shrink: 0;
}

.admin-nav-link.is-active .admin-nav-icon {
  background: rgba(255, 255, 255, 0.2);
}

.admin-nav-icon svg {
  width: 1rem;
  height: 1rem;
}

.content-tabs {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
}

.content-tab {
  padding: 0.6rem 0.9rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--muted-foreground);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}

.content-tab:hover {
  color: var(--foreground);
}

.content-tab.is-active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

.admin-gate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
}

.admin-gate-card {
  width: 100%;
  max-width: 24rem;
  border-radius: var(--radius-2xl);
  background: var(--brand-dark);
  color: white;
  padding: 2rem;
  text-align: center;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
}

.admin-gate-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  margin-bottom: 1rem;
}

.admin-gate-card input {
  border-color: rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.05);
  color: white;
  margin-bottom: 0.75rem;
}

.admin-denied {
  padding-block: 3rem;
  text-align: center;
  color: var(--muted-foreground);
}

/* ---------------------------------------------------------------------- */
/* Chat                                                                   */
/* ---------------------------------------------------------------------- */
.chat-shell {
  display: flex;
  flex-direction: column;
  height: 32rem;
  min-width: 0;
  border-radius: var(--radius-xl);
  box-shadow: inset 0 0 0 1px var(--border);
  overflow: hidden;
}

.chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border);
}

.chat-messages {
  flex: 1;
  min-width: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.chat-row {
  display: flex;
  min-width: 0;
}

.chat-row.is-mine {
  justify-content: flex-end;
}

.chat-bubble {
  max-width: 75%;
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-lg);
  background: var(--muted);
  font-size: 0.9rem;
}

.chat-row.is-mine .chat-bubble {
  background: var(--primary);
  color: var(--primary-foreground);
}

.offer-card {
  width: 16rem;
  max-width: 100%;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.offer-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.25rem 0.5rem;
  font-size: 0.85rem;
}

.offer-grid dt {
  color: var(--muted-foreground);
}

.offer-total {
  font-weight: 600;
  color: var(--primary);
}

.offer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.offer-actions .btn {
  flex: 1;
}

.chat-composer {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem;
  border-top: 1px solid var(--border);
}

.chat-composer input {
  flex: 1;
  min-width: 0;
}

/* Admin team chat -- deliberately more distinctive than the plain
   buyer/seller chat above (dark header, avatars, tighter bubble corners)
   since it's an internal, admin-only room and should read that way. */
.team-chat-shell {
  height: 36rem;
  box-shadow: 0 0 0 1px var(--border), 0 12px 32px rgba(0,0,0,0.08);
}

.team-chat-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 92%, black), var(--primary));
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.team-chat-live-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: #4ade80;
  box-shadow: 0 0 0 3px rgba(74,222,128,0.25);
  animation: team-chat-pulse 2s ease-in-out infinite;
}

@keyframes team-chat-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

.team-chat-messages {
  background: var(--muted);
}

.team-chat-row {
  align-items: flex-end;
  gap: 0.5rem;
}

.team-chat-avatar {
  flex-shrink: 0;
}

.team-chat-bubble {
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
  border-radius: 1rem;
}

.team-chat-row:not(.is-mine) .team-chat-bubble {
  border-end-start-radius: 0.25rem;
}

.team-chat-row.is-mine .team-chat-bubble {
  border-end-end-radius: 0.25rem;
}

.team-chat-composer {
  background: var(--card);
}

/* Escrow order stepper -- a light, card-based look (matches the rest of
   the page) instead of the fixed-dark box this used to be. Two-tone accent
   per the user's own design reference: fresh green for completed steps
   (reusing --primary, the site's own brand green -- no new token needed),
   warm gold for the one step currently in progress (reusing --rating,
   already the site's one warm-gold token, used elsewhere for star ratings
   -- picked over inventing a new color so the accent stays consistent with
   the rest of the design system instead of a one-off). */
.escrow-stepper {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 1.25rem;
  padding: 1.25rem;
  color: var(--card-foreground);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.06);
}

.escrow-stepper-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.85rem;
  font-size: 0.85rem;
  font-weight: 700;
  margin-bottom: 1.25rem;
}

.escrow-stepper-heading {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
}

/* Optional small product thumbnail (see escrowStepperHTML's `photoUrl`
   param -- only cart.js passes one today, since it's the one call site
   that already has the product's own photo on hand while rendering this
   row; every other page just omits it and this block never renders). */
.escrow-stepper-thumb {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 0.75rem;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.escrow-stepper-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.escrow-stepper-price {
  background: var(--accent);
  color: var(--accent-foreground);
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
  flex-shrink: 0;
}

.escrow-stepper-steps {
  display: flex;
  align-items: flex-start;
  /* 5 fixed-width steps + their connector lines need ~330px minimum --
     narrower than that (most phones in portrait) they used to spill
     straight out past the card's own edge instead of stopping at it. Scoped
     to just this row (not the whole card) so it scrolls in place instead. */
  overflow-x: auto;
  padding-bottom: 0.25rem;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

.escrow-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
  width: 3.75rem;
}

.escrow-step-icon {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  color: var(--muted-foreground);
  flex-shrink: 0;
}

.escrow-step-icon svg {
  width: 1.05rem;
  height: 1.05rem;
}

.escrow-step.is-done .escrow-step-icon {
  background: var(--primary);
  color: var(--primary-foreground);
}

/* The one step actually in progress gets the warm-gold treatment (not
   green -- green means "done", gold means "this is where things stand
   right now"), plus a slow, subtle breathing glow so it reads as live
   rather than a static illustration. Kept understated on purpose: a
   4-second cycle and a soft box-shadow pulse, not a jumpy scale/bounce
   that would feel gimmicky on something as serious as a payment tracker. */
.escrow-step.is-current .escrow-step-icon {
  background: var(--rating);
  color: #2a1c00;
  animation: escrow-step-pulse 2.6s ease-in-out infinite;
}

@keyframes escrow-step-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--rating) 22%, transparent);
  }
  50% {
    box-shadow: 0 0 0 7px color-mix(in srgb, var(--rating) 12%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .escrow-step.is-current .escrow-step-icon {
    animation: none;
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--rating) 22%, transparent);
  }
}

.escrow-step-label {
  font-size: 0.62rem;
  text-align: center;
  line-height: 1.25;
  color: var(--muted-foreground);
}

.escrow-step.is-done .escrow-step-label {
  color: var(--foreground);
  font-weight: 600;
}

.escrow-step.is-current .escrow-step-label {
  color: color-mix(in srgb, var(--rating) 70%, var(--foreground));
  font-weight: 700;
}

.escrow-step-line {
  flex: 1 1 auto;
  height: 2px;
  min-width: 0.5rem;
  background: var(--border);
  margin-top: 1.1rem;
  transition: background 0.4s ease;
}

.escrow-step-line.is-done {
  background: var(--primary);
}

@media (max-width: 420px) {
  .escrow-stepper {
    padding: 1rem 0.65rem;
  }
  /* Title + price pill on one row used to force the title to wrap
     mid-phrase once the pill ate into its space -- stacking them removes
     that squeeze entirely. */
  .escrow-stepper-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }
  .escrow-stepper-thumb {
    width: 2.25rem;
    height: 2.25rem;
  }
  .escrow-step {
    width: 2.6rem;
  }
  .escrow-step-icon {
    width: 1.75rem;
    height: 1.75rem;
  }
  .escrow-step-icon svg {
    width: 0.85rem;
    height: 0.85rem;
  }
  .escrow-step-label {
    font-size: 0.56rem;
  }
  .escrow-step-line {
    min-width: 0.3rem;
  }
}

.escrow-stepper-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  border-radius: 0.75rem;
}

.escrow-stepper-banner.is-dispute {
  background: var(--destructive-tint);
  color: var(--destructive);
}

.escrow-stepper-banner.is-refund {
  background: var(--muted);
  color: var(--muted-foreground);
}

.escrow-stepper-banner.is-success {
  background: var(--accent);
  color: var(--accent-foreground);
}

.escrow-stepper-banner-title {
  font-weight: 700;
  font-size: 0.85rem;
}

.escrow-stepper-banner-note {
  font-size: 0.75rem;
  margin-top: 0.2rem;
  opacity: 0.85;
}

/* Interactive counterpart to the stepper above (renderEscrowActions /
   escrowPaymentMethodsHTML in ui.js) -- same light card treatment, so it
   reads as one continuous widget with the stepper it sits under. */
.escrow-actions {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 1rem;
  padding: 1.1rem;
  color: var(--card-foreground);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.05);
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.escrow-amount-breakdown {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.85rem;
}

.escrow-amount-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--muted-foreground);
}

.escrow-amount-row.is-total {
  margin-top: 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--border);
  color: var(--foreground);
  font-weight: 700;
}

.escrow-actions-buttons {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.escrow-payment-methods-title {
  font-size: 0.8rem;
  font-weight: 700;
}

.escrow-payment-methods {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.escrow-payment-method {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  padding: 0.55rem 0.75rem;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.escrow-payment-method:has(input:checked) {
  border-color: var(--primary);
  background: var(--accent);
}

.escrow-payment-method input {
  accent-color: var(--primary);
  flex-shrink: 0;
}

.escrow-payment-method-label {
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
}

.escrow-payment-method-value {
  font-size: 0.8rem;
  color: var(--primary);
  font-weight: 600;
  margin-inline-start: auto;
}

.escrow-payment-methods-note {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.escrow-method-circles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
}

.escrow-method-circle {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  width: 4.25rem;
}

.escrow-method-circle input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.escrow-method-circle-icon {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  border: 2px solid var(--border);
  color: var(--muted-foreground);
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}

.escrow-method-circle-icon svg {
  width: 1.4rem;
  height: 1.4rem;
}

.escrow-method-circle input:checked ~ .escrow-method-circle-icon {
  border-color: var(--primary);
  background: var(--accent);
  color: var(--primary);
  transform: scale(1.05);
}

.escrow-method-circle input:focus-visible ~ .escrow-method-circle-icon {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.escrow-method-circle-label {
  font-size: 0.68rem;
  text-align: center;
  color: var(--muted-foreground);
  line-height: 1.2;
}

.escrow-method-circle input:checked ~ .escrow-method-circle-label {
  color: var(--foreground);
  font-weight: 700;
}

.escrow-method-value-display {
  font-size: 0.8rem;
  background: var(--accent);
  border: 1px solid color-mix(in srgb, var(--primary) 35%, transparent);
  border-radius: 0.5rem;
  padding: 0.5rem 0.75rem;
  color: var(--foreground);
}

/* Admin-side view of a buyer's payment proof (admin-payments.js). */
.payment-proof {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}

.payment-proof-ref {
  font-size: 0.8rem;
  color: var(--muted-foreground);
}

.payment-proof-thumb {
  display: block;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 0.5rem;
  overflow: hidden;
  border: 1px solid var(--border);
  flex-shrink: 0;
}

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

/* Same hover-magnifier mechanism as the product gallery zoom (see
   js/ui.js's wireZoomableImages), sized for a small admin thumbnail
   instead of the 16:9 gallery box -- used for payment-proof screenshots,
   which are otherwise too small to read comfortably. */
.zoomable-image {
  position: relative;
  display: inline-block;
  width: 5rem;
  height: 5rem;
  border-radius: 0.5rem;
  overflow: hidden;
  border: 1px solid var(--border);
  flex-shrink: 0;
  cursor: zoom-in;
}

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

.zoomable-image-lens {
  display: none;
  position: absolute;
  border: 2px solid var(--primary);
  background: rgba(255, 255, 255, 0.25);
  pointer-events: none;
}

.zoomable-image-result {
  display: none;
  position: absolute;
  inset-inline-start: 0;
  top: calc(100% + 0.5rem);
  width: 280px;
  height: 210px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background-repeat: no-repeat;
  background-color: var(--card);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  z-index: 30;
}

@media (max-width: 1023px) {
  .zoomable-image-lens,
  .zoomable-image-result {
    display: none !important;
  }
}

.payment-method-icon-preview {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  color: var(--foreground);
  flex-shrink: 0;
}

.payment-method-icon-preview svg {
  width: 1.15rem;
  height: 1.15rem;
}

.offer-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--muted) 40%, transparent);
  padding: 1rem;
}

.offer-form-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
}

.offer-form-total {
  font-size: 0.875rem;
}

/* ---------------------------------------------------------------------- */
/* Guided tour ("leaf mascot")                                            */
/* ---------------------------------------------------------------------- */
.tour-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
}

.tour-ring {
  position: absolute;
  border-radius: var(--radius-lg);
  /* Second shadow layer dims the whole viewport via a huge spread; box-shadow
     never renders under its own element, so the target rect stays lit up
     while everything else (including any heading sitting right behind the
     tour card) reads clearly as backgrounded, not cut off. */
  box-shadow:
    0 0 0 4px color-mix(in srgb, var(--primary) 70%, transparent),
    0 0 0 9999px rgba(0, 0, 0, 0.55);
  transition: all 0.3s ease;
}

.tour-arrow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.tour-arrow path {
  stroke: var(--primary);
  stroke-width: 2;
  fill: none;
  stroke-dasharray: 6 4;
  animation: tour-grow 0.6s ease-out;
}

.tour-card {
  position: absolute;
  width: 18rem;
  pointer-events: auto;
  border: 2px solid var(--primary);
  border-radius: var(--radius-2xl);
  background: var(--card);
  padding: 1rem;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}

.tour-mascot {
  height: 2rem;
  width: auto;
  animation: tour-sway 2.5s ease-in-out infinite;
  margin-bottom: 0.5rem;
}

.tour-text {
  font-size: 0.875rem;
  margin-bottom: 0.75rem;
}

.tour-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.tour-skip {
  background: none;
  border: none;
  font-size: 0.8rem;
  color: var(--muted-foreground);
  cursor: pointer;
  text-decoration: underline;
}

.tour-dismiss {
  position: absolute;
  top: -0.5rem;
  inset-inline-end: -0.5rem;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  background: var(--destructive);
  color: white;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tour-dismiss svg {
  width: 0.9rem;
  height: 0.9rem;
}

@keyframes tour-sway {
  0%,
  100% {
    transform: rotate(-2deg) translateY(0);
  }
  50% {
    transform: rotate(2deg) translateY(-3px);
  }
}

@keyframes tour-grow {
  from {
    stroke-dashoffset: 30;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* ---------------------------------------------------------------------- */
/* Analytics leaderboards (admin)                                         */
/* ---------------------------------------------------------------------- */
.leaderboard-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}

@media (min-width: 1024px) {
  .leaderboard-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.leaderboard-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: 0.6rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
}

.leaderboard-row:last-child {
  border-bottom: none;
}

.role-stat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}

@media (min-width: 640px) {
  .role-stat-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* ---------------------------------------------------------------------- */
/* Ads / branding image previews                                         */
/* ---------------------------------------------------------------------- */
.image-preview-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.image-preview {
  position: relative;
  width: 6rem;
  height: 6rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--border);
}

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

.image-preview-remove {
  position: absolute;
  top: 0.25rem;
  inset-inline-end: 0.25rem;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.image-preview-remove svg {
  width: 0.75rem;
  height: 0.75rem;
}

/* ---------------------------------------------------------------------- */
/* Image input (paste URL or upload from device)                          */
/* ---------------------------------------------------------------------- */
.image-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.location-picker {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.location-picker-search {
  position: relative;
}

.location-picker-search-icon {
  position: absolute;
  inset-inline-start: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted-foreground);
  display: flex;
  pointer-events: none;
}

.location-picker-search-icon svg {
  width: 1rem;
  height: 1rem;
}

.location-picker-search-input {
  padding-inline-start: 2.25rem;
}

.location-picker-suggestions {
  position: absolute;
  z-index: 500;
  top: calc(100% + 0.35rem);
  inset-inline: 0;
  max-height: 16rem;
  overflow-y: auto;
  background: var(--popover);
  color: var(--popover-foreground);
  border-radius: var(--radius-lg);
  padding: 0.25rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15), inset 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent);
}

.location-picker-suggestion {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.65rem;
  border-radius: var(--radius-md);
  font-size: 0.85rem;
  cursor: pointer;
  line-height: 1.35;
}

.location-picker-suggestion svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  color: var(--muted-foreground);
}

.location-picker-suggestion:hover,
.location-picker-suggestion.is-active {
  background: var(--muted);
}

.location-picker-suggestion.is-empty {
  color: var(--muted-foreground);
  cursor: default;
}

.location-picker-suggestion.is-empty:hover {
  background: none;
}

.location-picker-map {
  height: 260px;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
}

.profile-mini-map {
  height: 180px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.06);
}

/* Crop/category chips on a farmer's public profile -- soft-tinted pills,
   one consistent icon (a single glyph reads calmer at this size than a
   different one per category, and this app has no per-category icon set
   to begin with, only full photos meant for much bigger tiles). */
.profile-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.profile-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
  font-size: 0.8rem;
  font-weight: 600;
}

.profile-chip svg {
  width: 0.9rem;
  height: 0.9rem;
}

/* The pickup-point card on a farmer's public profile. */
.profile-address-card {
  margin-top: 1.25rem;
  padding: 1.1rem;
  border-radius: var(--radius-lg);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.05);
}

/* farmers.html's directory cards -- a small lift + shadow on hover, per
   the user's own request to make this section feel more polished, so the
   grid reads as a set of real interactive cards rather than static tiles. */
.farmer-card {
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.farmer-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08);
}

/* index.html's "أبرز المزارعين" (Featured Farmers) strip -- admin-curated
   spotlight (SellerProfiles.setFeatured), rendered as an Instagram-story-style
   row of circular chips rather than farmers.html's full directory cards,
   since this is a quick visual highlight, not a browsable listing. */
.featured-farmers-scroll {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  padding: 0.5rem 0.15rem 0.75rem;
  margin-top: 0.5rem;
}

.featured-farmer-chip {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  width: 6rem;
  text-align: center;
}

.featured-farmer-ring {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--primary), var(--rating));
  transition: transform 0.18s ease;
}

.featured-farmer-chip:hover .featured-farmer-ring {
  transform: scale(1.05);
}

.featured-farmer-ring .avatar {
  box-shadow: 0 0 0 3px var(--background);
}

.featured-farmer-name {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  max-width: 100%;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.featured-farmer-name svg {
  flex-shrink: 0;
  width: 0.85rem;
  height: 0.85rem;
}

/* product.html's seller row -- used to be a single line of small underlined
   text with no photo at all, easy to miss entirely. A real card with the
   farmer's actual photo now, per the user's own request to make whose
   listing this actually is clearly visible. */
.product-seller-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
  padding: 0.75rem 0.9rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--card);
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.product-seller-card:hover {
  background: var(--muted);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.05);
}
.product-seller-info {
  flex: 1;
  min-width: 0;
}
.product-seller-name {
  font-weight: 700;
  color: var(--foreground);
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
.product-seller-chevron {
  width: 1.1rem;
  height: 1.1rem;
  color: var(--muted-foreground);
  flex-shrink: 0;
  /* Points toward the direction tapping this card navigates, same as the
     contact widget's own chevron -- "forward" is the inline-end side
     (left) in this site's RTL layout, not literally "down". */
  transform: rotate(90deg);
}

/* ---------------------------------------------------------------------- */
/* seller-profile.html -- Instagram/Facebook-style profile header: a       */
/* gradient cover, an avatar overlapping it, a centered stat row, and a    */
/* horizontally-scrolling "highlights" strip of the farmer's own crops     */
/* (their site's take on story highlights -- built from data this app      */
/* already has, not a new ephemeral-post upload feature). Per the owner's  */
/* own request to make this page's identity match those apps closely.     */
/* ---------------------------------------------------------------------- */
.avatar-2xl {
  width: 6.5rem;
  height: 6.5rem;
  font-size: 1.9rem;
}

.seller-profile-card {
  padding: 0;
  overflow: visible;
}

.seller-profile-cover {
  position: relative;
  height: 9rem;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  overflow: hidden;
  background: linear-gradient(135deg, var(--primary), var(--brand-light) 60%, var(--rating));
}

.seller-profile-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 82% 15%, rgba(255, 255, 255, 0.28), transparent 45%), radial-gradient(circle at 12% 90%, rgba(255, 255, 255, 0.18), transparent 42%);
}

.seller-profile-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 0 1.5rem 1.5rem;
}

.seller-profile-avatar-ring {
  display: inline-flex;
  padding: 4px;
  border-radius: 999px;
  background: var(--card);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
  margin-top: -3.5rem;
}

.seller-profile-avatar-ring .avatar {
  box-shadow: inset 0 0 0 1px var(--border);
}

.seller-profile-name {
  margin-top: 0.85rem;
  font-size: 1.35rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
}

.seller-profile-location {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.3rem;
  color: var(--muted-foreground);
  font-size: 0.875rem;
}

.seller-profile-bio {
  margin-top: 0.75rem;
  max-width: 32rem;
  white-space: pre-line;
  color: var(--foreground);
}

.seller-profile-stats {
  display: flex;
  width: 100%;
  max-width: 22rem;
  margin-top: 1.15rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.seller-profile-stat {
  flex: 1;
  padding: 0.75rem 0.5rem;
}

.seller-profile-stat + .seller-profile-stat {
  border-inline-start: 1px solid var(--border);
}

.seller-profile-stat-value {
  display: block;
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--foreground);
}

.seller-profile-stat-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.seller-profile-highlights {
  display: flex;
  gap: 1.15rem;
  overflow-x: auto;
  max-width: 100%;
  margin-top: 1.25rem;
  padding: 0.2rem 0.15rem 0.4rem;
}

.seller-profile-highlight {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  width: 4.25rem;
}

.seller-profile-highlight-bubble {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
  box-shadow: inset 0 0 0 1px var(--border);
}

.seller-profile-highlight-label {
  max-width: 100%;
  font-size: 0.72rem;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.seller-profile-follow-btn {
  margin-top: 1.25rem;
  width: 100%;
  max-width: 16rem;
  justify-content: center;
}

/* A picked pin drops in rather than just appearing -- purely cosmetic,
   matches the small-polish bar the rest of this picker is held to now. */
.leaflet-marker-icon {
  animation: location-pin-drop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes location-pin-drop {
  0% {
    transform: translateY(-14px) scale(0.6);
    opacity: 0;
  }
  100% {
    transform: translateY(0) scale(1);
    opacity: 1;
  }
}

.location-picker-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.location-picker-address {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--foreground);
  min-width: 0;
}

.location-picker-address-icon {
  display: flex;
  color: var(--primary);
  flex-shrink: 0;
}

.location-picker-address-icon svg {
  width: 0.95rem;
  height: 0.95rem;
}

.location-picker-address-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.location-picker-address-text.is-loading {
  color: var(--muted-foreground);
  animation: location-address-pulse 1.2s ease-in-out infinite;
}

@keyframes location-address-pulse {
  0%,
  100% {
    opacity: 0.55;
  }
  50% {
    opacity: 1;
  }
}

.image-input-url {
  flex: 1;
  min-width: 12rem;
}

.image-input-upload-btn {
  cursor: pointer;
  white-space: nowrap;
}

.image-input-status {
  font-size: 0.75rem;
}

/* ---------------------------------------------------------------------- */
/* Footer social links                                                    */
/* ---------------------------------------------------------------------- */
.footer-social {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.footer-social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  color: #eef2ec;
}

.footer-social-link:hover {
  background: rgba(255, 255, 255, 0.2);
}

.footer-social-link svg {
  width: 1rem;
  height: 1rem;
}

/* ---------------------------------------------------------------------- */
/* Admin ad-placement toggle rows                                         */
/* ---------------------------------------------------------------------- */
.placement-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.placement-row:last-child {
  border-bottom: none;
}

.placement-row-main {
  flex: 1;
}

.placement-row-desc {
  font-size: 0.8rem;
  color: var(--muted-foreground);
  margin-top: 0.125rem;
}

/* ---------------------------------------------------------------------- */
/* Toasts (real-time notification pop-ups)                                */
/* ---------------------------------------------------------------------- */
.toast-container {
  position: fixed;
  bottom: 1.25rem;
  inset-inline-end: 1.25rem;
  z-index: 200;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: 0.6rem;
  max-width: calc(100vw - 2rem);
}

/* The clip-path shape below is drawn in fixed physical pixel coordinates
   (tapered tip on the physical left, rounded "boat" end on the physical
   right where the badge sits) — clip-path/path() ignores text direction
   entirely, so every measurement here is deliberately physical (left/right,
   not inline-start/end) and the box itself is forced to `direction: ltr`
   to keep its flex children in that same fixed physical order. Only the
   Arabic/English text inside reverts to a natural reading alignment. */
.toast {
  position: relative;
  direction: ltr;
  display: flex;
  align-items: center;
  width: 395px;
  height: 105px;
  padding-left: 48px;
  padding-right: 72px;
  background: linear-gradient(155deg, color-mix(in srgb, var(--primary) 70%, #0d3016), color-mix(in srgb, var(--primary) 35%, #06210b));
  color: #fff;
  clip-path: path("M4,52.5 C50,10 175,2.5 335,10 Q387.5,12.5 395,37.5 L395,67.5 Q387.5,92.5 335,95 C175,102.5 50,95 4,52.5 Z");
  filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.35));
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.toast::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.35), transparent 55%);
  clip-path: inherit;
  pointer-events: none;
}

.toast.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.toast.is-clickable {
  cursor: pointer;
}

.toast-leaf-accent {
  position: absolute;
  right: 8px;
  top: -8px;
  width: 22px;
  height: 38px;
  background: linear-gradient(200deg, color-mix(in srgb, var(--primary) 80%, #e8f5e9), var(--primary));
  border-radius: 0 999px 0 999px;
  transform: rotate(25deg);
  z-index: 1;
}

.toast-badge {
  position: absolute;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  border-radius: 999px;
  background: #fff;
  padding: 8px;
  object-fit: contain;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3), 0 0 0 3px color-mix(in srgb, var(--primary) 40%, transparent);
  z-index: 2;
}

.toast-body {
  flex: 1;
  min-width: 0;
  position: relative;
  z-index: 1;
  text-align: right;
}

.toast-title {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4rem;
  font-weight: 700;
  font-size: 0.9rem;
}

.toast-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: #fff;
  flex-shrink: 0;
  order: 2;
}

.toast-subtitle {
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.8);
  margin-top: 0.15rem;
}

@media (max-width: 480px) {
  .toast {
    width: 300px;
    height: 80px;
    padding-left: 36px;
    padding-right: 55px;
    clip-path: path("M3,40 C38,8 133,2 255,8 Q295,10 300,29 L300,51 Q295,70 255,72 C133,78 38,72 3,40 Z");
  }

  .toast-badge {
    width: 42px;
    height: 42px;
    right: 10px;
  }

  .toast-leaf-accent {
    width: 17px;
    height: 29px;
    right: 6px;
    top: -6px;
  }
}

/* ---------------------------------------------------------------------- */
/* Notification bell + dropdown panel                                     */
/* ---------------------------------------------------------------------- */
/* Was an inline style on the element itself (id="notif-content") -- moved
   here as a plain rule so the mobile override below (same #notif-content
   selector, later in the file) can actually win the cascade instead of
   having to fight an inline style's automatic priority. */
#notif-content {
  inset-inline-end: 0;
  inset-inline-start: auto;
}

.notif-panel {
  width: 20rem;
  max-height: 24rem;
  overflow-y: auto;
  padding: 0.5rem;
  /* Soft gray backdrop so the white .notif-row cards actually read as
     cards, per the user's own design reference -- the dropdown itself
     already draws a shadow/border, this just tints its interior. */
  background: var(--muted);
  border-radius: inherit;
}

.notif-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.5rem 0.65rem;
  gap: 0.5rem;
}

.notif-row {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.65rem 0.6rem;
  border-radius: var(--radius-md);
  text-align: start;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.notif-row + .notif-row {
  margin-top: 0.3rem;
}

.notif-row:hover {
  background: var(--muted);
}

/* Unread used to be a tinted background on the whole row -- a tiny dot
   next to the title (per the user's own design reference) reads calmer
   across a whole list of them and doesn't fight with the per-type icon
   colors below. */
.notif-unread-dot {
  display: inline-block;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 999px;
  background: var(--primary);
  margin-inline-end: 0.35rem;
  vertical-align: middle;
}

.notif-row-icon {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.notif-row-icon svg {
  width: 1.05rem;
  height: 1.05rem;
}
.notif-row-icon-success {
  background: var(--accent);
  color: var(--primary);
}
.notif-row-icon-warning {
  background: color-mix(in srgb, var(--rating) 18%, transparent);
  color: var(--rating);
}
.notif-row-icon-destructive {
  background: var(--destructive-tint);
  color: var(--destructive);
}
.notif-row-icon-info {
  background: var(--muted);
  color: var(--foreground);
}
.notif-row-icon-neutral {
  background: var(--muted);
  color: var(--muted-foreground);
}
/* Admin-only alerts (new registration, new listing) -- a 5th color lane
   distinct from success/warning/destructive/info, per the user's own
   request that these stand out from regular transactional notifications
   at a glance. Reuses the existing trader chart color rather than
   inventing a new token, since it's already validated for contrast. */
.notif-row-icon-admin {
  background: color-mix(in srgb, var(--chart-role-trader) 15%, transparent);
  color: var(--chart-role-trader);
}

.notif-row-content {
  flex: 1;
  min-width: 0;
}

.notif-row-title {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--foreground);
}

.notif-row-body {
  font-size: 0.8rem;
  color: var(--muted-foreground);
  margin-top: 0.15rem;
}

.notif-row-time {
  font-size: 0.7rem;
  color: var(--muted-foreground);
  opacity: 0.8;
  margin-top: 0.3rem;
  text-align: end;
}

/* The panel was sized (20rem, 2rem icons, 0.85rem titles) for a desktop
   dropdown -- on an actual phone that's most of the screen width with
   every row still padded and typeset like it has room to spare, reading
   as one oversized, cramped block rather than a normal mobile menu. Scales
   the whole panel down to a slim, compact list per the user's own design
   reference: a 32px icon, 13px bold titles, 11px descriptions, minimal
   row padding. */
@media (max-width: 639px) {
  /* Anchoring this to the bell button's own position (like every other
     dropdown still does) is what let it spill off both edges of the
     screen at once on a real phone -- the bell sits wherever it lands in
     an already-crowded, horizontally-scrolling header, not reliably near
     either edge. Fixed + centered on the viewport itself instead, per the
     user's own request -- position:fixed changes what inset-inline-end/
     start (set in the unconditional #notif-content rule above) resolve
     against, from "the trigger's own box" to "the viewport", so they're
     overridden outright here rather than fought with more specificity. */
  #notif-content {
    position: fixed;
    inset-inline-end: auto;
    inset-inline-start: auto;
    /* Plain physical left/right (not the inline-start/end logical
       properties used everywhere else in this file) on purpose -- mixing
       a logical inset (which flips to "right" under dir=rtl) with the
       always-physical translateX(-50%) below silently miscentered this by
       half the panel's own width instead of actually centering it. left
       is unambiguous regardless of text direction, so the two combine
       correctly. */
    left: 50%;
    top: 4.25rem;
    transform: translateX(-50%);
    margin: 0;
    /* Glassmorphic, matching the contact widget's own panel (PR #163) --
       same reasoning: translucent + blurred so it reads as "floating over
       the page" rather than a solid box, and small/centered enough now to
       never touch the screen edges regardless of where the bell sits. */
    background: color-mix(in srgb, var(--popover) 78%, transparent);
    backdrop-filter: blur(20px) saturate(1.6);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
  }
  .notif-panel {
    width: calc(100vw - 3rem);
    max-width: 19rem;
    max-height: 65vh;
    padding: 0.3rem;
    /* Transparent instead of the solid --muted backdrop above -- with the
       panel itself already glassy, an opaque inner layer would just hide
       the blur again in every gap between the row cards. */
    background: transparent;
  }
  .notif-panel-header {
    padding: 0.25rem 0.35rem 0.4rem;
  }
  .notif-row {
    position: relative;
    padding: 0.45rem 0.5rem;
    gap: 0.5rem;
  }
  /* Unread used to be a bare dot next to the title (desktop still is) --
     on this slimmer mobile list the reference asks for a light tinted row
     background too, so an unread row reads as a distinct block even at a
     glance, not just a small dot easy to miss in a dense stack. */
  .notif-row.is-unread {
    background: color-mix(in srgb, var(--primary) 7%, var(--card));
  }
  .notif-row-icon {
    width: 2rem;
    height: 2rem;
  }
  .notif-row-icon svg {
    width: 1rem;
    height: 1rem;
  }
  .notif-row-title {
    font-size: 0.8125rem;
  }
  .notif-row-body {
    font-size: 0.6875rem;
  }
  .notif-row-time {
    font-size: 0.625rem;
  }
  /* The icon stays on the row's start side (right, in RTL) -- the dot
     moves off to the row's own opposite (end/left) edge instead of sitting
     inline right before the title, so the two indicators don't compete for
     the same corner. position:relative on .notif-row above is what this
     absolute position resolves against, regardless of how deep the dot
     itself is nested inside -content/-title. */
  .notif-unread-dot {
    position: absolute;
    top: 0.6rem;
    inset-inline-end: 0.4rem;
    margin: 0;
  }
}

/* ---------------------------------------------------------------------- */
/* Floating contact widget (opposite corner from the toast stack)         */
/* ---------------------------------------------------------------------- */
.contact-widget {
  position: fixed;
  bottom: 1.25rem;
  inset-inline-start: 1.25rem;
  z-index: 150;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

@keyframes contact-widget-breathe {
  0%, 100% {
    box-shadow: 0 10px 30px color-mix(in srgb, var(--primary) 45%, transparent), 0 0 0 4px color-mix(in srgb, var(--primary) 15%, transparent);
  }
  50% {
    box-shadow: 0 10px 34px color-mix(in srgb, var(--primary) 60%, transparent), 0 0 0 7px color-mix(in srgb, var(--primary) 22%, transparent);
  }
}

.contact-widget-fab {
  position: relative;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  background: linear-gradient(160deg, var(--primary), color-mix(in srgb, var(--primary) 60%, #0a2e12));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.7rem;
  overflow: hidden;
  animation: contact-widget-breathe 3.2s ease-in-out infinite;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.contact-widget-fab::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 30% 25%, rgba(255, 255, 255, 0.45), transparent 55%);
  pointer-events: none;
}

.contact-widget-fab:hover {
  transform: scale(1.08);
}

.contact-widget-fab:active {
  transform: scale(0.9);
  transition-duration: 0.1s;
}

.contact-widget-fab.is-open {
  transform: rotate(315deg);
}

.contact-widget-fab.is-open:hover {
  transform: rotate(315deg) scale(1.08);
}

.contact-widget-fab img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: brightness(0) invert(1);
  position: relative;
}

.contact-widget-panel {
  /* Absolutely positioned (not a normal flex child) so its box -- even while
     only visibility:hidden, which keeps layout space reserved -- never
     inflates the fixed-position .contact-widget container. Without this the
     closed panel's own height was silently ballooning that container to
     cover a large chunk of the page, intercepting taps meant for whatever
     content sat underneath it (worst on mobile, where it's a much bigger
     share of the viewport). */
  position: absolute;
  inset-inline-start: 0;
  bottom: 100%;
  margin-bottom: 0.9rem;
  width: 18rem;
  max-width: calc(100vw - 2.5rem);
  padding: 0.4rem;
  /* Glassmorphic per the user's own design reference: translucent (not
     solid) background + a real backdrop blur, so whatever's behind the
     widget (page content, the hero photo, ...) softly shows through
     instead of being fully hidden. color-mix keeps it theme-aware --
     translucent white in light mode, translucent near-black in dark --
     rather than a hardcoded rgba() that would go wrong in one of the two. */
  background: color-mix(in srgb, var(--popover) 78%, transparent);
  backdrop-filter: blur(20px) saturate(1.6);
  -webkit-backdrop-filter: blur(20px) saturate(1.6);
  border: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
  border-radius: 1rem;
  /* Light, airy card per the user's own design reference -- a soft, spread
     shadow (instead of the previous heavy dark one) is what actually
     separates a translucent panel from the page, since the border above is
     barely-there by design (a glass edge highlight, not a real outline). */
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12);
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.85rem) scale(0.96);
  transform-origin: bottom center;
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1), visibility 0s linear 0.22s;
  pointer-events: none;
}

.contact-widget-panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1), visibility 0s linear 0s;
  pointer-events: auto;
}

.contact-widget-header {
  font-weight: 700;
  font-size: 0.9rem;
  padding: 0.7rem 0.75rem 0.5rem;
  color: var(--popover-foreground);
}

.contact-widget-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--popover-foreground);
  background: none;
  opacity: 0;
  transform: translateY(0.4rem);
  transition: background 0.15s ease, opacity 0.2s ease, transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1);
}

.contact-widget-panel.is-open .contact-widget-item {
  opacity: 1;
  transform: translateY(0);
  transition: background 0.15s ease, opacity 0.24s ease var(--item-delay, 0s), transform 0.28s cubic-bezier(0.34, 1.2, 0.64, 1) var(--item-delay, 0s);
}

.contact-widget-item:hover {
  background: var(--muted);
}

.contact-widget-item:active {
  background: var(--accent);
}

.contact-widget-item-icon {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* WhatsApp's own two real brand colors, per the user's own design
   reference -- a pastel-mint badge holding a vibrant-brand-green glyph,
   not this app's usual muted --accent/--primary pairing every other row
   here uses. Fixed values (not theme tokens) on purpose, same reasoning as
   every other real brand mark: recognizability depends on the exact
   color, not on matching whatever theme happens to be active. */
.contact-widget-item-icon.is-whatsapp {
  background: #e8f9ee;
  color: #25d366;
}

.contact-widget-item-icon svg {
  width: 1.05rem;
  height: 1.05rem;
}

.contact-widget-item span:nth-child(2) {
  flex: 1;
}

.contact-widget-chevron {
  width: 1rem;
  height: 1rem;
  color: var(--muted-foreground);
  transform: rotate(90deg);
  flex-shrink: 0;
  opacity: 0.6;
}

@media (max-width: 639px) {
  .contact-widget {
    inset-inline-start: 1rem;
    bottom: 1rem;
  }

  .contact-widget-fab {
    width: 3rem;
    height: 3rem;
  }
}
