/*
 * Mug personalization constructor — page-scoped styles (Iteration 1, shell).
 * Loaded ONLY on product/personalize via document->addStyle (out of the main bundle).
 * Design tokens (var(--color-*), --space-*, --radius-*) come from :root in dev.css,
 * which is loaded globally, so they are available here.
 */

.kd-personalize__title {
  font-size: var(--text-xl, 30px);
  font-weight: 700;
  margin: var(--space-4, 16px) 0 var(--space-4, 16px);
}

.kd-personalize__missing {
  padding: var(--space-5, 20px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
  color: var(--color-text-muted, #94A3B8);
}

.kd-personalize {
  display: flex;
  flex-direction: column;
  gap: var(--space-4, 16px);
  margin-bottom: var(--space-8, 40px);
}

/* Toolbar */
.kd-personalize__toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2, 8px);
}

.kd-tool {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 8px);
  min-height: 44px; /* large touch target — mobile is primary traffic */
  padding: 0 var(--space-4, 16px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  color: var(--color-text-primary, #334155);
  font-size: var(--text-sm, 14px);
  cursor: pointer;
  transition: border-color var(--duration-fast, 150ms) var(--ease-default, ease),
              background var(--duration-fast, 150ms) var(--ease-default, ease);
}

.kd-tool:not(:disabled):hover { border-color: var(--color-primary, #00D68F); }
.kd-tool:disabled { opacity: .5; cursor: not-allowed; }

.kd-tool__ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  font-weight: 700;
}
.kd-tool__ico svg { width: 18px; height: 18px; display: block; }

/* Hidden file input — the [hidden] attribute alone gets overridden by theme resets. */
#kd-photo-input { display: none !important; }

/* Text properties panel (contextual — shown only when a text object is selected) */
.kd-text-props {
  display: flex;
  flex-wrap: wrap;
  /* Top-align fields; the unlabelled actions field pads its row down by exactly the
     label height + gap (#6), so bold + align sit on the same row as the labelled
     inputs without depending on flex-line stretch behaviour. */
  align-items: flex-start;
  gap: var(--space-3, 12px);
  padding: var(--space-3, 12px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
  overflow: hidden;
  transition:
    max-height var(--duration-slow, 300ms) var(--ease-default, ease),
    opacity var(--duration-normal, 200ms) ease,
    transform var(--duration-slow, 300ms) var(--ease-default, ease),
    padding-top var(--duration-slow, 300ms) var(--ease-default, ease),
    padding-bottom var(--duration-slow, 300ms) var(--ease-default, ease),
    border-width var(--duration-slow, 300ms) var(--ease-default, ease),
    margin-top var(--duration-slow, 300ms) var(--ease-default, ease);
  will-change: max-height, opacity;
}
/* Collapsed (default — no flash on load, no display:none so it can animate).
   margin-top cancels the parent's flex gap so a closed panel takes zero space
   (parent .kd-personalize is flex-column with gap) -> single gap toolbar<->stage. */
.kd-text-props:not(.kd-text-props--open) {
  max-height: 0;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-top-width: 0;
  border-bottom-width: 0;
  margin-top: calc(-1 * var(--space-4, 16px));
  transform: translateY(-4px);
  pointer-events: none;
}
.kd-text-props--open {
  max-height: 280px; /* > content height incl. mobile wrap */
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .kd-text-props { transition: none; }
}

.kd-text-props__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--text-xs, 12px);
  color: var(--color-text-muted, #94A3B8);
}
.kd-text-props__field select,
.kd-text-props__field input {
  min-height: 40px;
  padding: 0 var(--space-2, 8px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  color: var(--color-text-primary, #334155);
  font-size: var(--text-sm, 14px);
}
.kd-text-props__field--sm input { width: 76px; }
/* #5 — color picker: a clean rounded swatch (no square-in-rounded clash). Strip the
   native chrome and round the inner swatch on both engines. */
.kd-text-props__field input[type="color"] {
  width: 48px;
  padding: 3px;
  cursor: pointer;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
}
.kd-text-props__field input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.kd-text-props__field input[type="color"]::-webkit-color-swatch { border: none; border-radius: 6px; }
.kd-text-props__field input[type="color"]::-moz-color-swatch { border: none; border-radius: 6px; }

/* #7 — size stepper arrows: always visible (not hover-only) and a bit larger so
   they're easy to tap, instead of WebKit's default hover-reveal hairline. */
.kd-text-props__field input[type="number"] { padding-right: 2px; }
.kd-text-props__field input[type="number"]::-webkit-inner-spin-button,
.kd-text-props__field input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: inner-spin-button;
  opacity: 1;                       /* always shown */
  width: 20px;
  height: 36px;
  cursor: pointer;
}

/* #2 — "clear all" is a TEXT button, not a trash/cart icon (an icon reads as
   "delete THIS object", not the whole canvas). Sits in the toolbar like the other
   tools; subtle until hovered. */
.kd-tool--text-action { font-size: var(--text-sm, 14px); }
.kd-tool--text-action:not(:disabled):hover {
  color: var(--color-error, #F43F5E);
  border-color: var(--color-error, #F43F5E);
}

/* #6 — bold + align share one row, lined up with the labelled inputs. The field has
   no label, so pad the row down by the label height (18px, line-height) + the
   field gap (4px) = 22px to land it on the input row. */
.kd-text-props__field--actions { padding-top: 22px; }
.kd-text-props__actions { display: flex; gap: 4px; }
.kd-text-props__align { display: flex; gap: 4px; }
.kd-align {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  color: var(--color-text-primary, #334155);
  cursor: pointer;
  font-size: var(--text-md, 20px);
  line-height: 1;
}
.kd-align:hover { border-color: var(--color-primary, #00D68F); }
.kd-align svg { width: 18px; height: 18px; display: block; }

/* #6 — bold toggle (B). Square button matching .kd-align; pressed = filled brand. */
.kd-text-props__bold {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  color: var(--color-text-primary, #334155);
  cursor: pointer;
  font-weight: 800;                 /* a touch heavier so "B" reads as bold */
  font-size: var(--text-md, 20px);
  line-height: 1;
}
.kd-text-props__bold:not(:disabled):hover { border-color: var(--color-primary, #00D68F); }
.kd-text-props__bold.is-active {
  background: var(--color-primary, #00D68F);
  border-color: var(--color-primary, #00D68F);
  color: #fff;
}
/* Unavailable for this family — muted grey (not just faded), clearly inert. */
.kd-text-props__bold:disabled {
  background: var(--color-surface, #F8FAFC);
  border-color: var(--color-border, #E2E8F0);
  color: var(--color-text-muted, #94A3B8);
  cursor: not-allowed;
}

/* Stage — white mug mockup background; design canvas sits on top */
.kd-personalize__stage-wrap {
  display: flex;
  flex-direction: column;   /* stage, then the mobile pan slider below it */
  align-items: center;
}

.kd-personalize__stage {
  position: relative;
  width: 100%;
  max-width: 560px;
  /* fullwrap-3: ratio = printable zone + non-printable outside margins. Desktop
     shows the full unwrap; mobile clamps the side margins (see media query). The
     canvas backing store (editor.js) matches these, so the canvas never distorts.
     Fallback values ≈ full mug circumference / height. */
  aspect-ratio: var(--kd-aspect-d, 251.33 / 95);
  background: #fff;
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
  transition: border-color var(--duration-fast, 150ms) var(--ease-default, ease),
              box-shadow var(--duration-fast, 150ms) var(--ease-default, ease);
}
/* Drag-a-photo-over feedback (editor.js toggles .is-dragover); inset ring so it
   reads inside the clipped stage box. Mirrors the templates dropzone cue. */
.kd-personalize__stage.is-dragover {
  border-color: var(--color-primary, #00D68F);
  box-shadow: inset 0 0 0 2px var(--color-primary, #00D68F);
}
/* Fabric renders at a high fixed internal resolution; CSS downscales it to fit
   the stage (crisp text). Fabric sets px sizes inline on .canvas-container and the
   canvases — override them to fill the stage box. The container HEIGHT always
   fills the stage; its WIDTH is 100% on desktop (full unwrap fits) but is set in
   px by editor.js on mobile so the canvas is LARGER than the viewport and pans. */
.kd-personalize__stage .canvas-container {
  height: 100% !important;
}
.kd-personalize__stage canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}

/* ── #3 / #11: in-app-browser (Telegram/Instagram) gesture containment ────────
   Every interactive drag surface gets touch-action:none so a one-finger drag stays
   on the design / control and never triggers the host webview's pull-to-refresh or
   swipe-to-dismiss; overscroll-behavior:contain stops scroll chaining out of the
   stage. -webkit-tap-highlight-color:transparent kills the stray round iOS tap
   flash (#11) behind the upload zone. Harmless on desktop. */
.kd-personalize__stage,
.kd-preview__stage {
  overscroll-behavior: contain;
}
.kd-personalize__stage .canvas-container,
.kd-personalize__stage canvas,
#kd-mug-preview,
#kd-mug-preview-3d,
.kd-tpl-zoom {
  touch-action: none;
}
.kd-personalize__stage,
.kd-personalize__stage .canvas-container,
.kd-personalize__stage canvas,
.kd-personalize__hint,
.kd-tpl-dropzone,
.kd-tpl-crop {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
@media (min-width: 768px) {
  .kd-personalize__stage .canvas-container { width: 100% !important; }
}

@media (max-width: 767px) {
  /* Mobile (spec): the stage is a fixed-height WINDOW onto a wider canvas. The
     canvas is enlarged (≈2× the old fit-to-width size) so photos read big; the
     part beyond the window is reached with the pan slider, NOT a native swipe
     (touch-action:none stops the canvas from scrolling under the finger — one-
     finger drag stays on the design). editor.js sizes .canvas-container wider
     than this box and translateX-pans it. */
  .kd-personalize__stage {
    aspect-ratio: auto;
    height: 80vw;
    max-height: 340px;
    min-height: 220px;
    max-width: none;
    touch-action: none;
  }
  .kd-personalize__stage .canvas-container {
    width: 100%;                 /* fallback before editor.js sets the px width */
    will-change: transform;
    /* #12 — keep the panned wrapper on its own GPU layer + integer translate3d
       (editor.js) so the supersampled-then-downscaled bitmap stops shimmering on
       iPhone during a continuous pan drag. */
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    transition: transform 120ms ease;
  }
}

/* ── Mobile pan control: a full-width touch scrollbar that moves the VIEWPORT.
   No arrow buttons — modern/touch scrollbars are arrow-less; the proportional
   thumb already conveys position + how much is visible. Shown by editor.js only
   when the canvas overflows the window. ────────────────────────────────────── */
.kd-pan {
  display: flex;
  align-items: center;
  width: 100%;
  max-width: 560px;
  margin-top: var(--space-3, 12px);
  margin-bottom: calc(var(--space-3, 12px) + 6px); /* breathing room below the slider (mobile-only control) */
}
.kd-pan[hidden] { display: none; }
/* Scrollbar-style track + a WIDE thumb whose width = the visible fraction of the
   mug (set inline by editor.js), so the control reads as "how much you see now". */
.kd-pan__track {
  position: relative;
  flex: 1 1 auto;
  height: 24px;                /* ~20% shorter (was 30px) */
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
  border: 1px solid var(--color-border, #E2E8F0);
  touch-action: none;
  overflow: hidden;
}
/* Faint left/right chevron HINTS inside the track — purely a "this scrolls"
   affordance, never interactive (pointer-events:none). They sit in the end
   gutters; the thumb travels only inside .kd-pan__rail, so green never covers
   them — it stops at the air around each chevron. */
.kd-pan__track::before,
.kd-pan__track::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 5px;
  height: 5px;
  border: solid rgba(15, 23, 42, .38);
  border-width: 0 2px 2px 0;
  pointer-events: none;
}
.kd-pan__track::before { left: 9px;  transform: translateY(-50%) rotate(135deg); }
.kd-pan__track::after  { right: 9px; transform: translateY(-50%) rotate(-45deg); }
/* Inner rail = the thumb's travel band, inset by end gutters that reserve the
   air around the chevrons. The thumb is positioned relative to THIS, so it can
   never reach the chevron zone. */
.kd-pan__rail {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 24px;
  right: 24px;
}
.kd-pan__thumb {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;                  /* overwritten by editor.js (visible fraction) */
  border-radius: var(--radius-md, 8px);
  background: var(--color-primary, #00D68F);
  opacity: .9;
  cursor: grab;
  touch-action: none;
}
.kd-pan__thumb:active { cursor: grabbing; opacity: 1; }

/* Empty-state = a clean dropzone GATE (icon + bold underlined CTA + a desktop-only
   drag hint + a soft corner dot-pattern). Inset so the dashed frame sits inside the
   stage; pointer-events:none so the tap/click falls through to the click-to-upload
   canvas underneath. Auto-hidden by JS once the first object lands. */
.kd-personalize__hint {
  position: absolute;
  inset: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2, 8px);
  text-align: center;
  /* Slightly heavier bottom padding optically lifts the icon+CTA block to the
     true visual centre (text mass reads low when geometrically centred). */
  padding: var(--space-4, 16px) var(--space-4, 16px) calc(var(--space-4, 16px) + 8px);
  border: 1.5px dashed var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: linear-gradient(180deg, rgba(0, 214, 143, .045), rgba(248, 250, 252, .55));
  color: var(--color-text-muted, #94A3B8);
  pointer-events: none;
  overflow: hidden;
}
/* Brand-flavoured decorative dot pattern, top-left corner (ref cue). */
.kd-personalize__hint::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 46%;
  height: 60%;
  background-image: radial-gradient(var(--color-primary, #00D68F) 1.5px, transparent 1.6px);
  background-size: 13px 13px;
  opacity: .22;
  -webkit-mask-image: linear-gradient(135deg, #000, transparent 65%);
          mask-image: linear-gradient(135deg, #000, transparent 65%);
}
.kd-personalize__hint-ico {
  color: var(--color-text-primary, #334155);  /* softer than near-black */
  margin-bottom: var(--space-1, 4px);
}
.kd-personalize__hint-ico svg {
  width: 48px;
  height: 48px;
  stroke-width: 2;                       /* lighter outline (was 2.4) */
}
.kd-personalize__hint-ico .kd-hint-ico__accent {
  fill: var(--color-primary, #00D68F);   /* green sun + mountain */
  stroke: none;
}
.kd-personalize__hint-title {
  font-size: var(--text-md, 20px);
  font-weight: 600;                      /* was 700 — read too heavy */
  color: var(--color-text-primary, #334155);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1.5px;
  line-height: 1.2;
}
.kd-personalize__hint-sub {
  font-size: var(--text-sm, 14px);
  color: var(--color-text-muted, #94A3B8);
  line-height: 1.3;
}
/* Drag-and-drop is a desktop affordance; on phones (tap-to-upload) it'd mislead. */
@media (max-width: 767px) {
  .kd-personalize__hint-sub { display: none; }
}

/* Selection actions bar — big "✓ Готово" to exit edit mode (mobile-first).
   Same collapse/expand pattern as the text-props panel: collapsed is the CSS
   default (no flash on load), animates open when an object is selected. */
.kd-sel-actions {
  display: flex;
  justify-content: center;
  overflow: hidden;
  transition:
    max-height var(--duration-slow, 300ms) var(--ease-default, ease),
    opacity var(--duration-normal, 200ms) ease,
    margin-top var(--duration-slow, 300ms) var(--ease-default, ease);
  will-change: max-height, opacity;
}
.kd-sel-actions:not(.kd-sel-actions--open) {
  max-height: 0;
  opacity: 0;
  margin-top: calc(-1 * var(--space-4, 16px));
  pointer-events: none;
}
.kd-sel-actions--open {
  max-height: 80px;
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .kd-sel-actions { transition: none; }
}

.kd-btn--done {
  background: var(--color-primary, #00D68F);
  color: #fff;
  min-width: 200px;
  font-weight: 600;
}

/* Actions */
.kd-personalize__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3, 12px);
}


.kd-btn {
  min-height: 48px;
  padding: 0 var(--space-6, 24px);
  border-radius: var(--radius-md, 8px);
  font-size: var(--text-base, 16px);
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  transition: opacity var(--duration-fast, 150ms) var(--ease-default, ease),
              transform var(--duration-fast, 150ms) var(--ease-default, ease);
}

.kd-btn:disabled { opacity: .5; cursor: not-allowed; }

.kd-btn--primary {
  background: var(--color-primary, #00D68F);
  color: #fff;
}

.kd-btn--ghost {
  background: #fff;
  border-color: var(--color-border, #E2E8F0);
  color: var(--color-text-primary, #334155);
}

.kd-personalize__msg {
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--radius-md, 8px);
  font-size: var(--text-sm, 14px);
}
.kd-personalize__msg.is-ok {
  background: rgba(0, 214, 143, .12);
  color: #0a8f63;
  border: 1px solid var(--color-primary, #00D68F);
}
.kd-personalize__msg.is-err {
  background: rgba(244, 63, 94, .10);
  color: var(--color-error, #F43F5E);
  border: 1px solid var(--color-error, #F43F5E);
}

@media (min-width: 768px) {
  /* Wider stage for the full-unwrap ratio (fullwrap-3) so the print band keeps a
     usable editing height. */
  .kd-personalize__stage { max-width: 760px; }
}
@media (min-width: 1024px) {
  /* In the two-column desktop layout the stage fills the editor column. */
  .kd-personalize__stage { max-width: 100%; }
}

/* ── Spec 69: live 2D preview layout ──────────────────────────────────────
   .kd-personalize is the outer container. The editor lives in __main; the
   preview (variant B only) is __preview. Mobile = stacked (canvas, then
   preview below); desktop ≥1024 = two columns side by side. In the control
   arm the preview pane is absent from the DOM, so __main simply fills width. */
.kd-personalize__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-4, 16px);
  min-width: 0;
}

.kd-personalize__preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 8px);
}

.kd-preview__label {
  font-size: var(--text-md, 20px);
  font-weight: 600;
  color: var(--color-text-primary, #334155);
  text-align: center; /* sits above the centred mug, not far to its left */
}

/* "Попередній перегляд" heading above the mug preview. Matches the section-title
   weight (.kd-templates__heading) but centred over the mug. margin:0 — the preview
   pane is a flex column with its own gap, so no extra bottom margin. */
.kd-preview__heading {
  margin: 0;
  font-size: var(--text-md, 20px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
  text-align: center;
}


.kd-preview__stage {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  aspect-ratio: 1 / 1;
  background: var(--color-surface, #F8FAFC);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
}

.kd-preview__stage canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}

/* ── Mobile dead-zone scroll band on the preview (mug-mobile-scroll-deadzones) ──
   The mug canvas keeps `touch-action: none` (webview pull-close protection), so a
   drag on the mug can't scroll the page. Pad the stage with a small vertical band:
   that strip is plain page DOM (NOT the touch-action:none canvas), so dragging it
   scrolls the page natively, while the mug itself still orbits. box-sizing is
   border-box (Bootstrap reset), so the band insets the canvas; preview-3d.js
   measures the canvas box (not the padded stage), so the mug isn't squashed.
   overscroll-behavior:contain (base rule) keeps the in-app webview from pull-
   closing. Desktop is untouched. */
@media (max-width: 767px) {
  .kd-preview__stage { padding: 28px 0; }
}

.kd-preview__hint {
  font-size: var(--text-sm, 14px);
  color: var(--color-text-muted, #94A3B8);
  text-align: center;
}

/* Colour disclaimer — overlaid at the BOTTOM, INSIDE the preview stage, on a
   light fade-up gradient. Dark-grey text. pointer-events off so it never blocks
   the 3D orbit drag; sits in DOM right after the canvas so the zoom buttons
   (later siblings) still paint on top. */
.kd-preview__note {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: var(--space-5, 20px) var(--space-2, 8px) 6px;
  font-size: var(--text-xs, 12px);
  line-height: 1.4;
  color: var(--color-text-primary, #334155);
  text-align: center;
  background: linear-gradient(to top,
    rgba(255, 255, 255, 0.95) 0%,
    rgba(255, 255, 255, 0.72) 55%,
    rgba(255, 255, 255, 0) 100%);
  pointer-events: none;
}

@media (min-width: 1024px) {
  /* Row of [main | preview]; the actions band wraps to its own full-width line. */
  .kd-personalize { flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: var(--space-6, 24px); }
  .kd-personalize__main { flex: 1 1 0; }
  .kd-personalize__preview { flex: 0 0 420px; position: sticky; top: var(--space-4, 16px); }
  .kd-preview__stage { max-width: none; }
  /* Price + CTA span the full content width below both columns. */
  .kd-personalize__actions { flex: 1 1 100%; width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Interactive-3D affordances (fullwrap): "3D" badge + drag-to-rotate hint + zoom.
   Hidden until preview-3d.js confirms WebGL mounted (.kd-preview__stage.is-3d);
   removed again on a 2D fallback so the chrome never sits over a flat image.
   ══════════════════════════════════════════════════════════════════════════ */
.kd-preview__stage { position: relative; } /* anchor the absolute overlays */

.kd-preview__badge,
.kd-preview__zoom { display: none; }
.kd-preview__stage.is-3d .kd-preview__badge { display: flex; }
.kd-preview__stage.is-3d .kd-preview__zoom { display: inline-flex; }

.kd-preview__badge {
  position: absolute;
  top: var(--space-3, 12px);
  left: var(--space-3, 12px);
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  z-index: 2;
  pointer-events: none; /* never blocks the orbit drag */
  color: var(--color-text-primary, #334155);
}
.kd-preview__badge-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  font-size: var(--text-xs, 12px);
  font-weight: 700;
  letter-spacing: 0.04em;
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-pill, 50px);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.kd-preview__badge-chip svg { display: block; opacity: 0.85; }
/* The "3D — обертай …" label: a touch lighter than the bold chip default. */
.kd-preview__badge-chip > span { font-weight: 600; letter-spacing: 0; }
/* Clear "drag to rotate" hint — a small labeled pill (rotate icon + word) instead
   of an abstract squiggle. Bobs gently, fades after the first interaction. */
.kd-preview__badge-hint {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  font-size: var(--text-xs, 12px);
  font-weight: 600;
  color: var(--color-text-muted, #94A3B8);
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-pill, 50px);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 1;
  transition: opacity var(--duration-slow, 300ms) var(--ease-default, ease);
  animation: kd-hint-bob 2.4s ease-in-out infinite;
}
.kd-preview__badge-hint svg { display: block; opacity: 0.85; }
/* Mouse copy on desktop, finger copy on touch devices. */
.kd-bh-touch { display: none; }
@media (hover: none), (pointer: coarse) {
  .kd-bh-mouse { display: none; }
  .kd-bh-touch { display: inline; }
}
/* Fade the hint once the customer has rotated or zoomed (JS adds .is-touched). */
.kd-preview__stage.is-touched .kd-preview__badge-hint { opacity: 0; animation: none; }
@keyframes kd-hint-bob {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(3px); }
}

.kd-preview__zoom {
  position: absolute;
  right: var(--space-3, 12px);
  bottom: var(--space-3, 12px);
  flex-direction: column;
  gap: 6px;
  z-index: 2;
  pointer-events: none; /* container ignores clicks; buttons re-enable below */
}
.kd-zoom-btn {
  pointer-events: auto;
  /* mug-struct-8 (T5): suppress iOS double-tap-to-zoom + the 300ms tap delay so a
     second tap on these small controls zooms the 3D model, not the page. */
  touch-action: manipulation;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  color: var(--color-text-primary, #334155);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.1);
  cursor: pointer;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  transition: background var(--duration-fast, 150ms) var(--ease-default, ease),
              border-color var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-zoom-btn:hover { background: #fff; border-color: var(--color-primary, #00D68F); }
.kd-zoom-btn:active { background: var(--color-surface, #F8FAFC); }
.kd-zoom-btn svg { display: block; }
/* Larger tap targets on touch/mobile (the constructor's traffic is mostly phones). */
@media (max-width: 1023px) {
  .kd-zoom-btn { width: 44px; height: 44px; } /* mug-struct-8 (T5): WCAG 2.5.5 / Apple HIG ≥44px touch target */
  .kd-preview__zoom { bottom: calc(var(--space-3, 12px) + 20px); } /* lift zoom buttons clear of the bottom colour-note */
}

/* ══════════════════════════════════════════════════════════════════════════
   Two-flow launch: creation-method switch + Ready Templates + UX polish.
   Appended block — later rules override the base where intended.
   ══════════════════════════════════════════════════════════════════════════ */

/* The theme's resets clobber the plain [hidden] attribute; enforce it for every
   JS-toggled block inside the constructor (input step, fields, edit btn, overlay). */
.kd-personalize [hidden] { display: none !important; }

/* mug-struct-6: the creation-method mode-switch (.kd-modeswitch tabs) is removed —
   idea selection lives on the hub «Чашки з фото»; each spoke boots its own flow. */

/* ── Mode visibility: hide each flow's chrome from the root state classes ── */
/* Templates mode: hide the editor chrome (the canvas/preview are the engine). */
.kd-mode-templates .kd-personalize__toolbar,
.kd-mode-templates .kd-personalize__stage-wrap,
.kd-mode-templates .kd-text-props,
.kd-mode-templates .kd-sel-actions { display: none !important; }
/* Scratch mode: hide the templates panel + its edit-design button. */
.kd-mode-scratch .kd-templates { display: none !important; }
.kd-mode-scratch #kd-tpl-edit { display: none !important; }
/* mug-struct-8 (T3): scratch flow heading «Свій дизайн» — hidden by default (so it
   never shows in templates mode), revealed only in scratch mode for heading parity
   with the pet/faces input step. */
.kd-scratch-heading { display: none; }
.kd-mode-scratch .kd-scratch-heading { display: block; margin: 0 0 var(--space-4, 16px); }
/* Gallery substep: nothing to preview/buy yet → hide the preview+CTA aside. */
.kd-mode-templates.kd-tpl-step-gallery .kd-personalize__preview { display: none !important; }

/* ── Templates gallery (cards) ──────────────────────────────────────────── */
.kd-templates__heading {
  font-size: var(--text-md, 20px);
  font-weight: 700;
  margin: 0 0 var(--space-4, 16px);
  color: var(--color-text-primary, #334155);
}
.kd-tpl-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-4, 16px);
}
.kd-tpl-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  text-align: center;
  gap: var(--space-2, 8px);
  padding: var(--space-4, 16px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  cursor: pointer;
  /* mug-struct-8 (T3g): these cards are <a> links — kill the global underline so the
     «Інші ідеї» strip reads as cards (like the hub gallery), not underlined link text. */
  text-decoration: none;
  color: var(--color-text-primary, #334155);
  transition: transform var(--duration-fast, 150ms) var(--ease-default, ease),
              box-shadow var(--duration-fast, 150ms) var(--ease-default, ease),
              border-color var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-card:hover,
.kd-tpl-card:focus,
.kd-tpl-card:focus-visible { text-decoration: none; }
.kd-tpl-card:hover {
  transform: scale(1.02);
  box-shadow: 0 8px 24px rgba(15, 23, 42, .10);
  border-color: var(--color-primary, #00D68F);
}
.kd-tpl-card:focus-visible { outline: 2px solid var(--color-primary, #00D68F); outline-offset: 2px; }
/* Thumb = clean line-SVG icon tile (stroke=currentColor, themed). No emoji. */
.kd-tpl-card__thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
  color: var(--color-primary, #00D68F);
  line-height: 1;
}
.kd-tpl-card__thumb svg { width: 48px; height: 48px; }
/* mug-struct-6: «Інші ідеї» cards carry a real sibling-product thumbnail (interim
   art) instead of the line-SVG icon — fill the thumb tile. */
.kd-tpl-card__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-md, 8px); }
.kd-tpl-card--mini-img .kd-tpl-card__thumb { background: #fff; padding: 0; overflow: hidden; }
.kd-tpl-card__title {
  font-size: var(--text-base, 16px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
}
.kd-tpl-card__desc {
  font-size: var(--text-sm, 14px);
  font-weight: 400;
  color: var(--color-text-muted, #94A3B8);
}

/* ── Templates input step ───────────────────────────────────────────────── */
.kd-templates__input { display: flex; flex-direction: column; gap: var(--space-4, 16px); }
.kd-tpl-back {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 8px);
  min-height: 36px;
  padding: 0;                 /* left edge flush with the heading + fields below */
  border: 0;
  background: transparent;
  color: var(--color-primary, #00D68F); /* brand green, whole control */
  font-size: var(--text-sm, 14px);
  font-weight: 600;
  cursor: pointer;
}
.kd-tpl-back:hover { color: #00B87B; }
/* Line-SVG arrow (matches the site's icon style; the old "←" glyph clashed).
   stroke-width keeps it a touch heavier than the label text. */
.kd-tpl-back__ico { width: 16px; height: 16px; display: block; flex: 0 0 auto; }
.kd-tpl-field { display: flex; flex-direction: column; gap: var(--space-2, 8px); }
.kd-tpl-field__label {
  margin: 0;
  font-size: var(--text-sm, 14px);
  font-weight: 400;
  color: var(--color-text-muted, #94A3B8);
}
/* Decoration toggle (paws | hearts) — pet only. Compact segmented pill control. */
.kd-tpl-decor { display: inline-flex; gap: var(--space-2, 8px); flex-wrap: wrap; }
.kd-tpl-decor__opt {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border: 1.5px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-pill, 50px);
  background: #fff;
  color: var(--color-text-primary, #334155);   /* enabled, selectable — NOT a disabled grey */
  font: inherit; font-size: var(--text-sm, 14px); font-weight: 600;
  cursor: pointer;
  transition: color var(--duration-fast, 150ms) var(--ease-default, ease),
              border-color var(--duration-fast, 150ms) var(--ease-default, ease),
              background var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-decor__opt svg { width: 18px; height: 18px; flex: 0 0 auto; }
.kd-tpl-decor__opt:hover { border-color: var(--color-primary, #00D68F); color: var(--color-text-primary, #334155); }
.kd-tpl-decor__opt.is-active {
  border-color: var(--color-primary, #00D68F);
  background: var(--color-primary, #00D68F);
  color: #fff;
}
/* Photo zone: one dropzone + a row of round crop previews. */
.kd-tpl-photozone { gap: var(--space-3, 12px); }
/* The dropzone mirrors the "Свій дизайн" empty-canvas drop gate (.kd-personalize__
   hint): dashed border, faint brand gradient + dotted-corner cue, 48px icon with a
   green accent, underlined title. Static block in the form (not an absolute overlay). */
.kd-tpl-dropzone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2, 8px);
  min-height: 160px;
  padding: var(--space-5, 20px);
  border: 1.5px dashed var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: linear-gradient(180deg, rgba(0, 214, 143, .045), rgba(248, 250, 252, .55));
  color: var(--color-text-muted, #94A3B8);
  text-align: center;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--duration-fast, 150ms) var(--ease-default, ease),
              background var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-dropzone::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 46%;
  height: 60%;
  background-image: radial-gradient(var(--color-primary, #00D68F) 1.5px, transparent 1.6px);
  background-size: 13px 13px;
  opacity: .22;
  -webkit-mask-image: linear-gradient(135deg, #000, transparent 65%);
          mask-image: linear-gradient(135deg, #000, transparent 65%);
}
.kd-tpl-dropzone:hover,
.kd-tpl-dropzone.is-dragover { border-color: var(--color-primary, #00D68F); }
.kd-tpl-drop__ico { color: var(--color-text-primary, #334155); margin-bottom: var(--space-1, 4px); }
.kd-tpl-drop__ico svg { width: 48px; height: 48px; display: block; stroke-width: 2; }
.kd-tpl-drop__ico .kd-hint-ico__accent { fill: var(--color-primary, #00D68F); stroke: none; }
.kd-tpl-drop__title {
  font-size: var(--text-md, 20px);
  font-weight: 600;
  color: var(--color-text-primary, #334155);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1.5px;
  line-height: 1.2;
}
.kd-tpl-drop__hint { font-size: var(--text-sm, 14px); color: var(--color-text-muted, #94A3B8); line-height: 1.3; }
@media (max-width: 767px) { .kd-tpl-drop__hint { display: none; } }

/* Round crop previews (shown after upload). Each = draggable circle + zoom + remove. */
.kd-tpl-previews { display: none; flex-wrap: wrap; gap: var(--space-4, 16px); }
.kd-tpl-photozone.has-photos .kd-tpl-previews { display: flex; }
/* Single-column view (mobile/tablet): centre the photo crop so it shares one
   vertical axis with the centred mug preview below (form controls stay left). */
@media (max-width: 1023px) {
  .kd-tpl-previews { justify-content: center; }
}
.kd-tpl-preview { display: flex; flex-direction: column; align-items: center; gap: var(--space-2, 8px); }
/* One photo per template now → a bigger, easier-to-drag crop circle. */
.kd-tpl-crop-wrap { position: relative; width: 220px; height: 220px; }
.kd-tpl-crop {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  overflow: hidden;
  background: var(--color-surface, #F8FAFC) center/cover no-repeat;
  border: 3px solid #fff;
  box-shadow: 0 0 0 1px var(--color-border, #E2E8F0), 0 6px 18px rgba(15, 23, 42, .12);
  cursor: grab;
  touch-action: none; /* let pointer-drag pan instead of scrolling the page */
}
.kd-tpl-crop:active { cursor: grabbing; }
/* "Drag to reframe" affordance — a move icon over the photo (subtle, visible on
   mobile too); brighter on hover, hidden while actively dragging. */
.kd-tpl-crop__move {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(15, 23, 42, .38);
  color: #fff;
  pointer-events: none;
  opacity: 0; /* shown only when the photo can actually be panned (.is-pannable) */
  transition: opacity var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-crop__move svg { width: 22px; height: 22px; display: block; }
.kd-tpl-crop.is-pannable .kd-tpl-crop__move { opacity: .7; }
.kd-tpl-crop.is-pannable:hover .kd-tpl-crop__move { opacity: 1; }
.kd-tpl-crop.is-dragging .kd-tpl-crop__move { opacity: 0; }
/* Remove "×" — top-right of the crop circle (no text). */
.kd-tpl-remove {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #fff;
  color: var(--color-text-primary, #334155);
  box-shadow: 0 1px 5px rgba(15, 23, 42, .3);
  cursor: pointer;
  transition: color var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-remove:hover { color: var(--color-error, #F43F5E); }
.kd-tpl-remove svg { width: 14px; height: 14px; display: block; }
/* Zoom slider — scale the photo inside the crop circle. Track + thumb are styled
   explicitly (accent-color alone left the thumb near-invisible on white). */
.kd-tpl-zoomrow { display: flex; align-items: center; gap: var(--space-2, 8px); width: 100%; max-width: 220px; }
.kd-tpl-zoom__btn {
  flex: 0 0 auto; width: 18px; text-align: center;
  font-size: var(--text-md, 20px); line-height: 1; font-weight: 700;
  color: var(--color-text-muted, #94A3B8); user-select: none;
}
.kd-tpl-zoom {
  flex: 1 1 auto; min-width: 0; height: 18px; margin: 0;
  -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer;
}
.kd-tpl-zoom::-webkit-slider-runnable-track {
  height: 6px; border-radius: 50px; background: var(--color-border, #E2E8F0);
}
.kd-tpl-zoom::-moz-range-track {
  height: 6px; border-radius: 50px; background: var(--color-border, #E2E8F0);
}
.kd-tpl-zoom::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -6px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--color-primary, #00D68F); border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(15, 23, 42, .35); cursor: pointer;
}
.kd-tpl-zoom::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--color-primary, #00D68F); border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(15, 23, 42, .35); cursor: pointer;
}
/* Mobile: fatter zoom slider — bigger thumb + taller hit area for touch. */
@media (max-width: 1023px) {
  .kd-tpl-zoom { height: 34px; }
  .kd-tpl-zoom::-webkit-slider-runnable-track { height: 8px; }
  .kd-tpl-zoom::-moz-range-track { height: 8px; }
  .kd-tpl-zoom::-webkit-slider-thumb { width: 30px; height: 30px; margin-top: -11px; }
  .kd-tpl-zoom::-moz-range-thumb { width: 30px; height: 30px; }
  .kd-tpl-zoom__btn { width: 24px; font-size: var(--text-lg, 24px); }
}
.kd-tpl-nameinput {
  min-height: 46px;
  padding: 0 var(--space-4, 16px);
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px) !important; /* theme resets input radius to 0 */
  background: #fff;
  color: var(--color-text-primary, #334155);
  /* Secondary (optional) field: 16px keeps it from dominating AND avoids iOS
     Safari zoom-on-focus (which triggers below 16px). */
  font-size: var(--text-base, 16px);
  font-weight: 500;
}
.kd-tpl-nameinput:focus { outline: none; border-color: var(--color-primary, #00D68F); }
/* Placeholder must read as a hint, not as entered text: muted grey + regular
   weight (the input itself is dark #334155 / 600, which made "Патрон" look typed). */
.kd-tpl-nameinput::placeholder {
  color: var(--color-text-muted, #94A3B8);
  font-weight: 400;
  opacity: 1; /* Firefox dims placeholders by default — keep our exact tone */
}

/* ── Simplified toolbar: separator + icon-only undo/redo ────────────────── */
.kd-toolbar__sep {
  width: 1px;
  align-self: stretch;
  margin: 4px var(--space-1, 4px);
  background: var(--color-border, #E2E8F0);
}
.kd-tool { font-weight: 500; }
.kd-tool--icon { padding: 0; width: 44px; justify-content: center; }
.kd-tool--icon .kd-tool__ico { width: auto; font-size: var(--text-md, 20px); }
/* Pressed/active state for a toggle tool (e.g. "remove white background" ON). */
.kd-tool.is-active {
  background: var(--color-primary, #00D68F);
  border-color: var(--color-primary, #00D68F);
  color: #fff;
}
.kd-tool.is-active .kd-tool__ico { color: #fff; }

/* ── "Remove white background" tolerance — contextual slider under the toolbar ── */
.kd-bg-tools {
  display: flex;
  align-items: center;
  margin-top: var(--space-2, 8px);
}
.kd-bg-tools[hidden] { display: none; }
.kd-bg-tools__field {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 8px);
  font-size: var(--text-sm, 14px);
  color: var(--color-text-primary, #334155);
}
/* Explicit track + thumb: the theme resets input appearance, so the native rail
   doesn't render — only the thumb showed. Draw a visible rounded rail ourselves. */
.kd-bg-tools__field input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 180px;
  max-width: 52vw;
  height: 18px;            /* hit area; the visual rail is drawn on the track */
  margin: 0;
  background: transparent; /* track drawn via ::-webkit-slider-runnable-track */
  cursor: pointer;
}
.kd-bg-tools__field input[type="range"]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: var(--radius-pill, 50px);
  background: var(--color-border, #E2E8F0);
}
.kd-bg-tools__field input[type="range"]::-moz-range-track {
  height: 6px;
  border-radius: var(--radius-pill, 50px);
  background: var(--color-border, #E2E8F0);
}
.kd-bg-tools__field input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  margin-top: -6px;        /* centre the 18px thumb on the 6px track */
  border-radius: 50%;
  background: var(--color-primary, #00D68F);
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25);
}
.kd-bg-tools__field input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-primary, #00D68F);
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25);
}

/* ── Contextual "Центрувати" in the selection bar ───────────────────────── */
.kd-sel-actions .kd-btn--ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 8px);
  min-width: 0;
}

/* ── Bigger 2D preview (spec #7) + stronger CTA (spec #2) ────────────────── */
/* Stage cap raised ~35% (480→640) so the mug reads like a product photo. */
.kd-preview__stage { max-width: 640px; }

/* CTA block: price + a large primary "Додати в кошик", stacked under the mug. */
.kd-personalize__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3, 12px);
  margin-top: var(--space-4, 16px);
}
.kd-price {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-2, 8px);
}
.kd-price__label {
  font-size: var(--text-sm, 14px);
  font-weight: 400;
  color: var(--color-text-muted, #94A3B8);
}
.kd-price__value {
  font-size: var(--text-xl, 30px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
}

/* Product head row above the CTA: name on the left (like a normal product
   title), price on the right of the same row. */
.kd-product-head {
  display: flex;
  align-items: center; /* keep name (may wrap to 2 lines) + larger price vertically centred */
  justify-content: space-between;
  gap: var(--space-4, 16px);
}
.kd-product-head__name {
  flex: 1 1 auto;
  font-size: var(--text-md, 20px);
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-text-primary, #334155);
  text-align: left;
}
.kd-product-head__price {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: var(--text-xl, 30px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
}
.kd-btn--cart {
  width: 100%;
  min-height: 56px;
  font-size: var(--text-md, 20px);
  font-weight: 700;
  box-shadow: 0 6px 18px rgba(0, 214, 143, .28);
}
.kd-btn--cart:not(:disabled):hover { transform: translateY(-1px); }
.kd-tpl-editbtn { width: 100%; }

/* Preview "preparing…" overlay while a template photo loads. */
.kd-preview__stage { position: relative; }
.kd-preview__wait {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(248, 250, 252, .85);
  color: var(--color-text-muted, #94A3B8);
  font-size: var(--text-sm, 14px);
}

/* ── Desktop split: scratch canvas ~55% / preview ~45% (spec #1) ─────────── */
@media (min-width: 1024px) {
  .kd-personalize__main { flex: 1 1 55%; min-width: 0; }
  .kd-personalize__preview { flex: 0 0 45%; max-width: 45%; }
  /* Templates input step: compact form (≈36%) | large mug (≈64%), top-aligned;
     the mug is not sticky here (the form is short, and the CTA sits below both). */
  .kd-mode-templates .kd-personalize__preview { position: static; }
  .kd-mode-templates.kd-tpl-step-input .kd-personalize__main { flex: 0 0 36%; max-width: 36%; }
  .kd-mode-templates.kd-tpl-step-input .kd-personalize__preview { flex: 1 1 0; max-width: none; }
}
/* Nothing to buy in the gallery step → hide the price + CTA band there too. */
.kd-mode-templates.kd-tpl-step-gallery .kd-personalize__actions { display: none !important; }
/* Keep the CTA band from stretching absurdly wide on large screens. */
.kd-personalize__actions { max-width: 720px; margin-left: auto; margin-right: auto; }

/* ── Desktop scratch ("Свій дизайн"): canvas + 3D preview in ONE row ──────────
   The 55/45 flex split above WRAPS the preview below the canvas (the 24px column
   gap pushes 55%+45% past 100%). Use a 2-col grid instead: the wide unwrap canvas
   (+ its toolbar) on the left, the square 3D/2D preview filling the right column
   at full height, price/CTA tucked under the canvas. Grid sidesteps the gap-
   overflow wrap and lets the preview span both left-side rows. Only main, preview
   and actions are visible scratch children (backbar + "more" are display:none),
   so they map 1:1 to the three grid areas. */
@media (min-width: 1024px) {
  .kd-personalize.kd-mode-scratch {
    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    grid-template-areas:
      "canvas  preview"
      "actions preview";
    align-items: start;
    align-content: start;
    column-gap: var(--space-6, 24px);
    row-gap: var(--space-5, 20px);
  }
  .kd-mode-scratch .kd-personalize__main    { grid-area: canvas;  flex: initial; min-width: 0; max-width: none; }
  .kd-mode-scratch .kd-personalize__preview { grid-area: preview; flex: initial; max-width: none; position: static; }
  .kd-mode-scratch .kd-personalize__actions { grid-area: actions; max-width: none; margin: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Unified configurator (templates → input step) — held together by alignment,
   NOT by boxes/lines. No outer border, no card, no column divider (those read
   as visual noise). Desktop = a 2-col grid: form + price/CTA stacked in the left
   column, mug spanning the right (grid block below). Mobile = single column,
   price/CTA below the mug. The CTA is de-"AI'd": solid accent, calm
   darken-on-hover, no neon glow. Scoped to the input step — gallery and the
   scratch editor untouched. (Appended last.)
   ══════════════════════════════════════════════════════════════════════════ */

/* ── CTA: confident & flat, not glowing ─────────────────────────────────── */
.kd-btn--cart {
  min-width: 280px;
  min-height: 54px;
  font-size: var(--text-base, 16px);
  font-weight: 700;
  box-shadow: none;            /* kill the neon-green glow (looked AI-generated) */
  transition: background var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-btn--cart:not(:disabled):hover {
  background: #00B87B;         /* darken instead of lift + glow */
  transform: none;
}
.kd-btn--cart:not(:disabled):active { background: #00A06C; }

/* Price + CTA base (mobile / shared): full-bleed, no centering cap. Desktop
   repositions it into the left grid column (grid block below). */
.kd-mode-templates.kd-tpl-step-input .kd-personalize__actions {
  max-width: none;
  margin: 0;
}
.kd-price__value { color: var(--color-dark, #0F172A); }

@media (min-width: 1024px) {
  /* Desktop input step: a 2-column GRID so the price + CTA sit in the LEFT column
     directly under the form (not as a full-width band below both columns). The mug
     preview occupies the right column and spans both the form and CTA rows. Grid
     (not flex) because flex-wrap can't make the mug span two rows beside a stacked
     form + CTA. Only display:none children (scratch toolbar/stage, hidden "more"
     copies) drop out, so the grid items are exactly: backbar, main, preview, actions. */
  .kd-personalize.kd-mode-templates.kd-tpl-step-input {
    display: grid;
    grid-template-columns: 40% 1fr;
    grid-template-areas:
      "back    back"
      "main    preview"
      "actions preview";
    align-content: start;
    column-gap: var(--space-8, 40px);
    row-gap: var(--space-5, 20px);
  }
  .kd-mode-templates.kd-tpl-step-input .kd-tpl-backbar { grid-area: back; }
  .kd-mode-templates.kd-tpl-step-input .kd-personalize__main {
    grid-area: main;
    max-width: none;
  }
  .kd-mode-templates.kd-tpl-step-input .kd-personalize__preview {
    grid-area: preview;
    max-width: none;
    align-self: start;          /* mug keeps its natural height, top of the span */
  }
  /* Price + CTA: stacked in the left column under the form; CTA fills the column. */
  .kd-mode-templates.kd-tpl-step-input .kd-personalize__actions {
    grid-area: actions;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3, 12px);
    max-width: none;
    margin: 0;
  }
  .kd-mode-templates.kd-tpl-step-input .kd-btn--cart { width: 100%; }
}

/* ── Back-to-gallery bar — its own row under the mode tabs (input step only) ── */
.kd-tpl-backbar { display: none; }
.kd-mode-templates.kd-tpl-step-input .kd-tpl-backbar { display: block; }
@media (min-width: 1024px) {
  /* Full-width row at the very top of the configurator, above both columns. */
  .kd-mode-templates.kd-tpl-step-input .kd-tpl-backbar { flex: 0 0 100%; }
}

/* ── Form spacing: tight after the input title, a clear break before "other
   ideas" so the two zones read as separate groups. The input title drops the
   base heading margin (it relies on the column's flex gap alone). ── */
#kd-tpl-input-title { margin-bottom: 0; }

/* ── "Other ideas" row: the gallery cards, smaller, on one row ───────────────
   Same card look as the main gallery (thumb tile + title), just compact. Wraps
   instead of scrolling so the hover lift/shadow is never clipped by an
   overflow container. */
.kd-templates__more {
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 12px);
  margin-top: var(--space-6, 24px); /* clear break above "Інші ідеї" */
}
/* Heading matches the section title "З улюбленцем" (.kd-templates__heading). */
.kd-templates__more-heading {
  margin: 0;
  font-size: var(--text-md, 20px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
}
.kd-tpl-cards--mini {
  display: flex;
  flex-wrap: wrap;             /* no overflow container → hover never clipped */
  gap: var(--space-3, 12px);
}
/* mug-struct-8 (T3g): «Інші ідеї» cards now mirror the hub idea cards — a bordered
   card with a square (1/1) photo thumb filling the top edge-to-edge, a padded title
   below, NO underline, and the same hover lift. The strip reads as the same component
   as the hub gallery (not tiny underlined thumbnails). Self-contained: these <a>s carry
   only .kd-tpl-card--mini (not the base .kd-tpl-card), so every rule is set here. */
.kd-tpl-card--mini {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  width: 172px;
  padding: 0;
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--color-border, #E2E8F0);
  border-radius: var(--radius-md, 8px);
  background: #fff;
  text-decoration: none;
  color: var(--color-text-primary, #334155);
  transition: transform var(--duration-fast, 150ms) var(--ease-default, ease),
              box-shadow var(--duration-fast, 150ms) var(--ease-default, ease),
              border-color var(--duration-fast, 150ms) var(--ease-default, ease);
}
.kd-tpl-card--mini:hover,
.kd-tpl-card--mini:focus,
.kd-tpl-card--mini:focus-visible {
  text-decoration: none;
  border-color: var(--color-primary, #00D68F);
  box-shadow: 0 8px 24px rgba(15, 23, 42, .10);
  transform: translateY(-2px);
}
.kd-tpl-card--mini .kd-tpl-card__thumb {
  aspect-ratio: 1 / 1;
  border-radius: 0;
}
.kd-tpl-card--mini .kd-tpl-card__thumb svg { width: 40px; height: 40px; }
.kd-tpl-card--mini-img .kd-tpl-card__thumb img { border-radius: 0; }
.kd-tpl-card--mini .kd-tpl-card__title {
  font-size: var(--text-base, 16px);
  text-align: center;
  padding: var(--space-2, 8px) var(--space-3, 12px) var(--space-3, 12px);
}

/* "Інші ідеї" is intentionally NOT shown while the user is editing the chosen
   idea (input step) — it cluttered the editor and distracted from the active
   design. The gallery (with full-size cards) and the "Всі ідеї" backbar are the
   way to switch ideas. Both copies stay hidden on the input step. */
.kd-templates__more--bottom { display: none; }
.kd-mode-templates.kd-tpl-step-input .kd-templates__more { display: none; }
@media (max-width: 1023px) {
  .kd-templates__more--inline { display: none; }
}

/* ===================== mug-struct-3: hero shell + lazy-boot ===================== */
/* The constructor (#kd-personalize) is hidden until the editor boots — the page
   ships a fast, JS-free hero (.kd-hero) instead. .kd-preboot is set server-side
   (a CSS default, not hide-until-JS): the constructor is hidden from first paint;
   the loader REMOVES .kd-preboot (adds .kd-booted) on the CTA click, swapping the
   hero out for the live editor. If JS never loads, the crawler/visitor still sees
   the full hero (title/mockup/price/CTA/copy). */
/* mug-struct-7 + 7b: the constructor is ALWAYS visible at the bottom of the spoke
   (no longer display:none until boot). The hero + SEO copy stay above it; the CTA is
   a scroll-to shortcut. The heavy editor scripts still load lazily — on a CTA click
   OR when the section nears the viewport (IntersectionObserver in personalize.tpl) —
   so CWV is unaffected (boot is post-LCP). Until the editor mounts, a lightweight
   skeleton holds stage-sized space (no dead/empty canvas, no CLS); the real editor
   chrome is hidden pre-boot and swapped in on boot. */
#kd-personalize {
  scroll-margin-top: 90px;     /* clear any sticky header on the CTA jump */
  /* hero↔editor seam border removed: it duplicated the «ОПИС» tab underline
     directly above, leaving the description double-ruled. Section separation
     now comes from the margin alone (matches the ready-mug PDP). */
  margin-top: var(--space-8, 32px);
}
/* Pre-boot: neutralise the editor's grid + hide its interactive guts; show only the
   skeleton placeholder (the only direct child left visible). */
.kd-preboot #kd-personalize { display: block; }
.kd-preboot #kd-personalize > :not(.kd-editor-skeleton) { display: none !important; }

/* Skeleton placeholder — visible pre-boot AND while the editor mounts (.kd-booting).
   Reserves stage-sized space so the live editor mounts without a jump. It is itself a
   boot trigger ([data-kd-boot]). */
.kd-editor-skeleton { display: none; }
.kd-preboot .kd-editor-skeleton,
.kd-booting #kd-personalize > .kd-editor-skeleton {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 420px;
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
  border: 1px dashed var(--color-border, #E2E8F0);
  cursor: pointer;
  text-align: center;
  padding: var(--space-6, 24px);
}

/* Booting (lazy-boot reveal gap): boot() removes .kd-preboot so #kd-stage is laid out
   and measurable, then loads the heavy editor (Fabric, 2D/3D previews). For the
   ~100-400ms until it mounts, the raw constructor shell (the «Всі ідеї» backbar, the
   empty preview pane, the price/CTA) used to flash. Instead, hold the same skeleton
   placeholder over the whole constructor until kd:editor-ready (removed by the boot
   loader, with a safety timeout). visibility:hidden — NOT display:none — keeps every
   child laid out, so editor.js still measures #kd-stage and the 2D/3D canvases still
   mount; the skeleton is re-shown as an absolute overlay on top. */
.kd-booting #kd-personalize { position: relative; }
.kd-booting #kd-personalize > * { visibility: hidden; }
.kd-booting #kd-personalize > .kd-editor-skeleton {
  visibility: visible;
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
}
.kd-editor-skeleton__label {
  font-weight: 600;
  font-size: var(--text-md, 20px);
  color: var(--color-text-muted, #94A3B8);
}
@media (max-width: 767px) {
  .kd-preboot .kd-editor-skeleton { min-height: 60vh; }
}

/* mug-struct-6: spoke hero rebuilt to read as a real PDP — photo column |
   compact product-info column. Mirrors the storefront PDP (product.tpl
   .product-info): the info column is a bounded buy-box (NOT full-flex), with
   the name + a big green price stacked at the top (no space-between fling),
   then ETA, CTA, prepay. «Інші ідеї» drop to a full-width row below. The H1
   stays above the hero (it is the page H1). */
.kd-hero {
  display: flex;
  flex-wrap: wrap;
  /* gap = the PDP inter-column gutter: two col-md-6 each with 25px side padding =>
     50px between the image content and the info content. With flex:1 1 0 this makes
     each column exactly (innerWidth - 50)/2 = the PDP 580px, H1 landing at the same
     x as the PDP .product-info. */
  gap: 50px;
  align-items: flex-start;
  /* No top gap — the PDP product row starts immediately under the breadcrumb. */
  margin: 0 0 var(--space-6, 24px);
}
.kd-hero__media,
.kd-hero__body {
  /* True 50/50 split, exactly like the PDP image col-md-6 | info col-md-6. Both
     flex:1 1 0 so each takes half the row regardless of content; the info content
     hugs the top-left like the PDP buy-box. min-width forces the stack on mobile. */
  flex: 1 1 0;
  min-width: 320px;
}
.kd-hero__img {
  display: block;
  width: 100%;
  height: auto;
  /* PDP main image sits 4px below its column top (the H1 is at the column top); match
     that exactly so the photo lands on the same pixel row as the PDP. */
  margin-top: 4px;
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface, #F8FAFC);
}
.kd-hero__body {
  min-width: 320px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* H1 — identical to the PDP .product-info .title (30/47/600, #334155, no margin).
   align-self:stretch so it fills the 580px info column and WRAPS at the same width
   as the PDP title (the flex column's align-items:flex-start would otherwise shrink
   it to its text width and wrap earlier). */
.kd-hero__title {
  align-self: stretch;
  /* = the PDP .product-info .title box: margin 0 + 14px padding-bottom, so the brand
     line sits 14+10px below the H1 text (the PDP gap), not just 10px. */
  margin: 0;
  padding-bottom: 14px;
  font-size: var(--text-xl, 30px);
  line-height: 47px;
  font-weight: 600;
  color: var(--color-text-primary, #334155);
}
/* Brand line — identical to the PDP .productvendor: «Бренд: » 14/400 #475569 +
   the manufacturer as a 16/700 #00D68F link with no underline. line-height 25px
   matches the PDP box (so the price below lands on the same row). */
.kd-hero__brand {
  margin: 10px 0 20px;
  line-height: 25px;
  letter-spacing: 0.02em;             /* = PDP .productvendor — keeps the link x exact */
}
.kd-hero__brand-label {
  color: #475569;
  font-weight: 400;
  font-size: 14px;
}
.kd-hero__brand-link {
  color: var(--color-primary, #00D68F);
  font-weight: 700;
  font-size: 16px;
  text-decoration: none;
}
.kd-hero__brand-link:hover { text-decoration: none; }
.kd-hero__head {
  display: block;                      /* was flex+space-between — stack, no fling */
  margin-bottom: var(--space-4, 16px);
}
.kd-hero__price {                       /* identical to the PDP .product-info .price */
  display: block;
  font-size: var(--text-2xl, 36px);
  line-height: 31px;
  font-weight: 600;
  color: var(--color-primary, #00D68F);
  /* PDP price has margin-top:3px, but there it COLLAPSES with the brand's 20px
     bottom-margin (block flow) -> a 20px gap. This info column is flex (no margin
     collapse), so the 3px would ADD to make 23px. Zero it to keep the PDP 20px gap. */
  margin-top: 0;
}
.kd-hero__eta {
  margin: var(--space-4, 16px) 0 var(--space-3, 12px);
  font-size: var(--text-sm, 14px);
  color: var(--color-text-muted, #94A3B8);
}
/* mug-struct-6: CTA bounded to the PDP add-to-cart sizing (intrinsic width, not
   the full-bleed bar that read as unfinished). PDP #button-cart is auto-width with
   padding; mirror that — content-sized, min-width keeps it prominent + tappable. */
.kd-btn--start { width: auto; display: inline-flex; align-items: center; justify-content: center; min-width: 240px; max-width: 100%; }
.kd-hero__prepay {
  margin: var(--space-2, 8px) 0 0;
  font-size: var(--text-xs, 12px);
  color: var(--color-text-muted, #94A3B8);
}
.kd-hero__more {
  flex: 1 1 100%;                       /* full-width row below the photo + buy-box */
  margin-top: var(--space-5, 20px);
}
.kd-hero__more-heading {
  font-size: var(--text-md, 20px);
  font-weight: 700;
  color: var(--color-text-primary, #334155);
  margin: 0 0 var(--space-3, 12px);
}
/* mug-struct-6: bottom description in the PDP «Опис» tab shell — only spacing here;
   the look (uppercase green label + 16/24 #475569 body) comes from the theme's
   .tt-tabs rules, so it is byte-for-byte the PDP description block. */
.kd-spoke-tabs { margin: var(--space-6, 24px) 0 var(--space-8, 40px); }

/* ETA + prepay beside the in-editor add-to-cart CTA. */
.kd-personalize__eta {
  margin: 0 0 var(--space-2, 8px);
  font-size: var(--text-sm, 14px);
  color: var(--color-text-muted, #94A3B8);
  text-align: center;
}
.kd-personalize__prepay {
  margin: var(--space-2, 8px) 0 0;
  font-size: var(--text-xs, 12px);
  color: var(--color-text-muted, #94A3B8);
  text-align: center;
}

@media (max-width: 767px) {
  .kd-hero { gap: var(--space-4, 16px); }
  /* Mobile: single column stack — photo on top, info below, «Інші ідеї» last. */
  .kd-hero__media { flex: 1 1 100%; max-width: 360px; margin: 0 auto; }
  .kd-hero__body { flex: 1 1 100%; max-width: 100%; }
  .kd-hero__price { font-size: var(--text-xl, 30px); }
}
