/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/* ===== Brand & Secondary Colors ===== */
:root {
  /* Brand Primary */
  --brand-primary: #2468EA;
  --core-bright-blue: #64E1FF;
  --core-ocean-blue: #00304B;
  --core-mist-blue: #EAEEF0;

  /* Secondary Colors (Light Mode) */
  --secondary-orange: #FFC091;
  --secondary-yellow: #FFEB69;
  --secondary-blue: #A0E1E1;
  --secondary-pink: #FFD7EF;

  /* Status Colors (Light Mode) - uses secondary colors */
  --status-in-stock: #FFC091;
  --status-in-stock-text: #1a1a1a;
  --status-listed: #FFEB69;
  --status-listed-text: #1a1a1a;
  --status-sold: #A0E1E1;
  --status-sold-text: #1a1a1a;
  --status-defective: #FFD7EF;
  --status-defective-text: #1a1a1a;
}

html[data-theme="dark"] {
  /* Secondary Colors (Dark Mode) */
  --secondary-orange: #260A2F;
  --secondary-yellow: #3A341C;
  --secondary-blue: #21231D;
  --secondary-pink: #320707;

  /* Status Colors (Dark Mode) */
  --status-in-stock: #260A2F;
  --status-in-stock-text: #FFC091;
  --status-listed: #3A341C;
  --status-listed-text: #FFEB69;
  --status-sold: #21231D;
  --status-sold-text: #A0E1E1;
  --status-defective: #320707;
  --status-defective-text: #FFD7EF;
}

/* Design system helpers */
.design-colors__core-shift {
  filter: hue-rotate(110deg);
}

/* Inventory item row chevron rotation when details is open */
details[open] .inventory-chevron {
  transform: rotate(90deg);
}

/* Make hover background have equal padding on all sides (6px) */
.inventory-table__row::after {
  left: 6px !important;
  right: 6px !important;
}

/* Inventory item row highlight when expanded - matches hover ::after styling */
details[open] > summary.inventory-table__row::after {
  background-color: color-mix(in oklab, var(--primary) 10%, transparent);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  bottom: 0;
}

details[open] > .inventory-expanded-content {
  position: relative;
  margin-left: 6px;
  margin-right: 6px;
  margin-bottom: 6px;
  padding-left: calc(1.25rem - 6px);
  padding-right: calc(1.25rem - 6px);
  background-color: color-mix(in oklab, var(--primary) 10%, transparent);
  border-bottom-left-radius: 2px;
  border-bottom-right-radius: 2px;
}

/* Make form field containers transparent to show expanded row background (exclude modals) */
details[open] > .inventory-expanded-content .bg-\[var\(--surface2\)\]:not(.inventory-status__modal-panel) {
  background-color: transparent !important;
}

/* Modal overlay - ensure it covers everything */
.inventory-status__modal-overlay {
  z-index: 9999 !important;
}

/* Keep modal panels with solid background */
.inventory-status__modal-panel {
  background-color: #ffffff !important;
  position: relative;
  z-index: 10000 !important;
}

html[data-theme="dark"] .inventory-status__modal-panel {
  background-color: #292d29 !important;
}

/* Make borders more visible inside expanded content (exclude status pills) */
details[open] > .inventory-expanded-content .border-\[var\(--border\)\]:not(.status-pill) {
  border-color: color-mix(in oklab, var(--text) 30%, transparent) !important;
}

/* Remove browser focus ring from inputs inside expanded content */
details[open] > .inventory-expanded-content input:focus,
details[open] > .inventory-expanded-content textarea:focus {
  outline: none !important;
  box-shadow: none !important;
}

/* ===== Inventory table frame — Hairline Ledger (Mono) =====
   White card bounded by a single 1px hairline (no elevation, squared 2px corners).
   The hairline is ink-tinted to ~3.6:1 on the WHITE page (--bg is white under
   .app-mono) so the boundary reads in bright sunlight — a plain --line hairline is
   only 1.27:1 and dissolved into the page (the original bug; WCAG 1.4.11 wants
   ≥3:1 for a non-text boundary). Replaces the old no-border / shallow-shadow /
   24px-round frame. The .app-mono prefix gives (0,2,0) so these beat ui.css's base
   .inventory-table__* rules (which load AFTER this file) — no !important needed. */
.app-mono .inventory-table__frame {
  background: var(--surface2);
  border: 1px solid color-mix(in oklab, var(--ink) 45%, var(--white));
  box-shadow: none;
  border-radius: 2px;
}
/* Inner card transparent so the mist frame surface reads through; .app-mono
   scope wins over ui.css's --surface2 card on specificity (non-Mono keeps it). */
.app-mono .inventory-table__card {
  background: transparent;
  border-radius: 2px;
}
/* Hover/expanded overlay corner follows the squared frame (was 16px). */
.app-mono .inventory-table__row::after {
  border-radius: 2px;
}

/* ===== Item-details Mono coherence (PR: item-details-mono-coherence) =====
   One canonical hairline everywhere on the page. The 3.6:1 ink-tinted boundary
   (WCAG 1.4.11 ≥3:1 in sunlight) replaces the faint --line (~1.27:1) on cards and
   the ~2.0:1 input/upload border. Scoped to .app-mono because --ink/--white are
   Mono tokens; (0,2,0) beats ui.css base rules without !important. */
.app-mono .ds-card,
.app-mono .ds-surface-card,
.app-mono .ds-input-container,
.app-mono .ds-upload {
  border-color: color-mix(in oklab, var(--ink) 45%, var(--white));
}

/* Stat/KPI cards: Mono is hairline-over-shadow — drop the elevation so the tiles
   match the flat hairline frame instead of reading as raised bubbles. */
.app-mono .ds-card {
  box-shadow: none;
}

/* Photo dropzone: squared 2px corners (was 12px) + a dashed "drop here" edge, and
   a solid ink focus ring to match inputs (was a sub-3:1 coloured glow). */
.app-mono .ds-upload {
  border-radius: 2px;
  border-style: dashed;
}
.app-mono .ds-upload:focus-within {
  border-color: var(--focus_ring);
  box-shadow: inset 0 0 0 1px var(--focus_ring);
}

/* Financial tiles: equal-height rows that hug content (no forced h-full, which
   stretched tiles to the neighbour column and left dead vertical space). */
.app-mono .ds-financial-grid {
  grid-auto-rows: 1fr;
}

/* Units table: one interior inset — the row separator sits flush with the 20px
   (px-5) content edge instead of an orphaned 22px. */
.app-mono .inventory-table__separator {
  margin: 0 20px;
}

/* Adjust grid columns to fit status chip in one row; trailing cell holds the
   Sell action + chevron, so it needs more than the old 28px chevron-only width. */
.inventory-table__grid {
  grid-template-columns: 36px minmax(180px, 2.5fr) minmax(70px, 0.6fr) minmax(100px, 0.8fr) minmax(110px, 0.85fr) minmax(72px, auto) !important;
}

/* Prevent status badge text from wrapping */
.status-badge {
  white-space: nowrap !important;
}

/* Profit cards use same gray as table frame background */
.profit-card {
  background: color-mix(in oklab, var(--text) 8%, transparent);
}

/* Mono card elevation — exposes the subtle SoT drop shadow (ui.css --shadow-card)
   on a flat ds-surface-card, matching the Claude Design capture prototype
   (card-flat + box-shadow: var(--shadow-card)) without ds-card's flex layout. */
.ds-elevated {
  box-shadow: var(--shadow-card);
}

/* Mono Tag default: white hairline chip (ink text), no off-brand blue. */
.category-tag-chip {
  background-color: var(--white) !important;
  border: 1px solid var(--line) !important;
  color: var(--ink) !important;
}

/* ===== Status Badge & Pill Overrides (Light Mode) ===== */
.status-badge--in_stock,
.peer:checked + .status-pill--in_stock {
  background-color: #FFC091 !important;
  color: #1a1a1a !important;
  border-color: #FFC091 !important;
  border-width: 2px !important;
  border-style: solid !important;
}

.status-badge--listed,
.peer:checked + .status-pill--listed {
  background-color: #FFEB69 !important;
  color: #1a1a1a !important;
  border-color: #FFEB69 !important;
  border-width: 2px !important;
  border-style: solid !important;
}

.status-badge--sold,
.peer:checked + .status-pill--sold {
  background-color: #A0E1E1 !important;
  color: #1a1a1a !important;
  border-color: #A0E1E1 !important;
  border-width: 2px !important;
  border-style: solid !important;
}

.status-badge--defective,
.peer:checked + .status-pill--defective {
  background-color: #FFD7EF !important;
  color: #1a1a1a !important;
  border-color: #FFD7EF !important;
  border-width: 2px !important;
  border-style: solid !important;
}

/* Status bar fills (Light Mode) */
.status-bar__fill--in_stock {
  background-color: #FFC091 !important;
}

.status-bar__fill--listed {
  background-color: #FFEB69 !important;
}

.status-bar__fill--sold {
  background-color: #A0E1E1 !important;
}

.status-bar__fill--defective {
  background-color: #FFD7EF !important;
}

/* Status bar container text colors (Light Mode) */
.status-bar-container:has(.status-bar__fill--in_stock),
.status-bar-container:has(.status-bar__fill--listed),
.status-bar-container:has(.status-bar__fill--sold),
.status-bar-container:has(.status-bar__fill--defective) {
  color: #1a1a1a !important;
}

/* ===== Status Badge & Pill Overrides (Dark Mode) ===== */
html[data-theme="dark"] .status-badge--in_stock,
html[data-theme="dark"] .peer:checked + .status-pill--in_stock {
  background-color: #260A2F !important;
  color: #FFC091 !important;
  border-color: #260A2F !important;
  border-width: 2px !important;
  border-style: solid !important;
}

html[data-theme="dark"] .status-badge--listed,
html[data-theme="dark"] .peer:checked + .status-pill--listed {
  background-color: #3A341C !important;
  color: #FFEB69 !important;
  border-color: #3A341C !important;
  border-width: 2px !important;
  border-style: solid !important;
}

html[data-theme="dark"] .status-badge--sold,
html[data-theme="dark"] .peer:checked + .status-pill--sold {
  background-color: #21231D !important;
  color: #A0E1E1 !important;
  border-color: #21231D !important;
  border-width: 2px !important;
  border-style: solid !important;
}

html[data-theme="dark"] .status-badge--defective,
html[data-theme="dark"] .peer:checked + .status-pill--defective {
  background-color: #320707 !important;
  color: #FFD7EF !important;
  border-color: #320707 !important;
  border-width: 2px !important;
  border-style: solid !important;
}

/* Status bar fills (Dark Mode) */
html[data-theme="dark"] .status-bar__fill--in_stock {
  background-color: #260A2F !important;
}

html[data-theme="dark"] .status-bar__fill--listed {
  background-color: #3A341C !important;
}

html[data-theme="dark"] .status-bar__fill--sold {
  background-color: #21231D !important;
}

html[data-theme="dark"] .status-bar__fill--defective {
  background-color: #320707 !important;
}

/* Status bar container text colors (Dark Mode) */
html[data-theme="dark"] .status-bar-container:has(.status-bar__fill--in_stock) {
  color: #FFC091 !important;
}

html[data-theme="dark"] .status-bar-container:has(.status-bar__fill--listed) {
  color: #FFEB69 !important;
}

html[data-theme="dark"] .status-bar-container:has(.status-bar__fill--sold) {
  color: #A0E1E1 !important;
}

html[data-theme="dark"] .status-bar-container:has(.status-bar__fill--defective) {
  color: #FFD7EF !important;
}

/* Remove borders from status bar containers in dark mode */
html[data-theme="dark"] .status-bar__fill {
  border: none !important;
}

/* Status bar container - remove border in dark mode */
html[data-theme="dark"] div:has(> .status-bar__fill) {
  border: none !important;
}

/* ===== Status Toggle Buttons (Inventory page) ===== */
.status-toggle-btn {
  color: var(--muted);
  transition: background-color 0.15s, color 0.15s;
}

.status-toggle-btn[data-active="true"] {
  background-color: var(--text);
  color: var(--bg);
}

/* ===== Segmented Control (Wise-style toggle) ===== */
.ds-segmented {
  position: relative;
  display: grid;
  align-items: center;
  padding: 4px;
  border-radius: 9999px;
  background: color-mix(in oklab, var(--text) 8%, transparent);
  overflow: hidden;
}

/* minmax(0, 1fr) — NOT bare 1fr. A bare 1fr is minmax(auto, 1fr), whose auto
   floor sizes each track to its own label width; with unequal labels (Today /
   This week / This month) on a narrow phone the tracks become unequal, so the
   centered text drifts off the equal-thirds sliding pill. minmax(0, …) forces
   genuinely equal tracks that match the pill geometry. */
.ds-segmented--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.ds-segmented--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Sliding pill indicator */
.ds-segmented::before {
  content: "";
  position: absolute;
  top: 4px;
  left: 4px;
  height: calc(100% - 8px);
  border-radius: 9999px;
  background: var(--surface2);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transition: transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
  pointer-events: none;
}

/* 2-option pill width */
.ds-segmented--2::before {
  width: calc(50% - 4px);
}

/* 3-option pill width */
.ds-segmented--3::before {
  width: calc(33.333% - 2.67px);
}

/* Pill positions for 2 options */
.ds-segmented--2[data-active="1"]::before {
  transform: translateX(0);
}

.ds-segmented--2[data-active="2"]::before {
  transform: translateX(100%);
}

/* Pill positions for 3 options */
.ds-segmented--3[data-active="1"]::before {
  transform: translateX(0);
}

.ds-segmented--3[data-active="2"]::before {
  transform: translateX(100%);
}

.ds-segmented--3[data-active="3"]::before {
  transform: translateX(200%);
}

/* Hide pill when no option is active (e.g., dropdown selection) */
.ds-segmented[data-active="0"]::before {
  opacity: 0;
  transform: translateX(-100%); /* Move off-screen for clean transition */
}

/* Segment button */
.ds-segment {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  padding: 0 12px;
  border-radius: 9999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border: none;
  outline: none;
  cursor: pointer;
  white-space: nowrap;
  transition: color 150ms ease;
}

.ds-segment:focus-visible {
  outline: 2px solid var(--focus_ring);
  outline-offset: 2px;
}

/* Active segment text */
.ds-segment[data-active="true"] {
  color: var(--text);
}

/* With icons */
.ds-segment__icon {
  width: 16px;
  height: 16px;
  margin-right: 6px;
  flex-shrink: 0;
}

/* Mobile touch targets (WCAG 2.1 minimum 44px) */
@media (max-width: 767px) {
  .ds-segmented {
    padding: 6px;
  }

  .ds-segment {
    min-height: 44px;
    padding: 0 16px;
  }

  .ds-segmented--2::before,
  .ds-segmented--3::before {
    top: 6px;
    left: 6px;
    height: calc(100% - 12px);
  }

  .ds-segmented--2::before {
    width: calc(50% - 6px);
  }

  .ds-segmented--3::before {
    width: calc(33.333% - 4px);
  }
}

/* ===== Button Component Variants ===== */
/* Explicit CSS to ensure button colors work regardless of Tailwind scanning */

.btn-variant-primary {
  background-color: var(--primary);
  color: var(--primary_fg);
}

.btn-variant-primary:hover {
  background-color: var(--primary_hover);
}

.btn-variant-secondary {
  background-color: var(--white);
  color: var(--ink);
  border: 1px solid var(--ink);
}

/* Derived from the button's OWN tokens, not the page theme. The base rule above pins --white and
   --ink, both scope-invariant, but --surface follows the theme: at :root in dark mode it is
   #1a1d18, so hovering put a near-black fill under a hardcoded #0e0e0c label — measured 1.13:1,
   an invisible label.

   SCOPE, precisely: this only ever bit :root-scoped pages. .landing and the ~49 .app-mono views
   set their scope class on <body>, which REDECLARES --surface on a nearer ancestor than
   html[data-theme="dark"] — custom-property inheritance, not specificity — so those surfaces
   resolve #F4F4F2 in both themes and never saw the dark value. Worth stating because a rendered
   spec pointed at /marketplace cannot fail, which is exactly the trap it caught during review.

   A tint of the button's own ink over its own white keeps fill and label in one family and reads
   identically in light and dark: rgb(238,238,238), 16.65:1. On the mono surfaces the hover step
   is now slightly STRONGER than before (17/255 vs 13/255); only :root-light is softer (was
   27/255). If :root-light parity is ever wanted, 8% lands at ~22/255. */
.btn-variant-secondary:hover {
  background-color: color-mix(in oklab, var(--ink) 6%, var(--white));
}

.btn-variant-ghost {
  background-color: transparent;
  color: var(--text);
}

.btn-variant-ghost:hover {
  background-color: var(--surface);
}

/* Mono 5th variant: quiet = muted hairline (transparent fill). */
.btn-variant-quiet {
  background-color: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
}

.btn-variant-quiet:hover {
  background-color: var(--surface);
}

.btn-variant-danger {
  background-color: var(--danger);
  color: var(--danger_fg);
}

.btn-variant-danger:hover {
  opacity: 0.9;
}

/* Mono focus = border thickens to a 2px ink frame, NO coloured ring.
   The inset box-shadow gives the 2px ink edge without affecting layout. */
.btn-variant-primary:focus-visible,
.btn-variant-secondary:focus-visible,
.btn-variant-ghost:focus-visible,
.btn-variant-quiet:focus-visible,
.btn-variant-danger:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--ink);
}

/* ===== Terminal CTA Button ===== */
/* Ocean blue bg with bright blue text, inverted in dark mode */
.btn-terminal-cta {
  background-color: var(--core-ocean-blue);
  color: var(--core-bright-blue);
  transition: transform 0.1s ease, filter 0.15s ease, box-shadow 0.15s ease;
}

.btn-terminal-cta:hover {
  filter: brightness(1.15);
  box-shadow: 0 6px 20px rgba(0, 48, 75, 0.3);
}

.btn-terminal-cta:active {
  transform: scale(0.97);
  filter: brightness(0.95);
  box-shadow: 0 2px 8px rgba(0, 48, 75, 0.2);
}

.btn-terminal-cta:focus-visible {
  outline: 2px solid var(--core-bright-blue);
  outline-offset: 2px;
}

.link-terminal-cta {
  color: var(--core-bright-blue);
  transition: opacity 0.15s ease;
}

.link-terminal-cta:hover {
  opacity: 0.8;
}

html[data-theme="dark"] {
  .btn-terminal-cta {
    background-color: var(--core-bright-blue);
    color: var(--core-ocean-blue);
  }

  .btn-terminal-cta:hover {
    box-shadow: 0 6px 20px rgba(100, 225, 255, 0.3);
  }

  .btn-terminal-cta:active {
    box-shadow: 0 2px 8px rgba(100, 225, 255, 0.2);
  }

  .btn-terminal-cta:focus-visible {
    outline-color: var(--core-ocean-blue);
  }

  .link-terminal-cta {
    color: var(--core-ocean-blue);
  }

  .pricing-card-premium {
    box-shadow:
      0 0 15px 0 rgba(100, 225, 255, 0.08),
      0 0 45px 0 rgba(100, 225, 255, 0.06),
      0 8px 80px -10px rgba(100, 225, 255, 0.10);
    background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.04), transparent 50%);
    background-color: color-mix(in oklab, var(--primary) 4%, var(--surface2));
  }
}

/* ===== Order Status Segmented Control ===== */
/* Matches theme toggle pattern from account menu */

.order-status-segmented {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  height: 40px;
  min-width: 200px;
  padding: 3px;
  border-radius: 9999px;
  background: var(--white);
  border: 1px solid var(--line);
  overflow: hidden;
}

.order-status-segmented::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: calc(50% - 3px);
  height: calc(100% - 6px);
  border-radius: 9999px;
  background: var(--ink);
  box-shadow: none;
  transition: transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.order-status-segmented[data-active="in_stock"]::before {
  transform: translateX(100%);
}

.order-status-segment {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  border-radius: 9999px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  background: transparent;
  padding: 0;
  border: none;
  cursor: pointer;
  /* Physicality: each segment presses with the one Mono spring (transform only),
     reduced-motion-safe. Tokens (--mono-press-scale / --mono-spring / --mono-dur-fast)
     are defined on :root in ui.css, which loads on every layout alongside this file. */
  transition: color 160ms ease, transform var(--mono-dur-fast) var(--mono-spring);
}

@media (prefers-reduced-motion: no-preference) {
  .order-status-segment:active:not(:disabled) {
    transform: scale(var(--mono-press-scale));
  }
}

/* Selected segment sits on the ink fill → white text, weight 600 */
.order-status-segment[aria-checked="true"] {
  color: var(--white);
  font-weight: 600;
}

/* Mono focus = 2px ink outline, no coloured ring (hardcode --ink so the
   non-.app-mono --focus_ring blue can't leak in). */
.order-status-segment:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ===== Arrival Date Modal Panel ===== */
/* Ensure modal has solid opaque background that stands out from page */

.arrival-modal__panel {
  /* Match account menu dropdown background */
  background-color: #292d29 !important;
  /* Subtle top highlight for elevation */
  background-image: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.06),
    transparent 50%
  );
}

/* Light mode: use white for clean appearance */
html[data-theme="light"] .arrival-modal__panel {
  background-color: #ffffff !important;
  background-image: none;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

/* ===== Form field tap target ===== */
/* The visible field is the 48px .ds-input-container; the bare input inside is ~24px.
   House pattern: the container is a <label>, so the WHOLE field forwards taps to its
   control. EXCEPTION — pill fields keep a <div> and focus via pill-input#focusInput:
   their pills each carry a ✕ <button>, and an implicit label's control is its first
   labelable descendant, so a padding tap would DELETE a pill instead of focusing.
   The cursor tells the same story on both; selects keep their own affordance. */
label.ds-input-container,
.ds-input-container[data-action*="pill-input#focusInput"] {
  cursor: text;
}

label.ds-input-container:has(select) {
  cursor: default;
}

/* ===== Order Items Table ===== */

/* Inventory pricing table: 5 columns on >=640px; stacked two-line rows on phones so the
   editable price cell never forces horizontal scroll (the seller prices from her phone).
   The Cost/Qty columns collapse into the meta line below the item name at narrow widths —
   cost basis stays visible, because that is the number a price is decided against. */
.order-items-table__grid--pricing {
  display: grid;
  gap: 2px 10px;
  align-items: center;
  grid-template-areas:
    "name  price chev"
    "meta  price chev";
  grid-template-columns: minmax(0, 1fr) 128px 28px;
}

.oi-cell--name { grid-area: name; }

/* Item name: wrap to two lines, never a single-line hard truncate — the name is what the
   seller prices against. Clamp keeps extreme names from breaking row rhythm. */
.oi-name-clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.oi-cell--cost { grid-area: cost; display: none; }
.oi-cell--qty { grid-area: qty; display: none; }
.oi-cell--meta { grid-area: meta; }
.oi-cell--price { grid-area: price; }
.oi-cell--chev { grid-area: chev; }

/* Vertical rhythm — the 48px price FIELD is the row's alignment datum, not the price CELL.
   The cell is a stack (field + the "Buyer pays" hint), so centring every cell on the row's
   midline floated the field ~9px above the item name it prices. Instead each text cell owns
   the same 48px band as the field and centres inside it; the hint hangs below the band.
   Scoped to .inventory-table__row: the header label row keeps its own compact height. */
.inventory-table__row .order-items-table__grid--pricing { align-items: start; }

/* A single-column grid, not flex — a grid item still stretches to the full column width, so
   the name's 2-line clamp and the cost/qty `text-right` keep behaving exactly as before. */
.inventory-table__row .oi-cell--name { min-height: 48px; display: grid; align-items: center; }

/* Already display:flex from the template; it only needs the band. */
.inventory-table__row .oi-cell--chev { min-height: 48px; align-items: center; }

/* Reserve the hint lane (48 field + 4 gap + 18 hint) so rows keep one rhythm whether a row shows
   a buyer-pays line, a mixed min–max range, or nothing — but ONLY on a table where a hint can
   actually appear (.oi-hint-lane, set when the fee is active or some batch is mixed). On a BR
   account, a demo account, or with the fee flag off, no row can ever show one.
   The saving is 22px per row at >=640px and exactly 0px at 390px — on phones the stacked grid
   (name 48 + meta 33 = 81px) already exceeds the lane, so it never drove row height there.
   Measured, because an earlier version of this comment credited the saving to "the phone pricing
   surface", which is the one width where it does not apply. */
.oi-hint-lane .inventory-table__row .oi-cell--price { min-height: 70px; }

/* The column header labels nothing at phone width (rows label themselves). */
.order-items-table__grid--pricing.inventory-table__header {
  display: none;
}

@media (min-width: 640px) {
  .order-items-table__grid--pricing {
    grid-template-areas: "name cost qty price chev";
    grid-template-columns: minmax(140px, 1fr) minmax(64px, 0.45fr) minmax(48px, 0.35fr) 128px 28px;
    gap: 10px;
  }

  .oi-cell--cost,
  .oi-cell--qty { display: block; }
  .oi-cell--meta { display: none; }

  /* Same 48px band as the name and the field (see the datum note above). The header's own
     cost/qty cells stay `display: block` — they are not inside .inventory-table__row. */
  .inventory-table__row .oi-cell--cost,
  .inventory-table__row .oi-cell--qty { display: grid; min-height: 48px; align-items: center; }

  .order-items-table__grid--pricing.inventory-table__header {
    display: grid;
  }
}

/* Hide the last row's trailing separator (rows are id'd divs, replaced by turbo_stream) */
.inventory-table__card > div:last-child .inventory-table__separator {
  display: none;
}

/* Row links (title + chevron) — background hover is sufficient feedback */
.inventory-table__card a {
  text-decoration: none;
}

/* ===== Typography: Display System ===== */
/* Based on design system: Archivo Black, bold, 85% line-height, 1.5% letter-spacing, uppercase */

/* Display Small - for item codes and secondary display elements */
.display-small {
  font-family: 'Archivo Black', sans-serif;
  font-size: 20px;
  font-weight: 700;
  line-height: 0.85;
  letter-spacing: 0.015em;
  text-transform: uppercase;
}

/* Display Medium - 40px mobile, 64px desktop */
.display-medium {
  font-family: 'Archivo Black', sans-serif;
  font-size: 40px;
  font-weight: 700;
  line-height: 0.85;
  letter-spacing: 0.015em;
  text-transform: uppercase;
}

@media (min-width: 768px) {
  .display-medium {
    font-size: 64px;
  }
}

/* ===== Landing Page - Ocean Blue Hero ===== */
/* Replaces landing-dark-surface with ocean blue like header */
.landing-section-ocean-hero {
  background: var(--core-ocean-blue);
  color: #ffffff;
  /* Set CSS variables for components inside hero */
  --text: #ffffff;
  --muted: rgba(255, 255, 255, 0.8);
  --subtle: rgba(255, 255, 255, 0.6);
  --surface: rgba(255, 255, 255, 0.08);
  --surface2: rgba(255, 255, 255, 0.12);
  --border: rgba(255, 255, 255, 0.15);
  --primary: var(--core-bright-blue);
  --accent: var(--primary);
  --primary_fg: var(--core-ocean-blue);
  --primary_hover: color-mix(in oklab, var(--core-bright-blue) 85%, white);
}

.landing-section-ocean-hero .lucro-logo-text {
  color: var(--core-bright-blue);
}

.landing-section-ocean-hero .logo-dark {
  display: block;
}

.landing-section-ocean-hero .logo-light {
  display: none;
}

/* Hero display typography on ocean background */
.landing-section-ocean-hero .landing-display-xl {
  color: var(--core-bright-blue);
}

.landing-section-ocean-hero .landing-display-lg,
.landing-section-ocean-hero .landing-display-md {
  color: #ffffff;
}

/* ===== Screenshot Browser Frame (Wise-style) ===== */
.landing-screenshot-frame {
  background: #1a1d21;
  border-radius: 12px;
  padding: 12px 12px 0;
  box-shadow:
    0 25px 50px -12px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  overflow: hidden;
}

.landing-screenshot-frame__header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.landing-screenshot-frame__dots {
  display: flex;
  gap: 6px;
}

.landing-screenshot-frame__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #3a3d42;
}

.landing-screenshot-frame__dot--red {
  background: #ff5f57;
}

.landing-screenshot-frame__dot--yellow {
  background: #febc2e;
}

.landing-screenshot-frame__dot--green {
  background: #28c840;
}

.landing-screenshot-frame__url {
  flex: 1;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.5);
  text-align: center;
}

.landing-screenshot-frame__content {
  border-radius: 8px 8px 0 0;
  overflow: hidden;
}

.landing-screenshot-frame__content img {
  display: block;
  width: 100%;
  height: auto;
}

/* Screenshot frame in hero - slightly elevated */
.landing-section-ocean-hero .landing-screenshot-frame {
  box-shadow:
    0 30px 60px -15px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(100, 225, 255, 0.2);
}

/* ===== Landing Screenshot Flow (3-step visual) ===== */
.landing-screenshot-flow {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  align-items: start;
}

@media (max-width: 767px) {
  .landing-screenshot-flow {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

.landing-screenshot-flow__step {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.landing-screenshot-flow__number {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--core-bright-blue);
  color: var(--core-ocean-blue);
  font-weight: 700;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 12px;
}

.landing-screenshot-flow__image {
  width: 100%;
  border-radius: 12px;
  box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.3);
  margin-bottom: 16px;
}

.landing-screenshot-flow__label {
  font-weight: 600;
  font-size: 14px;
  color: #ffffff;
}

.landing-screenshot-flow__desc {
  font-size: 13px;
  color: rgba(255, 255, 255, 0.7);
  margin-top: 4px;
}

/* ===== Marketplace Product Card ===== */
/* Vestiaire Collective inspired - uses existing design tokens */

.product-card {
  background: var(--surface2);
  border-radius: var(--radius-medium);
  overflow: hidden;
  transition: background-color 0.15s ease, transform 0.15s ease;
}

.product-card:hover {
  background: var(--surface2-hover);
}

.group:hover .product-card {
  transform: translateY(-2px);
}

/* Product Image Container */
.product-card__image-container {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 2px;
}

.product-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.group:hover .product-card__image {
  transform: scale(1.03);
}

.product-card__image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  background: var(--surface);
}

/* Condition Badge — Mono: full pill, hairline border, white bg, Plex-mono 500 */
.product-card__badge {
  position: absolute;
  top: var(--size-12);
  left: var(--size-12);
  padding: var(--size-4) var(--size-8);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 9999px;
  font-family: var(--ui-font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text);
}

/* Product Details */
.product-card__details {
  padding: var(--size-12) var(--size-12) var(--size-16);
}

/* Mono eyebrow: Plex Mono, weight 500 ("medium is the new green") */
.product-card__brand {
  display: block;
  font-family: var(--ui-font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: var(--size-4);
}

/* Mono quiet seller line */
.product-card__seller {
  display: block;
  margin-top: 4px;
  font-family: var(--ui-font-sans);
  font-size: 13px;
  color: var(--muted);
}

/* Mono garment name: Fraunces (--ui-font-display), 18px, weight 400 */
.product-card__title {
  font-family: var(--ui-font-display);
  font-size: 18px;
  font-weight: 400;
  color: var(--text);
  line-height: 1.2;
  margin: 0 0 var(--size-4);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.product-card__size {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-bottom: var(--size-8);
}

.product-card__price-container {
  display: flex;
  align-items: baseline;
  gap: var(--size-8);
}

/* Mono price: Plex Mono (ledger voice), 16px, weight 500 */
.product-card__price {
  font-family: var(--ui-font-mono);
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
}

.product-card__price--original {
  font-size: 13px;
  font-weight: 400;
  color: var(--muted);
  text-decoration: line-through;
}

/* ===== Marketplace Product Grid ===== */
/* Responsive: 2 cols mobile, 4 cols tablet, 5 cols desktop */

.marketplace-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--size-16);
}

@media (min-width: 768px) {
  .marketplace-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--size-24);
  }
}

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

/* ===== Marketplace Category Pills ===== */
.marketplace-category-pill {
  display: inline-flex;
  align-items: center;
  padding: var(--size-8) var(--size-16);
  border-radius: 9999px;
  font-size: 13px;
  font-weight: 500;
  transition: background-color 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}

.marketplace-category-pill--inactive {
  background: var(--surface2);
  color: var(--muted);
}

.marketplace-category-pill--inactive:hover {
  background: var(--surface2-hover);
  color: var(--text);
}

.marketplace-category-pill--active {
  background: var(--text);
  color: var(--bg);
}

/* ===== Marketplace Empty State ===== */
.marketplace-empty {
  text-align: center;
  padding: var(--size-64) var(--size-24);
}

.marketplace-empty__icon {
  width: 64px;
  height: 64px;
  margin: 0 auto var(--size-16);
  color: var(--muted);
}

.marketplace-empty__title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--size-8);
}

.marketplace-empty__text {
  font-size: 14px;
  color: var(--muted);
}

/* ===== Verify Order Page - Responsive Document Layout ===== */
/* Mobile: single column, document on top. Desktop: two-column grid. */

.verify-mobile-doc {
  display: block;
}

.verify-desktop-doc {
  display: none;
}

.verify-layout {
  display: block;
}

@media (min-width: 768px) {
  .verify-mobile-doc {
    display: none;
  }

  .verify-desktop-doc {
    display: block;
    position: sticky;
    top: 1rem;
    align-self: start;
  }

  .verify-layout {
    display: grid;
    grid-template-columns: 3fr 2fr;
    gap: 1.5rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}

/* ===== Document Viewer Modal - Image Styling ===== */
/* Ensures image fills modal container and is centered for zoom/pan */
[data-document-viewer-target="container"] img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform-origin: center center;
}

/* Kill Safari's blue focus rectangle on all design system inputs */
.ds-input-container input:focus,
.ds-input-container input:focus-visible,
.ds-input:focus,
.ds-input:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

/* ===== Brand Logo Theme Switching ===== */
/* Light variant visible by default, dark variant hidden */
.brand-logo--dark { display: none; }
.brand-logo--light { display: inline-block; }

/* Dark mode: swap variants */
html[data-theme="dark"] .brand-logo--light { display: none; }
html[data-theme="dark"] .brand-logo--dark { display: inline-block; }

/* ===== Sale Animation Toast ===== */
/* Micro-interaction toasts for sell page: WhatsApp reserved + payment sold */

.sale-toast {
  position: fixed;
  top: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 9998;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.875rem 1.25rem 0.875rem 1.5rem;
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(0, 0, 0, 0.06);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.12),
    0 2px 8px rgba(0, 0, 0, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  pointer-events: none;
  opacity: 0;
}

html[data-theme="dark"] .sale-toast {
  background: rgba(40, 44, 40, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.4),
    0 2px 8px rgba(0, 0, 0, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* Spring-like entrance with overshoot */
.sale-toast.sale-toast--animating {
  animation: sale-toast-enter 450ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.sale-toast.sale-toast--exiting {
  animation: sale-toast-exit 250ms cubic-bezier(0.4, 0, 1, 1) forwards;
}

@keyframes sale-toast-enter {
  0% { opacity: 0; transform: translateX(-50%) translateY(-1.5rem) scale(0.9); }
  100% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

@keyframes sale-toast-exit {
  0% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-0.75rem) scale(0.95); }
}

.sale-toast__text {
  font-family: 'Archivo Black', sans-serif;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.01em;
  color: var(--text);
  white-space: nowrap;
}

.sale-toast__icons {
  position: relative;
  display: flex;
  align-items: center;
  width: 64px;
  height: 32px;
  flex-shrink: 0;
}

/* WhatsApp: shirt flies into basket */
.sale-anim-shirt {
  position: absolute;
  left: 0;
  width: 24px;
  height: 24px;
  color: #22c55e;
  opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(34, 197, 94, 0.3));
}

.sale-toast--animating .sale-anim-shirt {
  animation: sale-shirt-fly 800ms 150ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes sale-shirt-fly {
  0% { opacity: 1; transform: scale(1) translateX(0) translateY(0); }
  30% { opacity: 1; transform: scale(0.85) translateX(8px) translateY(-8px); }
  60% { opacity: 0.8; transform: scale(0.6) translateX(22px) translateY(-4px); }
  85% { opacity: 0.4; transform: scale(0.35) translateX(32px) translateY(2px); }
  100% { opacity: 0; transform: scale(0.2) translateX(36px) translateY(4px); }
}

.sale-anim-basket {
  position: absolute;
  right: 0;
  width: 26px;
  height: 26px;
  color: #22c55e;
  opacity: 0.3;
  filter: drop-shadow(0 1px 2px rgba(34, 197, 94, 0.2));
}

.sale-toast--animating .sale-anim-basket {
  animation: sale-basket-receive 500ms 750ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes sale-basket-receive {
  0% { opacity: 0.3; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.25); }
  100% { opacity: 1; transform: scale(1); }
}

/* Payment: coins arc into wallet */
.sale-anim-coin {
  position: absolute;
  left: 0;
  width: 16px;
  height: 16px;
  color: #f59e0b;
  opacity: 0;
  filter: drop-shadow(0 1px 3px rgba(245, 158, 11, 0.4));
}

.sale-anim-coin:nth-child(2) { left: 7px; top: 3px; }
.sale-anim-coin:nth-child(3) { left: 3px; top: -3px; }

.sale-toast--animating .sale-anim-coin {
  animation: sale-coin-arc 750ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.sale-toast--animating .sale-anim-coin:nth-child(2) {
  animation-delay: 100ms;
}

.sale-toast--animating .sale-anim-coin:nth-child(3) {
  animation-delay: 200ms;
}

@keyframes sale-coin-arc {
  0% { opacity: 1; transform: translateX(0) translateY(0) scale(1) rotate(0deg); }
  25% { opacity: 1; transform: translateX(10px) translateY(-14px) scale(0.95) rotate(45deg); }
  50% { opacity: 0.9; transform: translateX(22px) translateY(-8px) scale(0.7) rotate(90deg); }
  75% { opacity: 0.5; transform: translateX(32px) translateY(0) scale(0.45) rotate(135deg); }
  100% { opacity: 0; transform: translateX(38px) translateY(4px) scale(0.2) rotate(180deg); }
}

.sale-anim-wallet {
  position: absolute;
  right: 0;
  width: 26px;
  height: 26px;
  color: #f59e0b;
  opacity: 0.3;
  filter: drop-shadow(0 1px 3px rgba(245, 158, 11, 0.3));
}

.sale-toast--animating .sale-anim-wallet {
  animation: sale-wallet-receive 500ms 600ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes sale-wallet-receive {
  0% { opacity: 0.3; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.2); }
  100% { opacity: 1; transform: scale(1); }
}

/* Reduced motion: show toast statically, no animations */
@media (prefers-reduced-motion: reduce) {
  .sale-toast.sale-toast--animating {
    opacity: 1;
    transform: translateX(-50%);
    animation: none;
  }
  .sale-toast.sale-toast--exiting {
    opacity: 0;
    animation: none;
  }
  .sale-toast--animating .sale-anim-shirt,
  .sale-toast--animating .sale-anim-basket,
  .sale-toast--animating .sale-anim-coin,
  .sale-toast--animating .sale-anim-wallet {
    animation: none;
    opacity: 1;
  }
}

/* ===== Guide Page Styles ===== */
a.guide-card,
a.guide-card:hover,
a.guide-card:visited {
  text-decoration: none !important;
  color: inherit;
}

.guide-card {
  border-radius: var(--radius-medium);
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.guide-card:hover {
  border-color: color-mix(in oklab, var(--link) 30%, var(--border));
  box-shadow:
    0 4px 6px -1px color-mix(in oklab, var(--text) 4%, transparent),
    0 10px 15px -3px color-mix(in oklab, var(--text) 6%, transparent);
  transform: translateY(-1px);
}

.guide-card:hover h2 {
  color: var(--link);
}

.guide-tip {
  border-left: 3px solid var(--link);
}

/* ── Cookie consent banner ────────────────────────────────────────────────────
   Positioning lives here rather than in Tailwind utilities on purpose: the classes
   this needs (.inset-x-0, responsive bottom-* variants) are absent from the frozen
   build, and adding them would require a tailwind:freeze on every future tweak.

   Only :root-scoped tokens are used. --mist and --ui-font-mono are defined ONLY under
   .landing and .app-mono, and bin/ui doctor rejects just the .landing ones — so an
   .app-mono-scoped token passes the gate and then renders as nothing on the two other
   surfaces this banner appears on. */
.cookie-banner {
  /* MONO ON EVERY SURFACE — a local re-skin of the shared token vocabulary.
     This banner renders on three layouts. `marketplace` is .landing and `public` is .app-mono
     (every app/views/ship/* view sets content_for :body_class, "app-mono"), so both were
     already Mono. The `application` layout resolves :root, where --primary/--link are #00304B
     and --primary_fg is #64E1FF — that shipped an ocean-blue fill with cyan text, against
     "ink does everything; the only colour is brick".
     Re-skinned here rather than by adding the .app-mono class: that class also carries 35
     descendant rules (it squares .ds-button to 2px, among others), and a consent banner
     should look IDENTICAL wherever it appears rather than inherit each page's scope.
     Every value below resolves at :root, so it cannot silently render as nothing. */
  --surface2: var(--paper);
  /* --surface is deliberately NOT re-skinned here any more. It existed to fix the Decline
     button's hover fill differing by scope; that is now fixed at source in
     .btn-variant-secondary:hover, which derives its tint from --ink/--white instead of the
     theme. Nothing inside the banner reads var(--surface), so a declaration here would be dead
     code carrying a comment that claims otherwise. */
  --border: var(--line);
  --text: var(--ink);
  /* #4A4A45, NOT var(--gray). .app-mono sets --muted to this deliberately (ui.css: "Figma DS1
     spec, 9:1 on white, distinct from --subtle's #6B6B66"). Using --gray made the consent
     notice the LEAST readable text on the ~30 .app-mono views it interrupts — still AA, but a
     regression on its host page. Body copy in a banner must never be lighter than the page's. */
  --muted: #4A4A45;
  --primary: var(--ink);
  --primary_fg: var(--paper);
  --primary_hover: color-mix(in oklab, var(--ink) 88%, var(--paper));
  --link: var(--ink);
  /* :root's --focus_ring is #3080ff — blue, and the most visible off-brand element on the
     banner for a keyboard user. */
  --focus_ring: var(--ink);

  position: fixed;
  left: 0;
  right: 0;
  /* No env(safe-area-inset-bottom) here — padding-bottom below already carries it, and when an
     obstruction is present the measured offset is the height of a bar that itself already spans
     into the safe area. Adding it here counted the inset twice (three times with JS measuring). */
  bottom: var(--cookie-banner-offset, 0px);
  /* Above the mobile bottom nav (z-50) and the marketplace header (z-50); below the
     app-wide toast (z-9999), which must always be able to speak over this. */
  z-index: 60;
  background: var(--surface2);
  border-top: 1px solid var(--border);
  padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom));
  box-shadow: var(--shadow-card);
}

/* Two surfaces already own the bottom of the viewport, and BOTH are rendered from views rather
   than layouts — so the layout that renders this banner cannot know they are there. :has() lets
   the CSS detect them. Precedent: body:has(.desktop-sidebar) in ui.css. Covering .pdp__buybar
   would hide the buy button on the highest-intent page in the product.

   These set the VARIABLE, not `bottom`, so the measured inline value from
   cookie_consent_controller.js overrides them. They are the no-JS / pre-hydration fallback only.

   The constants are deliberately the TALLEST variant of each element, not the common one. A
   first attempt used 64px for the buy bar — correct for the normal bar, but
   .pdp__buybar--unavailable (ui.css:4728) wraps a full-width hint row and measures 105px, so
   the banner covered the CTA by 41px. Erring tall costs a visible gap; erring short hides a
   purchase button. Only the runtime measurement below is actually exact. */
body:has(.mobile-bottom-nav) .cookie-banner {
  --cookie-banner-offset: 77px; /* 76px + 1px top border */
}

body:has(.pdp__buybar) .cookie-banner {
  --cookie-banner-offset: 105px; /* .pdp__buybar--unavailable, the tallest variant */
}

/* The floating "Sell (N)" cart bar (#510) — bottom:72px plus its own height. It exists so a
   seller deep in the catalog grid is not stranded from checkout; covering it would restore the
   exact bug that PR removed. It sits at z-40, below this banner, so stacking will not save us. */
body:has(.catalog-sell-bar:not([hidden])) .cookie-banner {
  --cookie-banner-offset: 120px;
}

/* The fullscreen camera viewfinder (#567) is also z-[60] and is rendered EARLIER in the body, so
   an equal z-index plus later DOM order means this banner would paint over its shutter and
   confirm controls. Yielding entirely is right: the overlay is a modal task, and a consent
   prompt over a live viewfinder is the wrong moment to ask. */
body:has([data-camera-capture-target="overlay"]:not(.hidden)) .cookie-banner {
  display: none;
}

/* Both obstructions are mobile-only; each disappears at its own breakpoint. The runtime
   measurement gets this for free (a display:none element measures 0), so these exist purely
   for the no-JS case. */
@media (min-width: 1024px) {
  body:has(.mobile-bottom-nav) .cookie-banner {
    --cookie-banner-offset: 0px;
  }
}

@media (min-width: 900px) {
  body:has(.pdp__buybar) .cookie-banner {
    --cookie-banner-offset: 0px;
  }
}

.cookie-banner__inner {
  max-width: 72rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

@media (min-width: 640px) {
  .cookie-banner__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
  }
}

.cookie-banner__copy {
  min-width: 0;
}

/* Interface font, not --ui-font-display. Display resolves to Fraunces under Mono but to
   Archivo Black at :root — two different faces for the same banner — and Archivo Black ships
   only weight 400, so `font-weight: 600` on it was synthetic bold. The `public` layout loads
   no font partial at all, so a display face degrades to system serif there regardless. A
   consent banner is chrome, not editorial: Inter at 600 is the same on all three surfaces. */
.cookie-banner__title {
  font-family: var(--ui-font-sans);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 0.25rem;
}

.cookie-banner__text {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--muted);
  margin: 0;
}

.cookie-banner__link {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Equal-width controls. The legal requirement is that refusing costs no more effort than
   accepting; letting the buttons size to their labels would make the shorter one smaller,
   which is the asymmetry regulators actually measure. */
.cookie-banner__actions {
  display: flex;
  gap: 0.75rem;
  flex-shrink: 0;
}

.cookie-banner__button {
  flex: 1 1 0;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .cookie-banner__button {
    flex: 0 0 auto;
    min-width: 9rem;
  }
}
