/* =============================================================
   iPear Custom Studio v3 — Mobile UI (HOTFIX)
   ============================================================= */

/* ── Design tokens ─────────────────────────────────────────── */
:root {
  --ipear-brand:        #8AE900;
  --ipear-brand-hover:  #7fd800;
  --ipear-brand-ink:    #1a5c00;
  --ipear-brand-tint:   #f0ffd6;

  --ipear-ink:          #0a0a0a;
  --ipear-ink-soft:     #333333;
  --ipear-muted:        #6b6b6b;
  --ipear-border:       #e5e5e5;
  --ipear-surface:      #ffffff;
  --ipear-bg:           #f7f7f7;
  --ipear-bg-sunk:      #efefef;

  --ipear-danger:       #d64545;
  --ipear-warning:      #f5a623;

  --ipear-radius-sm:    8px;
  --ipear-radius-md:    12px;
  --ipear-radius-lg:    18px;
  --ipear-radius-pill:  999px;

  --ipear-shadow-sm:    0 1px 2px rgba(0,0,0,.06);
  --ipear-shadow-md:    0 4px 12px rgba(0,0,0,.08);
  --ipear-shadow-lg:    0 8px 24px rgba(0,0,0,.10);

  --ipear-tap-min:      44px;

  --ipear-font:         "Lexend Deca", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* ── Studio-page scoped chrome hides ──
   REMOVED per user directive: no guessed WoodMart / MailPoet selectors ship
   here. Header, search, hamburger, mobile drawer, account menu are NEVER
   touched. The contained model-list scroll + Studio bottom padding already
   keep the customer inside the Studio during Steps 1–2.

   If the theme's bottom nav or back-to-top still overlaps the Studio sticky
   bar on this install, add the confirmed selectors below (scoped under
   body.ipear-studio-v3), based on real DOM inspection — do not guess. */
/*
body.ipear-studio-v3 .YOUR-CONFIRMED-BACK-TO-TOP-SELECTOR,
body.ipear-studio-v3 .YOUR-CONFIRMED-BOTTOM-NAV-SELECTOR,
body.ipear-studio-v3 .YOUR-CONFIRMED-NEWSLETTER-SELECTOR {
  display: none !important;
}
*/

/* ── Studio root — normal-flow contained widget (NOT a full-screen shell) ── */
.ipear-v3 {
  font-family: var(--ipear-font);
  color: var(--ipear-ink);
  background: var(--ipear-bg);
  box-sizing: border-box;
  width: 100%;
  position: relative;
  /* The sticky bar is position:sticky INSIDE .ipear-v3, so it flows with
     the panel — no reserved space required. Only add the iOS safe-area
     inset so the CTA never sits on the very edge on devices with a home
     indicator. No legacy theme-toolbar reserve — that has been removed. */
  padding-bottom: env(safe-area-inset-bottom, 0);
  /* Step-change scrollIntoView uses scroll-margin-top as its header offset
     — the site's sticky header sits above the Studio, so we reserve room for
     it here rather than reading its live height from JS. Override at the
     :root level (per install) if the theme header is bigger/smaller than
     the default 72px. */
  scroll-margin-top: var( --ipear-header-offset, 72px );
}
.ipear-v3 *,
.ipear-v3 *::before,
.ipear-v3 *::after {
  box-sizing: border-box;
}
.ipear-v3 button {
  font-family: inherit;
  cursor: pointer;
  background: none;
  border: none;
  color: inherit;
  padding: 0;
}

/* ── Progress strip (5 pills) ─────────────────────────────── */
.ipear-v3-progress {
  display: flex;
  gap: 4px;
  padding: 10px 14px;
  background: var(--ipear-surface);
  border-bottom: 1px solid var(--ipear-border);
}
.ipear-v3-progress-pill {
  flex: 1;
  height: 4px;
  background: var(--ipear-border);
  border-radius: var(--ipear-radius-pill);
  transition: background .2s ease;
}
.ipear-v3-progress-pill.is-done,
.ipear-v3-progress-pill.is-active {
  background: var(--ipear-brand);
}

/* ── Step 1: preview stage is hidden entirely ──
   The customer hasn't picked a model yet, so the mockup carries zero
   information; showing an empty stage crowds Step 1 with useless chrome.
   From Step 2 onwards the stage reappears with the picked model. */
.ipear-v3[data-current-step="1"] .ipear-v3-stage {
  display: none !important;
}
/* Editmode toolbar can never surface on Step 1 either (it only ever
   makes sense once an image exists on Step 3/4). */
.ipear-v3[data-current-step="1"] .ipear-v3-editmode-row {
  display: none !important;
}

/* ── Stage — fixed max-height, contains scaled mockup ──
   The legacy .ipear-phone-shell keeps its authoritative dimensions
   (196×423 case, per-type sizes for airpods/powerbank/charger).
   A CSS transform:scale on the wrapper fits it inside the visible area
   without touching the shell's own width/height — aspect ratio preserved. */
.ipear-v3-stage {
  position: relative;
  background: linear-gradient(180deg, #fafafa 0%, #f0f0f0 100%);
  height: min(46svh, 440px);
  min-height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  overflow: hidden;
}
.ipear-v3-stage-inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.ipear-v3-stage-empty {
  text-align: center;
  color: var(--ipear-muted);
  font-size: 14px;
  line-height: 1.5;
  max-width: 260px;
}
.ipear-v3-stage-empty-icon {
  width: 88px;
  height: 88px;
  margin: 0 auto 12px;
  border-radius: 24px;
  background: var(--ipear-surface);
  box-shadow: var(--ipear-shadow-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ipear-border);
}
.ipear-v3-stage-badge {
  position: absolute;
  top: 10px;
  left: 12px;
  background: rgba(255,255,255,.92);
  backdrop-filter: blur(8px);
  padding: 4px 10px;
  border-radius: var(--ipear-radius-pill);
  font-size: 11px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  box-shadow: var(--ipear-shadow-sm);
  display: none;
  z-index: 5;
}
.ipear-v3-stage-badge.is-visible { display: block; }

/* Mockup scale wrapper — JS sets --v3-mockup-scale so the whole legacy
   preview shrinks proportionally to fit the stage. Never mutates the
   shell's intrinsic width/height. */
.ipear-v3-mockup {
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale( var(--v3-mockup-scale, 1) );
  transform-origin: center center;
  transition: transform .12s ease-out;
}
.ipear-v3-mockup[hidden] { display: none; }

/* ══════════════════════════════════════════════════════════════════
   Editing-mode gating — strict pointer-events isolation
   Runs off the [data-edit-mode] attribute set by JS on .ipear-v3 root.
   stopPropagation alone can miss edge cases (early-capture listeners,
   passive touchmove); CSS pointer-events physically stops the event
   from ever reaching the wrong target.
   ══════════════════════════════════════════════════════════════════ */
/* Editmode row lives INSIDE the panel (Step 3 upload block) — never
   overlays the mockup, camera cutout, or image content. Compact pill
   toggles for Image/Text mode and Fit/Fill. */
.ipear-v3-editmode-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  margin: 12px 0 4px;
  padding: 8px;
  background: var(--ipear-surface);
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
}
.ipear-v3-editmode-row[hidden] { display: none; }
.ipear-v3-editmode {
  display: inline-flex;
  gap: 4px;
  padding: 2px;
  background: var(--ipear-bg);
  border-radius: var(--ipear-radius-pill);
}
.ipear-v3-editmode-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  min-height: 34px;
  border-radius: var(--ipear-radius-pill);
  font-size: 12px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  background: transparent;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.ipear-v3-editmode-btn.is-active {
  background: var(--ipear-brand);
  color: #000;
}
.ipear-v3-editmode-btn[hidden] { display: none; }
.ipear-v3-editmode-btn svg { flex-shrink: 0; }

.ipear-v3-fitfill {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  background: var(--ipear-bg);
  border-radius: var(--ipear-radius-pill);
}
.ipear-v3-fitfill-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  min-height: var(--ipear-tap-min);
  border-radius: var(--ipear-radius-pill);
  font-size: 13px;
  font-weight: 700;
  color: var(--ipear-ink-soft);
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}
.ipear-v3-fitfill-btn.is-active {
  background: var(--ipear-surface);
  color: var(--ipear-ink);
  box-shadow: var(--ipear-shadow-sm);
}
.ipear-v3-fitfill-btn svg { flex-shrink: 0; }

/* Step 3 layout: Fit/Fill takes the full width as a segmented control.
   Its two children (Προσαρμογή / Γέμισμα) each get 1fr, so they never
   collide, wrap, or shrink under the 44px touch minimum at 375px. */
.ipear-v3-editmode-row.is-fitfill-only {
  padding: 6px;
  margin: 10px 0 6px;
}
.ipear-v3-editmode-row.is-fitfill-only .ipear-v3-editmode {
  display: none;
}
.ipear-v3-editmode-row.is-fitfill-only .ipear-v3-fitfill {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  width: 100%;
}
.ipear-v3-editmode-row.is-fitfill-only .ipear-v3-fitfill-btn {
  min-width: 0;
  padding: 10px 8px;
  font-size: 14px;
}

/* Step 4 layout: only Image/Text toggle. Fit/Fill group is hidden by JS. */
.ipear-v3-editmode-row.is-editmode-only .ipear-v3-fitfill {
  display: none;
}
.ipear-v3-editmode-row.is-editmode-only {
  justify-content: center;
}

/* IMAGE mode: image drag receives pointer events; text overlay is inert. */
.ipear-v3[data-edit-mode="image"] .ipear-text-overlay {
  pointer-events: none !important;
}
/* TEXT mode: phone-screen is inert (image drag disabled); text overlay
   explicitly re-enables its own pointer-events so drag/tap on the text
   still works. Because pointer-events:none propagates to descendants,
   the .ipear-text-overlay must set pointer-events:auto to reactivate. */
.ipear-v3[data-edit-mode="text"] .ipear-phone-screen {
  pointer-events: none !important;
  cursor: default !important;
}
.ipear-v3[data-edit-mode="text"] .ipear-text-overlay.has-text {
  pointer-events: auto !important;
  cursor: grab;
}
.ipear-v3[data-edit-mode="text"] .ipear-text-overlay.has-text.is-dragging {
  cursor: grabbing;
}
/* When no image is loaded, drag hint is irrelevant */
.ipear-v3:not([data-edit-mode]) .ipear-text-overlay { pointer-events: none; }

/* Drag hint — hidden by default, shown briefly after image load via .show */
.ipear-v3-mockup .ipear-drag-hint {
  position: absolute;
  inset: auto 8px 8px 8px;
  display: none;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: rgba(0,0,0,0.55);
  color: #fff;
  font-size: 11px;
  font-weight: 500;
  border-radius: var(--ipear-radius-pill);
  z-index: 6;
  pointer-events: none;
  justify-content: center;
  opacity: 0;
  transition: opacity .3s ease;
}
.ipear-v3-mockup .ipear-drag-hint.show { display: inline-flex; opacity: 1; }
.ipear-v3-mockup .ipear-drag-hint svg { flex-shrink: 0; }

/* ============================================================
   Legacy phone-preview rules — extracted VERBATIM from
   ipear-configurator.css so the mockup renders identically to
   legacy without loading the full 121 KB legacy stylesheet.

   Source ranges:  ipear-configurator.css lines 778–914 (base),
                   1117–1208 (uv-texture + drag-hint + phone-ph).
   Any behaviour change must be mirrored in both files.
   ============================================================ */

.ipear-phone-wrap {
  position: relative;
  display: inline-block;
  margin: 0;
  padding: 0 6px;
}
.ipear-phone-wrap::after { display: none; }

.ipear-phone-btn-vol {
  position: absolute;
  left: 0px;
  width: 3px;
  border-radius: 1px 0 0 1px;
  background: rgba(0,0,0,0.40);
}
.ipear-phone-btn-vol.top    { top: 22%; height: 9%; }
.ipear-phone-btn-vol.bottom { top: 34%; height: 13%; }
.ipear-phone-btn-power {
  position: absolute;
  right: 0px; top: 25%;
  width: 3px; height: 11%;
  border-radius: 0 1px 1px 0;
  background: rgba(0,0,0,0.40);
}

.ipear-phone-shell {
  border-radius: 38px;
  background: transparent;
  border: none;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18), 0 0 0 1.5px rgba(0,0,0,0.18);
  position: relative;
  overflow: hidden;
  z-index: 1;
}
.ipear-phone-shell.ipear-shell-square { border-radius: 26px; }

.ipear-phone-screen {
  position: absolute;
  inset: 0;
  border-radius: 0;
  overflow: hidden;
  isolation: isolate;   /* z-index containment: overlays never escape */
  contain: paint;        /* paint-time clip — image can never bleed outside */
  background: #ffffff;
  background-color: var( --ipear-case-bg, #ffffff );
  cursor: grab;
  touch-action: none;
}
/* Shell inherits shell border-radius so the case corners are visually
   preserved even if a child gets stray positioning. Redundant with
   overflow:hidden already declared on shell, but reinforces clipping. */
.ipear-phone-shell {
  isolation: isolate;
}
.ipear-phone-screen:active { cursor: grabbing; }

/* Transparent case — checkerboard */
.ipear-phone-screen.ipear-case-transparent {
  background-color: transparent;
  background-image:
    linear-gradient(45deg, #d6d6d6 25%, transparent 25%),
    linear-gradient(-45deg, #d6d6d6 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #d6d6d6 75%),
    linear-gradient(-45deg, transparent 75%, #d6d6d6 75%);
  background-size: 14px 14px;
  background-position: 0 0, 0 7px, 7px -7px, -7px 0;
}

.ipear-phone-img {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: auto; height: auto;
  display: none;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
  transform-origin: center center;
}
.ipear-phone-img.show { display: block; }

/* Camera cutout — base + variants (square/wide/tall) */
.ipear-camera-cut {
  position: absolute;
  top: 3%;
  left: 5%;
  width: 40%;
  aspect-ratio: 1 / 1;
  border: 2px solid rgba(0,0,0,0.18);
  border-radius: 28%;
  pointer-events: none;
  z-index: 100;
  background: #ffffff;
  background-color: #ffffff;
  box-shadow: inset 0 0 0 999px #ffffff, 0 1px 5px rgba(0,0,0,0.10);
}
.ipear-camera-cut::before,
.ipear-camera-cut::after { display: none; }

.ipear-camera-cut.ipear-cam-square {
  width: 44%;
  height: 0;
  padding-top: 44%;
  aspect-ratio: auto;
  border-radius: 22%;
  top: 3%;
  left: 5%;
}
.ipear-camera-cut.ipear-cam-wide {
  top: 2%;
  left: 5%;
  right: 5%;
  width: auto;
  height: 0;
  padding-top: 42%;
  aspect-ratio: auto;
  border-radius: 16px;
  transform: none;
}
.ipear-camera-cut.ipear-cam-tall {
  top: 2%;
  left: 4%;
  width: 34%;
  height: 0;
  padding-top: 78%;
  aspect-ratio: auto;
  border-radius: 16px;
  transform: none;
}

/* UV texture (for 3D print preview) */
.ipear-uv-texture {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 8;
  display: none;
  background: repeating-linear-gradient(
    -42deg, transparent 0px, transparent 3.5px,
    rgba(255,255,255,0.028) 3.5px, rgba(255,255,255,0.028) 4.5px );
  mix-blend-mode: screen;
}
.ipear-uv-texture::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(145deg,
    rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.04) 28%,
    transparent 52%, rgba(255,255,255,0.03) 78%,
    rgba(255,255,255,0.09) 100% );
}
.ipear-uv-texture.show { display: block; }
.ipear-uv-texture.show.is-3d {
  background: repeating-linear-gradient(
    -42deg, transparent 0px, transparent 3.5px,
    rgba(255,255,255,0.055) 3.5px, rgba(255,255,255,0.055) 4.5px );
}
.ipear-uv-texture.show.is-3d::after {
  background: linear-gradient(145deg,
    rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.08) 28%,
    transparent 52%, rgba(255,255,255,0.05) 78%,
    rgba(255,255,255,0.16) 100% );
}

/* Placeholder shown before an image is uploaded */
.ipear-phone-ph {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 8px; z-index: 2; padding: 12px;
}
.ipear-phone-ph p {
  font-size: 11px; font-weight: 500;
  text-align: center; line-height: 1.5;
  color: rgba(0,0,0,0.22);
  margin: 0;
}
.ipear-phone-ph svg { opacity: 0.2; }

/* ── Step panel ─────────────────────────────────────────── */
.ipear-v3-panel {
  background: var(--ipear-bg);
  padding: 16px 16px 20px;
  /* Defensive: keep the panel from expanding beyond its grid/flex ancestor
     when placed inside WoodMart's product-page column. Without min-width:0
     a text/input child with min-content > column width can push the whole
     panel wider than its container. See Step 1 search-bar overflow fix. */
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
}
.ipear-v3-step {
  display: none;
  min-width: 0;
  max-width: 100%;
}
.ipear-v3-step.is-active { display: block; animation: ipearStepIn .18s ease-out; }
@keyframes ipearStepIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.ipear-v3-step-title {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.25;
  margin: 4px 0 4px;
  color: var(--ipear-ink);
  letter-spacing: -0.01em;
}
.ipear-v3-step-sub {
  font-size: 14px;
  color: var(--ipear-muted);
  margin: 0 0 18px;
  line-height: 1.5;
}

.ipear-v3-card {
  background: var(--ipear-surface);
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  padding: 14px;
  margin-bottom: 12px;
}

/* Brand tab row (Step 1) */
.ipear-v3-brand-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 12px;
}
.ipear-v3-brand-tab {
  min-height: var(--ipear-tap-min);
  padding: 10px 8px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  font-size: 14px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.ipear-v3-brand-tab.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  color: var(--ipear-brand-ink);
}

/* Step 2 authoritative-availability error card (network/AJAX failure).
   Neutral "connection error" surface with a retry button — NEVER worded
   as "product unavailable" so the customer doesn't misread a transient
   error as OOS. Continue stays disabled via canContinue(). */
.ipear-v3-avail-error {
  text-align: center;
  padding: 20px 16px;
}
.ipear-v3-avail-error-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--ipear-ink);
  margin: 0 0 6px;
}
.ipear-v3-avail-error-sub {
  font-size: 13px;
  color: var(--ipear-muted);
  margin: 0 0 14px;
  line-height: 1.5;
}
.ipear-v3-avail-error .ipear-v3-btn {
  min-height: var(--ipear-tap-min);
  padding: 10px 22px;
  font-weight: 600;
  border-radius: var(--ipear-radius-pill);
  border: 1.5px solid var(--ipear-brand);
  background: var(--ipear-brand);
  color: var(--ipear-brand-ink);
  cursor: pointer;
  font-family: inherit;
}
.ipear-v3-avail-error .ipear-v3-btn:active { transform: scale(.97); }

/* Loading state for case-type cards while the authoritative availability
   matrix is being fetched from the server (setModel → bulk endpoint).
   Cards are visually dimmed and clicks are swallowed; the sticky-bar
   Continue button is separately locked by canContinue(). */
.ipear-v3-ct-card.is-loading {
  pointer-events: none;
  opacity: .55;
  position: relative;
}
.ipear-v3-ct-card.is-loading::after {
  content: '';
  position: absolute;
  right: 12px;
  top: 12px;
  width: 14px;
  height: 14px;
  border: 2px solid var(--ipear-border);
  border-top-color: var(--ipear-brand);
  border-radius: 50%;
  animation: ipearSpin .8s linear infinite;
}
@keyframes ipearSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Search field
   Fix (2026-08-16 audit): on mobile the input rendered wider than its parent
   and pushed the page into horizontal scroll. Root cause was two-fold:
     (a) user agent stylesheets give input[type="search"] a default `size` of
         ~20 chars, which some themes translate into a min-content width that
         defeats width:100% inside a narrow flex/grid ancestor;
     (b) neither the wrapper nor the input carried `min-width:0`, so the
         WoodMart theme's inherited box model could expand the input beyond
         its parent's content box.
   The rules below are additive and defensive — no negative margins, no
   width:100vw, no theme-specific overrides. They match the audit spec. */
.ipear-v3-search {
  position: relative;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  margin-bottom: 12px;
}
.ipear-v3-search input {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  min-height: var(--ipear-tap-min);
  padding: 10px 14px 10px 40px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  font-size: 15px;
  font-family: inherit;
  color: var(--ipear-ink);
  box-sizing: border-box;
  /* Reset the WebKit search-field chrome so iOS doesn't add its own inner
     padding / cancel-button on top of ours (which was making the field
     visually wider than its parent on 320–390px viewports). */
  -webkit-appearance: none;
  appearance: none;
}
.ipear-v3-search input::-webkit-search-decoration,
.ipear-v3-search input::-webkit-search-cancel-button,
.ipear-v3-search input::-webkit-search-results-button,
.ipear-v3-search input::-webkit-search-results-decoration {
  -webkit-appearance: none;
  display: none;
}
.ipear-v3-search input:focus {
  outline: none;
  border-color: var(--ipear-brand);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-search svg {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ipear-muted);
  pointer-events: none;
}

/* Model list — contained scroll panel so the page doesn't grow into newsletter/footer */
.ipear-v3-model-list-wrap {
  max-height: min(52svh, 520px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Confine gestures to vertical panning so the page scroll and the list scroll
     don't compete on iOS. Horizontal swipes still bubble to the browser (needed
     for iOS back-swipe / Instagram in-app browser controls). */
  touch-action: pan-y;
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  padding: 6px;
  scroll-margin-top: 80px;
}
.ipear-v3-model-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ipear-v3-model-btn {
  width: 100%;
  min-height: 52px;
  padding: 10px 12px;
  text-align: left;
  border: 1.5px solid transparent;
  border-radius: var(--ipear-radius-sm);
  background: transparent;
  font-size: 15px;
  font-weight: 500;
  color: var(--ipear-ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  transition: border-color .15s ease, background .15s ease;
}
.ipear-v3-model-btn:not(.is-active):not(.is-unavailable):active {
  background: var(--ipear-bg);
}
.ipear-v3-model-btn.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  color: var(--ipear-brand-ink);
}
.ipear-v3-model-btn.is-active::after {
  content: "";
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--ipear-brand);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  background-size: 12px;
  background-position: center;
  background-repeat: no-repeat;
  flex-shrink: 0;
}
.ipear-v3-model-btn.is-unavailable {
  opacity: .5;
  cursor: not-allowed;
}
.ipear-v3-model-btn.is-unavailable .ipear-v3-model-label {
  text-decoration: line-through;
  color: var(--ipear-muted);
}
.ipear-v3-model-label { flex: 1; }
.ipear-v3-model-flag {
  font-size: 10px;
  font-weight: 700;
  color: var(--ipear-danger);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 3px 6px;
  border-radius: var(--ipear-radius-pill);
  background: rgba(214,69,69,.08);
  white-space: nowrap;
}
.ipear-v3-model-empty {
  padding: 20px 14px;
  color: var(--ipear-muted);
  font-size: 14px;
  text-align: center;
  line-height: 1.5;
}

.ipear-v3-placeholder {
  text-align: center;
  padding: 40px 20px;
  background: var(--ipear-surface);
  border: 1.5px dashed var(--ipear-border);
  border-radius: var(--ipear-radius-lg);
  color: var(--ipear-muted);
  font-size: 14px;
  line-height: 1.6;
}
.ipear-v3-placeholder strong {
  display: block;
  color: var(--ipear-ink-soft);
  font-size: 16px;
  margin-bottom: 6px;
}

/* Step 2 — case type + color + print */
.ipear-v3-group { margin-bottom: 18px; }
.ipear-v3-group-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--ipear-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 10px;
}

/* Case-type cards — BIG icon left (80px), title/badge row + sub + price
   stacked in body. Card min-height 100px so images have room to breathe.
   Badge lives inline in the title row → no absolute overflow. */
.ipear-v3-ct-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}
.ipear-v3-ct-card {
  position: relative;
  display: grid;
  grid-template-columns: 80px 1fr;
  grid-column-gap: 14px;
  align-items: center;
  min-height: 100px;
  padding: 14px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  text-align: left;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.ipear-v3-ct-card.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-ct-card.is-unavailable {
  opacity: .55;
  cursor: not-allowed;
  background: var(--ipear-bg-sunk);
  /* Never look active — even if the class was carried across */
  border-color: var(--ipear-border);
  box-shadow: none;
}
.ipear-v3-ct-card.is-unavailable .ipear-v3-ct-title {
  color: var(--ipear-muted);
}
.ipear-v3-ct-card.is-unavailable .ipear-v3-ct-price {
  color: var(--ipear-danger);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ipear-v3-ct-icon {
  grid-column: 1;
  width: 80px; height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-bg);
  overflow: hidden;
  padding: 6px;
}
.ipear-v3-ct-icon img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}
.ipear-v3-ct-icon-fallback { font-size: 34px; line-height: 1; }
.ipear-v3-ct-body {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.ipear-v3-ct-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ipear-v3-ct-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--ipear-ink);
  line-height: 1.2;
}
.ipear-v3-ct-badge {
  background: var(--ipear-brand);
  color: #000;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--ipear-radius-pill);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.ipear-v3-ct-badge[hidden] { display: none !important; }
.ipear-v3-ct-sub {
  font-size: 12px;
  color: var(--ipear-muted);
  line-height: 1.35;
}
.ipear-v3-ct-price {
  font-size: 13px;
  font-weight: 700;
  color: var(--ipear-ink);
  margin-top: 4px;
}
.ipear-v3-ct-price:empty { display: none; }

/* Step 2 inline empty state — replaces the black CTA toast for the
   "no available case type for this device" scenario. */
.ipear-v3-empty {
  text-align: center;
  padding: 32px 20px;
  background: var(--ipear-surface);
  border: 1.5px dashed var(--ipear-border);
  border-radius: var(--ipear-radius-lg);
  margin-bottom: 16px;
}
.ipear-v3-empty-icon {
  width: 64px; height: 64px;
  margin: 0 auto 12px;
  border-radius: 50%;
  background: var(--ipear-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ipear-muted);
}
.ipear-v3-empty-text {
  font-size: 14px;
  color: var(--ipear-ink-soft);
  line-height: 1.5;
  margin: 0 0 14px;
}
.ipear-v3-empty-cta {
  min-height: var(--ipear-tap-min);
  padding: 10px 20px;
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-ink);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
}

/* Color swatches */
.ipear-v3-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ipear-v3-swatch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 6px;
  min-height: var(--ipear-tap-min);
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-surface);
  transition: border-color .15s ease, background .15s ease;
}
.ipear-v3-swatch.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
}
.ipear-v3-swatch.is-active .ipear-v3-swatch-dot::after {
  content: "";
  position: absolute; inset: 3px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 2px var(--ipear-brand);
}
.ipear-v3-swatch.is-unavailable {
  opacity: .55; /* raised from .35 for contrast */
  cursor: not-allowed;
}
.ipear-v3-swatch.is-unavailable .ipear-v3-swatch-name {
  text-decoration: line-through;
  color: var(--ipear-muted);
}
.ipear-v3-swatch-dot {
  position: relative;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(0,0,0,.15);
  flex-shrink: 0;
}
.ipear-v3-swatch-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--ipear-ink);
  white-space: nowrap;
}
.ipear-v3-swatch-hint {
  font-size: 12px;
  color: var(--ipear-muted);
  margin-top: 8px;
  line-height: 1.4;
}
.ipear-v3-swatch-hint:empty { display: none; }
.ipear-v3-swatch-hint.is-error {
  color: var(--ipear-danger);
  font-weight: 600;
}

/* Print type pills */
.ipear-v3-print-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.ipear-v3-print-card {
  display: grid;
  grid-template-columns: 32px 1fr;
  grid-template-rows: auto auto;
  grid-column-gap: 10px;
  padding: 12px 12px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  text-align: left;
  min-height: var(--ipear-tap-min);
  transition: border-color .15s ease, background .15s ease;
}
.ipear-v3-print-card.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-print-card.is-unavailable {
  opacity: .55;
  cursor: not-allowed;
  background: var(--ipear-bg-sunk);
  border-color: var(--ipear-border);
  box-shadow: none;
}
.ipear-v3-print-card.is-unavailable .ipear-v3-print-title,
.ipear-v3-print-card.is-unavailable .ipear-v3-print-price {
  color: var(--ipear-muted);
}
.ipear-v3-print-icon {
  grid-row: 1 / span 2;
  grid-column: 1;
  width: 32px; height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ipear-ink-soft);
}
.ipear-v3-print-card.is-active .ipear-v3-print-icon { color: var(--ipear-brand-ink); }
.ipear-v3-print-body { grid-column: 2; display: flex; flex-direction: column; }
.ipear-v3-print-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ipear-ink);
  line-height: 1.2;
}
.ipear-v3-print-sub {
  font-size: 11px;
  color: var(--ipear-muted);
  line-height: 1.3;
  margin-top: 2px;
}
.ipear-v3-print-price {
  grid-row: 2; grid-column: 2;
  font-size: 12px;
  font-weight: 700;
  color: var(--ipear-brand-ink);
  margin-top: 4px;
}
.ipear-v3-print-price:empty { display: none; }

/* Sticky bottom bar — position: sticky flows above theme's bottom nav.
   The Studio root's padding-bottom reserves room for BOTH bars. */
/* Sticky bottom bar — two-row grid.
   Row 1 = the validation hint (inline, subtle, ONLY when visible — the
     .is-visible class from JS controls that). No absolute overlay so it
     never covers the step's own controls (2D/3D pills, colour swatches,
     etc.). Empty row collapses to zero height when hint is idle.
   Row 2 = back / price / CTA (original 3-column layout).
   Keeps DOM identical to the pre-2026-08-17 template — only visual
   arrangement moved into the bar. */
.ipear-v3-bar {
  position: sticky;
  bottom: 0;
  z-index: 20;
  background: var(--ipear-surface);
  border-top: 1px solid var(--ipear-border);
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0));
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "hint hint hint"
    "back price cta";
  align-items: center;
  gap: 10px;
  row-gap: 8px;
  box-shadow: 0 -6px 16px rgba(0,0,0,.05);
  margin-top: 8px;
  /* Reserve `--ipear-bar-min` so back-to-back hint show/hide is not a
     visual jolt: the bar keeps at least the "with hint" height, then
     the hint fades in/out inside it. Chosen at 88px (mobile: back CTA
     row ≈ 64px + hint row ≈ 24px). Overridden in desktop breakpoints. */
  min-height: var(--ipear-bar-min, 88px);
  transition: min-height .18s ease;
}
.ipear-v3-bar-back  { grid-area: back;  }
.ipear-v3-bar-price { grid-area: price; }
.ipear-v3-bar-cta   { grid-area: cta;   }

/* Reserve room under the panel so the last control the customer scrolls
   to is never hidden behind the sticky bar. Sticky elements DO paint
   over preceding content while the user is mid-scroll — this padding
   gives them the extra travel needed to bring the true last row out
   from behind the bar. Includes iOS safe-area on notched devices.
   Desktop layouts have their own bar column, so the reserve is only
   the small breathing gap already declared elsewhere. */
.ipear-v3-panel {
  padding-bottom: calc( var(--ipear-bar-min, 88px) + 24px + env(safe-area-inset-bottom, 0) );
}
.ipear-v3-bar-back {
  min-width: 68px;
  min-height: var(--ipear-tap-min);
  padding: 0 12px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  font-size: 14px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}
.ipear-v3-bar-back[hidden] { visibility: hidden; }
.ipear-v3-bar-price {
  text-align: center;
  line-height: 1.2;
  min-width: 0;
}
.ipear-v3-bar-price-label {
  display: block;
  font-size: 10px;
  font-weight: 600;
  color: var(--ipear-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.ipear-v3-bar-price-label:empty { display: none; }
.ipear-v3-bar-price-amount {
  display: block;
  font-size: 17px;
  font-weight: 700;
  color: var(--ipear-ink);
}
.ipear-v3-bar-price.is-pending .ipear-v3-bar-price-amount {
  font-size: 12px;
  font-weight: 500;
  color: var(--ipear-muted);
  line-height: 1.35;
  white-space: normal;
  max-width: 200px;
  margin: 0 auto;
}
.ipear-v3-bar-price.is-error .ipear-v3-bar-price-amount {
  font-size: 12px;
  font-weight: 600;
  color: var(--ipear-danger);
  line-height: 1.35;
  white-space: normal;
  max-width: 200px;
  margin: 0 auto;
}
.ipear-v3-bar-cta {
  min-width: 122px;
  min-height: var(--ipear-tap-min);
  padding: 0 16px;
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-brand);
  color: #000;
  font-size: 15px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: background .15s ease, transform .05s ease;
}
.ipear-v3-bar-cta:active { transform: scale(.98); }
.ipear-v3-bar-cta:hover { background: var(--ipear-brand-hover); }
.ipear-v3-bar-cta[disabled],
.ipear-v3-bar-cta.is-disabled {
  background: var(--ipear-bg-sunk);
  color: var(--ipear-muted);
  cursor: not-allowed;
  pointer-events: none;
}

/* Inline hint inside the sticky bar's top row (grid-area: hint).
   Zero height when idle so the bar sits at its normal height; expands
   with a soft slide when a validation reason is set.
   Not a toast, not an overlay — never covers the step's own controls. */
.ipear-v3-bar-hint {
  grid-area: hint;
  display: none;
  align-items: flex-start;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--ipear-radius-md);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.35;
  color: #7a5b00;
  background: #fffbe6;
  border: 1px solid #f0d67a;
  text-align: left;
  /* Safe wrap: a two-line hint (e.g. long device name) keeps the grid
     intact — text just wraps, back/price/CTA stay in the second row. */
  min-width: 0;
  max-width: 100%;
  overflow-wrap: break-word;
  word-wrap:     break-word;
  animation: ipearHintIn .18s ease-out;
}
.ipear-v3-bar-hint:empty { display: none !important; }
.ipear-v3-bar-hint.is-visible { display: inline-flex; }
.ipear-v3-bar-hint::before {
  content: 'ℹ';
  flex: 0 0 auto;
  font-weight: 700;
  color: #b98600;
  font-size: 13px;
  line-height: 1.35; /* match parent line-height so the icon sits on the first line */
}
@keyframes ipearHintIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

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

/* ══════════════════════════════════════════════════════════════════
   Step 3 — Image / Gallery
   Mobile-first: no nested scroll, no horizontal overflow, touch-safe
   tap targets, controls hidden until an image loads.
   ══════════════════════════════════════════════════════════════════ */

/* Source tabs — pill-style toggle between upload / gallery */
.ipear-v3-source-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  padding: 4px;
  background: var(--ipear-bg-sunk);
  border-radius: var(--ipear-radius-pill);
  margin-bottom: 14px;
}
.ipear-v3-source-tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--ipear-tap-min);
  border-radius: var(--ipear-radius-pill);
  font-size: 13px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  background: transparent;
  transition: background .15s ease, color .15s ease;
}
.ipear-v3-source-tab.is-active {
  background: var(--ipear-surface);
  color: var(--ipear-ink);
  box-shadow: var(--ipear-shadow-sm);
}
.ipear-v3-source-tab svg { flex-shrink: 0; opacity: .85; }

/* Panels — one visible at a time */
.ipear-v3-src-panel { display: none; }
.ipear-v3-src-panel.is-active { display: block; }

/* Dropzone (empty upload state) */
.ipear-v3-upload-wrap { position: relative; }
.ipear-v3-dropzone {
  position: relative;
  display: block;
  padding: 28px 20px;
  border: 1.5px dashed var(--ipear-border);
  border-radius: var(--ipear-radius-lg);
  background: var(--ipear-surface);
  text-align: center;
  color: var(--ipear-ink-soft);
  transition: border-color .15s ease, background .15s ease;
  cursor: pointer;
  min-height: 148px;
}
.ipear-v3-dropzone:focus-visible {
  outline: 3px solid rgba(138,233,0,.35);
  outline-offset: 2px;
}
.ipear-v3-dropzone.is-dragging {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
}
.ipear-v3-file-input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: pointer;
}
.ipear-v3-dropzone-inner {
  position: relative;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.ipear-v3-dropzone-icon {
  width: 56px; height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ipear-bg-sunk);
  color: var(--ipear-brand-ink);
}
.ipear-v3-dropzone-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--ipear-ink);
}
.ipear-v3-dropzone-sub {
  font-size: 12px;
  color: var(--ipear-muted);
  line-height: 1.4;
}

/* Progress bar during upload */
.ipear-v3-upload-progress {
  margin-top: 10px;
  height: 4px;
  background: var(--ipear-bg-sunk);
  border-radius: var(--ipear-radius-pill);
  overflow: hidden;
}
.ipear-v3-upload-progress[hidden] { display: none !important; }
.ipear-v3-upload-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--ipear-brand);
  transition: width .18s ease;
}

/* Message area (error / info) — success is silent */
.ipear-v3-upload-msg {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.4;
  min-height: 0;
}
.ipear-v3-upload-msg:empty { display: none; }
.ipear-v3-upload-msg.is-error {
  color: var(--ipear-danger);
  font-weight: 600;
}
.ipear-v3-upload-msg.is-info {
  color: var(--ipear-muted);
}

/* Preview chip — visible once state.imageUrl is set */
.ipear-v3-preview-chip {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  background: var(--ipear-surface);
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
}
.ipear-v3-preview-chip[hidden] { display: none !important; }
.ipear-v3-preview-chip-thumb {
  width: 52px; height: 52px;
  flex-shrink: 0;
  border-radius: var(--ipear-radius-sm);
  background-color: var(--ipear-bg-sunk);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  border: 1px solid var(--ipear-border);
}
.ipear-v3-preview-chip-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ipear-v3-preview-chip-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ipear-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ipear-v3-preview-chip-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.ipear-v3-chip-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-surface);
  font-size: 12px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.ipear-v3-chip-btn:hover { border-color: var(--ipear-ink-soft); }
.ipear-v3-chip-btn.is-danger { color: var(--ipear-danger); }
.ipear-v3-chip-btn.is-danger:hover { border-color: var(--ipear-danger); background: rgba(214,69,69,.05); }
.ipear-v3-chip-btn svg { flex-shrink: 0; }

/* Neutral image-info line — purely descriptive (dimensions only, no verdict) */
.ipear-v3-quality-hint {
  margin-top: 10px;
  padding: 8px 12px;
  border-radius: var(--ipear-radius-sm);
  background: var(--ipear-bg);
  border: 1px solid var(--ipear-border);
  color: var(--ipear-muted);
  font-size: 12px;
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
}
.ipear-v3-quality-hint:empty {
  display: none;
  padding: 0;
  border: none;
  margin: 0;
}

/* Image controls (sliders + reset) — hidden until image loads */
.ipear-v3-image-controls {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  background: var(--ipear-surface);
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
}
.ipear-v3-image-controls[hidden] { display: none !important; }

.ipear-v3-control-row {
  display: grid;
  grid-template-columns: 44px 1fr 44px 54px;
  align-items: center;
  gap: 8px;
}
/* Step buttons (+/−, rotate) — full 44px touch target */
.ipear-v3-step-btn {
  min-height: 44px;
  min-width: 44px;
  padding: 0 8px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  color: var(--ipear-ink-soft);
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color .12s ease, background .12s ease, color .12s ease;
  font-variant-numeric: tabular-nums;
}
.ipear-v3-step-btn:hover  { border-color: var(--ipear-brand); background: var(--ipear-brand-tint); color: var(--ipear-brand-ink); }
.ipear-v3-step-btn:active { transform: scale(.96); }
.ipear-v3-step-btn:focus-visible {
  outline: 3px solid rgba(138,233,0,.35);
  outline-offset: 2px;
}

/* Grab cursor on preview when image is loaded and we're in image mode */
.ipear-v3[data-edit-mode="image"] .ipear-phone-screen {
  cursor: grab;
}
.ipear-v3[data-edit-mode="image"] .ipear-phone-screen:active {
  cursor: grabbing;
}

.ipear-v3-control-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ipear-muted);
  opacity: .8;
}
.ipear-v3-control-value {
  text-align: right;
  font-size: 12px;
  font-weight: 700;
  color: var(--ipear-ink-soft);
  font-variant-numeric: tabular-nums;
}

/* Slider styling — WebKit + Firefox, iOS-safe tap area */
.ipear-v3-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 32px;
  background: transparent;
  cursor: pointer;
  padding: 0;
  margin: 0;
  touch-action: manipulation;
}
.ipear-v3-slider::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-bg-sunk);
}
.ipear-v3-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 24px; height: 24px;
  margin-top: -10px;
  border-radius: 50%;
  background: var(--ipear-brand);
  border: 2px solid var(--ipear-surface);
  box-shadow: 0 1px 4px rgba(0,0,0,.25);
  cursor: grab;
}
.ipear-v3-slider::-moz-range-track {
  height: 4px;
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-bg-sunk);
}
.ipear-v3-slider::-moz-range-thumb {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--ipear-brand);
  border: 2px solid var(--ipear-surface);
  box-shadow: 0 1px 4px rgba(0,0,0,.25);
  cursor: grab;
}
.ipear-v3-slider:focus-visible {
  outline: 3px solid rgba(138,233,0,.35);
  outline-offset: 2px;
  border-radius: var(--ipear-radius-pill);
}

.ipear-v3-reset-btn {
  align-self: flex-start;
}

/* Legacy compatibility: the DraggableImage engine toggles `.show` on the
   zoom/rot wrappers. Since we always render them inside .ipear-v3-image-controls
   (which is what actually gates visibility), we don't need `.show`-based
   display swaps here — but keep the class harmless. */
.ipear-v3-image-controls .ipear-zoom-controls,
.ipear-v3-image-controls .ipear-rot-controls { display: grid; }

/* 2026-08-16 customer request — split by viewport:
   Mobile (touch): pinch-to-zoom only, no on-screen bars. Rotation via the
     ±90° buttons + reset chip. The zoom slider / ± buttons / rotation
     slider are hidden.
   Desktop (mouse, ≥1024px): the customer has no pinch gesture, so keep
     the sliders and ± buttons visible for practical control. Mouse wheel
     over the mockup zooms too (handled by the DraggableImage engine).
   The DOM stays intact under both — we only toggle visibility. */
.ipear-v3-image-controls .ipear-zoom-controls,
.ipear-v3-image-controls .ipear-rot-controls .ipear-rot-slider,
.ipear-v3-image-controls .ipear-rot-controls .ipear-rot-level {
  display: none !important;
}
.ipear-v3-image-controls .ipear-rot-controls {
  display: flex;
  gap: 8px;
  justify-content: center;
}
@media (min-width: 1024px) {
  /* Restore desktop controls — the same rules the plugin shipped before
     the mobile-only hide above. Slider ranges are re-applied from JS
     according to the active Fit/Fill envelope (10%..2000%).
     Body-scoped selector bumps specificity so a WoodMart / theme rule
     with its own !important cannot silently hide the zoom slider on
     desktop (customer report 2026-08-24). */
  body .ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls,
  body .ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls[data-role="zoom-wrap"] {
    display: grid !important;
    visibility: visible !important;
  }
  body .ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls > * {
    display: inline-flex !important;
    visibility: visible !important;
  }
  body .ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls .ipear-v3-slider {
    display: block !important;
    visibility: visible !important;
  }
  body .ipear-v3 .ipear-v3-image-controls .ipear-rot-controls {
    display: grid !important;
  }
  body .ipear-v3 .ipear-v3-image-controls .ipear-rot-controls .ipear-rot-slider,
  body .ipear-v3 .ipear-v3-image-controls .ipear-rot-controls .ipear-rot-level {
    display: initial !important;
    visibility: visible !important;
  }
}

/* Gallery grid — mobile-first: 3 cols on phones, 4 on wider */
.ipear-v3-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  padding: 4px 0;
}
@media (min-width: 480px) {
  .ipear-v3-gallery { grid-template-columns: repeat(4, 1fr); }
}
.ipear-v3-gallery-item {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  overflow: hidden;
  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;
}
.ipear-v3-gallery-item:active { transform: scale(.98); }
.ipear-v3-gallery-item.is-selected {
  border-color: var(--ipear-brand);
  box-shadow: 0 0 0 3px rgba(138,233,0,.25);
}
.ipear-v3-gallery-item img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.ipear-v3-gallery-state {
  grid-column: 1 / -1;
  padding: 32px 16px;
  text-align: center;
  color: var(--ipear-muted);
  font-size: 13px;
  line-height: 1.5;
  background: var(--ipear-surface);
  border: 1.5px dashed var(--ipear-border);
  border-radius: var(--ipear-radius-lg);
}
.ipear-v3-gallery-state.is-error { color: var(--ipear-danger); }
.ipear-v3-gallery-retry {
  display: inline-block;
  margin-top: 10px;
  padding: 6px 14px;
  border: 1.5px solid var(--ipear-danger);
  border-radius: var(--ipear-radius-pill);
  color: var(--ipear-danger);
  font-size: 12px;
  font-weight: 700;
  background: transparent;
}

/* ══════════════════════════════════════════════════════════════════
   Step 4 — Text overlay controls
   ══════════════════════════════════════════════════════════════════ */

.ipear-v3-step-opt {
  font-size: 12px;
  font-weight: 500;
  color: var(--ipear-muted);
  letter-spacing: 0;
  margin-left: 6px;
}

.ipear-v3-textarea-wrap { position: relative; }
.ipear-v3-textarea {
  width: 100%;
  min-height: 72px;
  padding: 12px 14px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  font-family: inherit;
  font-size: 15px;
  color: var(--ipear-ink);
  line-height: 1.4;
  resize: vertical;
  box-sizing: border-box;
}
.ipear-v3-textarea:focus-visible {
  outline: 3px solid rgba(138,233,0,.35);
  outline-offset: 2px;
  border-color: var(--ipear-brand);
}
.ipear-v3-textarea-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 6px;
}
.ipear-v3-text-counter {
  font-size: 12px;
  color: var(--ipear-muted);
  font-variant-numeric: tabular-nums;
}
.ipear-v3-text-clear {
  font-size: 12px;
  font-weight: 600;
  color: var(--ipear-ink-soft);
  background: transparent;
  padding: 4px 8px;
  border-radius: var(--ipear-radius-pill);
  border: 1px solid var(--ipear-border);
  cursor: pointer;
}
.ipear-v3-text-clear:hover { border-color: var(--ipear-ink-soft); }
.ipear-v3-text-notice {
  margin-top: 8px;
  font-size: 12px;
  color: #8a5a00;
  padding: 6px 10px;
  border-radius: var(--ipear-radius-sm);
  background: rgba(245,166,35,.10);
  border: 1px solid rgba(245,166,35,.28);
  line-height: 1.4;
  display: none;
}
.ipear-v3-text-notice.is-visible { display: block; }

.ipear-v3-font-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
@media (min-width: 480px) {
  .ipear-v3-font-row { grid-template-columns: repeat(4, 1fr); }
}
.ipear-v3-font-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-height: 66px;
  padding: 10px 6px;
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  background: var(--ipear-surface);
  color: var(--ipear-ink);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.ipear-v3-font-btn.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-font-sample {
  font-size: 22px;
  line-height: 1;
  color: var(--ipear-ink);
}
.ipear-v3-font-name {
  font-size: 11px;
  color: var(--ipear-muted);
  font-weight: 600;
}
/* Font sample rules moved below with !important so WoodMart body font
   doesn't override them. See the .ipear-text-overlay font blocks. */

.ipear-v3-color-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.ipear-v3-color-preset {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 2px solid var(--ipear-border);
  cursor: pointer;
  padding: 0;
  transition: transform .05s ease, border-color .15s ease, box-shadow .15s ease;
}
.ipear-v3-color-preset:active { transform: scale(.94); }
.ipear-v3-color-preset.is-active {
  border-color: var(--ipear-brand-ink);
  box-shadow: 0 0 0 3px rgba(138,233,0,.35);
}
.ipear-v3-color-picker-wrap {
  position: relative;
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 2px dashed var(--ipear-border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ipear-muted);
  font-size: 20px;
  cursor: pointer;
  overflow: hidden;
}
.ipear-v3-color-picker {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  border: none;
  padding: 0;
}

.ipear-v3-text-actions {
  margin-top: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.ipear-v3-text-hint {
  font-size: 12px;
  color: var(--ipear-muted);
  line-height: 1.4;
}

/* ── Text overlay on mockup — visible only when it has-text ── */
.ipear-text-overlay {
  position: absolute;
  z-index: 7;
  display: none;
  pointer-events: none;
  padding: 0;
  transform: translate(-50%, -50%);
  transform-origin: center center;
}
.ipear-text-overlay.has-text {
  display: block;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
}
.ipear-text-overlay.is-dragging { cursor: grabbing; }
.ipear-text-overlay .ipear-text-preview {
  display: inline-block;
  white-space: nowrap;
  font-size: 22px;
  font-weight: 700;
  text-shadow: 0 1px 4px rgba(0,0,0,.4);
  color: #ffffff;
  padding: 2px 6px;
}
/* !important on font-family — WoodMart's global body font can otherwise
   win specificity on the .ipear-text-preview inner span (which inherits
   the theme font by default). Also required to overcome theme rules that
   scope font by tag selector. font-weight/letter-spacing are left plain
   so the theme's italic/weight defaults never fight the intentional look. */
.ipear-text-overlay.ipear-font-default  .ipear-text-preview {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
  font-weight: 700;
}
.ipear-text-overlay.ipear-font-pacifico .ipear-text-preview {
  font-family: 'Pacifico', cursive !important;
  font-weight: 400;
}
.ipear-text-overlay.ipear-font-bebas    .ipear-text-preview {
  font-family: 'Bebas Neue', Impact, sans-serif !important;
  font-weight: 400;
  letter-spacing: 1.5px;
}
.ipear-text-overlay.ipear-font-dancing  .ipear-text-preview {
  font-family: 'Dancing Script', cursive !important;
  font-weight: 700;
}
/* Font sample inside the picker button — same !important treatment so the
   admin can visually confirm the font before picking it. */
.ipear-v3-font-btn.ipear-font-pacifico .ipear-v3-font-sample { font-family: 'Pacifico', cursive !important; }
.ipear-v3-font-btn.ipear-font-bebas    .ipear-v3-font-sample { font-family: 'Bebas Neue', Impact, sans-serif !important; letter-spacing: 1px; }
.ipear-v3-font-btn.ipear-font-dancing  .ipear-v3-font-sample { font-family: 'Dancing Script', cursive !important; font-weight: 700; }

/* ══════════════════════════════════════════════════════════════════
   Step 5 — Review + upsells + cart
   ══════════════════════════════════════════════════════════════════ */

.ipear-v3-review {
  background: var(--ipear-surface);
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  padding: 4px 14px;
  margin-bottom: 14px;
}
.ipear-v3-review-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--ipear-border);
  font-size: 14px;
  line-height: 1.35;
}
.ipear-v3-review-row:last-child { border-bottom: none; }
.ipear-v3-review-label {
  color: var(--ipear-muted);
  font-weight: 600;
  flex-shrink: 0;
}
.ipear-v3-review-value {
  color: var(--ipear-ink);
  font-weight: 500;
  text-align: right;
  word-break: break-word;
}
.ipear-v3-review-row.is-total {
  padding-top: 14px;
  font-size: 16px;
}
.ipear-v3-review-row.is-total .ipear-v3-review-label,
.ipear-v3-review-row.is-total .ipear-v3-review-value {
  font-weight: 800;
  color: var(--ipear-ink);
}
.ipear-v3-review-row.is-extra .ipear-v3-review-label {
  color: var(--ipear-ink-soft);
  font-weight: 500;
}
.ipear-v3-review-note {
  padding: 8px 14px 12px;
  font-size: 11px;
  color: var(--ipear-muted);
  line-height: 1.4;
  font-style: italic;
}

.ipear-v3-upsells {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x mandatory;
  padding: 4px 0 8px;
  margin: 0 -16px;   /* bleed to viewport edges so cards scroll fully */
  padding-left: 16px;
  padding-right: 16px;
}
.ipear-v3-upsell-card {
  flex: 0 0 auto;
  width: 148px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  background: var(--ipear-surface);
  border: 1.5px solid var(--ipear-border);
  border-radius: var(--ipear-radius-md);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.ipear-v3-upsell-card.is-selected {
  border-color: var(--ipear-brand);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-upsell-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  background-color: var(--ipear-bg-sunk);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  border-radius: var(--ipear-radius-sm);
}
.ipear-v3-upsell-thumb-empty { background-color: var(--ipear-bg); }
.ipear-v3-upsell-thumb { position: relative; }
.ipear-v3-upsell-sale {
  position: absolute;
  top: 6px; left: 6px;
  background: var(--ipear-danger);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: var(--ipear-radius-pill);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.ipear-v3-upsell-price-old {
  color: var(--ipear-muted);
  text-decoration: line-through;
  font-weight: 500;
  margin-right: 4px;
}
.ipear-v3-upsell-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--ipear-ink);
  line-height: 1.3;
  min-height: 32px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.ipear-v3-upsell-price {
  font-size: 13px;
  font-weight: 700;
  color: var(--ipear-brand-ink);
  font-variant-numeric: tabular-nums;
}
.ipear-v3-upsell-btn {
  margin-top: 4px;
  padding: 6px 10px;
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-pill);
  background: var(--ipear-surface);
  color: var(--ipear-ink-soft);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.ipear-v3-upsell-card.is-selected .ipear-v3-upsell-btn {
  background: var(--ipear-brand);
  border-color: var(--ipear-brand);
  color: #000;
}

.ipear-v3-cart-msg {
  margin: 12px 0 4px;
  font-size: 13px;
  line-height: 1.4;
  padding: 8px 12px;
  border-radius: var(--ipear-radius-sm);
  min-height: 0;
  display: none;
}
.ipear-v3-cart-msg:empty { display: none; }
.ipear-v3-cart-msg.is-info    { display: block; background: var(--ipear-bg); color: var(--ipear-ink-soft); border: 1px solid var(--ipear-border); }
.ipear-v3-cart-msg.is-error   { display: block; background: rgba(214,69,69,.08); color: var(--ipear-danger); border: 1px solid rgba(214,69,69,.30); font-weight: 600; }
.ipear-v3-cart-msg.is-success { display: block; background: rgba(138,233,0,.15); color: var(--ipear-brand-ink); border: 1px solid rgba(138,233,0,.40); font-weight: 600; }

.ipear-v3-delivery {
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--ipear-bg);
  border: 1px solid var(--ipear-border);
  border-radius: var(--ipear-radius-sm);
  color: var(--ipear-ink-soft);
  font-size: 12px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}
.ipear-v3-delivery svg { flex-shrink: 0; color: var(--ipear-brand-ink); }

/* ══════════════════════════════════════════════════════════════════
   Tablet (768–1023px): controlled middle layout — centred card,
   slightly wider than mobile, still a single column. NO 2-column
   split at this size — the shell would either shrink or the column
   would be too narrow for controls.
   ══════════════════════════════════════════════════════════════════ */
@media (min-width: 768px) and (max-width: 1023.98px) {
  .ipear-v3 {
    max-width: 620px;
    margin: 24px auto;
    box-shadow: var(--ipear-shadow-md);
    border-radius: var(--ipear-radius-lg);
    overflow: hidden;
    padding-bottom: 0;
  }
  .ipear-v3-stage { height: 480px; }
}

/* ══════════════════════════════════════════════════════════════════
   Desktop (≥1024px): TRUE 2-column workspace.
   - LEFT: sticky preview + zoom/rot controls, large mockup at native size
   - RIGHT: step panel + progress + CTA/summary
   - Mockup is NOT CSS-scaled on desktop → drag math is 1:1 by default
     (scale=1). Achieved by overriding the mockup wrapper's transform.
   - Sticky bar becomes a right-column summary, NOT a full-viewport dock
   ══════════════════════════════════════════════════════════════════ */
@media (min-width: 1024px) {
  .ipear-v3 {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 420px;
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas:
      "preview progress"
      "preview panel"
      "preview panel"
      "preview bar";
    gap: 0 32px;
    max-width: 1200px;
    margin: 24px auto;
    padding: 24px;
    background: transparent;
    padding-bottom: 24px;
    box-shadow: none;
  }
  /* Step 1 on desktop: no preview column at all — collapse to single column
     so the empty sticky sidebar doesn't dominate the picker view. */
  .ipear-v3[data-current-step="1"] {
    grid-template-columns: 1fr;
    grid-template-areas:
      "progress"
      "panel"
      "bar";
    max-width: 720px;
  }
  .ipear-v3-progress { grid-area: progress; }
  .ipear-v3-stage    {
    grid-area: preview;
    position: sticky;
    top: calc( var( --ipear-header-offset, 72px ) + 20px );
    height: auto;
    min-height: 520px;
    max-height: calc( 100vh - var( --ipear-header-offset, 72px ) - 60px );
    background: var(--ipear-surface);
    border-radius: var(--ipear-radius-lg);
    box-shadow: var(--ipear-shadow-md);
    padding: 20px;
    align-items: center;
  }
  .ipear-v3-panel    {
    grid-area: panel;
    padding: 20px 0 0;
    background: transparent;
  }
  .ipear-v3-bar      {
    grid-area: bar;
    position: sticky;
    bottom: 20px;
    margin-top: 20px;
    border-radius: var(--ipear-radius-lg);
    border-top: 1px solid var(--ipear-border);
    box-shadow: var(--ipear-shadow-md);
    /* Desktop: the bar lives in its own grid slot next to the panel, so
       we don't need the mobile min-height reserve. Let the row height
       collapse when the hint is idle. */
    min-height: 0;
  }
  /* Desktop panel has its own column — no need to reserve room under it
     for a fixed-position bar as we do on mobile. Keep the minimal top
     padding (20px) that the desktop layout already declared. */
  .ipear-v3-panel {
    padding-bottom: 20px;
  }

  /* Aspect-preserved upscaling on desktop:
     The shell KEEPS its authoritative native px dimensions (196×423 case,
     etc.) so ALL internal % coordinates (camera cutout, side buttons,
     text position) and px border-radius stay in the exact legacy geometry.
     We scale the WHOLE mockup wrapper via the same `--v3-mockup-scale`
     CSS variable that the drag adapter reads for pointer compensation,
     so drag stays 1:1 with the mouse. The scale factor is set by JS
     (applyMockupScale) based on stage height — larger stage on desktop
     naturally yields a larger scale up to a sane cap of 1.8×. NEVER
     override width/height of the shell on desktop; that would break
     the internal % coordinates and desync the camera/buttons. */
  .ipear-v3-stage { align-items: stretch; }

  /* Editmode toggle sits above the preview area (not overlapping mockup) */
  .ipear-v3-editmode { top: 4px; }

  /* Bottom padding no longer needed on desktop — sticky bar is contained
     inside the right column, not a full-viewport dock */
  .ipear-v3 { padding-bottom: 24px !important; }

  /* Gallery grid can breathe more on desktop */
  .ipear-v3-gallery { grid-template-columns: repeat(3, 1fr); }

  /* Upsell carousel: on desktop, remove the negative-margin bleed since
     the panel column has its own padding */
  .ipear-v3-upsells {
    margin-left: 0;
    margin-right: 0;
    padding-left: 0;
    padding-right: 0;
  }
}

/* Extra breathing room at ≥1366 (default desktop laptops upward).
   Shell dimensions are NOT overridden here — see the aspect-preservation
   note above. Bigger preview column → JS chooses higher scale factor. */
@media (min-width: 1366px) {
  .ipear-v3 {
    max-width: 1280px;
    grid-template-columns: minmax(0, 1fr) 440px;
    gap: 0 40px;
  }
}

/* Even more at ≥1440 */
@media (min-width: 1440px) {
  .ipear-v3 { max-width: 1360px; }
}

/* ── Reduced motion ───────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ipear-v3-step,
  .ipear-v3-bar-cta,
  .ipear-v3-bar-hint,
  .ipear-v3-brand-tab,
  .ipear-v3-model-btn,
  .ipear-v3-mockup {
    animation: none !important;
    transition: none !important;
  }
}

/* ══════════════════════════════════════════════════════════════════
   2026-08-17 UI polish — segmented / toggle controls
   Add a visible border to every clickable segmented control that used
   to look like plain text (2D/3D, Fit/Fill, Image/Text, Upload/Gallery).
   Three-state visual language, identical across every control:
     • unselected  — white surface + 1.5px --ipear-border, ink text
     • selected    — 1.5px --ipear-brand border + brand-tint background
     • unavailable — 1.5px --ipear-border, dimmed, cursor:not-allowed
   Constant 1.5px border on ALL states + box-sizing:border-box → the
   layout never shifts as the customer clicks between options. Focus
   ring is a separate outline offset by 2px so it doesn't fight the
   colour swap. Touch target lifted to 44px where it wasn't already.
   Nothing here alters behaviour, pricing, validation or backend.
   ══════════════════════════════════════════════════════════════════ */

/* Print 2D/3D pills — visible border on all states so they read as
   clickable buttons instead of icon+label rows. */
.ipear-v3-print-card {
  box-sizing: border-box;
  border: 1.5px solid var(--ipear-border);
  min-height: var(--ipear-tap-min);
  cursor: pointer;
}
.ipear-v3-print-card:hover:not(.is-unavailable):not(.is-active) {
  border-color: var(--ipear-ink-soft);
}

/* Fit/Fill segmented control — was pill-flat with only a background
   swap. Give both segments a real, always-visible border so the
   customer sees two distinct buttons before hovering. */
.ipear-v3-fitfill {
  padding: 4px;
}
.ipear-v3-fitfill-btn {
  box-sizing: border-box;
  border: 1.5px solid var(--ipear-border);
  background: var(--ipear-surface);
  min-height: var(--ipear-tap-min);
  cursor: pointer;
}
.ipear-v3-fitfill-btn.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  color: var(--ipear-brand-ink);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-fitfill-btn:hover:not(.is-active):not(:disabled) {
  border-color: var(--ipear-ink-soft);
}
.ipear-v3-fitfill-btn:disabled,
.ipear-v3-fitfill-btn[aria-disabled="true"] {
  opacity: .55;
  cursor: not-allowed;
  background: var(--ipear-bg-sunk);
}

/* Image / Text edit-mode toggle — same treatment. Raise the touch
   target to 44px (was 34px) so it clears the accessibility minimum. */
.ipear-v3-editmode {
  padding: 4px;
}
.ipear-v3-editmode-btn {
  box-sizing: border-box;
  border: 1.5px solid var(--ipear-border);
  background: var(--ipear-surface);
  min-height: var(--ipear-tap-min);
  padding: 8px 14px;
  font-size: 13px;
  cursor: pointer;
}
.ipear-v3-editmode-btn.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  color: var(--ipear-brand-ink);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-editmode-btn:hover:not(.is-active):not(:disabled) {
  border-color: var(--ipear-ink-soft);
}

/* Upload / Έτοιμα Σχέδια source tabs. */
.ipear-v3-source-tab {
  box-sizing: border-box;
  border: 1.5px solid var(--ipear-border);
  background: var(--ipear-surface);
  cursor: pointer;
}
.ipear-v3-source-tab.is-active {
  border-color: var(--ipear-brand);
  background: var(--ipear-brand-tint);
  color: var(--ipear-brand-ink);
  box-shadow: 0 0 0 3px rgba(138,233,0,.18);
}
.ipear-v3-source-tab:hover:not(.is-active) {
  border-color: var(--ipear-ink-soft);
}

/* Uniform focus-visible ring for all four segmented controls +
   the case-type cards / brand tabs / print pills that already carry
   their own outlines. Uses outline (not box-shadow) so it doesn't
   fight the selection ring, and offset 2px so it sits clearly outside
   the border on any background. */
.ipear-v3-print-card:focus-visible,
.ipear-v3-fitfill-btn:focus-visible,
.ipear-v3-editmode-btn:focus-visible,
.ipear-v3-source-tab:focus-visible,
.ipear-v3-ct-card:focus-visible,
.ipear-v3-brand-tab:focus-visible {
  outline: 2px solid var(--ipear-brand);
  outline-offset: 2px;
}

/* ══════════════════════════════════════════════════════════════════
   2026-08-17 Non-case mockup parity with legacy configurator.css.
   The v3 shortcode enqueues only ipear-configurator-mobile.css, so the
   legacy decorator rules never landed. Mirror the exact blocks from
   assets/css/ipear-configurator.css:914-1108 verbatim (same selectors,
   same values) so a v3 airpods/powerbank/charger mockup reads the same
   as `?ui=v2`. Never touched: the case shell above; case is unaffected
   because these rules all key on [data-product-type="…"] non-case.
   ══════════════════════════════════════════════════════════════════ */

/* ── AirPods Case shell — portrait 74.5% ──────────────── */
[data-product-type="airpods"] .ipear-phone-wrap { padding: 0; }
[data-product-type="airpods"] .ipear-phone-shell {
  width: 210px;
  border-radius: 32px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18), 0 0 0 1.5px rgba(0,0,0,0.18);
}
[data-product-type="airpods"] .ipear-phone-shell::before { padding-top: 74.5%; }
[data-product-type="airpods"][data-airpods-size="small"] .ipear-phone-shell { width: 158px; }
[data-product-type="airpods"][data-airpods-size="small"] .ipear-phone-shell::before { padding-top: 98.7%; }

/* ── Powerbank shell — landscape 16:9 ───────────────────── */
[data-product-type="powerbank"] .ipear-phone-wrap { padding: 0; }
[data-product-type="powerbank"] .ipear-phone-shell {
  width: 224px;
  border-radius: 16px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18), 0 0 0 1.5px rgba(0,0,0,0.18);
}
[data-product-type="powerbank"] .ipear-phone-shell::before { padding-top: 56.25%; /* 9/16 */ }

/* ── Wall Charger — phone-wrap is the flex-column stack ─────── */
[data-product-type="charger"] .ipear-phone-wrap {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  padding: 0;
  gap: 0;
}
[data-product-type="charger"] .ipear-cg-pins-wrap {
  display: flex;
  flex-direction: row;
  gap: 34px;
  margin: 0;
  padding: 0;
  line-height: 0;
}
[data-product-type="charger"] .ipear-phone-shell {
  width: 160px;
  border-radius: 6px 6px 0 0;
  box-shadow: 0 4px 20px rgba(0,0,0,0.18), 0 0 0 1.5px rgba(0,0,0,0.18);
  margin: 0;
}
[data-product-type="charger"] .ipear-phone-shell::before { padding-top: 116.25%; /* 186/160 */ }

/* AirPods Case lid seam */
.ipear-airpods-lid {
  position: absolute;
  left: 0; right: 0;
  top: 25%;
  height: 3px;
  background: linear-gradient(
    90deg,
    transparent 0%, rgba(0,0,0,0.18) 8%,
    rgba(0,0,0,0.30) 50%,
    rgba(0,0,0,0.18) 92%, transparent 100%
  );
  z-index: 10;
  pointer-events: none;
}
.ipear-airpods-lid::after {
  content: '';
  position: absolute;
  left: 8%; right: 8%;
  top: 3px;
  height: 1px;
  background: rgba(255,255,255,0.22);
}

/* Powerbank decorators */
.ipear-pb-btn {
  position: absolute;
  left: 2%;
  top: 50%;
  transform: translateY(-50%);
  width: 3%;
  height: 22%;
  min-width: 5px; min-height: 12px;
  background: rgba(255,255,255,0.22);
  border: 1.5px solid rgba(0,0,0,0.22);
  border-radius: 3px;
  box-shadow: inset 0 1px 2px rgba(255,255,255,0.30);
  z-index: 10;
  pointer-events: none;
}
.ipear-pb-leds {
  position: absolute;
  left: 2%;
  bottom: 20%;
  display: flex;
  flex-direction: column;
  gap: 3px;
  z-index: 10;
  pointer-events: none;
}
.ipear-pb-leds span {
  display: block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(230,230,230,0.85);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.12);
}
.ipear-pb-usba {
  position: absolute;
  right: 2%;
  top: 28%;
  width: 3%;
  height: 18%;
  min-width: 5px; min-height: 8px;
  background: rgba(0,0,0,0.10);
  border: 1.5px solid rgba(0,0,0,0.22);
  border-radius: 2px;
  z-index: 10;
  pointer-events: none;
}
.ipear-pb-usbc {
  position: absolute;
  right: 2%;
  top: 54%;
  width: 3%;
  height: 12%;
  min-width: 5px; min-height: 6px;
  background: rgba(0,0,0,0.10);
  border: 1.5px solid rgba(0,0,0,0.22);
  border-radius: 50px;
  z-index: 10;
  pointer-events: none;
}

/* Wall Charger decorators */
[data-product-type="charger"] .ipear-cg-pin-l,
[data-product-type="charger"] .ipear-cg-pin-r {
  display: block;
  width: 8px;
  height: 48px;
  background: linear-gradient(to bottom, #eee 0%, #ccc 85%, #555 100%);
  border: 1px solid #bbb;
  border-top: none;
  border-radius: 0 0 4px 4px;
  margin: 0;
  padding: 0;
  pointer-events: none;
}
[data-product-type="charger"] .ipear-cg-conn {
  display: block;
  width: 114px;
  height: 80px;
  background: linear-gradient(to bottom, #efefef 0%, #e5e5e5 100%);
  border: 1px solid #d5d5d5;
  border-top: none;
  border-bottom: none;
  border-radius: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
}
[data-product-type="charger"] .ipear-cg-body-line { display: none !important; }

/* ─────────────────────────────────────────────────────────────
 * F7.2 — Stage-hidden safety.
 * When Studio.prototype.renderStage() closes the mockup reveal
 * gate it sets `hidden` on `.ipear-v3-stage`. Some author rules
 * force `display:block` on children and can defeat the HTML
 * `hidden` attribute; this scoped rule guarantees the stage
 * takes zero layout space when hidden. No opacity/visibility —
 * we do NOT want an empty white shell reserving vertical room.
 * ────────────────────────────────────────────────────────────── */
.ipear-v3-stage[hidden] { display: none !important; }

/* ─────────────────────────────────────────────────────────────
 * F7.11 — Restore zoom + rotation sliders on MOBILE too.
 * Overrides the 2026-08-16 "pinch-only mobile" rule after
 * customer feedback: users want sliders on both mobile & desktop.
 * Full zoom range (up to 20×) already supported by the engine.
 * Scoped strictly to `.ipear-v3-image-controls` — no side-effects.
 * ─────────────────────────────────────────────────────────────
 */
.ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls,
.ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls[data-role="zoom-wrap"] {
  display: grid !important;
  visibility: visible !important;
}
.ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls > * {
  display: inline-flex !important;
  visibility: visible !important;
}
.ipear-v3 .ipear-v3-image-controls .ipear-zoom-controls .ipear-v3-slider {
  display: block !important;
  visibility: visible !important;
}
.ipear-v3 .ipear-v3-image-controls .ipear-rot-controls {
  display: grid !important;
}
.ipear-v3 .ipear-v3-image-controls .ipear-rot-controls .ipear-rot-slider,
.ipear-v3 .ipear-v3-image-controls .ipear-rot-controls .ipear-rot-level {
  display: initial !important;
  visibility: visible !important;
}
