/* ==========================================================================
   DE JEO HOSPITAL AND SCIENTIFIC SUPPLY LIMITED
   css/style.css
   Custom rules, micro-animations and component classes that sit on top of
   Tailwind CSS (loaded via CDN on every page). Tailwind utility classes
   handle layout/spacing; this file handles brand-specific components that
   are reused identically across index.html, products.html, checkout.html,
   services.html, track-order.html and admin.html.
   ========================================================================== */

:root {
  --jeo-navy: #0a192f;
  --jeo-navy-light: #112240;
  --jeo-navy-lighter: #1d2d50;
  --jeo-cyan: #00b4d8;
  --jeo-cyan-dark: #0090ad;
  --jeo-cyan-light: #90e0ef;
  /* Eyebrow text on light grounds. --jeo-cyan-dark is only 3.59:1 on gray-50,
     which fails AA for this size; this clears it at 5.25:1. */
  --jeo-cyan-deep: #00738b;
  --jeo-white: #ffffff;
  --jeo-gray-100: #f5f7fa;
  --jeo-gray-300: #cbd5e1;
  --jeo-gray-500: #64748b;
  --jeo-success: #16a34a;
  --jeo-warning: #d97706;
  --jeo-error: #dc2626;
  --shadow-cyan-glow: 0 8px 30px rgba(0, 180, 216, 0.25);
}

* {
  scroll-behavior: smooth;
}

html,
body {
  background-color: var(--jeo-white);
  font-family: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Custom scrollbar for a more premium, deliberate feel */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: var(--jeo-gray-100);
}
::-webkit-scrollbar-thumb {
  background: var(--jeo-navy-lighter);
  border-radius: 999px;
  border: 2px solid var(--jeo-gray-100);
}
::-webkit-scrollbar-thumb:hover {
  background: var(--jeo-cyan);
}

/* Focus visibility kept crisp and on-brand instead of the default outline */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--jeo-cyan);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   HERO / SECTION BACKGROUNDS
   -------------------------------------------------------------------------- */
.hero-grid-bg {
  /* Inner-page header band. Shares the home hero's language - aurora wash,
     two-tier measurement grid, grain - so the six pages that use it do not
     read as a different site. isolation + z-index:-1 keeps the decorative
     layers behind the content without needing z-index on every child. */
  position: relative;
  isolation: isolate;
  background-color: var(--jeo-navy);
  background-image:
    radial-gradient(ellipse 70% 90% at 12% 0%, rgba(0, 180, 216, 0.28), transparent 60%),
    radial-gradient(ellipse 60% 80% at 88% 100%, rgba(144, 224, 239, 0.16), transparent 62%);
  overflow: hidden;
}

.hero-grid-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(rgba(144, 224, 239, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(144, 224, 239, 0.06) 1px, transparent 1px),
    linear-gradient(rgba(144, 224, 239, 0.11) 1px, transparent 1px),
    linear-gradient(90deg, rgba(144, 224, 239, 0.11) 1px, transparent 1px);
  background-size: 40px 40px, 40px 40px, 200px 200px, 200px 200px;
  -webkit-mask-image: radial-gradient(ellipse 95% 80% at 40% 40%, #000 25%, transparent 80%);
  mask-image: radial-gradient(ellipse 95% 80% at 40% 40%, #000 25%, transparent 80%);
}

.hero-grid-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.14;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

.hero-glow-text {
  text-shadow: 0 0 40px rgba(0, 180, 216, 0.35);
}

.section-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  background: rgba(0, 180, 216, 0.1);
  color: var(--jeo-cyan-dark);
  border: 1px solid rgba(0, 180, 216, 0.25);
}

.dark-section .section-badge {
  background: rgba(0, 180, 216, 0.14);
  color: var(--jeo-cyan);
  border-color: rgba(0, 180, 216, 0.3);
}

/* --------------------------------------------------------------------------
   HEADER / NAVIGATION
   -------------------------------------------------------------------------- */
[data-site-header] {
  transition: box-shadow 0.3s ease, background-color 0.3s ease;
}

.site-header-scrolled {
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.45);
}

.nav-link {
  position: relative;
  color: rgba(255, 255, 255, 0.8);
  font-size: 0.925rem;
  font-weight: 500;
  padding-bottom: 4px;
  transition: color 0.2s ease;
}

.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 0%;
  height: 2px;
  background: var(--jeo-cyan);
  transition: width 0.25s ease;
  border-radius: 2px;
}

.nav-link:hover {
  color: var(--jeo-white);
}

.nav-link:hover::after,
.nav-link.active::after {
  width: 100%;
}

.nav-link.active {
  color: var(--jeo-white);
}

.lang-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 0.4rem 0.7rem;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.03);
  transition: background 0.2s ease, border-color 0.2s ease;
}

.lang-btn:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(0, 180, 216, 0.4);
}

.lang-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  min-width: 160px;
  background: var(--jeo-navy-light);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  padding: 0.4rem;
  box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.6);
  z-index: 60;
  animation: dropdownFade 0.18s ease;
}

.lang-dropdown button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border-radius: 6px;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.85);
  transition: background 0.15s ease, color 0.15s ease;
}

.lang-dropdown button:hover {
  background: rgba(0, 180, 216, 0.15);
  color: var(--jeo-white);
}

@keyframes dropdownFade {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.cart-icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 10px;
  color: var(--jeo-white);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 1.05rem;
  transition: background 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

.cart-icon-btn:hover {
  background: rgba(0, 180, 216, 0.18);
  border-color: rgba(0, 180, 216, 0.45);
  transform: translateY(-1px);
}

.cart-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
  font-size: 0.68rem;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--jeo-navy);
  line-height: 1;
}

.cart-badge-pop {
  animation: badgePop 0.4s ease;
}

@keyframes badgePop {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.45);
  }
  100% {
    transform: scale(1);
  }
}

.mobile-menu {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.35s ease, opacity 0.25s ease;
}

.mobile-menu-open {
  max-height: 560px;
  opacity: 1;
}

/* --------------------------------------------------------------------------
   BUTTONS (extend Tailwind, not replace it — used for the animated states
   Tailwind utilities alone don't express cleanly)
   -------------------------------------------------------------------------- */
.btn-glow {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.btn-glow::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: translateX(-120%);
  transition: transform 0.6s ease;
}

.btn-glow:hover::before {
  transform: translateX(120%);
}

/* --------------------------------------------------------------------------
   PRODUCT / CONTENT CARDS
   -------------------------------------------------------------------------- */
.card-hover {
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.card-hover:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-cyan-glow);
  border-color: rgba(0, 180, 216, 0.4);
}

.product-image-wrap {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--jeo-navy) 0%, var(--jeo-navy-light) 100%);
}

.product-image-wrap img {
  transition: transform 0.5s ease;
}

.card-hover:hover .product-image-wrap img {
  transform: scale(1.06);
}

/* --------------------------------------------------------------------------
   CLIENT / PARTNER LOGO TILES
   -------------------------------------------------------------------------- */
.client-logo-tile {
  transition: border-color 0.25s ease, background-color 0.25s ease;
}

.client-logo-tile:hover {
  border-color: rgba(0, 180, 216, 0.4);
  background-color: var(--jeo-white);
}

/* --------------------------------------------------------------------------
   FAQ ACCORDION (native <details>/<summary>)
   -------------------------------------------------------------------------- */
.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary {
  -webkit-tap-highlight-color: transparent;
}

.faq-item[open] summary i {
  transform: rotate(180deg);
}

/* --------------------------------------------------------------------------
   SKIP LINK — keyboard users can jump past the nav straight to content.
   Visually hidden until focused, then pinned to the top-left.
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
  font-weight: 700;
  font-size: 0.875rem;
  border-radius: 0 0 0.5rem 0;
}

.skip-link:focus {
  left: 0;
}

/* --------------------------------------------------------------------------
   HORIZONTAL CHIP SCROLLER (mobile category filters, etc.) — keeps pills
   on a single scrollable line instead of wrapping into a tall stack.
   -------------------------------------------------------------------------- */
.chip-scroll {
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.chip-scroll::-webkit-scrollbar {
  display: none;
}

/* --------------------------------------------------------------------------
   FORM ELEMENTS (shared by checkout.html and services.html)
   -------------------------------------------------------------------------- */
.form-label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--jeo-navy);
  margin-bottom: 0.35rem;
  letter-spacing: 0.01em;
}

.form-input,
.form-select,
.form-textarea {
  width: 100%;
  padding: 0.75rem 1rem;
  border-radius: 10px;
  border: 1.5px solid #e2e8f0;
  background: var(--jeo-white);
  color: var(--jeo-navy);
  font-size: 0.925rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  border-color: var(--jeo-cyan);
  box-shadow: 0 0 0 4px rgba(0, 180, 216, 0.15);
  outline: none;
}

.form-input::placeholder,
.form-textarea::placeholder {
  color: #94a3b8;
}

/* --------------------------------------------------------------------------
   STEP INDICATOR (checkout.html multi-step flow)
   -------------------------------------------------------------------------- */
.step-circle {
  width: 38px;
  height: 38px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.9rem;
  border: 2px solid #cbd5e1;
  color: #94a3b8;
  background: var(--jeo-white);
  transition: all 0.3s ease;
}

.step-circle.active {
  border-color: var(--jeo-cyan);
  background: var(--jeo-cyan);
  color: var(--jeo-white);
  box-shadow: 0 0 0 6px rgba(0, 180, 216, 0.15);
}

.step-circle.completed {
  border-color: var(--jeo-success);
  background: var(--jeo-success);
  color: var(--jeo-white);
}

.step-line {
  flex: 1;
  height: 2px;
  background: #cbd5e1;
  transition: background 0.3s ease;
}

.step-line.completed {
  background: var(--jeo-success);
}

/* --------------------------------------------------------------------------
   STATUS PILLS (order tracking + admin dashboard)
   -------------------------------------------------------------------------- */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.status-pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
}

.status-pending {
  background: #fef3c7;
  color: #b45309;
}

.status-approved {
  background: #dbeafe;
  color: #1d4ed8;
}

.status-shipped {
  background: #d1fae5;
  color: #047857;
}

.status-delivered {
  background: #dcfce7;
  color: #15803d;
}

.status-cancelled {
  background: #fee2e2;
  color: #b91c1c;
}

/* --------------------------------------------------------------------------
   ADMIN DASHBOARD TABS (Orders / Service Requests)
   -------------------------------------------------------------------------- */
.admin-tab-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 1rem 0.25rem;
  margin-right: 2rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: #94a3b8;
  border-bottom: 3px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.admin-tab-btn:hover {
  color: var(--jeo-navy);
}

.admin-tab-active {
  color: var(--jeo-navy);
  border-bottom-color: var(--jeo-cyan);
}

.admin-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: #eef2f6;
  color: #64748b;
  font-size: 0.7rem;
  font-weight: 800;
}

.admin-tab-active .admin-tab-count {
  background: var(--jeo-cyan);
  color: var(--jeo-white);
}

/* --------------------------------------------------------------------------
   ADMIN ACTION BUTTONS (order table row actions)
   -------------------------------------------------------------------------- */
.admin-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.75rem;
  border-radius: 8px;
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
  transition: background 0.2s ease, color 0.2s ease, transform 0.15s ease;
}

.admin-action-btn:active {
  transform: scale(0.96);
}

.admin-action-view {
  background: #eef2f6;
  color: var(--jeo-navy);
  padding: 0.5rem;
}

.admin-action-view:hover {
  background: #e2e8f0;
}

.admin-action-approve {
  background: rgba(0, 180, 216, 0.12);
  color: var(--jeo-cyan-dark);
}

.admin-action-approve:hover {
  background: var(--jeo-cyan);
  color: var(--jeo-white);
}

.admin-action-ship {
  background: rgba(22, 163, 74, 0.12);
  color: var(--jeo-success);
}

.admin-action-ship:hover {
  background: var(--jeo-success);
  color: var(--jeo-white);
}

/* --------------------------------------------------------------------------
   ADMIN DATA TABLE
   -------------------------------------------------------------------------- */
.admin-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

.admin-table thead th {
  background: var(--jeo-navy);
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.9rem 1rem;
  text-align: left;
  white-space: nowrap;
}

.admin-table thead th:first-child {
  border-top-left-radius: 12px;
}

.admin-table thead th:last-child {
  border-top-right-radius: 12px;
}

.admin-table tbody tr {
  background: var(--jeo-white);
  transition: background 0.15s ease;
}

.admin-table tbody tr:hover {
  background: #f8fafc;
}

.admin-table tbody td {
  padding: 0.9rem 1rem;
  font-size: 0.875rem;
  color: #334155;
  border-bottom: 1px solid #eef2f6;
  vertical-align: middle;
}

/* --------------------------------------------------------------------------
   WHATSAPP FLOATING BUTTON
   -------------------------------------------------------------------------- */
.whatsapp-float {
  position: fixed;
  bottom: 24px;
  right: 24px;
  width: 60px;
  height: 60px;
  border-radius: 999px;
  background: #25d366;
  color: var(--jeo-white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  box-shadow: 0 10px 30px rgba(37, 211, 102, 0.5);
  z-index: 70;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.whatsapp-float::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: #25d366;
  animation: whatsappPulse 2.2s ease-out infinite;
  z-index: -1;
}

.whatsapp-float:hover {
  transform: scale(1.08);
  box-shadow: 0 14px 36px rgba(37, 211, 102, 0.65);
  color: var(--jeo-white);
}

@keyframes whatsappPulse {
  0% {
    transform: scale(1);
    opacity: 0.55;
  }
  100% {
    transform: scale(1.9);
    opacity: 0;
  }
}

@media (max-width: 640px) {
  .whatsapp-float {
    width: 52px;
    height: 52px;
    font-size: 1.5rem;
    bottom: 16px;
    right: 16px;
  }
}

/* --------------------------------------------------------------------------
   TOAST NOTIFICATIONS
   -------------------------------------------------------------------------- */
.toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  max-width: min(380px, calc(100vw - 32px));
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  background: var(--jeo-navy);
  color: var(--jeo-white);
  border-radius: 12px;
  padding: 0.9rem 1rem;
  box-shadow: 0 18px 40px -8px rgba(0, 0, 0, 0.4);
  border-left: 4px solid var(--jeo-cyan);
  animation: toastIn 0.32s ease;
  font-size: 0.875rem;
  line-height: 1.4;
}

.toast-icon {
  font-size: 1.1rem;
  margin-top: 1px;
}

.toast-message {
  flex: 1;
}

.toast-close {
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.85rem;
  padding: 2px;
  transition: color 0.2s ease;
}

.toast-close:hover {
  color: var(--jeo-white);
}

.toast-success {
  border-left-color: var(--jeo-success);
}
.toast-success .toast-icon {
  color: var(--jeo-success);
}

.toast-error {
  border-left-color: var(--jeo-error);
}
.toast-error .toast-icon {
  color: #f87171;
}

.toast-warning {
  border-left-color: var(--jeo-warning);
}
.toast-warning .toast-icon {
  color: #fbbf24;
}

.toast-info .toast-icon {
  color: var(--jeo-cyan);
}

.toast-out {
  animation: toastOut 0.3s ease forwards;
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateX(40px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes toastOut {
  to {
    opacity: 0;
    transform: translateX(40px);
  }
}

/* --------------------------------------------------------------------------
   MISC UTILITIES
   -------------------------------------------------------------------------- */
.gradient-text {
  background: linear-gradient(90deg, var(--jeo-cyan) 0%, #90e0ef 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.price-usd {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--jeo-gray-500);
  margin-top: 2px;
}

.dark-section .price-usd,
.price-usd-light {
  color: rgba(255, 255, 255, 0.55);
}

.divider-glow {
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(0, 180, 216, 0.5), transparent);
}

.fade-up {
  animation: fadeUp 0.6s ease both;
}

@keyframes fadeUp {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.spinner {
  width: 18px;
  height: 18px;
  border-radius: 999px;
  border: 3px solid rgba(255, 255, 255, 0.35);
  border-top-color: var(--jeo-white);
  animation: spin 0.7s linear infinite;
  display: inline-block;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.skeleton {
  background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 37%, #e2e8f0 63%);
  background-size: 400% 100%;
  animation: skeletonWave 1.4s ease infinite;
}

@keyframes skeletonWave {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}

/* Inline WhatsApp mark (Font Awesome Free 6.5.1 brands glyph, CC BY 4.0).
   Inlined rather than loaded from the webfont: WhatsApp was the only brand
   icon still used on the site, and shipping the 117KB fa-brands font for one
   glyph is not worth it. Sized in em and filled with currentColor so it drops
   into every slot the old <i> occupied and inherits existing colour classes. */
.icon-wa {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   CART DRAWER (slide-out mini cart)
   Markup is injected by initCartDrawer() in js/cart.js, so these styles are
   the only place its appearance is defined.

   z-index sits above the sticky header (z-50) but below .toast-container
   (z-100), so confirmation toasts stay readable over an open drawer.
   -------------------------------------------------------------------------- */
.cart-drawer-root {
  position: fixed;
  inset: 0;
  z-index: 90;
}

.cart-drawer-root[hidden] {
  display: none;
}

.cart-drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 25, 47, 0.55);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 0.28s ease;
}

.cart-drawer-root.is-open .cart-drawer-backdrop {
  opacity: 1;
}

.cart-drawer-panel {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: min(27rem, 100vw);
  background: var(--jeo-white);
  display: flex;
  flex-direction: column;
  box-shadow: -12px 0 40px rgba(10, 25, 47, 0.22);
  transform: translateX(100%);
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}

.cart-drawer-root.is-open .cart-drawer-panel {
  transform: translateX(0);
}

/* Stop the page behind the drawer scrolling while it is open. */
body.cart-drawer-lock {
  overflow: hidden;
}

/* ---------- Head ---------- */
.cart-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 1.5rem;
  background: var(--jeo-navy);
  color: var(--jeo-white);
  flex-shrink: 0;
}

.cart-drawer-title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 1rem;
  font-weight: 800;
  margin: 0;
}

.cart-drawer-title i {
  color: var(--jeo-cyan);
}

.cart-drawer-count {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--jeo-navy);
  background: var(--jeo-cyan);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}

.cart-drawer-close {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--jeo-white);
  background: rgba(255, 255, 255, 0.08);
  transition: background-color 0.2s ease, color 0.2s ease;
  flex-shrink: 0;
}

.cart-drawer-close:hover {
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
}

/* ---------- Body ---------- */
.cart-drawer-body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5rem 1.5rem;
}

.cart-drawer-line {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  gap: 0.9rem;
  align-items: start;
  padding: 1.1rem 0;
  border-bottom: 1px solid #e5e7eb;
}

.cart-drawer-line:last-child {
  border-bottom: 0;
}

.cart-drawer-thumb {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 0.75rem;
  object-fit: cover;
  background: var(--jeo-gray-100);
}

.cart-drawer-line-main {
  min-width: 0;
}

.cart-drawer-line-cat {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--jeo-cyan-dark);
  margin: 0;
}

.cart-drawer-line-name {
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--jeo-navy);
  line-height: 1.35;
  margin: 0.15rem 0 0;
}

.cart-drawer-line-unit {
  font-size: 0.75rem;
  color: var(--jeo-gray-500);
  margin: 0.2rem 0 0;
}

.cart-drawer-line-controls {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.6rem;
  flex-wrap: wrap;
}

.cart-drawer-stepper {
  display: flex;
  align-items: center;
  border: 1px solid #e5e7eb;
  border-radius: 0.5rem;
  overflow: hidden;
}

.cart-drawer-stepper button {
  width: 1.9rem;
  height: 1.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--jeo-gray-500);
  transition: background-color 0.15s ease, color 0.15s ease;
}

.cart-drawer-stepper button:hover {
  background: var(--jeo-gray-100);
  color: var(--jeo-navy);
}

.cart-drawer-stepper span {
  min-width: 2rem;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--jeo-navy);
}

.cart-drawer-remove {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--jeo-gray-500);
  transition: color 0.15s ease;
}

.cart-drawer-remove:hover {
  color: var(--jeo-error);
}

.cart-drawer-line-total {
  font-size: 0.875rem;
  font-weight: 800;
  color: var(--jeo-navy);
  white-space: nowrap;
  margin: 0;
}

/* ---------- Empty state ---------- */
.cart-drawer-empty {
  text-align: center;
  padding: 3.5rem 1rem;
}

.cart-drawer-empty-icon {
  width: 4rem;
  height: 4rem;
  border-radius: 999px;
  background: var(--jeo-gray-100);
  color: var(--jeo-gray-300);
  font-size: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1.25rem;
}

.cart-drawer-empty-title {
  font-weight: 800;
  color: var(--jeo-navy);
  margin: 0;
}

.cart-drawer-empty-copy {
  font-size: 0.85rem;
  color: var(--jeo-gray-500);
  line-height: 1.6;
  margin: 0.5rem auto 1.5rem;
  max-width: 17rem;
}

.cart-drawer-empty-btn {
  display: inline-block;
  background: var(--jeo-navy);
  color: var(--jeo-white);
  font-weight: 700;
  font-size: 0.85rem;
  padding: 0.75rem 1.5rem;
  border-radius: 0.6rem;
  transition: background-color 0.2s ease;
}

.cart-drawer-empty-btn:hover {
  background: var(--jeo-navy-lighter);
}

/* ---------- Foot ---------- */
.cart-drawer-foot:not(:empty) {
  border-top: 1px solid #e5e7eb;
  padding: 1.25rem 1.5rem calc(1.25rem + env(safe-area-inset-bottom, 0px));
  background: var(--jeo-white);
  flex-shrink: 0;
}

.cart-drawer-subtotal {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.9rem;
  color: var(--jeo-gray-500);
}

.cart-drawer-subtotal strong {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--jeo-navy);
  text-align: right;
}

.cart-drawer-note {
  font-size: 0.7rem;
  color: var(--jeo-gray-500);
  line-height: 1.5;
  margin: 0.6rem 0 1rem;
}

.cart-drawer-checkout {
  display: block;
  text-align: center;
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
  font-weight: 800;
  font-size: 0.9rem;
  padding: 0.9rem 1rem;
  border-radius: 0.7rem;
  transition: background-color 0.2s ease;
}

.cart-drawer-checkout:hover {
  background: var(--jeo-cyan-dark);
}

.cart-drawer-continue {
  display: block;
  width: 100%;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--jeo-gray-500);
  padding: 0.75rem 0 0;
  transition: color 0.2s ease;
}

.cart-drawer-continue:hover {
  color: var(--jeo-navy);
}

/* Respect a reduced-motion preference: the drawer still appears, it just
   does not slide or fade. */
@media (prefers-reduced-motion: reduce) {
  .cart-drawer-panel,
  .cart-drawer-backdrop {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   INLINE FORM VALIDATION
   Applied by initFormValidation() in js/cart.js. The forms keep their native
   constraints; these styles only cover how a failure is reported.
   -------------------------------------------------------------------------- */
.form-input.form-invalid,
.form-select.form-invalid,
.form-textarea.form-invalid {
  border-color: var(--jeo-error);
  background-color: rgba(220, 38, 38, 0.03);
}

.form-input.form-invalid:focus,
.form-select.form-invalid:focus,
.form-textarea.form-invalid:focus {
  border-color: var(--jeo-error);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.15);
}

.form-error {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  margin-top: 0.4rem;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--jeo-error);
}

/* Warning glyph drawn in CSS so the message needs no icon font to read as an
   error, and stays visible if the icon font is ever unavailable. */
.form-error::before {
  content: "!";
  flex-shrink: 0;
  width: 0.95rem;
  height: 0.95rem;
  margin-top: 0.05rem;
  border-radius: 999px;
  background: var(--jeo-error);
  color: var(--jeo-white);
  font-size: 0.65rem;
  font-weight: 800;
  line-height: 0.95rem;
  text-align: center;
}

/* --------------------------------------------------------------------------
   BACK TO TOP
   Injected by initBackToTop() in js/cart.js. Sits directly above the floating
   WhatsApp button (bottom: 24px, height: 60px) so the two never overlap.
   -------------------------------------------------------------------------- */
.back-to-top {
  position: fixed;
  right: 24px;
  bottom: 96px;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--jeo-navy);
  color: var(--jeo-white);
  font-size: 0.9rem;
  box-shadow: 0 6px 20px rgba(10, 25, 47, 0.28);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s,
    background-color 0.2s ease;
  z-index: 45;
}

.back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.back-to-top:hover {
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
}

@media (max-width: 480px) {
  .back-to-top {
    right: 18px;
    bottom: 84px;
    width: 40px;
    height: 40px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .back-to-top {
    transition: opacity 0.25s ease, visibility 0.25s;
    transform: none;
  }

  .back-to-top.is-visible {
    transform: none;
  }
}

/* ==========================================================================
   ART DIRECTION: "CALIBRATION"

   The visual language is borrowed from the equipment DE JEO actually sells -
   diagnostic displays, calibration targets, measurement grids, signal traces.
   Every decorative element here is meant to earn its place against that idea
   rather than being ornament for its own sake.

   Everything is CSS-only (no JS, no libraries, no extra network requests) and
   every animation is disabled under prefers-reduced-motion at the bottom of
   this block.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. AURORA FIELD
   Three blurred colour volumes drifting behind the hero. Animated with
   transform only, so the compositor handles it and no layout is recalculated.
   -------------------------------------------------------------------------- */
.aurora {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* Fades the whole field out toward the bottom so it never fights the
     content that follows. */
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
}

.aurora span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(72px);
  opacity: 0.55;
  will-change: transform;
}

.aurora span:nth-child(1) {
  width: 46vw;
  height: 46vw;
  min-width: 320px;
  min-height: 320px;
  left: -8vw;
  top: -14vw;
  background: radial-gradient(circle, rgba(0, 180, 216, 0.55), transparent 68%);
  animation: aurora-drift-a 22s ease-in-out infinite alternate;
}

.aurora span:nth-child(2) {
  width: 38vw;
  height: 38vw;
  min-width: 280px;
  min-height: 280px;
  right: -6vw;
  top: 4vw;
  background: radial-gradient(circle, rgba(144, 224, 239, 0.4), transparent 68%);
  animation: aurora-drift-b 26s ease-in-out infinite alternate;
}

.aurora span:nth-child(3) {
  width: 34vw;
  height: 34vw;
  min-width: 240px;
  min-height: 240px;
  left: 34%;
  bottom: -16vw;
  background: radial-gradient(circle, rgba(29, 45, 80, 0.9), transparent 70%);
  animation: aurora-drift-c 30s ease-in-out infinite alternate;
}

@keyframes aurora-drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(6vw, 4vw, 0) scale(1.15); }
}

@keyframes aurora-drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(-5vw, 6vw, 0) scale(0.95); }
}

@keyframes aurora-drift-c {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-7vw, -3vw, 0) scale(1.2); }
}

/* --------------------------------------------------------------------------
   2. MEASUREMENT GRID
   A finer, two-tier grid than a plain 42px mesh: light hairlines every 40px
   with a heavier rule every 200px, like the reticle on a calibration target.
   -------------------------------------------------------------------------- */
.grid-field {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(144, 224, 239, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(144, 224, 239, 0.07) 1px, transparent 1px),
    linear-gradient(rgba(144, 224, 239, 0.13) 1px, transparent 1px),
    linear-gradient(90deg, rgba(144, 224, 239, 0.13) 1px, transparent 1px);
  background-size: 40px 40px, 40px 40px, 200px 200px, 200px 200px;
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 35%, #000 30%, transparent 78%);
  mask-image: radial-gradient(ellipse 90% 70% at 50% 35%, #000 30%, transparent 78%);
}

/* --------------------------------------------------------------------------
   3. FILM GRAIN
   Fractal noise as a data URI, so it costs no request. Kept very low opacity;
   its job is to stop the large flat gradients from banding on cheap panels.
   -------------------------------------------------------------------------- */
.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   4. CALIBRATION MARKS
   Corner registration marks, the kind printed on a test target. Purely
   decorative, so they are aria-hidden in the markup.
   -------------------------------------------------------------------------- */
.calib {
  position: absolute;
  width: 16px;
  height: 16px;
  pointer-events: none;
  opacity: 0.5;
}

.calib::before,
.calib::after {
  content: "";
  position: absolute;
  background: var(--jeo-cyan);
}

.calib::before { top: 0; left: 0; width: 100%; height: 1px; }
.calib::after  { top: 0; left: 0; width: 1px; height: 100%; }

.calib-tr { transform: scaleX(-1); }
.calib-bl { transform: scaleY(-1); }
.calib-br { transform: scale(-1); }

/* --------------------------------------------------------------------------
   5. KINETIC HEADLINE
   Each line is masked and rises into place. Uses its own animation rather
   than the shared Motion scroll-reveal because the hero is above the fold and
   should not wait on an IntersectionObserver.
   -------------------------------------------------------------------------- */
.kinetic-line {
  display: block;
  overflow: hidden;
}

.kinetic-line > span {
  display: block;
  transform: translateY(105%);
  animation: kinetic-rise 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.kinetic-line:nth-child(1) > span { animation-delay: 0.05s; }
.kinetic-line:nth-child(2) > span { animation-delay: 0.16s; }
.kinetic-line:nth-child(3) > span { animation-delay: 0.27s; }

@keyframes kinetic-rise {
  to { transform: translateY(0); }
}

/* Everything else in the hero fades up behind the headline. */
.hero-stagger > * {
  opacity: 0;
  transform: translateY(14px);
  animation: hero-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.hero-stagger > *:nth-child(1) { animation-delay: 0.34s; }
.hero-stagger > *:nth-child(2) { animation-delay: 0.42s; }
.hero-stagger > *:nth-child(3) { animation-delay: 0.5s; }
.hero-stagger > *:nth-child(4) { animation-delay: 0.58s; }

@keyframes hero-in {
  to { opacity: 1; transform: translateY(0); }
}

/* --------------------------------------------------------------------------
   6. DISPLAY TYPE
   Inter pushed to a display setting: tighter tracking and optical sizing at
   large sizes, which is what stops a UI face from looking like body copy set
   big. clamp() carries it from 320px to wide desktop without breakpoints.
   -------------------------------------------------------------------------- */
.display-xl {
  /* Capped so each .kinetic-line holds a single visual line inside the 7/12
     column; above this the third line wraps and breaks the intended rhythm. */
  font-size: clamp(2.35rem, 4.9vw, 3.9rem);
  line-height: 0.98;
  letter-spacing: -0.035em;
  font-weight: 800;
  font-variation-settings: "opsz" 32;
}

.display-rule {
  display: inline-block;
  width: 2.5rem;
  height: 2px;
  background: var(--jeo-cyan);
  vertical-align: middle;
  margin-right: 0.85rem;
}

/* --------------------------------------------------------------------------
   7. INSTRUMENT PANEL
   The hero's right-hand visual. Glass over the aurora, with a scanning sweep
   and a signal trace along the bottom edge.
   -------------------------------------------------------------------------- */
.instrument {
  position: relative;
  border-radius: 1.5rem;
  overflow: hidden;
  background: linear-gradient(160deg, rgba(29, 45, 80, 0.75), rgba(10, 25, 47, 0.9));
  border: 1px solid rgba(144, 224, 239, 0.22);
  box-shadow:
    0 30px 70px -20px rgba(0, 0, 0, 0.65),
    inset 0 1px 0 rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(6px);
}

.instrument-media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.instrument-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Cool the photo toward the palette so it sits inside the art direction
     instead of reading as a pasted-in stock shot. */
  filter: saturate(0.85) contrast(1.05);
}

.instrument-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 35%, rgba(10, 25, 47, 0.92) 100%);
}

/* Scanning sweep, like a diagnostic display refreshing. */
.instrument-scan {
  position: absolute;
  left: 0;
  right: 0;
  height: 28%;
  top: -28%;
  background: linear-gradient(180deg, transparent, rgba(144, 224, 239, 0.16), transparent);
  animation: scan-sweep 4.5s ease-in-out infinite;
  pointer-events: none;
}

@keyframes scan-sweep {
  0%   { top: -28%; opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

.instrument-readout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.15rem;
  border-top: 1px solid rgba(144, 224, 239, 0.16);
}

.readout-label {
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(144, 224, 239, 0.75);
}

.readout-value {
  font-size: 0.95rem;
  font-weight: 800;
  color: var(--jeo-white);
  letter-spacing: -0.01em;
}

/* Live dot - a status indicator for the support desk, not a data readout. */
.readout-pulse {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7);
  animation: readout-pulse 2.2s ease-out infinite;
  flex-shrink: 0;
}

@keyframes readout-pulse {
  70%  { box-shadow: 0 0 0 9px rgba(34, 197, 94, 0); }
  100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
}

/* --------------------------------------------------------------------------
   8. MAGNETIC / GLOW CTA
   A sheen that tracks the pointer via --mx/--my, set in js/cart.js.
   -------------------------------------------------------------------------- */
.btn-magnetic {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.btn-magnetic::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.3s ease;
  background: radial-gradient(
    circle 110px at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, 0.28),
    transparent 65%
  );
}

.btn-magnetic:hover::after {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   9. SCROLL PROGRESS
   A hairline under the sticky header showing read position.
   -------------------------------------------------------------------------- */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--jeo-cyan), var(--jeo-cyan-light));
  z-index: 60;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   10. REDUCED MOTION
   Nothing above is load-bearing for comprehension, so all of it stops.
   Critically, the kinetic headline and hero stagger must resolve to their
   final visible state rather than staying translated off-screen.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .aurora span,
  .instrument-scan,
  .readout-pulse {
    animation: none;
  }

  .instrument-scan {
    display: none;
  }

  .kinetic-line > span,
  .hero-stagger > * {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* Eyebrow leads the hero, so it fades in ahead of the headline rise. */
.hero-eyebrow {
  opacity: 0;
  animation: hero-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.02s forwards;
}

@media (prefers-reduced-motion: reduce) {
  .hero-eyebrow { animation: none; opacity: 1; }
}

/* ==========================================================================
   CARD + SECTION TREATMENT
   Carries the hero's art direction through the rest of the page. A striking
   hero over a conventional body is what keeps a site out of a gallery, so the
   same language - measured rules, cyan edge light, calibration detail - is
   applied to the components that repeat.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Cards: an edge-lit border that resolves on hover.

   Drawn with a masked gradient border rather than border-image so the radius
   stays crisp, and composited on a pseudo-element so it costs no layout.
   -------------------------------------------------------------------------- */
.card-hover {
  position: relative;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.35s ease, border-color 0.35s ease;
}

.card-hover::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(140deg, rgba(0, 180, 216, 0.9), rgba(144, 224, 239, 0.15) 45%, transparent 70%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
}

.card-hover:hover::after {
  opacity: 1;
}

.card-hover:hover {
  transform: translateY(-6px);
  box-shadow: 0 22px 48px -18px rgba(0, 180, 216, 0.45), 0 8px 20px -12px rgba(10, 25, 47, 0.5);
  border-color: rgba(0, 180, 216, 0.28);
}

/* --------------------------------------------------------------------------
   Product imagery: a sweep of light across the frame on hover, echoing the
   hero's scanning readout.
   -------------------------------------------------------------------------- */
.product-image-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.22) 50%, transparent 62%);
  transform: translateX(-120%);
  transition: transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.card-hover:hover .product-image-wrap::after {
  transform: translateX(120%);
}

/* --------------------------------------------------------------------------
   Section eyebrow: the hero's measured rule, reused so section openers share
   one voice instead of the hero having its own.

   .section-badge is left in place for the pages that still use the pill; this
   is the variant applied where the editorial treatment reads better.
   -------------------------------------------------------------------------- */
.section-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--jeo-cyan-deep);
}

.section-eyebrow::before {
  content: "";
  width: 2.25rem;
  height: 2px;
  background: var(--jeo-cyan);
  flex-shrink: 0;
}

/* Any navy ground, however it is applied - a tagged dark section, a header
   band, or a Tailwind bg-navy callout - needs the light tone. */
.dark-section .section-eyebrow,
.hero-grid-bg .section-eyebrow,
.bg-navy .section-eyebrow {
  color: var(--jeo-cyan-light);
}

/* Centred section openers need the rule on both sides to stay balanced. */
.section-eyebrow-center::after {
  content: "";
  width: 2.25rem;
  height: 2px;
  background: var(--jeo-cyan);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Dark sections pick up the same grain and edge light as the hero, so the
   page reads as one surface rather than a bright body with dark bands.
   -------------------------------------------------------------------------- */
.dark-section {
  position: relative;
  isolation: isolate;
}

.dark-section > .grain {
  z-index: -1;
}

/* A hairline of cyan along the top edge of dark bands. */
.edge-lit {
  position: relative;
}

.edge-lit::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(0, 180, 216, 0.55), transparent);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .card-hover,
  .card-hover::after,
  .product-image-wrap::after,
  .product-image-wrap img {
    transition: none;
  }

  .card-hover:hover {
    transform: none;
  }

  .card-hover:hover .product-image-wrap::after {
    transform: translateX(-120%);
  }
}

/* Calibration marks are fine detail for wide viewports. Below lg they land on
   top of the eyebrow and read as rendering artefacts rather than intent, so
   they are dropped rather than repositioned. */
@media (max-width: 1023px) {
  .calib { display: none; }

  /* Slightly tighter tracking so the eyebrow holds one line further down. */
  .hero-eyebrow {
    letter-spacing: 0.14em;
  }
}

/* Three large blur(72px) layers animating continuously is real compositing
   work every frame. On phones - mid-range Android is common in this market -
   the drift is not worth the battery, so the aurora holds a static pose. The
   look is preserved; only the animation stops. Blur radius is also reduced,
   since a smaller radius on a smaller viewport reads the same. */
@media (max-width: 1023px) {
  .aurora span {
    animation: none;
    filter: blur(52px);
  }
}

/* --------------------------------------------------------------------------
   Section headings. The hero sets the type voice; without this, section
   headings fall back to default Tailwind tracking and read as a different
   system sitting under an art-directed hero.
   -------------------------------------------------------------------------- */
.display-lg {
  font-size: clamp(1.85rem, 3.1vw, 2.6rem);
  line-height: 1.08;
  letter-spacing: -0.028em;
  font-weight: 800;
  font-variation-settings: "opsz" 28;
  text-wrap: balance;
}

/* ==========================================================================
   PAYMENT RECEIPT UPLOAD (checkout step 2)
   ========================================================================== */

/* Visually hidden but still focusable and in the accessibility tree, so the
   control is reachable by keyboard and announced by screen readers. Not
   display:none, which would remove it from both. */
.receipt-input-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.receipt-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem 1.25rem;
  border: 2px dashed rgba(10, 25, 47, 0.18);
  border-radius: 1rem;
  background: #f9fafb;
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
}

.receipt-dropzone:hover {
  border-color: var(--jeo-cyan);
  background: rgba(0, 180, 216, 0.05);
}

/* The label is the visible control, so it has to carry the focus ring for the
   input it is bound to - otherwise keyboard users get no visible focus at all. */
.receipt-input-hidden:focus-visible + .receipt-dropzone {
  outline: 3px solid var(--jeo-cyan);
  outline-offset: 3px;
  border-color: var(--jeo-cyan);
}

.receipt-dropzone.is-dragover {
  border-color: var(--jeo-cyan);
  background: rgba(0, 180, 216, 0.09);
  transform: scale(1.01);
}

.receipt-preview {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.9rem 1rem;
  border: 1px solid rgba(22, 163, 74, 0.3);
  border-radius: 0.85rem;
  background: rgba(22, 163, 74, 0.06);
}

.receipt-thumb {
  width: 52px;
  height: 52px;
  border-radius: 0.6rem;
  background-color: var(--jeo-navy);
  background-size: cover;
  background-position: center;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--jeo-cyan);
  font-size: 1.25rem;
}

/* Busy state on the submit button while the order is in flight. */
.is-submitting {
  position: relative;
  pointer-events: none;
}

.is-submitting > * {
  opacity: 0.35;
}

.is-submitting::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border: 2px solid rgba(10, 25, 47, 0.25);
  border-top-color: var(--jeo-navy);
  border-radius: 50%;
  animation: receipt-spin 0.7s linear infinite;
}

@keyframes receipt-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .receipt-dropzone,
  .receipt-dropzone.is-dragover {
    transition: none;
    transform: none;
  }

  /* The spinner is the only signal that work is happening, so it is slowed
     rather than removed - a static ring would read as a frozen page. */
  .is-submitting::after {
    animation-duration: 2.4s;
  }
}

/* ==========================================================================
   PRODUCTS: STICKY HEADER + FILTER BAR

   Two stacked sticky bars were holding 205px - a quarter of an 820px
   viewport - permanently occupied while browsing the catalog. The site
   header now steps out of the way on scroll down and returns on scroll up,
   and the filter bar condenses once it is pinned.
   ========================================================================== */

:root {
  /* How far down the filter bar sits. JS drops this to 0 when the site
     header hides, so the bar rides up rather than leaving a gap. */
  --header-offset: 80px;
}

[data-site-header] {
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}

[data-site-header].header-hidden {
  transform: translateY(-100%);
}

.filter-bar {
  position: sticky;
  top: var(--header-offset);
  /* Frosted rather than a flat white slab, so it reads as a layer over the
     catalog instead of a second opaque bar bolted under the header. */
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  transition: top 0.28s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease;
}

/* Backdrop-filter is unreliable on some older Android browsers; without it
   the translucent background would let content show through as mush. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .filter-bar {
    background: #ffffff;
  }
}

.filter-bar-inner {
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
}

/* Pinned state changes appearance only - never height.

   An earlier version also shrank the padding here. Because the bar sits in
   normal flow, that removed 60px from document height mid-scroll; the
   browser's scroll anchoring compensated, the compensation registered as an
   upward scroll, and the auto-hiding header sprang back. Anything that
   changes this element's height while pinned will reintroduce that loop. */
.filter-bar.is-stuck {
  box-shadow: 0 6px 20px -12px rgba(10, 25, 47, 0.4);
  border-bottom-color: rgba(10, 25, 47, 0.08);
}

@media (prefers-reduced-motion: reduce) {
  [data-site-header],
  .filter-bar,
  .filter-bar-inner {
    transition: none;
  }
}

/* The category chips scroll horizontally with the scrollbar hidden, so
   without an affordance the last visible chip just looks clipped mid-word.
   A mask fades the trailing edge, which reads as "more this way" rather than
   as a rendering fault. The fade is removed once scrolled to the end so it
   does not dim a chip the user has already reached. */
#category-filters {
  --chip-fade: 2.5rem;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--chip-fade)), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - var(--chip-fade)), transparent 100%);
  transition: -webkit-mask-image 0.2s ease, mask-image 0.2s ease;
}

#category-filters.is-scroll-end {
  --chip-fade: 0rem;
}

/* ==========================================================================
   UTILITIES REPLACING INLINE style= ATTRIBUTES

   These existed only so style-src could stop allowing 'unsafe-inline'.
   Adding a style attribute back to any page re-opens that hole.
   ========================================================================== */

/* Corner registration marks. Position lived inline; the .calib-* modifiers
   already existed for the mirroring, so they now carry placement too. */
.calib-tl { top: 96px; left: 28px; }
.calib-tr { top: 96px; right: 28px; }
.calib-bl { bottom: 28px; left: 28px; }
.calib-br { bottom: 28px; right: 28px; }

/* Honeypot wrapper: off-screen but still focusable and in the a11y tree,
   which is why it is not display:none. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ==========================================================================
   STOREFRONT HERO

   The search field is the hero's primary action, so it is sized like one:
   large target, high contrast against the navy, and visually the heaviest
   element after the headline.
   ========================================================================== */

.hero-search {
  position: relative;
  display: flex;
  align-items: center;
  max-width: 34rem;
  margin-inline: auto;
}

.hero-search-icon {
  position: absolute;
  left: 1.25rem;
  color: #94a3b8;
  pointer-events: none;
  font-size: 0.95rem;
}

.hero-search-input {
  width: 100%;
  padding: 1.15rem 4rem 1.15rem 3.1rem;
  border-radius: 999px;
  border: 1px solid rgba(144, 224, 239, 0.28);
  background: rgba(255, 255, 255, 0.97);
  color: var(--jeo-navy);
  font-size: 0.98rem;
  font-weight: 500;
  box-shadow: 0 18px 40px -22px rgba(0, 0, 0, 0.85);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.hero-search-input::placeholder { color: #94a3b8; }

.hero-search-input:focus {
  outline: none;
  border-color: var(--jeo-cyan);
  box-shadow: 0 0 0 4px rgba(0, 180, 216, 0.25), 0 18px 40px -22px rgba(0, 0, 0, 0.85);
}

.hero-search-btn {
  position: absolute;
  right: 0.4rem;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  border: 0;
  background: var(--jeo-cyan);
  color: var(--jeo-navy);
  font-size: 0.95rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease, transform 0.2s ease;
}

.hero-search-btn:hover { background: var(--jeo-cyan-light); }
.hero-search-btn:active { transform: scale(0.94); }

/* Category shortcuts under the search field. */
.hero-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 0.95rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  color: #e2e8f0;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.hero-chip:hover {
  background: rgba(0, 180, 216, 0.16);
  border-color: var(--jeo-cyan);
  color: #ffffff;
}

.hero-chip-all {
  background: rgba(0, 180, 216, 0.16);
  border-color: rgba(0, 180, 216, 0.5);
  color: var(--jeo-cyan-light);
}

@media (prefers-reduced-motion: reduce) {
  .hero-search-input,
  .hero-search-btn,
  .hero-chip { transition: none; }
  .hero-search-btn:active { transform: none; }
}

