/* ==========================================================================
   GOOD HARVEST PRODUCTS - application components.

   Extends the adopted design system in site.css and reuses its tokens
   (--primary, --primary-glow, --bg-cream etc). Everything here is either a
   component the static mockup did not have (real chart, real map, product
   detail, forms, pagination, empty states) or an accessibility affordance the
   mockup was missing (skip link, visible focus, reduced motion, Thai metrics).
   ========================================================================== */

:root {
  --gh-clay: #b4623a;              /* reserved for partial-year data only */
  --gh-cream: #f7f4ec;
  --focus-ring: 0 0 0 3px rgba(16, 185, 129, 0.45);
}

/* ------------------------------------------------------------- foundations */

/* Thai needs its own metrics: vowels stack above and tone marks below the
   baseline, so a Latin-tuned line-height clips them. Thai also has no word
   spaces, so letter-spacing and uppercase are actively harmful. */
.lang-th body,
.lang-th {
  line-height: 1.85;
}
.lang-th h1, .lang-th h2, .lang-th h3, .lang-th h4 {
  line-height: 1.5;
  letter-spacing: normal;
}
.lang-th .section-eyebrow,
.lang-th .hero-badge,
.lang-th .product-card-cat,
.lang-th .export-card-kicker,
.lang-th .about-vision-label {
  text-transform: none;
  letter-spacing: normal;
}

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

.skip-link {
  position: absolute;
  left: 8px; top: -60px;
  z-index: 2000;
  padding: 12px 20px;
  background: var(--primary-dark);
  color: #fff;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  transition: top .18s ease;
}
.skip-link:focus { top: 0; }

/* A visible focus ring everywhere. WCAG 2.2 also requires that focus is not
   obscured, hence the scroll-margin under the sticky header. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--primary-glow);
  outline-offset: 2px;
  box-shadow: var(--focus-ring);
  border-radius: 4px;
}
:target, main :focus { scroll-margin-top: 100px; }

.container.narrow { max-width: 860px; }
.text-center { text-align: center; }
.mt-xl { margin-top: 64px; }

.section-actions {
  margin-top: 40px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
.section-header .section-actions,
.text-center .section-actions { justify-content: center; }

/* Honeypot: removed from the layout and from the a11y tree, never display:none
   (some bots skip those) and never reachable by keyboard. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* ------------------------------------------------------------------ motion */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .6s cubic-bezier(.16,1,.3,1), transform .6s cubic-bezier(.16,1,.3,1);
}
.reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------------------ header */
.header-nav.scrolled {
  background: rgba(255, 255, 255, .95);
  backdrop-filter: blur(10px);
  box-shadow: var(--shadow-md);
}
/* One chip per language rather than a toggle: a toggle can only ever express
   two. The current language is a non-link, so its state does not depend on
   colour alone. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 11px;
  border: 1px solid rgba(255,255,255,.35);
  border-radius: var(--radius-full);
}
.lang-switch-icon { flex: 0 0 auto; color: rgba(255,255,255,.75); }
.lang-switch-list {
  display: flex;
  align-items: center;
  gap: 2px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.lang-switch-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Anchors the hidden half of the label, so it cannot escape upwards to the
     header and land somewhere unexpected. */
  position: relative;
  min-width: 34px;
  min-height: 28px;
  padding: 4px 8px;
  border-radius: var(--radius-full);
  font-size: .75rem;
  font-weight: 700;
  line-height: 1.9;
  white-space: nowrap;
  color: #fff;
}
.lang-switch-item.is-current { background: rgba(255,255,255,.22); }

/* The trigger only exists where the three chips will not fit. */
.lang-switch-toggle { display: none; }

/* Both names are in the markup at every width; this hides the one that is not
   being shown without removing it from the accessibility tree. Deliberately
   not the .visually-hidden utility, which is !important and so cannot be
   reversed by the media query below. */
.lang-switch-full,
.lang-switch-purpose {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.header-nav.scrolled .lang-switch { border-color: var(--border-color); }
.header-nav.scrolled .lang-switch-icon { color: var(--text-muted); }
.header-nav.scrolled .lang-switch-item { color: var(--primary-dark); }
.header-nav.scrolled .lang-switch-item.is-current { background: var(--primary); color: #fff; }


/* -------------------------------------------------------------------- hero */
.hero-container { position: relative; z-index: 5; }
.hero-slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 1s ease;
}
.hero-slide.active { opacity: 1; }
.hero-slide picture, .hero-slide-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.hero-title-accent { color: #6ee7b7; }
.btn-hero-secondary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 16px 32px;
  border-radius: var(--radius-full);
  border: 1.5px solid rgba(255,255,255,.7);
  color: #fff;
  font-weight: 600;
}
.btn-hero-secondary:hover { background: rgba(255,255,255,.14); }
.hero-arrow-btn.is-paused { opacity: .6; }

/* ------------------------------------------------------------------ buttons */
.btn-outline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 28px;
  border-radius: var(--radius-full);
  border: 1.5px solid var(--primary);
  color: var(--primary);
  font-weight: 600;
  background: transparent;
}
.btn-outline:hover { background: var(--primary); color: #fff; }
.btn-outline-light { border-color: rgba(255,255,255,.6); color: #fff; }
.btn-outline-light:hover { background: rgba(255,255,255,.15); color: #fff; }

/* -------------------------------------------------------------- page heroes */
.page-hero {
  padding: 140px 0 56px;
  background: linear-gradient(180deg, var(--primary-subtle), transparent);
}
.page-hero-dark { background: var(--bg-dark); }
.page-title { font-size: clamp(2rem, 4vw, 3rem); letter-spacing: -.02em; }
.page-title-light, .section-title-light { color: #fff; }
.page-lead { font-size: 1.125rem; color: var(--text-muted); max-width: 62ch; margin-top: 12px; }
.page-lead-light, .section-desc-light { color: rgba(255,255,255,.78); }
.section-eyebrow-light { background: rgba(110,231,183,.15); color: #6ee7b7; }

/* ------------------------------------------------------------ media helpers */
.media-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 180px;
  background: var(--gh-cream);
  border: 1px dashed #d8d2c2;
  border-radius: var(--radius-md);
  color: #8a8371;
  text-align: center;
  padding: 24px;
}
.media-placeholder svg {
  width: 40px; height: 40px;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .7;
}
.media-placeholder span { font-size: .8125rem; }

/* ------------------------------------------------------------ product cards */
.products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 24px;
}
.product-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: var(--transition);
}
.product-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.product-card-link { display: block; height: 100%; }
.product-card-media { position: relative; background: var(--bg-surface-alt); }
.product-card-media img, .product-card-media picture { display: block; width: 100%; }
.product-card-cat {
  position: absolute; top: 12px; left: 12px;
  background: rgba(255,255,255,.92);
  color: var(--primary);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 5px 12px;
  border-radius: var(--radius-full);
}
.product-card-body { padding: 20px; }
.product-card-title { font-size: 1.125rem; margin-bottom: 6px; }
.product-card-desc { color: var(--text-muted); font-size: .875rem; margin-bottom: 14px; }
.product-card-cta { color: var(--primary-glow); font-weight: 700; font-size: .875rem; }

.products-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
}
.product-search { display: flex; gap: 10px; flex: 1 1 280px; max-width: 420px; }
.product-search .form-input { flex: 1; }
.products-filter-bar { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-btn {
  padding: 9px 18px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-color);
  background: var(--bg-surface);
  color: var(--text-muted);
  font-size: .875rem;
  font-weight: 600;
  cursor: pointer;
}
.filter-btn.active { background: var(--primary); border-color: var(--primary); color: #fff; }
.results-count { color: var(--text-muted); font-size: .875rem; margin-bottom: 20px; }

/* ---------------------------------------------------------- product detail */
.breadcrumb { padding: 108px 0 0; font-size: .8125rem; color: var(--text-muted); }
.breadcrumb ol { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.breadcrumb li + li::before { content: "/"; margin-right: 8px; opacity: .5; }
.breadcrumb a { color: var(--primary); }

.product-detail { padding: 32px 0 64px; }
.product-detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 56px;
  align-items: start;
}
.product-detail-media img, .product-detail-media picture { width: 100%; border-radius: var(--radius-lg); }
.product-detail-title { font-size: clamp(1.75rem, 3.5vw, 2.5rem); margin: 8px 0 16px; }
.product-detail-desc { color: var(--text-muted); font-size: 1.0625rem; margin-bottom: 32px; }
.product-spec-heading { font-size: 1.125rem; margin-bottom: 12px; }
.product-spec-list { border-top: 1px solid var(--border-color); margin-bottom: 16px; }
.product-spec-row {
  display: grid;
  grid-template-columns: minmax(140px, 38%) 1fr;
  gap: 16px;
  padding: 13px 0;
  border-bottom: 1px solid var(--border-color);
}
.product-spec-row dt { color: var(--text-muted); font-size: .875rem; }
.product-spec-row dd { font-weight: 600; }
.product-spec-note { color: var(--text-light); font-size: .8125rem; margin-bottom: 28px; }
.product-detail-actions { display: flex; gap: 14px; flex-wrap: wrap; }

.product-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}
.product-gallery-item img, .product-gallery-item picture { border-radius: var(--radius-md); width: 100%; }
.product-gallery-item figcaption { font-size: .75rem; color: var(--text-muted); margin-top: 6px; }

@media (max-width: 900px) {
  .product-detail-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* -------------------------------------------------------------------- farms */
.farms-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 24px; }
.farm-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); overflow: hidden; }
.farm-card-media img, .farm-card-media picture { width: 100%; }
.farm-card-body { padding: 20px; }
.farm-card-title { font-size: 1.125rem; }
.farm-card-meta { color: var(--primary-glow); font-size: .8125rem; font-weight: 600; margin: 4px 0 10px; }
.farm-card-desc { color: var(--text-muted); font-size: .9375rem; }

.farm-feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
  margin-bottom: 72px;
}
.farm-feature.is-reversed .farm-feature-media { order: 2; }
.farm-feature-media img, .farm-feature-media picture { width: 100%; border-radius: var(--radius-lg); }
.farm-feature-heading { font-size: 1.75rem; margin-bottom: 4px; }
.farm-thumbs { display: flex; gap: 10px; margin-top: 18px; }
.farm-thumbs picture, .farm-thumb { width: 92px; border-radius: var(--radius-sm); overflow: hidden; }
@media (max-width: 900px) {
  .farm-feature { grid-template-columns: 1fr; gap: 24px; }
  .farm-feature.is-reversed .farm-feature-media { order: 0; }
}

/* ------------------------------------------------------------------ process */
.timeline-flow {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 20px;
  counter-reset: step;
}
.timeline-step {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 24px;
}
.timeline-num { font-family: 'Outfit', sans-serif; font-size: 1.75rem; font-weight: 800; color: var(--primary-subtle); display: block; }
.timeline-title { font-size: 1.0625rem; margin: 4px 0 8px; }
.timeline-desc { color: var(--text-muted); font-size: .875rem; }

.process-list { list-style: none; }
.process-item {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) minmax(0, 320px);
  gap: 28px;
  align-items: center;
  padding: 32px 0;
  border-bottom: 1px solid var(--border-color);
}
.process-item-num { font-family: 'Outfit', sans-serif; font-size: 2.25rem; font-weight: 800; color: var(--primary-subtle); }
.process-item-title { font-size: 1.375rem; margin-bottom: 8px; }
.process-item-metric { color: var(--primary-glow); font-weight: 700; font-size: .875rem; margin-top: 8px; }
.process-item-media img, .process-item-media picture { width: 100%; border-radius: var(--radius-md); }
@media (max-width: 860px) {
  .process-item { grid-template-columns: 56px 1fr; }
  .process-item-media { grid-column: 1 / -1; }
}

/* -------------------------------------------------------------- about page */
.timeline-vertical { list-style: none; border-left: 2px solid var(--border-color); padding-left: 28px; }
.timeline-vertical-item { position: relative; padding-bottom: 24px; }
.timeline-vertical-item::before {
  content: ""; position: absolute; left: -35px; top: 6px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--primary-glow); box-shadow: 0 0 0 4px var(--primary-subtle);
}
.timeline-vertical-year { font-family: 'Outfit', sans-serif; font-weight: 800; color: var(--primary-glow); }
.timeline-vertical-title { font-size: 1.125rem; margin: 2px 0 4px; }

.model-grid { display: flex; align-items: stretch; gap: 20px; flex-wrap: wrap; margin-top: 24px; }
.model-card {
  flex: 1 1 240px;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 24px;
}
.model-card-kicker { font-size: .75rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--primary-glow); }
.model-card-title { font-size: 1.125rem; margin-top: 6px; }
.model-arrow { display: flex; align-items: center; color: var(--text-light); }
.model-arrow svg { width: 32px; height: 32px; }
@media (max-width: 700px) { .model-arrow { transform: rotate(90deg); margin: 0 auto; } }

.team-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 24px; margin-top: 24px; }
.team-card { text-align: center; }
.team-card-media picture, .team-card-media img { border-radius: var(--radius-lg); width: 100%; }
.team-card-name { font-size: 1rem; margin-top: 12px; }
.team-card-title { color: var(--text-muted); font-size: .875rem; }

/* ---------------------------------------------------------- sales chart ---
   CSS-grid bars over a real table. The 2026 series is a PARTIAL year, so it
   is distinguished by colour AND a hatch AND an explicit label - never by
   colour alone. */
.perf-figure { margin: 0; }
.perf-legend { display: flex; flex-wrap: wrap; gap: 20px; margin-bottom: 24px; font-size: .875rem; }
.perf-legend-item { display: inline-flex; align-items: center; gap: 8px; color: var(--text-muted); }
.perf-swatch { width: 14px; height: 14px; border-radius: 3px; background: var(--primary); display: inline-block; }
.perf-legend-item[data-year="2025"] .perf-swatch { background: var(--primary-glow); }
.perf-legend-item.is-partial .perf-swatch {
  background: var(--gh-clay);
  background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.55) 0 2px, transparent 2px 5px);
}

.perf-chart {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(78px, 1fr);
  gap: 10px;
  align-items: end;
  min-height: 320px;
  padding: 20px 0 0;
  border-bottom: 2px solid var(--border-color);
  overflow-x: auto;
}
.perf-group { display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
.perf-bars { display: flex; align-items: flex-end; justify-content: center; gap: 4px; height: 280px; }
.perf-bar {
  position: relative;
  flex: 1 1 0;
  max-width: 26px;
  height: var(--h);
  background: var(--primary);
  border-radius: 4px 4px 0 0;
  transition: height .8s cubic-bezier(.16,1,.3,1);
}
.perf-bar[data-year="2025"] { background: var(--primary-glow); }
.perf-bar.is-partial {
  background-color: var(--gh-clay);
  background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.45) 0 3px, transparent 3px 7px);
}
.perf-bar-val {
  position: absolute; top: -20px; left: 50%; transform: translateX(-50%);
  font-size: .6875rem; font-weight: 700; color: var(--text-muted); white-space: nowrap;
}
.perf-group-label {
  display: block; text-align: center; margin-top: 12px;
  font-size: .75rem; font-weight: 600; color: var(--text-main);
}
.perf-caption { margin-top: 16px; font-size: .8125rem; color: var(--text-muted); }

.perf-table-wrap { margin-top: 24px; }
.perf-table-wrap summary { cursor: pointer; font-weight: 600; color: var(--primary); padding: 8px 0; }
.table-scroll { overflow-x: auto; }
.perf-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: .875rem; }
.perf-table th, .perf-table td { padding: 10px 14px; border-bottom: 1px solid var(--border-color); text-align: right; }
.perf-table thead th, .perf-table tbody th { text-align: left; }
.perf-table thead th { background: var(--bg-surface-alt); font-weight: 700; }
.perf-table tfoot th, .perf-table tfoot td { font-weight: 700; background: var(--bg-surface-alt); }
.perf-unit-note { font-size: .75rem; color: var(--text-muted); margin-top: 8px; }

@media (max-width: 720px) {
  /* On small screens the table is the primary presentation, not a fallback. */
  .perf-chart { min-height: 240px; }
  .perf-bars { height: 200px; }
  .perf-bar-val { display: none; }
  .perf-table-wrap[open] summary { margin-bottom: 4px; }
}

.data-pending {
  background: var(--gh-cream);
  border: 1px dashed #d8d2c2;
  border-radius: var(--radius-lg);
  padding: 40px;
  text-align: center;
}
.data-pending-title { font-size: 1.25rem; margin-bottom: 8px; }
.data-pending-body { color: var(--text-muted); max-width: 56ch; margin: 0 auto 20px; }

/* -------------------------------------------------------------------- map */
.export-grid { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1fr); gap: 32px; align-items: start; }
.export-map-card { background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.12); border-radius: var(--radius-lg); padding: 14px; }
/* The map is portrait now that it is drawn to scale, so it is capped rather
   than left to grow to whatever height its column width implies. */
.map-svg-wrap { display: block; width: 100%; height: auto; max-height: 660px; margin-inline: auto; }
.map-graticule line { stroke: rgba(255,255,255,.07); stroke-width: 1; }
.map-grat-label {
  fill: rgba(255,255,255,.30);
  font-family: var(--font-label, inherit);
  font-size: 9px; font-weight: 500; letter-spacing: .06em;
}
.map-context-label {
  fill: rgba(255,255,255,.34);
  font-family: var(--font-label, inherit);
  font-size: 10px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
}
.map-legend-label { fill: rgba(255,255,255,.62); font-size: 10.5px; font-weight: 500; }
.map-pin-origin { fill: var(--primary-glow); }
.map-pin-dest { fill: #f59e0b; }
.map-pin { stroke: rgba(4,22,15,.85); stroke-width: 1.5; }
.map-pulse { fill: none; stroke: var(--primary-glow); stroke-width: 1.5; opacity: .7; }
.map-label { fill: #fff; font-family: 'Outfit', sans-serif; font-size: 12.5px; font-weight: 600; }
.map-label-dest { fill: #fbbf24; }
/* A solid line with an arrowhead, over a dark casing so it stays readable
   where it crosses land. The earlier dashed gradient read as a decoration. */
.map-route { stroke-width: 2.2; stroke-linecap: round; }
.map-route-shadow { stroke: rgba(3,16,11,.55); stroke-width: 5; stroke-linecap: round; }

@media (prefers-reduced-motion: no-preference) {
  .map-pulse { animation: ghPulse 2.6s ease-out infinite; }
}
@keyframes ghPulse { 0% { r: 7; opacity: .8; } 100% { r: 24; opacity: 0; } }

.export-market-cards { display: grid; gap: 16px; }
.export-card { background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.12); border-radius: var(--radius-md); padding: 20px; color: #fff; }
.export-card.is-origin { border-color: rgba(16,185,129,.5); }
.export-card-kicker { font-size: .6875rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #6ee7b7; }
.export-card-title { color: #fff; font-size: 1.125rem; margin: 4px 0 8px; }
.export-card-desc { color: rgba(255,255,255,.75); font-size: .875rem; }
.export-card-meta { color: rgba(255,255,255,.6); font-size: .8125rem; margin-top: 8px; }
.export-card-meta span { color: #6ee7b7; font-weight: 600; }
.route-text-equivalent { color: rgba(255,255,255,.7); font-size: .875rem; margin-top: 20px; text-align: center; }

@media (max-width: 900px) { .export-grid { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------- customers */
.customers-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px; }
.customer-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 28px; }
.customer-header { display: flex; align-items: center; gap: 16px; margin-bottom: 12px; }
.customer-logo { width: 90px; flex: 0 0 auto; }
.customer-name { font-size: 1.25rem; }
.customer-desc { color: var(--text-muted); }
.customer-tags { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.customer-tag { background: var(--primary-subtle); color: var(--primary); font-size: .75rem; font-weight: 600; padding: 5px 12px; border-radius: var(--radius-full); }

/* ------------------------------------------------------------------- forms */
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.form-group.col-full { grid-column: 1 / -1; }
.form-label { display: block; font-weight: 600; font-size: .875rem; margin-bottom: 6px; }
.form-optional { font-weight: 400; color: var(--text-light); }
.form-input, .form-select, .form-textarea {
  width: 100%;
  padding: 12px 16px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  color: var(--text-main);
}
.form-textarea { resize: vertical; min-height: 120px; }
.form-hint { font-size: .75rem; color: var(--text-muted); margin-top: 4px; }
.form-consent { display: flex; gap: 12px; align-items: flex-start; }
.form-consent input { margin-top: 5px; width: 18px; height: 18px; flex: 0 0 auto; }
.form-consent label { font-size: .875rem; color: var(--text-muted); }
.form-required-note { font-size: .8125rem; color: var(--text-muted); margin-bottom: 20px; }
.btn-form-submit {
  width: 100%;
  padding: 16px 32px;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--primary);
  color: #fff;
  font-weight: 700;
  cursor: pointer;
}
.btn-form-submit:hover { background: var(--primary-light); }

.form-errors {
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-left: 4px solid #dc2626;
  border-radius: var(--radius-sm);
  padding: 18px 22px;
  margin-bottom: 24px;
}
.form-errors-title { font-size: 1rem; color: #991b1b; margin-bottom: 8px; }
.form-errors ul { margin-left: 18px; color: #991b1b; font-size: .875rem; }
.form-success {
  background: var(--primary-subtle);
  border-radius: var(--radius-sm);
  padding: 18px 22px;
  margin-bottom: 24px;
}
.form-success h2 { font-size: 1rem; }

.contact-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 40px; align-items: start; }
.contact-info-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 32px; }
.contact-info-title { font-size: 1.25rem; margin-bottom: 24px; }
.contact-detail-item { display: flex; gap: 16px; margin-bottom: 22px; }
.contact-icon-box {
  flex: 0 0 auto; width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--primary-subtle);
  color: var(--primary);
}
.contact-icon-box svg { width: 20px; height: 20px; }
.contact-detail-label { font-size: .75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-light); }
.contact-detail-val { font-style: normal; color: var(--text-main); }
.contact-detail-val a { color: var(--primary); font-weight: 600; }
.contact-map-frame { width: 100%; height: 260px; border: 0; border-radius: var(--radius-md); margin-top: 12px; }
.quote-form-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 32px; }

@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------- empty + success */
.empty-state {
  background: var(--gh-cream);
  border: 1px dashed #d8d2c2;
  border-radius: var(--radius-lg);
  padding: 56px 32px;
  text-align: center;
}
.empty-state-title { font-size: 1.375rem; margin-bottom: 10px; }
.empty-state-body { color: var(--text-muted); max-width: 58ch; margin: 0 auto 24px; }

.success-check-icon {
  width: 72px; height: 72px; margin: 0 auto 24px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--primary-subtle);
  color: var(--primary);
}
.success-check-icon svg { width: 34px; height: 34px; }
.reference-box {
  display: inline-block;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 24px 40px;
  margin: 24px 0;
}
.reference-label { font-size: .75rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-light); }
.reference-value { font-family: 'Outfit', monospace; font-size: 1.75rem; font-weight: 800; color: var(--primary); letter-spacing: .04em; }
.reference-note { font-size: .8125rem; color: var(--text-muted); margin-top: 6px; }

/* ---------------------------------------------------------------- cta band */
.cta-band { background: var(--primary-dark); color: #fff; padding: 72px 0; }
.cta-band-inner { display: flex; flex-wrap: wrap; gap: 32px; align-items: center; justify-content: space-between; }
.cta-band-title { color: #fff; font-size: clamp(1.5rem, 3vw, 2.25rem); }
.cta-band-lead { color: rgba(255,255,255,.75); margin-top: 8px; max-width: 56ch; }
.cta-band-actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* --------------------------------------------------------------- trust bar */
.trust-strip { list-style: none; }
.trust-item { list-style: none; }

/* ------------------------------------------------------------------ footer */
.footer-address { font-style: normal; color: rgba(255,255,255,.7); font-size: .875rem; line-height: 1.9; }
.footer-address a { color: rgba(255,255,255,.9); }
.footer-chat { display: flex; gap: 14px; margin-top: 10px; }
.footer-chat a { color: var(--primary-glow); font-weight: 600; font-size: .875rem; }
.footer-cta { margin-top: 18px; display: inline-flex; }
.footer-title { font-size: .9375rem; }

/* ------------------------------------------------- no horizontal overflow */
html, body { max-width: 100%; overflow-x: hidden; }
img, picture, svg, table { max-width: 100%; }


/* --------------------------------------------------- header, refinements --
   Ten navigation items plus a logo, a language switch and a CTA do not fit on
   one line at every width, so the type tightens progressively and the drawer
   takes over well before anything can overlap. */
.nav-menu { gap: 18px; flex-wrap: nowrap; }
.nav-link { white-space: nowrap; font-size: .8125rem; letter-spacing: .02em; }

@media (max-width: 1440px) {
  .nav-menu { gap: 14px; }
  .nav-link { font-size: .75rem; }
  .nav-logo-tagline { display: none; }
}
@media (max-width: 1280px) {
  .nav-menu { gap: 11px; }
  .nav-link { font-size: .6875rem; }
}

.mobile-nav-toggle {
  align-items: center; justify-content: center;
  width: 42px; height: 42px;
  border: 1px solid rgba(255,255,255,.35);
  border-radius: var(--radius-sm);
  background: transparent; color: #fff; cursor: pointer;
}
.mobile-nav-toggle svg { width: 22px; height: 22px; }
.header-nav.scrolled .mobile-nav-toggle { color: var(--primary-dark); border-color: var(--border-color); }

/* The slide indicators are <button>s for keyboard operability, so the user
   agent's button chrome has to be removed - otherwise they render as boxes. */
.indicator-item {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  font-family: inherit;
}
.hero-arrow-btn {
  display: inline-grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.45);
  background: rgba(255,255,255,.10);
  color: #fff;
  cursor: pointer;
}
.hero-arrow-btn:hover { background: rgba(255,255,255,.22); }

/* The hero is a viewport-height band; cap it so a tall window does not stretch
   it to several screens. */
.hero-section { min-height: 640px; height: 100svh; max-height: 900px; }

/* --------------------------------------------- header layout, final pass --
   The primary navigation carries all ten sections the PRD requires, plus a
   logo, a language switch and the main CTA. That does not fit inside the
   1280px content container, so the header gets a wider one of its own and the
   actions are pinned so the CTA can never be squeezed out of view. */
.header-nav .container { max-width: 1560px; }
.nav-inner { gap: 24px; }
.nav-primary { min-width: 0; }
.nav-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 12px; }
.nav-logo { flex: 0 0 auto; }
.nav-logo-text { white-space: nowrap; }

/* White on the transparent hero header, dark once it turns solid. */
.lang-switch-item { color: #fff; }

/* The panel chrome belongs to the drawer only; above the breakpoint the
   navigation is a plain row of links. */
.nav-drawer-head,
.nav-drawer-foot { display: none; }

/* ------------------------------------------------------- the mobile drawer --
   Nine sections only fit on one row above this width; below it the navigation
   becomes a panel that covers the whole viewport.

   Full-viewport rather than a 330px slide-out: at 380px a slide-out leaves a
   sliver of the page showing down one side, which reads as a rendering fault
   rather than as a menu, and it let the panel be sized by its own content
   instead of by the screen. Covering the viewport also means the header bar
   behind it is gone, so the panel carries its own title, its own close button,
   the primary call to action and the language choice - everything the bar was
   holding. */
@media (max-width: 1280px) {
  .nav-primary {
    position: fixed;
    inset: 0;
    z-index: 1300;
    display: flex;
    flex-direction: column;
    background: var(--bg-surface);
    padding: 0;
    transform: translateX(100%);
    /* Hidden from the keyboard as well as the eye while it is closed. */
    visibility: hidden;
    transition: transform .3s cubic-bezier(.4, 0, .2, 1), visibility .3s;
  }
  .nav-primary.is-open { transform: none; visibility: visible; }

  .nav-drawer-head {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-color);
  }
  .nav-drawer-brand {
    font-family: var(--font-display, inherit);
    font-size: 1.0625rem;
    font-weight: 800;
    letter-spacing: .04em;
    color: var(--primary-dark);
  }
  .nav-drawer-close {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--primary-dark);
    cursor: pointer;
  }
  .nav-drawer-close svg { width: 22px; height: 22px; }

  /* Only the list of sections scrolls; the title and the footer stay put, so
     the way out and the call to action are always on screen. */
  .nav-menu {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 4px 20px 20px;
  }
  .nav-menu a {
    display: block;
    padding: 15px 4px;
    color: var(--text-main);
    font-size: 1.0625rem;
    border-bottom: 1px solid var(--border-color);
  }
  .nav-menu li:last-child a { border-bottom: 0; }
  .nav-menu a.active { color: var(--primary); font-weight: 700; }
  .nav-link { font-size: 1.0625rem; letter-spacing: normal; }
  .nav-link::after { display: none; }

  .nav-drawer-foot {
    display: block;
    flex: 0 0 auto;
    padding: 18px 20px;
    padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--border-color);
    background: var(--gh-cream, #f7f4ec);
  }
  .nav-drawer-cta { display: flex; width: 100%; justify-content: center; }
  .nav-drawer-lang-label {
    margin: 16px 0 8px;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
  }
  .nav-drawer-lang {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .nav-drawer-lang-item {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 8px 16px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-full);
    color: var(--text-main);
    font-size: .875rem;
    font-weight: 600;
  }
  .nav-drawer-lang-item.is-current {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
  }

  .mobile-nav-toggle { display: inline-flex; }
  body.nav-open { overflow: hidden; }
  /* The panel carries the call to action now, so the bar does not repeat it. */
  .header-actions-desktop { display: none; }
}
/* Thai tone marks need the extra leading here too. */
.lang-th .nav-drawer-lang-item,
.lang-th .nav-menu a { line-height: 1.9; }

/* ------------------------------------- what was actually breaking the panel --
   A backdrop-filter with any value other than none makes the element a
   CONTAINING BLOCK for its position:fixed descendants. The header takes one as
   soon as it turns solid, so the panel inside it was being measured against the
   header bar - about 70px tall - instead of against the viewport. The head and
   the footer overflowed it but were still painted, the scrollable list of
   sections was squeezed to a few pixels, and the page showed through below.
   The menu was never missing; it had nowhere to go.

   This is also why it depended on where you pressed: the header only gains the
   blur once the page is scrolled, or on any page that is not the home page.

   Dropped for as long as the panel is open. transition:none matters as much as
   the property itself - --transition is `all`, so otherwise the blur animates
   out over 250ms and keeps trapping the panel for that whole time. The panel
   covers the header, so nothing is lost by not blurring it. */
body.nav-open .header-nav {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  /* The same trap, other properties. Guarding against them being added later. */
  filter: none;
  transform: none;
  perspective: none;
  transition: none;
}
@media (min-width: 1281px) {
  .mobile-nav-toggle { display: none; }
  .nav-link { font-size: .78rem; }
  .nav-menu { gap: 15px; }
  .nav-logo-tagline { display: none; }
}
/* Thai tone marks sit above the baseline and get clipped by tight pill
   line-heights, so give any short Thai UI chip room to breathe. */
.lang-switch-item { line-height: 1.9; padding-top: 5px; padding-bottom: 5px; }
.lang-th .hero-badge,
.lang-th .section-eyebrow,
.lang-th .product-card-cat,
.lang-th .customer-tag,
.lang-th .export-card-kicker { line-height: 1.9; }

/* ------------------------------------------- header on non-hero pages -----
   Only the home page has a full-bleed image behind the header. Every other
   page has a light background, where white nav links would be invisible, so
   the header starts solid there instead of waiting for a scroll. */
.has-solid-header .header-nav {
  background: rgba(255, 255, 255, .96);
  backdrop-filter: blur(10px);
  box-shadow: var(--shadow-md);
}
.has-solid-header .nav-logo-text { color: var(--primary-dark); }
.has-solid-header .nav-logo-tagline { color: var(--text-muted); }
.has-solid-header .nav-link { color: var(--text-main); }
.has-solid-header .nav-link:hover,
.has-solid-header .nav-link.active { color: var(--primary); }
.has-solid-header .lang-switch { border-color: var(--border-color); }
.has-solid-header .lang-switch-icon { color: var(--text-muted); }
.has-solid-header .lang-switch-item { color: var(--primary-dark); }
.has-solid-header .lang-switch-item.is-current { background: var(--primary); color: #fff; }
.has-solid-header .mobile-nav-toggle { color: var(--primary-dark); border-color: var(--border-color); }

/* The dark Global Markets banner keeps light header text. */
.has-solid-header .page-hero-dark { padding-top: 150px; }

/* Most source photographs are portrait; at half-width a 4:5 crop becomes very
   tall and leaves the spec column stranded, so cap the detail image. */
.product-detail-media { max-width: 480px; margin-inline: auto; }
.product-detail { padding-bottom: 40px; }
.product-gallery { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

/* ------------------------------------------------- narrow-screen header ---
   At 390px the logo, language switch and menu button together exceed the
   container, and because the body clips horizontal overflow that silently cut
   off the hero text as well. Everything below shrinks the header row so the
   page never exceeds the viewport width. */
@media (max-width: 560px) {
  .header-nav .container { padding-inline: 16px; }
  .nav-inner { gap: 10px; }
  .nav-logo { gap: 8px; }
  .nav-logo-icon { width: 34px; height: 34px; }
  .nav-logo-icon svg { width: 18px; height: 18px; }
  .nav-logo-text { font-size: 1rem; }
  .mobile-nav-toggle { width: 38px; height: 38px; }

  /* Changing language is a top-level task for this site - a buyer in Malaysia
     should not have to open the menu to find it - so it keeps its place in the
     bar. What changes is the shape: a button that says which language you are
     reading, and the list drops out of it. */
  .lang-switch {
    display: inline-flex;
    position: relative;
    border: 0;
    padding: 0;
    gap: 0;
  }
  .lang-switch-icon { display: none; }  /* the button carries its own globe */

  .lang-switch-toggle {
    display: inline-flex;
    align-items: center;
    position: relative;
    gap: 5px;
    height: 38px;
    padding: 0 9px;
    border: 1px solid rgba(255,255,255,.35);
    border-radius: var(--radius-sm);
    background: transparent;
    color: #fff;
    font-family: inherit;
    font-size: .75rem;
    font-weight: 700;
    line-height: 1.9;
    white-space: nowrap;
    cursor: pointer;
  }
  .lang-switch-toggle svg { width: 17px; height: 17px; flex: 0 0 auto; }
  .lang-switch-caret { width: 13px; height: 13px; transition: transform .2s ease; }
  .lang-switch-toggle[aria-expanded="true"] .lang-switch-caret { transform: rotate(180deg); }
  .has-solid-header .lang-switch-toggle,
  .header-nav.scrolled .lang-switch-toggle {
    color: var(--primary-dark);
    border-color: var(--border-color);
  }

  /* display:none rather than opacity, so a closed list is out of the tab
     order as well as out of sight. */
  .lang-switch-list {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 20;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    min-width: 172px;
    padding: 6px;
    background: var(--bg-surface, #fff);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg, 0 12px 32px rgba(0,0,0,.16));
  }
  .lang-switch.is-open .lang-switch-list { display: flex; }

  .lang-switch-item {
    justify-content: flex-start;
    min-width: 0;
    min-height: 44px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    font-size: .875rem;
    font-weight: 600;
    color: var(--text-main);
  }
  .lang-switch-item.is-current { background: var(--primary); color: #fff; }
  .has-solid-header .lang-switch-item,
  .header-nav.scrolled .lang-switch-item { color: var(--text-main); }
  .has-solid-header .lang-switch-item.is-current,
  .header-nav.scrolled .lang-switch-item.is-current { color: #fff; }

  /* Swap which of the two names is the visible one. */
  .lang-switch-full {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
  }
  .lang-switch-short {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
}
@media (max-width: 400px) {
  .nav-logo-text { font-size: .9375rem; }
  /* Below this the row is genuinely out of width; the caret is the one part
     of the button that carries no information. */
  .lang-switch-caret { display: none; }
  .lang-switch-toggle { padding: 0 7px; gap: 4px; }
}

/* Belt and braces: nothing in the page may establish a width wider than the
   viewport. Long unbroken strings (URLs, emails) wrap instead of pushing. */
.container { width: 100%; }
body { overflow-x: clip; }
p, li, dd, h1, h2, h3, .hero-description, .contact-detail-val { overflow-wrap: anywhere; }
.hero-content-wrap { max-width: min(660px, 100%); }

/* ---------------------------------------- reconcile the two mobile menus ---
   site.css (inherited from the static mockup) turns .nav-menu itself into a
   fixed, full-width drop panel below 768px. This application instead uses the
   .nav-primary <nav> as the drawer, because that is what carries the ARIA
   wiring, the Escape handler and the body scroll lock. Two fixed elements
   fighting over the same menu was also what pushed the header past the
   viewport. Neutralise the inherited rules and keep one implementation. */
@media (max-width: 768px) {
  .nav-menu {
    position: static;
    top: auto; left: auto;
    width: auto;
    background: transparent;
    box-shadow: none;
    transform: none;
    opacity: 1;
    visibility: visible;
    flex-direction: column;
    align-items: stretch;
  }
  /* Padding is deliberately not reset here: this block sits after the drawer
     rules, so zeroing it would strip the padding the drawer sets. */
}

/* ==========================================================================
   THAI TYPOGRAPHY — Prompt for headline, body and label
   ==========================================================================
   English keeps Plus Jakarta Sans (headline) + Inter (body/label).

   On Thai pages Prompt is made the PRIMARY face rather than merely a fallback.
   As a fallback it only kicks in for characters Inter and Plus Jakarta Sans
   lack, so a Thai sentence containing Latin ("จำหน่ายแบบ B2B", "Makro") would
   render in two different typefaces mid-line. Putting Prompt first keeps the
   whole line in one face.
   ========================================================================== */
.lang-th {
  --font-headline: 'Prompt', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-body:     'Prompt', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-label:    'Prompt', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.lang-th body,
.lang-th input,
.lang-th select,
.lang-th textarea,
.lang-th button {
  font-family: var(--font-body);
}
.lang-th h1, .lang-th h2, .lang-th h3,
.lang-th h4, .lang-th h5, .lang-th h6 {
  font-family: var(--font-headline);
}

/* Prompt runs visually heavier and taller than Plus Jakarta Sans at the same
   nominal size, so Thai display type is eased back slightly and given room for
   its stacked vowels and tone marks. */
.lang-th .hero-title {
  font-weight: 700;
  font-size: clamp(2rem, 4.4vw, 3.5rem);
  line-height: 1.32;
}
.lang-th .section-title,
.lang-th .page-title {
  font-weight: 600;
  line-height: 1.45;
}
.lang-th .hero-description,
.lang-th .section-desc,
.lang-th .page-lead {
  line-height: 1.85;
}
.lang-th .product-card-title,
.lang-th .farm-card-title,
.lang-th .timeline-title,
.lang-th .export-card-title,
.lang-th .customer-name { font-weight: 600; line-height: 1.5; }

/* Buttons and small chips: Prompt needs a touch more vertical room than Inter
   or its descenders and tone marks clip inside pill shapes. */
.lang-th .btn-pill-primary,
.lang-th .btn-hero-primary,
.lang-th .btn-hero-secondary,
.lang-th .btn-outline,
.lang-th .btn-form-submit,
.lang-th .filter-btn,
.lang-th .nav-link,
.lang-th .form-label,
.lang-th .product-card-cta {
  font-family: var(--font-label);
  line-height: 1.8;
}
.lang-th .btn-hero-primary,
.lang-th .btn-hero-secondary { padding-top: 14px; padding-bottom: 14px; }

/* ==========================================================================
   INTERACTION STATES — hover, press, focus
   ==========================================================================
   The inherited stylesheet had hover styling but no :active state anywhere, so
   nothing gave feedback at the moment of the press.

   Hover effects are wrapped in @media (hover: hover) because on a touchscreen
   :hover latches after a tap and the button stays visually "hovered" until you
   tap elsewhere. Press feedback (:active) is what a touch device should get,
   and it works on both.
   ========================================================================== */

/* Shared timing. Press is deliberately faster than hover so the button feels
   like it responds instantly to a finger or a click. */
.btn-pill-primary,
.btn-hero-primary,
.btn-hero-secondary,
.btn-outline,
.btn-form-submit,
.filter-btn,
.lang-switch-item,
.lang-switch-toggle,
.nav-drawer-close,
.nav-drawer-lang-item,
.hero-arrow-btn,
.mobile-nav-toggle,
.indicator-item,
.product-card,
.btn-primary,
.btn-small {
  transition: background-color .22s ease, color .22s ease, border-color .22s ease,
              box-shadow .22s ease, transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) and (pointer: fine) {
  .btn-pill-primary:hover,
  .btn-hero-primary:hover,
  .btn-form-submit:hover { transform: translateY(-2px); }

  .btn-outline:hover      { transform: translateY(-2px); box-shadow: var(--shadow-md); }
  .btn-hero-secondary:hover { transform: translateY(-2px); border-color: #fff; }
  .filter-btn:hover       { border-color: var(--primary); color: var(--primary); }
  .filter-btn.active:hover { color: #fff; }
  .lang-switch-item:hover { background: rgba(255,255,255,.16); }
  .has-solid-header .lang-switch-item:hover,
  .header-nav.scrolled .lang-switch-item:hover { background: var(--primary-subtle); }
  .lang-switch-toggle:hover { background: rgba(255,255,255,.16); }
  .has-solid-header .lang-switch-toggle:hover,
  .header-nav.scrolled .lang-switch-toggle:hover { background: var(--primary-subtle); }
  .nav-drawer-close:hover { background: var(--primary-subtle); border-color: var(--primary); }
  .nav-drawer-lang-item:hover { border-color: var(--primary); color: var(--primary); }
  .hero-arrow-btn:hover   { transform: scale(1.08); }
  .indicator-item:hover   { color: #fff; }
  .product-card-cta,
  .product-card:hover .product-card-cta { text-decoration: none; }
  .product-card:hover .product-card-cta { text-decoration: underline; text-underline-offset: 3px; }
  .btn-primary:hover      { transform: translateY(-1px); }
  .btn-small:hover        { border-color: var(--a-line, #cbd5e1); }
}

/* Pressed. Every interactive control returns to the resting plane and darkens
   slightly, which reads as a physical push on both mouse and touch. */
.btn-pill-primary:active,
.btn-hero-primary:active,
.btn-form-submit:active,
.btn-primary:active {
  transform: translateY(1px) scale(.985);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .22);
  filter: brightness(.94);
}
.btn-outline:active,
.btn-hero-secondary:active {
  transform: translateY(1px) scale(.985);
  background: var(--primary);
  color: #fff;
}
.btn-hero-secondary:active { background: rgba(255,255,255,.28); }
.filter-btn:active,
.btn-small:active,
.lang-switch-item:active,
.lang-switch-toggle:active,
.nav-drawer-lang-item:active,
.nav-drawer-close:active { transform: scale(.96); }
.hero-arrow-btn:active   { transform: scale(.9); background: rgba(255,255,255,.3); }
.mobile-nav-toggle:active { transform: scale(.92); background: rgba(255,255,255,.2); }
.indicator-item:active   { transform: translateY(1px); }
.product-card:active     { transform: translateY(-1px) scale(.995); }

/* Links inside body copy get a clear affordance rather than a colour-only cue. */
.contact-detail-val a,
.footer-links a,
.breadcrumb a,
.export-card a {
  text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .contact-detail-val a:hover,
  .breadcrumb a:hover { text-decoration: underline; }
  .footer-links a:hover { color: var(--primary-glow); padding-left: 3px; }
}

/* A control that is doing something must not look identical to one that is
   idle, but motion is a preference, not a requirement. */
@media (prefers-reduced-motion: reduce) {
  .btn-pill-primary,
  .btn-hero-primary,
  .btn-hero-secondary,
  .btn-outline,
  .btn-form-submit,
  .filter-btn,
  .lang-switch-item,
  .hero-arrow-btn,
  .mobile-nav-toggle,
  .indicator-item,
  .product-card,
  .btn-primary,
  .btn-small { transition: background-color .01ms, color .01ms; }

  .btn-pill-primary:hover, .btn-hero-primary:hover, .btn-form-submit:hover,
  .btn-outline:hover, .btn-hero-secondary:hover, .btn-primary:hover,
  .hero-arrow-btn:hover, .product-card:hover { transform: none; }

  .btn-pill-primary:active, .btn-hero-primary:active, .btn-form-submit:active,
  .btn-outline:active, .btn-hero-secondary:active, .btn-primary:active,
  .filter-btn:active, .btn-small:active, .lang-switch-item:active,
  .nav-drawer-close:active, .nav-drawer-lang-item:active,
  .hero-arrow-btn:active, .mobile-nav-toggle:active, .indicator-item:active,
  .product-card:active { transform: none; }
}

/* Disabled controls must not appear pressable. */
button[disabled], .btn-primary[disabled], .btn-form-submit[disabled] {
  opacity: .55;
  cursor: not-allowed;
  transform: none !important;
  filter: none !important;
}

/* ==========================================================================
   MOBILE — touch targets, sticky CTA, layout density
   ========================================================================== */

/* --- WCAG 2.2 §2.5.8 Target Size (Minimum): 24x24 CSS px ------------------
   Measured offenders were the hero slide numbers (16px), the footer link rows
   (~19px) and the consent checkbox (18px). Padding is used rather than fixed
   heights so nothing reflows. */
.indicator-item {
  min-width: 24px;
  min-height: 24px;
  padding: 4px 6px 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.footer-links a,
.footer-address a,
.breadcrumb a,
.footer-chat a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding-block: 2px;
}
.form-consent input[type="checkbox"] {
  width: 24px;
  height: 24px;
  margin-top: 2px;
}
.perf-table-wrap summary { min-height: 24px; display: flex; align-items: center; }

/* --- Sticky quote bar -----------------------------------------------------
   Only where the header CTA is hidden. */
.mobile-cta-bar { display: none; }

@media (max-width: 560px) {
  .mobile-cta-bar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 900;
    display: flex;
    gap: 10px;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
    background: rgba(255, 255, 255, .96);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--border-color);
    box-shadow: 0 -6px 20px rgba(15, 61, 46, .1);
  }
  .mobile-cta-btn {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 48px;
    padding: 12px 20px;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: #fff;
    font-weight: 700;
    font-size: .9375rem;
  }
  .mobile-cta-btn:active { transform: scale(.97); filter: brightness(.94); }
  .mobile-cta-alt {
    flex: 0 0 auto;
    display: inline-grid;
    place-items: center;
    width: 48px; height: 48px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    color: var(--primary);
    background: #fff;
  }
  .mobile-cta-alt:active { transform: scale(.92); background: var(--primary-subtle); }

  /* Keep the sticky bar clear of the last of the page content. */
  body { padding-bottom: 76px; }
  .footer-main { padding-bottom: 24px; }
}

/* --- Density and rhythm on small screens --------------------------------- */
@media (max-width: 640px) {
  .section-padding { padding: 56px 0; }
  .page-hero { padding: 120px 0 36px; }
  .container { padding-inline: 18px; }
  .section-header { margin-bottom: 32px; }

  /* Stacked CTA rows: full-width buttons are easier to hit than centred pills. */
  .hero-actions,
  .section-actions,
  .cta-band-actions,
  .product-detail-actions { flex-direction: column; align-items: stretch; }
  .hero-actions a,
  .section-actions a,
  .cta-band-actions a,
  .product-detail-actions a {
    justify-content: center;
    width: 100%;
    min-height: 48px;
  }

  .trust-strip { padding: 18px 20px; gap: 14px; }
  .trust-item { width: 100%; }

  /* The filter row scrolls instead of wrapping into three ragged lines. */
  .products-filter-bar {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 4px;
    margin-inline: -18px;
    padding-inline: 18px;
  }
  .products-filter-bar::-webkit-scrollbar { display: none; }
  .filter-btn { flex: 0 0 auto; min-height: 40px; }

  .product-search { flex-direction: column; }
  .product-search .btn-pill-primary { justify-content: center; min-height: 48px; }

  /* Two product cards per row reads better than one very tall column. */
  .products-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .product-card-body { padding: 14px; }
  .product-card-title { font-size: .9375rem; }
  .product-card-desc { font-size: .8125rem; }

  .product-gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
  .farm-thumbs picture, .farm-thumb { width: 72px; }

  .about-stats-row { grid-template-columns: 1fr; }
  .timeline-flow { grid-template-columns: 1fr; }
  .process-item { grid-template-columns: 44px 1fr; gap: 16px; row-gap: 12px; }
  .process-item-num { font-size: 1.75rem; }

  .cta-band { padding: 48px 0; }
  .footer-grid { gap: 28px; }

  /* Forms: 16px minimum stops iOS Safari zooming the page on focus. */
  .form-input, .form-select, .form-textarea { font-size: 16px; min-height: 48px; }
  .form-textarea { min-height: 120px; }
  .btn-form-submit { min-height: 52px; }

  /* Reference number can be long; let it shrink rather than overflow. */
  .reference-box { padding: 20px 24px; width: 100%; }
  .reference-value { font-size: 1.375rem; }
}

@media (max-width: 400px) {
  .product-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- products toolbar on mobile ------------------------------------------
   The toolbar is a flex row; as a flex item the filter bar defaults to
   min-width:auto, so it sized to its content and sat pushed off to the left
   with "All" out of view instead of scrolling from the start. Stacking the
   toolbar and pinning the scroller to flex-start fixes the start position. */
@media (max-width: 640px) {
  .products-toolbar { flex-direction: column; align-items: stretch; gap: 14px; }
  .product-search { max-width: none; }
  .products-filter-bar {
    min-width: 0;
    width: 100%;
    justify-content: flex-start;
    scroll-padding-inline-start: 18px;
  }
}

/* Product grid: one column on small phones where the card carries a real
   description, two from 480px where there is room for a readable pair. */
@media (max-width: 640px) { .products-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 479px) { .products-grid { grid-template-columns: 1fr; } }

/* .product-search sets flex:1 on the input so it fills the row on desktop.
   Once the toolbar stacks, that same rule grows the input along the COLUMN
   axis and it balloons to fill the container height. Reset it when stacked. */
@media (max-width: 640px) {
  /* flex-basis is measured along the container's main axis. Once the toolbar
     stacks, `flex: 1 1 280px` on the search block becomes a 280px HEIGHT and
     `flex: 1` on the input grows it vertically. Both need resetting. */
  .product-search { flex: 0 0 auto; }
  .product-search .form-input { flex: 0 0 auto; height: 48px; }
}

/* ==========================================================================
   HERO CROSSFADE
   ==========================================================================
   The inherited rule faded opacity but toggled `visibility` outside the
   transition list, so the outgoing slide vanished on the same frame the class
   changed. The dark section background showed through the gap while the new
   image faded up — a visible flash on every change, which is what made the
   rotation feel abrupt.

   This is a dip-free dissolve instead:

     • the incoming slide sits ON TOP (z-index) and fades 0 -> 1
     • the outgoing slide HOLDS at full opacity for the length of the fade
       (transition-delay), then drops to 0 while already hidden underneath

   Because the outgoing image never dims while it is still the visible one,
   the composite is opaque at every instant — no dip to background, no flash.
   A plain two-way crossfade would dip to ~25% background at the midpoint.
   ========================================================================== */

.hero-section { --hero-fade: 1.15s; --hero-dwell: 4.15s; }

.hero-slide {
  /* Neutralise the inherited visibility toggle and box-level zoom: the zoom
     now lives on the image, so the slide box itself never moves. */
  visibility: visible;
  transform: none;
  opacity: 0;
  z-index: 1;
  /* Fade OUT, held back until the incoming slide has fully covered it. */
  transition: opacity var(--hero-fade) ease-in-out var(--hero-fade);
  will-change: opacity;
}

.hero-slide.active {
  opacity: 1;
  z-index: 2;
  /* Fade IN immediately. */
  transition: opacity var(--hero-fade) ease-in-out 0s;
}

/* A slow, continuous drift so a still photograph does not feel frozen between
   changes. It is an animation rather than a transition so it replays from the
   start every time a slide becomes active. Compositor-only (transform), so it
   costs nothing on the main thread. */
.hero-slide.active img,
.hero-slide.active .hero-slide-img {
  animation: ghHeroDrift var(--hero-dwell) cubic-bezier(.22, .61, .36, 1) both;
}
@keyframes ghHeroDrift {
  from { transform: scale(1.06); }
  to   { transform: scale(1); }
}

/* Motion is a preference. With it reduced the slideshow does not auto-advance
   at all (handled in site.js), so slides only change on a deliberate click:
   cut the dissolve short and drop the drift entirely. */
@media (prefers-reduced-motion: reduce) {
  .hero-section { --hero-fade: .01ms; }
  .hero-slide,
  .hero-slide.active { transition: opacity .01ms; }
  .hero-slide.active img,
  .hero-slide.active .hero-slide-img { animation: none; transform: none; }
}

/* ==========================================================================
   CUSTOMER LOGOS
   ==========================================================================
   These are the customers' trademarks, shown only while logo_permission is
   'granted'. The two files have very different proportions (a wide wordmark
   against a circular badge), so each sits in a fixed box and is contained
   rather than stretched — that is what makes them read as the same size.
   ========================================================================== */
.customer-header {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.customer-logo {
  flex: 0 0 auto;
  width: 108px;
  height: 56px;
  display: grid;
  place-items: center;
  padding: 6px 10px;
  background: #fff;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
}
.customer-logo picture,
.customer-logo img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
.customer-name { font-size: 1.25rem; margin: 0; }

@media (max-width: 480px) {
  .customer-logo { width: 92px; height: 48px; }
}

/* The inherited rule uses justify-content:space-between, which was fine when
   the header held a name and a badge on opposite ends. With a logo added the
   name got flung to the far right, so pack them together instead. */
.customer-header { justify-content: flex-start; }

/* <picture> is inline by default, so max-height on it does not constrain the
   image inside — the Ohkajhu badge spilled out of its box and over the text.
   Take the picture element out of the layout and size the img directly. */
.customer-logo picture { display: contents; }
.customer-logo img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* A percentage max-height on a centred grid item does not reliably resolve
   against the grid area, so the tall badge kept its intrinsic 363px height and
   spilled over the description. Constrain it in absolute units instead — the
   box is a known size, so there is nothing to gain from percentages here. */
.customer-logo {
  --logo-h: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.customer-logo picture {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
.customer-logo img {
  display: block;
  max-height: var(--logo-h);
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
@media (max-width: 480px) {
  .customer-logo { --logo-h: 36px; }
}

/* --- map country outlines ------------------------------------------------- */
/* Context countries are land, not subjects: enough tone to separate them from
   the sea and from each other, no more. */
.map-countries path {
  fill: rgba(226, 232, 226, .07);
  stroke: rgba(255, 255, 255, .16);
  stroke-width: .9;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.map-country.is-origin {
  fill: rgba(16, 185, 129, .26);
  stroke: rgba(110, 231, 183, .9);
  stroke-width: 1.5;
}
.map-country.is-dest {
  fill: rgba(245, 158, 11, .20);
  stroke: rgba(251, 191, 36, .85);
  stroke-width: 1.4;
}
.map-label { paint-order: stroke; stroke: rgba(4, 22, 15, .75); stroke-width: 3px; }

/* ==========================================================================
   PARTNER CARDS — logo led, no framing box
   ==========================================================================
   The logo is the thing a buyer recognises, so it is given the space and the
   card chrome is dropped. The three marks have very different proportions
   (a wide wordmark and two circular badges), so each sits in a fixed-height
   band and is contained: that is what makes them read as equal in size.
   ========================================================================== */
.customers-grid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 28px; }

.partner-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  padding: 28px 20px;
  background: transparent;
  border: 0;
}
.partner-logo {
  --partner-logo-h: 84px;
  height: var(--partner-logo-h);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
.partner-logo picture { display: flex; align-items: center; justify-content: center; }
.partner-logo img {
  display: block;
  max-height: var(--partner-logo-h);
  max-width: 200px;
  width: auto;
  height: auto;
  object-fit: contain;
  /* A neutral resting state so three different brand palettes sit together,
     resolving to full colour on hover or when the card is focused. */
  transition: filter .3s ease, transform .3s ease;
}
@media (hover: hover) and (pointer: fine) {
  .partner-card:hover .partner-logo img { transform: scale(1.04); }
}

.partner-name { font-size: 1.0625rem; margin: 0; }
.partner-desc { color: var(--text-muted); font-size: .9375rem; max-width: 34ch; margin: 0; }
.partner-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 0;
}

@media (max-width: 640px) {
  .customers-grid { grid-template-columns: 1fr; gap: 8px; }
  .partner-card { padding: 20px 12px; }
  .partner-logo { --partner-logo-h: 68px; }
}

/* Two of the three logo files are flattened onto white, so on the page they
   would draw a white rectangle — exactly the framing box this layout removes.
   multiply makes white blend away against the light section background while
   preserving the anti-aliased edges that a colour-key transparency would
   fringe. The section this appears in is always light, which is the condition
   multiply needs. */
.partner-logo img { mix-blend-mode: multiply; }

/* The reveal animation must not leave a card stranded at half opacity if the
   observer never fires (no JS, or the element is already past the threshold on
   load). Cards start visible and the observer only adds motion. */
.partner-card.reveal { opacity: 1; transform: none; }
.partner-card.reveal:not(.is-visible) { opacity: 1; }

/* ==========================================================================
   FOOTER — visit us / location
   ==========================================================================
   A buyer evaluating a supplier often wants to see the place before ordering,
   so the address is made actionable rather than just printed. */
.footer-locate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 32px;
  align-items: center;
  margin-top: 48px;
  padding-top: 40px;
  border-top: 1px solid rgba(255, 255, 255, .12);
}
.footer-locate-lead {
  color: rgba(255, 255, 255, .7);
  font-size: .9375rem;
  margin: 8px 0 14px;
  max-width: 46ch;
}
.footer-locate-address {
  font-style: normal;
  color: #fff;
  font-weight: 600;
  line-height: 1.8;
  margin-bottom: 18px;
  max-width: 40ch;
}
.footer-locate-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 11px 22px;
  border-radius: var(--radius-full);
  background: var(--primary-glow);
  color: #06281c;
  font-weight: 700;
  font-size: .9375rem;
  transition: transform .12s ease, filter .22s ease;
}
@media (hover: hover) and (pointer: fine) {
  .footer-locate-btn:hover { filter: brightness(1.08); transform: translateY(-2px); color: #06281c; }
}
.footer-locate-btn:active { transform: translateY(1px) scale(.98); filter: brightness(.94); }

.footer-locate-map {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(255, 255, 255, .04);
}
.footer-locate-map iframe {
  display: block;
  width: 100%;
  height: 260px;
  border: 0;
  /* The embed is a bright light map inside a dark footer; easing it back keeps
     the footer calm without making the streets unreadable. */
  filter: saturate(.9) contrast(.96);
}

@media (max-width: 820px) {
  .footer-locate { grid-template-columns: 1fr; gap: 24px; margin-top: 36px; padding-top: 32px; }
  .footer-locate-map iframe { height: 220px; }
}

/* Directions link under the contact-page map. */
.contact-directions {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 12px;
  padding: 10px 20px;
  border-radius: var(--radius-full);
  border: 1.5px solid var(--primary);
  color: var(--primary);
  font-weight: 600;
  font-size: .9375rem;
}
@media (hover: hover) and (pointer: fine) {
  .contact-directions:hover { background: var(--primary); color: #fff; }
}
.contact-directions:active { transform: scale(.97); }

/* --- partner logos, enlarged ---------------------------------------------
   The logo is the recognition cue on this section, so it is given real size.
   Height still governs (not width) because the three marks differ so much in
   proportion — a wide wordmark against two circular badges — and matching
   their heights is what makes them read as equal weight. */
.partner-logo { --partner-logo-h: 150px; }
.partner-logo img { max-height: var(--partner-logo-h); max-width: 300px; }
.partner-card { gap: 18px; padding: 32px 20px; }

/* The circular badges carry their name inside the mark, so they can run a
   little larger than the wordmark without overpowering it. */
.customers-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 36px; }

@media (max-width: 1100px) {
  .partner-logo { --partner-logo-h: 124px; }
  .partner-logo img { max-width: 250px; }
}
@media (max-width: 640px) {
  .partner-logo { --partner-logo-h: 110px; }
  .partner-logo img { max-width: 220px; }
  .customers-grid { grid-template-columns: 1fr; gap: 12px; }
}

/* ==========================================================================
   CONTACT — information only
   ==========================================================================
   The page carries no form, so it is laid out as details beside a map rather
   than as two competing columns of equal weight. */
.contact-info-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 48px;
  align-items: start;
}
.contact-details {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 36px;
}
.contact-producer-note {
  color: var(--text-muted);
  font-size: .9375rem;
  margin: -12px 0 24px;
  max-width: 46ch;
}
.contact-inline-link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  margin-top: 6px;
  color: var(--primary-glow);
  font-weight: 600;
  font-size: .875rem;
  text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .contact-inline-link:hover { text-decoration: underline; }
}
.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--border-color);
}
.contact-map-col {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border-color);
}
.contact-map-col .contact-map-frame {
  width: 100%;
  height: 520px;
  border: 0;
  margin: 0;
  display: block;
}

@media (max-width: 900px) {
  .contact-info-grid { grid-template-columns: 1fr; gap: 24px; }
  .contact-details { padding: 24px; }
  .contact-map-col .contact-map-frame { height: 320px; }
  .contact-actions a { flex: 1 1 100%; justify-content: center; min-height: 48px; }
}

/* ---------------------------------------------------------------------------
 * Product photo zoom.
 *
 * The trigger is a real <a> pointing at the largest rendition, so with
 * JavaScript off a click simply opens the file. site.js upgrades it into the
 * overlay below.
 * ------------------------------------------------------------------------- */
.zoom-link {
  display: block;
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: zoom-in;
}
.product-gallery-item .zoom-link { border-radius: var(--radius-md); }
.zoom-link:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.zoom-hint {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-md);
  color: var(--text-main);
  opacity: 0;
  transform: translateY(6px);
  transition: var(--transition);
}
.zoom-hint svg {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}
.zoom-link:hover .zoom-hint,
.zoom-link:focus-visible .zoom-hint { opacity: 1; transform: translateY(0); }
.product-gallery-item .zoom-hint { right: 8px; bottom: 8px; width: 32px; height: 32px; }
.product-gallery-item .zoom-hint svg { width: 16px; height: 16px; }

/* Touch devices have no hover, so the affordance has to be permanent. */
@media (hover: none) {
  .zoom-hint { opacity: 1; transform: none; }
}

.lightbox {
  position: fixed;
  inset: 0;
  /* Above the fixed site header, which sits at 1000. */
  z-index: 1500;
  display: flex;
  flex-direction: column;
  padding: 20px 76px;
  background: rgba(11, 28, 20, 0.94);
  opacity: 0;
  /* A closed overlay must stop being a surface. Fading opacity alone leaves a
   * full-screen, fully clickable sheet lying over the page, which swallows
   * every click until the next page load. */
  visibility: hidden;
  pointer-events: none;
  transition: opacity .2s ease, visibility 0s linear .2s;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .2s ease, visibility 0s;
}
/* `display: flex` above and the user-agent's `[hidden] { display: none }` have
 * equal specificity, and this sheet loads later - so hiding has to be restated
 * here or the attribute does nothing at all. */
.lightbox[hidden], .lightbox-btn[hidden] { display: none; }
.lightbox-figure {
  margin: 0;
  /* flex:1 with min-height:0 gives the row a definite height, which is what
   * the image's percentage max-height resolves against. Without it the
   * photograph renders at its natural size and pushes the caption off screen. */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox-figure img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  /* Belt and braces for browsers that will not resolve the percentage against
   * a flex item: the viewport is always a definite length. */
  max-height: calc(100vh - 130px);
  object-fit: contain;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xl);
}
.lightbox-caption {
  margin-top: 14px;
  text-align: center;
  color: rgba(255, 255, 255, 0.86);
  font-size: .9375rem;
  line-height: 1.5;
  max-width: 70ch;
  margin-inline: auto;
}
.lightbox-counter {
  display: block;
  margin-top: 6px;
  color: rgba(255, 255, 255, 0.55);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
}

.lightbox-btn {
  position: absolute;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  cursor: pointer;
  transition: var(--transition);
}
.lightbox-btn:hover { background: rgba(255, 255, 255, 0.22); }
.lightbox-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.lightbox-btn svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lightbox-close { top: 16px; right: 16px; }
.lightbox-prev  { left: 16px;  top: 50%; transform: translateY(-50%); }
.lightbox-next  { right: 16px; top: 50%; transform: translateY(-50%); }

/* The scroll position must survive the overlay, so the page is pinned rather
 * than set to overflow:hidden, which Safari resets to the top. */
body.lightbox-open { overflow: hidden; }

@media (max-width: 700px) {
  .lightbox { padding: 12px; }
  .lightbox-figure img { max-height: calc(100vh - 150px); }
  .lightbox-btn { width: 42px; height: 42px; }
  .lightbox-prev { left: 8px; }
  .lightbox-next { right: 8px; }
  .lightbox-close { top: 8px; right: 8px; }
  .lightbox-caption { font-size: .875rem; }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox, .zoom-hint { transition: none; }
}
