/**
 * Lucent brand palette — high-end, light, neutral-leaning. Skews toward an
 * interior-design/lifestyle-brand look rather than a maker/hobbyist one,
 * per direction: white, tan, neutrals, coral, slight pastel. Headings use
 * a serif (Fraunces, loaded via Google Fonts in index.html) for a more
 * editorial/elevated feel; body stays a clean system sans for readability.
 * NEEDS-DECISION: exact hex values are a reasonable starting palette, not
 * a finalized brand kit — revisit once real product photography exists,
 * since photos (not CSS) will end up driving the actual color story.
 */
:root {
  --ink: #362f28;        /* warm charcoal, softer than pure black */
  --paper: #faf6f0;      /* warm off-white / cream */
  --panel: #ffffff;
  --tan: #b99676;        /* warm neutral tan — secondary actions, borders */
  --coral: #e2705a;      /* primary accent — muted coral, not neon */
  --coral-soft: #f6ded5; /* pastel coral tint — selected states, fills */
  --blush: #f3e8e0;      /* pastel neutral tint — subtle section backgrounds */
  --accent: var(--coral);
  --accent-2: var(--tan);
  --line: #e9ded2;
  --good: #5b7f5e;       /* soft sage, not a harsh green */
  --warn: #b8593a;       /* warm terracotta, not a harsh red */
  font-size: 16px;
}

* { box-sizing: border-box; }

html, body {
  /* FIX 2026-09-24: guards against the stray right-side white gutter seen on
     mobile — some child briefly wider than the viewport (a long unbreakable
     string, a flex item that didn't shrink, etc.) was pushing body wider
     than 100vw, and since body's own background is white, that overflow
     showed as blank space rather than an obvious visual bug. This doesn't
     fix the underlying element if one shows up again, just stops it from
     creating a horizontal scrollbar/gutter. */
  overflow-x: hidden;
  max-width: 100%;
}
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--panel); /* white main background — swapped 2026-07-16, was var(--paper).
    The peach/sand (--paper) now lives on the cards that sit ON the page
    (order card, how-it-works steps) instead of the page itself — see those
    rules below. */
  line-height: 1.5;
}

h1, h2, h3, .brand {
  font-family: "Fraunces", Georgia, "Times New Roman", serif;
  font-weight: 600;
}

a { color: var(--tan); }

.wrap { max-width: 1080px; margin: 0 auto; padding: 0 20px; }

/* ---------- header ---------- */
header.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--panel); /* follows the main bg swap — was var(--paper) */
  border-bottom: 1px solid var(--line);
}
header.site-header .wrap {
  display: flex; align-items: center; justify-content: space-between;
  height: 64px;
}
.brand {
  font-weight: 700; font-size: 1.2rem; color: var(--ink); text-decoration: none;
  display: inline-flex; align-items: center; gap: 8px;
}
.brand-logo { border-radius: 6px; display: block; }
nav.site-nav { display: flex; gap: 22px; align-items: center; }
nav.site-nav a { text-decoration: none; color: var(--ink); font-size: 0.92rem; }
/* FIX 2026-09-24: this is the actual source of the mobile right-side white
   gutter Matt flagged — nav.site-nav never wrapped and never shrank, so once
   it held 4 links (5 with the header upload button) it just ran past the
   edge of the screen instead of onto a second line. That pushed the whole
   page wider than the viewport, and since everything past the real content
   was blank body background, it read as a stray white column rather than an
   obvious overflow bug. Letting the header wrap onto two rows on mobile, and
   letting nav.site-nav wrap/center its own links, fixes it at the source
   instead of just papering over it with overflow-x: hidden above. */
@media (max-width: 640px) {
  header.site-header .wrap { flex-wrap: wrap; height: auto; padding: 10px 20px; row-gap: 8px; }
  /* Logo/title centered on its own row above the nav row, per Matt 2026-09-24. */
  .brand { width: 100%; justify-content: center; }
  nav.site-nav { flex-wrap: wrap; justify-content: center; gap: 8px 16px; width: 100%; }
}
/* FIX 2026-09-24: on regular (non-mobile) screens wider than the old 1080px
   .wrap cap, the logo and nav used to sit centered as a fixed-width block
   with empty margin on both sides rather than touching the screen edges.
   Matt wants the logo flush left and nav flush right on desktop, with just
   the standard .wrap side padding as breathing room, so the header's own
   .wrap drops the max-width cap that every other section keeps. */
header.site-header .wrap { max-width: none; }
/* FIX 2026-09-24: header "Upload Now" button hidden on mobile, both to cut
   header clutter next to the FAQ/Reviews/Feedback links and because the
   viewer-stage placeholder (now first on mobile, see .configurator-shell
   media query) is already the primary upload entry point there. */
@media (max-width: 860px) { #btn-header-upload { display: none; } }
.btn {
  display: inline-block; padding: 10px 18px; border-radius: 6px;
  background: var(--accent); color: #fff; text-decoration: none;
  font-weight: 600; border: none; cursor: pointer; font-size: 0.95rem;
}
.btn.secondary { background: var(--accent-2); }
.btn:disabled { background: #999; cursor: not-allowed; }

/* ---------- order confirmation banner (post-Stripe redirect) ---------- */
.order-confirmed-banner {
  background: var(--good); color: #fff; text-align: center; padding: 14px 0; font-size: 0.95rem;
}
.order-confirmed-banner strong { font-weight: 700; }

/* ---------- hero / motion banner ---------- */
.hero {
  position: relative; min-height: 420px; display: flex; align-items: center;
  justify-content: center; text-align: center; overflow: hidden;
  background: linear-gradient(160deg, #3a2f2a, #241d19);
  color: #fdf9f5;
}
.hero video, .hero .hero-fallback-note {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.6;
}
.hero .hero-fallback-note {
  display: flex; align-items: center; justify-content: center; color: #e8d9cc; font-size: 0.85rem;
  background: repeating-linear-gradient(45deg, #2d2420, #2d2420 10px, #362b25 10px, #362b25 20px);
}
.hero-content { position: relative; z-index: 2; max-width: 640px; padding: 40px 20px; }
.hero-content h1 { font-size: 2.3rem; margin-bottom: 10px; }
.hero-content p { font-size: 1.05rem; opacity: 0.92; margin-bottom: 22px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }

/* ---------- section shell ---------- */
/* Horizontal rules between sections (e.g. Reviews / How it Works) removed
   2026-07-16 per Matt's call — was `border-bottom: 1px solid var(--line)`. */
section { padding: 56px 0; }
section h2 { font-size: 1.5rem; margin-bottom: 6px; }
section .section-sub { color: #666; margin-bottom: 26px; font-size: 0.95rem; }
.placeholder-note {
  font-size: 0.8rem; color: var(--warn); border: 1px dashed var(--warn);
  padding: 8px 10px; border-radius: 6px; margin-top: 10px; background: #fdf1ec;
}

/* ---------- configurator (full-bleed GUI) ---------- */
.configurator-gui { padding: 0; border-bottom: none; background: #211c18; }
.configurator-shell {
  /* FIX ("options/viewer row should never need internal scroll"): this used
     to be a fixed `height: 78vh` capped at `max-height: 780px` — once the
     options list (Shape/Size/Materials/Image Placement/Extras, all their
     controls) got taller than that cap, .config-panel's own
     `overflow-y: auto` kicked in and the LEFT panel scrolled independently
     of the viewer on the right, which read as broken/cramped rather than
     intentional. Switched the row to `min-height` with no cap — the row
     (and the viewer's flex:1 side, see .viewer-stage) now grows to fit
     whatever height the options actually need, so there's never a shorter
     internal scroll box hiding controls.
  */
  display: flex; min-height: 78vh; align-items: stretch;
}
@media (max-width: 860px) {
  .configurator-shell { flex-direction: column; min-height: 0; }
  /* FIX 2026-09-24: on mobile, the 3D preview (viewer-stage) now comes
     before the options panel (config-panel), so a visitor sees the live
     preview first and scrolls down to Shape/Size/Materials/etc after. Order
     only matters in a column layout, so this is scoped to this breakpoint. */
  .viewer-stage { order: 1; }
  .config-panel { order: 2; }
}

.config-panel {
  width: 340px; flex-shrink: 0; background: #251f1a; color: #f1ece2;
  padding: 26px 22px; border-right: 1px solid #3a2f27;
  /* overflow-y: auto removed — see .configurator-shell comment above; this
     panel's natural content height now drives the row instead of clipping. */
}
@media (max-width: 860px) { .config-panel { width: auto; border-right: none; border-bottom: 1px solid #3a2f27; } }

.config-panel-title { font-size: 1.4rem; margin: 0 0 14px; color: #f8f4ee; }

.upload-panel-btn {
  width: 100%; background: var(--coral); text-align: center;
  margin-bottom: 6px;
}
/* FIX 2026-09-24 (REVERTED 2026-09-25, per Matt: "no way to change file
   after first image upload"): this button was hidden on mobile because the
   viewer-placeholder tap target seemed redundant with it — true only before
   any photo is uploaded. Once a photo loads, viewer-placeholder gets
   display:none (see app.js) and never comes back, leaving mobile users with
   zero way to open the file picker again. Keeping this button visible on
   mobile (at the head of the config panel, same as desktop) is the only
   persistent "change photo" control there is. */
.config-panel .upload-drop-note { font-size: 0.75rem; color: #a9998a; margin: 0 0 4px; text-align: center; }
.config-panel .upload-drop-note a { color: var(--coral); }
/* FIX 2026-09-24 (REVERTED 2026-09-25): this left-align existed only
   because upload-panel-btn used to be hidden on mobile, leaving nothing
   centered above this note to match. Now that the button is visible again
   on mobile too (see upload-panel-btn comment above), this note stays
   centered under it at every width — no override needed. */

.config-panel .option-group { margin-top: 22px; }
.config-panel .option-group h3 {
  font-size: 0.82rem; margin-bottom: 8px; text-transform: uppercase;
  letter-spacing: 0.06em; color: #cbbba9;
}
.config-panel .option-group-hint { font-size: 0.75rem; color: #a9998a; margin: -4px 0 10px; }
.config-panel .option-group-header {
  display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;
}
.config-panel .option-group-header h3 { margin-bottom: 0; }
.config-panel .icon-toggle-btn {
  display: flex; align-items: center; gap: 5px; border: 1px solid #4a3c30;
  background: #2c2520; color: #cbbba9; border-radius: 7px; padding: 5px 9px;
  cursor: pointer; font-size: 0.72rem; line-height: 1;
}
.config-panel .icon-toggle-btn.active { border-color: var(--coral); background: #3a271f; color: #f1ece2; }
.config-panel .icon-toggle-btn svg { flex-shrink: 0; }
.config-panel .option-row { display: flex; flex-wrap: wrap; gap: 8px; }
.config-panel .option-chip {
  border: 1px solid #4a3c30; background: #2c2520; color: #f1ece2;
  border-radius: 8px; padding: 9px 12px; cursor: pointer; font-size: 0.86rem;
  display: flex; justify-content: space-between; gap: 10px; min-width: 130px;
}
.config-panel .option-chip.selected { border-color: var(--coral); background: #3a271f; }
.config-panel .option-chip[disabled], .config-panel .option-chip.unavailable { opacity: 0.4; cursor: not-allowed; }
.config-panel .option-chip .delta { color: #a9998a; font-variant-numeric: tabular-nums; }

.config-panel .option-select {
  width: 100%; border: 1px solid #4a3c30; background: #2c2520; color: #f1ece2;
  border-radius: 8px; padding: 10px 12px; cursor: pointer; font-size: 0.86rem;
}
.config-panel .option-select:focus { outline: none; border-color: var(--coral); }
.config-panel .option-select + .option-row { margin-top: 10px; }
.config-panel .option-select + .option-group-hint { margin-top: 8px; }

.toggle-row { display: flex; gap: 8px; margin-top: 4px; }
.toggle-btn {
  flex: 1; border: 1px solid #4a3c30; background: #2c2520; color: #f1ece2;
  border-radius: 8px; padding: 8px; cursor: pointer; font-size: 0.8rem;
}
.toggle-btn.active { border-color: var(--coral); background: #3a271f; }

.slider-row { display: block; margin-top: 12px; font-size: 0.82rem; color: #d8cdc0; }
.slider-row span { display: block; margin-bottom: 4px; }
.slider-row input[type="range"] {
  width: 100%; accent-color: var(--coral); cursor: pointer;
}

.placeholder-note.dark {
  font-size: 0.75rem; color: #e3b39f; border: 1px dashed #6b4735;
  padding: 8px 10px; border-radius: 6px; margin-top: 24px; background: #2f231c;
}

/* MAIN viewer area — fills the rest of the row/screen */
.viewer-stage {
  flex: 1; position: relative;
  /* Lightened toward the site's own tan/cream (--tan/--paper), replacing the
     previous dark-brown-dominant glow — reads as a warmly lit space instead
     of a dim void, and ties the viewer back to the rest of the page's
     palette instead of looking like a separate dark app. Kept just dark
     enough at the edges that the light-colored overlay text (hint/status/
     placeholder) already tuned for a dark backdrop stays legible.
  */
  background: radial-gradient(circle at 50% 32%, #a68563, #7d6249 55%, #4f3c2c);
  min-height: 420px;
}
.viewer-stage.dragover::after {
  content: 'Drop photo to upload'; position: absolute; inset: 0; z-index: 4;
  display: flex; align-items: center; justify-content: center;
  background: rgba(226,112,90,0.28); color: #fff; font-size: 1rem; font-weight: 600;
  pointer-events: none;
}
.download-float {
  position: absolute; bottom: 16px; right: 16px; z-index: 5;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--coral); color: #fff; border: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.2rem; line-height: 1; cursor: pointer;
  box-shadow: 0 2px 10px rgba(0,0,0,0.35);
}
.download-float svg { display: block; }
.download-float:hover { filter: brightness(1.06); }

#preview-canvas-wrap { position: absolute; inset: 0; }
#preview-canvas-wrap canvas { display: block; width: 100%; height: 100%; }

.viewer-placeholder {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px;
  color: #cbbba9; text-align: center; padding: 20px; cursor: pointer;
}
.viewer-placeholder-spin {
  font-family: "Fraunces", Georgia, serif; font-size: 1.3rem; color: #f1ece2;
  animation: viewer-placeholder-spin-anim 2.6s ease-in-out infinite;
  transform-style: preserve-3d; display: inline-block; perspective: 400px;
}
/* BUGFIX: a full 0->360 rotateY shows the text's mirrored backface for half
   of every cycle (unreadable). Wobbling between -22deg/22deg instead stays
   on the front face the whole time, so it reads as a lively "3D tilt"
   instead of turning into backwards text twice a loop. */
@keyframes viewer-placeholder-spin-anim {
  0%, 100% { transform: rotateY(-22deg); }
  50% { transform: rotateY(22deg); }
}
/* FIX (2026-07-16): #8a7c6c was too close in hue/value to the viewer-stage's
   tan/brown gradient behind it — read as "nearly invisible" per Matt. Bumped
   to a light warm cream (close to --viewer-placeholder-spin's #f1ece2, just
   dimmer) plus a soft dark text-shadow so it stays legible against every
   part of the gradient, not just the darker edge. */
.viewer-placeholder-hint {
  font-size: 0.78rem; color: #f1e6d8;
  text-shadow: 0 1px 3px rgba(20,16,12,0.55);
}
/* FIX 2026-09-24: desktop/mobile text swap for the viewer placeholder hint,
   same 640px breakpoint as the rest of the mobile layout. See the two
   .viewer-placeholder-hint-* divs in index.html. */
.viewer-placeholder-hint-mobile { display: none; }
@media (max-width: 640px) {
  .viewer-placeholder-hint-desktop { display: none; }
  .viewer-placeholder-hint-mobile { display: block; }
}

.viewer-processing {
  position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px;
  background: rgba(20,16,12,0.35); color: #f1ece2; font-size: 0.85rem;
}
.viewer-processing .spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid rgba(241,236,226,0.25); border-top-color: var(--coral);
  animation: viewer-processing-spin 0.8s linear infinite;
}
@keyframes viewer-processing-spin { to { transform: rotate(360deg); } }

.viewer-hint-row {
  position: absolute; bottom: 16px; left: 16px; z-index: 5;
  display: flex; align-items: center; gap: 8px;
}
.viewer-hint {
  color: #cbbba9; font-size: 0.72rem; background: rgba(20,16,12,0.55);
  padding: 6px 14px; border-radius: 20px; pointer-events: none;
}
.viewer-reset-btn {
  width: 26px; height: 26px; border-radius: 50%; flex: 0 0 auto;
  background: rgba(20,16,12,0.55); color: #cbbba9; border: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
}
.viewer-reset-btn:hover { background: rgba(20,16,12,0.8); color: #fff; }
.viewer-reset-btn svg { display: block; }
.preview-status {
  position: absolute; top: 14px; left: 14px; right: 14px;
  font-size: 0.8rem; color: #f1ece2; background: rgba(20,16,12,0.55);
  padding: 6px 10px; border-radius: 6px;
}
.preview-status:empty { display: none; }

/* ---------- order / invoice — a white card butted to the bottom of the
   configurator, square top corners (flush against the dark GUI above),
   rounded bottom corners only ---------- */
.order-card-section { padding: 0; } /* border-bottom removed 2026-07-17 — missed in the earlier
  site-wide divider removal since this section sets its own border directly rather than
  inheriting from the generic `section { border-bottom }` rule that was cleared before. */
.order-card {
  max-width: 1080px; margin: 0 auto; background: var(--paper); /* peach/sand card on white page — was var(--panel)/white */
  border-radius: 0 0 16px 16px; box-shadow: 0 14px 30px rgba(0,0,0,0.12);
  padding: 26px 40px 34px;
}
.order-lead { text-align: center; font-size: 0.95rem; color: #666; margin: 0; }
.order-columns { display: flex; margin-top: 4px; }
.order-col-invoice { flex: 1; padding-right: 32px; }
.order-col-invoice h2 { text-align: left; margin-bottom: 10px; }
.order-col-actions {
  flex: 1; padding-left: 32px; position: relative;
  display: flex; flex-direction: column; justify-content: flex-start;
}
.order-col-actions h2 { text-align: left; margin-bottom: 6px; }
.order-file-note { font-size: 0.85rem; color: #666; margin: 0; }
.order-col-actions::before {
  content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 1px;
  background: var(--line);
}
@media (max-width: 720px) {
  .order-columns { flex-direction: column; }
  .order-col-invoice { padding-right: 0; }
  .order-col-actions { padding-left: 0; margin-top: 20px; }
  .order-col-actions::before { display: none; }
}

.price-line { display: flex; justify-content: space-between; font-size: 0.9rem; padding: 4px 0; }
.price-total { display: flex; justify-content: space-between; font-size: 1.3rem; font-weight: 700; margin-top: 12px; border-top: 1px solid var(--line); padding-top: 12px; }
.order-fine-note { font-size: 0.78rem; color: #888; text-align: right; margin: 4px 0 0; }

.checkbox-row { display: flex; align-items: flex-start; gap: 8px; font-size: 0.85rem; margin-top: 14px; }
.checkbox-row input { margin-top: 3px; }
.order-col-invoice .btn { width: 100%; margin-top: 12px; }
.order-buttons { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }

/* ---------- email / copyright modal (free download) ---------- */
.modal-overlay {
  position: fixed; inset: 0; z-index: 100; background: rgba(20,16,12,0.55);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal-box {
  background: var(--panel); border-radius: 12px; max-width: 440px; width: 100%;
  padding: 26px 28px; box-shadow: 0 20px 50px rgba(0,0,0,0.3);
}
.modal-box h3 { margin: 0 0 8px; }
.modal-copy { font-size: 0.85rem; color: #666; margin: 0 0 16px; }
.modal-field { display: block; font-size: 0.85rem; margin-bottom: 14px; }
.modal-field span { display: block; margin-bottom: 4px; color: #666; }
.modal-field input {
  width: 100%; padding: 10px 12px; border-radius: 6px; border: 1px solid var(--line);
  font-size: 0.95rem;
}
.modal-checkbox { margin-top: 4px; }
/* Added 2026-09-29 for the download-format toggle (STL/OBJ) in the free-
   download modal — matches .modal-field span's label styling, and
   .format-hint gives the "(for printing)" / "(for 3D software)" sub-text a
   muted, smaller treatment so the format name itself stays the visual focus. */
.modal-field-label { display: block; font-size: 0.85rem; margin-bottom: 4px; color: #666; }
#download-format-row { margin-bottom: 14px; }
.format-hint { font-size: 0.75rem; opacity: 0.7; font-weight: normal; }
.modal-actions { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-top: 20px; }
/* Donate sits on the same row as Cancel/Download but pinned to the left
   edge (margin-right: auto eats the row's remaining space), so Cancel and
   Download stay grouped together on the right exactly as before. Moved from
   .donate-link directly to the wrapping .donate-widget now that the button
   morphs in place into an amount field — see index.html's donate widget
   comment and app.js. */
.modal-actions .donate-widget { margin-right: auto; position: relative; }
.donate-widget .donate-link {
  background: transparent; color: var(--tan); border: 1px solid var(--tan);
  text-decoration: none;
}
.donate-widget .donate-link:hover { background: var(--blush); }

/* Two states, same container: the plain button (default) vs. the amount
   form (once .donate-widget-open is toggled on by app.js). Both markup
   pieces stay in the DOM the whole time — only visibility swaps — so no
   focus/DOM-rebuild flicker when the customer clicks "Donate". */
.donate-amount-form { display: none; align-items: center; gap: 6px; }
.donate-widget.donate-widget-open .donate-link { display: none; }
.donate-widget.donate-widget-open .donate-amount-form { display: flex; }
.donate-amount-input {
  width: 84px; padding: 7px 9px; border-radius: 6px 0 0 6px;
  border: 1px solid var(--tan); border-right: none; font-size: 0.85rem;
  background: #fff; color: #333;
}
.donate-amount-input::placeholder { color: #b6a898; }
.donate-amount-go {
  width: 30px; height: 30px; border-radius: 0 6px 6px 0; flex: 0 0 auto;
  background: var(--tan); color: #fff; border: 1px solid var(--tan);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  padding: 0;
}
.donate-amount-go:hover { filter: brightness(1.08); }
.donate-amount-go svg { display: block; }
.donate-amount-error {
  display: none; position: absolute; top: 100%; left: 0; margin-top: 4px;
  font-size: 0.72rem; color: #c0392b; white-space: nowrap;
}
.donate-amount-error.visible { display: block; }
.modal-field-row { display: flex; gap: 10px; }
.modal-field-row .modal-field { flex: 1; min-width: 0; }
.modal-field-row .modal-field:nth-child(2) { flex: 0 0 60px; }
.modal-field-row .modal-field:nth-child(3) { flex: 0 0 90px; }

.modal-box-wide { max-width: 640px; }
.photo-guide-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 16px; }
@media (max-width: 560px) { .photo-guide-grid { grid-template-columns: 1fr; } }
.photo-guide-img {
  /* Widened from a single square placeholder to fit TWO images side by side
     (source photo + its rendered lithophane preview), now that real example
     images replace the old text placeholder. */
  aspect-ratio: 1.8; background: var(--blush); border-radius: 8px;
  display: flex; align-items: stretch; justify-content: center; gap: 3px;
  overflow: hidden;
}
.photo-guide-img img {
  width: 50%; height: 100%; object-fit: contain; background: #fff;
}
.photo-guide-label { font-size: 0.78rem; margin: 8px 0 0; }
.photo-guide-label.good { color: var(--good); }
.photo-guide-label.bad { color: var(--warn); }

/* ---------- everything below "Your Order" is centered ---------- */
#reviews, #gallery, #how-it-works, #faq, #shipping-returns, #contact, #privacy { text-align: center; }
#reviews .wrap, #gallery .wrap, #how-it-works .wrap, #faq .wrap, #shipping-returns .wrap, #contact .wrap, #privacy .wrap {
  display: flex; flex-direction: column; align-items: center;
}

/* ---------- gallery ---------- */
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; width: 100%; }
.gallery-grid .tile { aspect-ratio: 1; background: var(--blush); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #9c8a7c; font-size: 0.75rem; text-align: center; padding: 8px; }

/* ---------- reviews ---------- */
.reviews-strip { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 6px; justify-content: center; width: 100%; }
.review-card { min-width: 240px; background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 14px; font-size: 0.85rem; text-align: left; }

/* ---------- process ---------- */
.process-steps { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; width: 100%; }
@media (max-width: 860px) { .process-steps { grid-template-columns: repeat(2, 1fr); } }
.step { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 14px; font-size: 0.85rem; text-align: center; } /* peach/sand card — was #fff */
.step .num { font-weight: 700; color: var(--accent); font-size: 1.1rem; }

.process-steps-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 860px) { .process-steps-4 { grid-template-columns: repeat(2, 1fr); } }
.step-icon { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 20px 14px; }
.step-media { color: var(--accent); display: flex; align-items: center; justify-content: center; height: 44px; }
.step-icon .num { font-size: 0.8rem; color: #999; font-weight: 700; }
.step-icon .step-label { font-size: 0.9rem; }

/* FIX: .how-it-works-explainer is a flex child of a `align-items: center`
   column (see "everything below Your Order is centered" above) with only a
   max-width, no explicit width — so its rendered width shrank/grew to fit
   whichever line of text was currently the widest, and the FAQ's <details>
   reuses this same class. Expanding/collapsing a question changes which
   lines are visible, which changed that widest-line width, which re-centered
   the whole block sideways — the reported "FAQ jumps around in alignment on
   expand/collapse." Giving it a real width so it fills the flex container up
   to max-width regardless of which content is visible fixes it for both the
   plain explainer text and the FAQ. */
.how-it-works-explainer { max-width: 640px; width: 100%; margin-top: 34px; text-align: left; }
.how-it-works-explainer h3 { font-size: 1rem; margin: 20px 0 6px; }
.how-it-works-explainer h3:first-child { margin-top: 0; }
.how-it-works-explainer p { font-size: 0.9rem; color: #555; line-height: 1.55; margin: 0; }

/* FAQ section reuses .how-it-works-explainer for width/spacing; these rules
   just style the <details>/<summary> wrapper the FAQ items use. */
.how-it-works-explainer details { margin: 0 0 6px; border-bottom: 1px solid #eee; padding-bottom: 10px; }
.how-it-works-explainer details:last-child { border-bottom: none; }
.how-it-works-explainer summary { cursor: pointer; list-style: none; padding: 10px 0 0; }
.how-it-works-explainer summary::-webkit-details-marker { display: none; }
.how-it-works-explainer summary h3 { display: inline; margin: 0; font-size: 1rem; }
/* FIX: a plain trailing space in generated content gets collapsed by normal
   CSS whitespace rules once it's the last thing in the inline box (which is
   exactly this case) — the "+ " kept its space but the "−" version (an
   entirely separate ::before rule, only swapped in for [open]) lost it,
   since collapsing is evaluated per box, not shared between the two states.
   A non-breaking space isn't collapsed, so both states keep the gap. */
.how-it-works-explainer summary::before { content: '+\00a0'; color: var(--accent); font-weight: 700; }
.how-it-works-explainer details[open] summary::before { content: '\2212\00a0'; }
.how-it-works-explainer details p { margin-top: 8px; }

/* ---------- footer ---------- */
footer.site-footer { padding: 30px 0; text-align: center; font-size: 0.8rem; color: #777; }
footer.site-footer a { color: #777; }
