/*
 * Scoutwise Necker Designer — ported from the Claude design file.
 *
 * Source: "Necker Design Tool.html" (29 KB, 241 rules) + _ds design-system tokens.
 * Every selector is scoped under .swnd-app so the design cannot leak into the
 * WordPress page and the theme cannot leak in.
 *
 * DELIBERATELY NOT PORTED
 *   - tokens/base.css        global resets on *, html, body, h1-h6 — would restyle the site
 *   - #tweaks-panel / .twk-* developer toggle panel, not product
 *   - html[data-density]     compact/spacious toggle (18 rules) — no toggles, per Oisin
 *   - html[data-canvas]      studio variant (3 rules) — blueprint is now the only canvas,
 *                            so its attribute prefix is stripped and it always applies
 *   - _ds_bundle.js (66 KB)  design-system runtime, unused here
 *
 * See the EMBED ADAPTATION block at the foot of this file for the one structural
 * change: the prototype was a full-viewport app, this is an in-flow page section.
 */

/* ============ DESIGN TOKENS (scoped) ============ */

/* --- tokens/colors.css --- */
.swnd-app {
  /* ─── Brand Core ─── */
  --color-purple-900: #2d0a5a;
  --color-purple-800: #3e0e7a;
  --color-purple-700: #52149a;
  --color-purple-600: #6e20a0;   /* Scouting Purple — primary */
  --color-purple-500: #8b3ab8;
  --color-purple-400: #a95dce;
  --color-purple-300: #c98ae0;
  --color-purple-200: #e4c4f5;
  --color-purple-100: #f3e8fc;
  --color-purple-50:  #faf4fe;

  /* ─── Orange Accent ─── */
  --color-orange-700: #c05a08;
  --color-orange-600: #e0700f;
  --color-orange-500: #f07c1e;   /* Primary CTA */
  --color-orange-400: #f49642;
  --color-orange-300: #f8b574;
  --color-orange-100: #fdebd8;

  /* ─── Neutrals ─── */
  --color-neutral-950: #0f0f12;
  --color-neutral-900: #1a1a24;
  --color-neutral-800: #2d2d3a;
  --color-neutral-700: #484857;
  --color-neutral-600: #636375;
  --color-neutral-500: #8a8a9e;
  --color-neutral-400: #b0b0c0;
  --color-neutral-300: #d0d0dc;
  --color-neutral-200: #e8e8f0;
  --color-neutral-100: #f4f4f8;
  --color-neutral-50:  #fafafc;
  --color-white: #ffffff;

  /* ─── Semantic Aliases ─── */
  --color-brand:          var(--color-purple-600);
  --color-brand-dark:     var(--color-purple-800);
  --color-brand-deeper:   var(--color-purple-900);
  --color-brand-light:    var(--color-purple-100);
  --color-brand-subtle:   var(--color-purple-50);

  --color-accent:         var(--color-orange-500);
  --color-accent-dark:    var(--color-orange-700);
  --color-accent-light:   var(--color-orange-100);

  --color-surface:        var(--color-white);
  --color-surface-raised: var(--color-neutral-50);
  --color-surface-sunken: var(--color-neutral-100);
  --color-surface-brand:  var(--color-purple-50);

  --color-text-primary:   var(--color-neutral-900);
  --color-text-secondary: var(--color-neutral-600);
  --color-text-muted:     var(--color-neutral-500);
  --color-text-on-brand:  var(--color-white);
  --color-text-on-accent: var(--color-white);
  --color-text-brand:     var(--color-purple-600);
  --color-text-accent:    var(--color-orange-600);

  --color-border:         var(--color-neutral-200);
  --color-border-brand:   var(--color-purple-300);

  --color-star:           #f5b800;

  /* ─── Status ─── */
  --color-success:        #1f8a5b;
  --color-warning:        #d97700;
  --color-error:          #c0392b;
}


/* --- tokens/typography.css --- */
/* ─── Scoutwise Typography Tokens ─── */

/* Google Fonts loaded via styles.css @import */

.swnd-app {
  /* ─── Font Families ─── */
  --font-display:  'Nunito', system-ui, sans-serif;   /* Headings, hero text */
  --font-body:     'Inter', system-ui, sans-serif;    /* Body, UI, labels */
  --font-mono:     'JetBrains Mono', 'Courier New', monospace;

  /* ─── Font Weights ─── */
  --weight-regular:    400;
  --weight-medium:     500;
  --weight-semibold:   600;
  --weight-bold:       700;
  --weight-extrabold:  800;
  --weight-black:      900;

  /* ─── Font Sizes (fluid-friendly scale) ─── */
  --text-xs:   0.75rem;    /*  12px */
  --text-sm:   0.875rem;   /*  14px */
  --text-base: 1rem;       /*  16px */
  --text-md:   1.125rem;   /*  18px */
  --text-lg:   1.25rem;    /*  20px */
  --text-xl:   1.5rem;     /*  24px */
  --text-2xl:  1.875rem;   /*  30px */
  --text-3xl:  2.25rem;    /*  36px */
  --text-4xl:  3rem;       /*  48px */
  --text-5xl:  3.75rem;    /*  60px */

  /* ─── Line Heights ─── */
  --leading-tight:   1.2;
  --leading-snug:    1.35;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;
  --leading-loose:   1.8;

  /* ─── Letter Spacing ─── */
  --tracking-tight:  -0.02em;
  --tracking-normal: 0em;
  --tracking-wide:   0.04em;
  --tracking-wider:  0.08em;
  --tracking-widest: 0.15em;

  /* ─── Semantic Text Styles ─── */
  --type-hero-size:        var(--text-4xl);
  --type-hero-weight:      var(--weight-extrabold);
  --type-hero-leading:     var(--leading-tight);
  --type-hero-tracking:    var(--tracking-tight);
  --type-hero-family:      var(--font-display);

  --type-h1-size:          var(--text-3xl);
  --type-h1-weight:        var(--weight-bold);
  --type-h1-leading:       var(--leading-snug);
  --type-h1-family:        var(--font-display);

  --type-h2-size:          var(--text-2xl);
  --type-h2-weight:        var(--weight-bold);
  --type-h2-leading:       var(--leading-snug);
  --type-h2-family:        var(--font-display);

  --type-h3-size:          var(--text-xl);
  --type-h3-weight:        var(--weight-bold);
  --type-h3-leading:       var(--leading-normal);
  --type-h3-family:        var(--font-display);

  --type-h4-size:          var(--text-lg);
  --type-h4-weight:        var(--weight-semibold);
  --type-h4-leading:       var(--leading-normal);
  --type-h4-family:        var(--font-display);

  --type-body-lg-size:     var(--text-md);
  --type-body-lg-weight:   var(--weight-regular);
  --type-body-lg-leading:  var(--leading-relaxed);

  --type-body-size:        var(--text-base);
  --type-body-weight:      var(--weight-regular);
  --type-body-leading:     var(--leading-relaxed);

  --type-body-sm-size:     var(--text-sm);
  --type-body-sm-weight:   var(--weight-regular);
  --type-body-sm-leading:  var(--leading-normal);

  --type-label-size:       var(--text-sm);
  --type-label-weight:     var(--weight-semibold);
  --type-label-tracking:   var(--tracking-wide);

  --type-caption-size:     var(--text-xs);
  --type-caption-weight:   var(--weight-medium);
  --type-caption-tracking: var(--tracking-wide);

  --type-overline-size:    var(--text-xs);
  --type-overline-weight:  var(--weight-bold);
  --type-overline-tracking: var(--tracking-widest);
}


/* --- tokens/spacing.css --- */
/* ─── Scoutwise Spacing & Layout Tokens ─── */

.swnd-app {
  /* ─── Base Spacing Scale (4px base) ─── */
  --space-0:   0px;
  --space-1:   4px;
  --space-2:   8px;
  --space-3:   12px;
  --space-4:   16px;
  --space-5:   20px;
  --space-6:   24px;
  --space-8:   32px;
  --space-10:  40px;
  --space-12:  48px;
  --space-16:  64px;
  --space-20:  80px;
  --space-24:  96px;
  --space-32:  128px;
  --space-40:  160px;
  --space-48:  192px;

  /* ─── Semantic Spacing ─── */
  --gap-xs:    var(--space-2);
  --gap-sm:    var(--space-3);
  --gap-md:    var(--space-4);
  --gap-lg:    var(--space-6);
  --gap-xl:    var(--space-8);
  --gap-2xl:   var(--space-12);
  --gap-3xl:   var(--space-16);

  --padding-card:     var(--space-6);
  --padding-card-sm:  var(--space-4);
  --padding-section:  var(--space-16);
  --padding-page-x:   var(--space-6);

  /* ─── Border Radius ─── */
  --radius-sm:   6px;
  --radius-md:   10px;
  --radius-lg:   16px;
  --radius-xl:   24px;
  --radius-2xl:  32px;
  --radius-full: 9999px;

  /* ─── Shadows ─── */
  --shadow-xs:   0 1px 3px rgba(110, 32, 160, 0.06), 0 1px 2px rgba(0,0,0,0.04);
  --shadow-sm:   0 2px 8px rgba(110, 32, 160, 0.08), 0 1px 3px rgba(0,0,0,0.06);
  --shadow-md:   0 4px 16px rgba(110, 32, 160, 0.10), 0 2px 6px rgba(0,0,0,0.06);
  --shadow-lg:   0 8px 32px rgba(110, 32, 160, 0.12), 0 4px 12px rgba(0,0,0,0.08);
  --shadow-xl:   0 16px 48px rgba(110, 32, 160, 0.16), 0 8px 24px rgba(0,0,0,0.10);

  /* ─── Border Widths ─── */
  --border-width:    1px;
  --border-width-md: 2px;
  --border-width-lg: 3px;

  /* ─── Layout ─── */
  --container-sm:   640px;
  --container-md:   768px;
  --container-lg:  1024px;
  --container-xl:  1280px;
  --container-2xl: 1440px;

  /* ─── Z-Index ─── */
  --z-base:    0;    /* @kind other */
  --z-raised:  10;   /* @kind other */
  --z-dropdown: 100; /* @kind other */
  --z-sticky:  200;  /* @kind other */
  --z-overlay: 300;  /* @kind other */
  --z-modal:   400;  /* @kind other */
  --z-toast:   500;  /* @kind other */

  /* ─── Transitions ─── */
  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);    /* @kind other */
  --ease-in-out:   cubic-bezier(0.4, 0, 0.2, 1);     /* @kind other */
  --ease-bounce:   cubic-bezier(0.34, 1.56, 0.64, 1); /* @kind other */
  --duration-fast: 120ms; /* @kind other */
  --duration-base: 200ms; /* @kind other */
  --duration-slow: 350ms; /* @kind other */
}


/* --- tokens/motion.css --- */
/* ─── Scoutwise Motion Tokens ─── */

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

@keyframes sw-pop-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes sw-slide-up {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

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

@keyframes sw-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.55; }
}

.swnd-app {
  --anim-fade-in:   sw-fade-in  var(--duration-base) var(--ease-out) both;
  --anim-pop-in:    sw-pop-in   var(--duration-base) var(--ease-bounce) both;
  --anim-slide-up:  sw-slide-up var(--duration-slow) var(--ease-out) both;
}



/* ============ PORTED COMPONENT CSS ============ */

.swnd-app {
    /* Colours sourced from the Scoutwise design-system token file */
    --bg: var(--color-purple-50, #faf4fe);
    --surface: var(--color-white, #ffffff);
    --surface-2: var(--color-purple-100, #f3e8fc);
    --surface-3: var(--color-purple-200, #e4c4f5);
    --ink: var(--color-neutral-900, #1a1a24);
    --ink-2: var(--color-neutral-600, #636375);
    --ink-3: var(--color-neutral-500, #8a8a9e);
    --line: var(--color-neutral-200, #e8e8f0);
    --line-2: var(--color-neutral-300, #d0d0dc);
    /* Scoutwise brand */
    --brand: var(--color-purple-600, #6e20a0);
    --brand-ink: var(--color-white, #ffffff);
    --accent: var(--color-orange-500, #f07c1e);
    --accent-strong: var(--color-purple-600, #6e20a0);
    --accent-ink: var(--color-white, #ffffff);
    --warn: var(--color-warning, #d97700);
    --toast-bg: var(--ink);
    --toast-ink: var(--surface);
    --radius: 14px;
    --radius-sm: 10px;
    --shadow-1: 0 1px 0 rgba(20,20,18,0.04), 0 1px 2px rgba(20,20,18,0.04);
    --shadow-2: 0 12px 32px -12px rgba(20,20,18,0.22);
    --rail-w: 460px;
    --topbar-h: 0px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  }
.swnd-app /* ===================================================================
     TWEAKS — three expressive controls that reshape the whole feel:
     colour mood, .swnd-app spatial density, .swnd-app and preview-backdrop presentation.
     Each one re-themes many rules at once via shared tokens, .swnd-app rather
     than exposing single pixel/colour sliders.
     =================================================================== */

  /* ---- Colour mood ---- */
  :root[data-mood="campfire"] {
    --bg: #fbf3ea;
    --surface: #fffdfa;
    --surface-2: #f6e6d3;
    --surface-3: #f0c9a0;
    --ink: #2b1a10;
    --ink-2: #7a5f4a;
    --ink-3: #a68b6f;
    --line: #ecdcc7;
    --line-2: #ddc4a3;
    --brand: #c05a08;
    --brand-ink: #ffffff;
    --accent: #f07c1e;
    --accent-strong: #c05a08;
    --accent-ink: #ffffff;
    --warn: #b5490a;
    --toast-bg: #2b1a10;
    --toast-ink: #fffdfa;
  }
.swnd-app[data-mood="midnight"] {
    --bg: #14101c;
    --surface: #1e1830;
    --surface-2: #2a2140;
    --surface-3: #3a2c58;
    --ink: #f4f0fb;
    --ink-2: #b9aed0;
    --ink-3: #8b7fa8;
    --line: #372a52;
    --line-2: #46375f;
    --brand: #a95dce;
    --brand-ink: #14101c;
    --accent: #f49642;
    --accent-strong: #c98ae0;
    --accent-ink: #14101c;
    --warn: #f6a54a;
    --toast-bg: #0c0916;
    --toast-ink: #f4f0fb;
  }
.swnd-app .canvas-frame::before {
    background:
      linear-gradient(var(--line-2) 1px, transparent 1px) 0 0/26px 26px,
      linear-gradient(90deg, var(--line-2) 1px, transparent 1px) 0 0/26px 26px;
    opacity: 0.7;
  }
.swnd-app .canvas-frame {
    background: color-mix(in oklab, var(--brand) 5%, var(--surface));
  }
.swnd-app * { box-sizing: border-box; }
.swnd-app, .swnd-app { margin: 0; padding: 0; }
.swnd-app {
    background: var(--bg);
    color: var(--ink);
    font-size: 15px;
    line-height: 1.45;
    min-height: 100vh;
    min-height: 100dvh;
    -webkit-text-size-adjust: 100%;
  }
.swnd-app button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
.swnd-app input { font: inherit; color: inherit; }
.swnd-app /* ---------- Layout ---------- */
  .workspace {
    display: grid;
    grid-template-columns: 1fr var(--rail-w);
    height: calc(100vh - var(--topbar-h));
    height: calc(100dvh - var(--topbar-h));
    overflow: hidden;
    gap: 0;
  }
@media (max-width: 1100px) {
.swnd-app { --rail-w: 380px; }
}
/* ===== Tablet & mobile: stack, pin the live preview to the top ===== */
@media (max-width: 960px) {
    .swnd-app .workspace { grid-template-columns: 1fr; grid-template-rows: 46vh 1fr; }
    .swnd-app .workspace .canvas-col {
      position: relative; top: auto; z-index: 6;
      height: auto; min-height: 0;
      padding: 14px 16px;
      border-bottom: 1px solid var(--line);
      background:
        radial-gradient(900px 500px at 30% 20%, color-mix(in oklab, var(--surface-3) 26%, transparent), transparent 60%),
        var(--bg);
    }
    .swnd-app .canvas-frame { width: auto; height: 100%; max-width: 100%; border-radius: 14px; }
    .swnd-app .main-image { padding: 16px; }
    .swnd-app .canvas-chip { left: 12px; top: 12px; }
    .swnd-app .canvas-meta { right: 12px; bottom: 12px; padding: 6px 10px; gap: 10px; font-size: 11px; }
    .swnd-app .workspace .rail { border-left: 0; border-top: 0; min-height: 0; }
  }
@media (max-width: 720px) {
.swnd-app .rail-section { padding: 20px 18px 16px; }
.swnd-app .styles-grid { gap: 8px; }
.swnd-app /* compact colour grid — saves vertical space, .swnd-app still 34px+ tap targets */
    .palette-grid { grid-template-columns: repeat(auto-fill, minmax(34px, 1fr)) !important; gap: 7px; }
.swnd-app /* 44px+ tap targets on the quantity stepper */
    .qty button { width: 40px; height: 40px; font-size: 18px; }
.swnd-app .qty input { width: 44px; height: 40px; font-size: 16px; }
.swnd-app .swnd-summary {
      padding: 14px 18px calc(16px + env(safe-area-inset-bottom, 0px));
      box-shadow: 0 -10px 26px -14px rgba(20,10,40,0.28);
    }
.swnd-app .cta { height: 52px; }
}
/* Style-card columns live in exactly two places: the base rule above (3, desktop)
   and the 960px mobile block (2). Do not add a third breakpoint here — the old
   4/3/2 ladder is what produced 4 unreadable columns on a handset. */
@media (max-width: 960px) and (max-height: 720px) {
.swnd-app .workspace { grid-template-rows: 40vh 1fr; }
}
/* ===== Touch devices: neutralise sticky :hover states ===== */
@media (hover: none) {
    .swnd-app .necker-style:hover { transform: none; box-shadow: none; border-color: var(--line); }
    .swnd-app .palette-grid .swatch-btn:hover {
      transform: none;
      box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 1px 2px rgba(20,20,18,0.06);
    }
    .swnd-app .cta:hover:not(:disabled) { transform: none; background: var(--accent); }
    .swnd-app .necker-style:active { transform: scale(0.97); }
    .swnd-app .palette-grid .swatch-btn:active { transform: scale(0.92); }
  }
.swnd-app /* ---------- Canvas (left) ---------- */
  .canvas-col {
    position: sticky; top: var(--topbar-h);
    height: calc(100vh - var(--topbar-h));
    display: flex; align-items: center; justify-content: center;
    padding: 32px;
    background:
      radial-gradient(1200px 600px at 30% 30%, color-mix(in oklab, var(--surface-3) 30%, transparent), transparent 60%),
      var(--bg);
  }
.swnd-app .canvas-frame {
    position: relative;
    width: min(620px, 100%);
    aspect-ratio: 1 / 1;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 18px;
    box-shadow: var(--shadow-2);
    overflow: hidden;
  }
.swnd-app .canvas-frame::before {
    content: "";
    position: absolute; inset: 0;
    background:
      linear-gradient(45deg, transparent 49%, var(--surface-2) 49% 51%, transparent 51%) 0 0/28px 28px,
      linear-gradient(-45deg, transparent 49%, var(--surface-2) 49% 51%, transparent 51%) 0 0/28px 28px;
    opacity: 0.28;
    pointer-events: none;
  }
.swnd-app .main-image {
    position: absolute; inset: 0;
    display: grid; place-items: center;
    padding: 28px;
  }
.swnd-app .main-image svg {
    width: 100%; height: 100%;
    pointer-events: none;
  }
.swnd-app .main-image svg * { transition: fill 140ms ease; }
.swnd-app .canvas-chip {
    position: absolute; left: 16px; top: 16px;
    z-index: 5;
    padding: 7px 12px;
    background: var(--brand);
    color: #fff;
    font-size: 12px; letter-spacing: 0.02em;
    border-radius: 999px;
    pointer-events: none;
  }
.swnd-app .canvas-meta {
    position: absolute; right: 18px; bottom: 18px;
    z-index: 5;
    padding: 8px 12px;
    background: color-mix(in oklab, var(--surface) 92%, transparent);
    border: 1px solid var(--line);
    color: var(--ink-2);
    font-size: 12px;
    border-radius: 10px;
    display: flex; gap: 14px; align-items: center;
  }
.swnd-app .canvas-meta b { color: var(--ink); font-weight: 600; }
.swnd-app .canvas-meta .sep { width: 1px; height: 14px; background: var(--line-2); }
.swnd-app .canvas-meta button {
    color: var(--ink-2);
    font-size: 12px;
    padding: 2px 6px;
    border-radius: 6px;
  }
.swnd-app .canvas-meta button:hover { color: var(--ink); background: var(--surface-2); }
.swnd-app /* ---------- Rail (right) ---------- */
  .rail {
    border-left: 1px solid var(--line);
    background: var(--surface);
    display: flex; flex-direction: column;
    min-height: 0; height: 100%; overflow: hidden;
  }
.swnd-app .rail-scroll { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; padding: 0; }
.swnd-app .rail-section {
    padding: 22px 26px 18px;
    border-bottom: 1px solid var(--line);
  }
.swnd-app .rail-section:last-of-type { border-bottom: 0; }
.swnd-app .rail-section h2 {
    margin: 0 0 2px;
    font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--ink-3);
  }
.swnd-app .rail-section .lead {
    margin: 0 0 14px;
    font-size: 18px; font-weight: 600; letter-spacing: -0.015em;
  }
.swnd-app .rail-section .sub { margin: -8px 0 14px; font-size: 13px; color: var(--ink-2); }
.swnd-app /* ---------- Accordion steps ---------- */
  .step-block { border-bottom: 1px solid var(--line); display: flex; flex-direction: column; flex: 0 0 auto; min-height: 0; }
.swnd-app .step-block.is-open { flex: 1 1 auto; min-height: 120px; }
.swnd-app .step-block:first-of-type { margin-top: auto; }
.swnd-app .step-block:last-of-type { border-bottom: 0; }
.swnd-app .step-head {
    width: 100%; box-sizing: border-box; min-height: 58px;
    display: grid; grid-template-columns: 26px 1fr auto auto; align-items: center; gap: 12px;
    padding: 18px 26px; text-align: left; flex: 0 0 auto;
    transition: background 120ms ease;
  }
.swnd-app .step-head:hover { background: var(--surface-2); }
.swnd-app .step-block.is-locked .step-head { cursor: not-allowed; }
.swnd-app .step-block.is-locked .step-head:hover { background: none; }
.swnd-app .step-block.is-locked .step-title, .swnd-app .step-block.is-locked .step-status { color: var(--ink-3); }
.swnd-app .step-num {
    width: 26px; height: 26px; border-radius: 999px;
    display: grid; place-items: center;
    background: var(--surface-2); color: var(--ink-2);
    font-size: 12px; font-weight: 700;
    transition: background 160ms ease, color 160ms ease;
  }
.swnd-app .step-block.is-open .step-num { background: var(--brand); color: #fff; }
.swnd-app .step-block.is-done .step-num { background: color-mix(in oklab, var(--brand) 16%, transparent); color: var(--brand); }
.swnd-app .step-block.is-open.is-done .step-num { background: var(--brand); color: #fff; }
.swnd-app .step-block.is-done .step-num::after { content: "✓"; }
.swnd-app .step-block.is-done .step-num .n { display: none; }
.swnd-app .step-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.swnd-app .step-status {
    font-size: 12.5px; color: var(--ink-3);
    max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
.swnd-app .step-block.is-open .step-status { opacity: 0; }
.swnd-app .step-chev { width: 14px; height: 14px; color: var(--ink-3); transition: transform 200ms cubic-bezier(0.16,1,0.3,1); }
.swnd-app .step-block.is-open .step-chev { transform: rotate(180deg); }
.swnd-app .step-panel { display: grid; grid-template-rows: 0fr; min-height: 0; transition: grid-template-rows 260ms cubic-bezier(0.16,1,0.3,1); }
.swnd-app .step-block:not(.is-open) .step-panel { display: none; }
.swnd-app .step-block.is-open .step-panel { grid-template-rows: 1fr; }
.swnd-app .step-panel > .step-body { overflow: hidden; min-height: 0; }
/* overflow:hidden above is only needed while the panel is collapsing. Once open
   it must be visible, not auto: `auto` makes .step-body its own scroll container,
   which becomes the scrollport for the sticky step CTA and stops it docking to
   the screen. The page is the scroller here, not the panel. */
.swnd-app .step-block.is-open .step-body { overflow: visible; }
.swnd-app .step-body-inner { padding: 0 26px 22px; }
.swnd-app .step-gate {
    display: none; margin: 0 0 14px;
    padding: 10px 12px; border-radius: 10px;
    background: color-mix(in oklab, var(--brand) 8%, transparent);
    color: var(--brand); font-size: 13px; font-weight: 600;
  }
.swnd-app .step-block.is-gated .step-gate { display: block; }
.swnd-app .step-block.is-gated .step-body-inner > *:not(.step-gate) { opacity: 0.4; pointer-events: none; }
.swnd-app .step-next {
    margin-top: 16px; height: 42px; width: 100%;
    border-radius: 999px; background: var(--brand); color: #fff;
    font-size: 14px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    transition: transform 120ms ease, background 120ms ease, opacity 120ms ease;
  }
.swnd-app .step-next:hover:not(:disabled) { transform: scale(1.015); }
.swnd-app .step-next:active:not(:disabled) { transform: scale(0.98); }
/* Disabled reads as a lighter SOLID shade, never as transparency. The CTA is
   docked over scrolling content, so opacity < 1 let swatches and card borders
   show straight through it. */
.swnd-app .step-next:disabled {
    opacity: 1;
    cursor: not-allowed;
    background: color-mix(in oklab, var(--brand) 16%, var(--surface));
    /* Darkened 2026-08-11: the previous mix measured ~3.5:1 against this pale
       background — under AA for a 15px label. The pale background is what signals
       "disabled"; the text does not have to be faint as well. */
    color: color-mix(in oklab, var(--brand) 88%, var(--ink));
  }
@media (max-width: 720px) {
.swnd-app .step-head { padding: 16px 18px; }
.swnd-app .step-body-inner { padding: 0 18px 18px; }
.swnd-app .step-status { max-width: 96px; }
.swnd-app .step-next { height: 48px; }
}
.swnd-app /* ---------- Styles grid ---------- */
  .styles-grid {
    display: grid;
    /* 3 across on desktop, 2 on mobile (see the 960px block). Was 4/3/2, which
       squeezed labels like "Half and Half + Double 1/2 Inch 4 Colour Border"
       into five wrapped lines and made the thumbnails too small to tell apart. */
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
  }
.swnd-app .necker-style {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 6px 6px 8px;
    display: flex; flex-direction: column; gap: 4px;
    text-align: left;
    transition: border-color 140ms ease, box-shadow 140ms ease, transform 80ms ease;
    cursor: pointer;
  }
.swnd-app .necker-style:hover { border-color: var(--line-2); transform: translateY(-1px); box-shadow: var(--shadow-1); }
.swnd-app .necker-style .thumb {
    aspect-ratio: 1 / 1;
    background: var(--color-neutral-100, #f4f4f8);
    border-radius: 6px;
    overflow: hidden;
    display: grid; place-items: center;
  }
.swnd-app .necker-style .thumb img {
    width: 100%; height: 100%;
    display: block; object-fit: contain;
    pointer-events: none;
  }
.swnd-app .necker-style .label {
    font-size: 10.5px; line-height: 1.2;
    color: var(--ink-2);
    text-wrap: pretty;
    min-height: 2.4em;
  }
/* "From €x.xx" — the junior price, which is the cheaper size on every style.
   Written by designer.js from WooCommerce's own formatted price, so multi-currency
   and any sale price are already applied; it is never a figure held in JS. */
.swnd-app .necker-style .from {
    font-size: 11px; line-height: 1.2;
    font-weight: 600;
    color: var(--ink-2);
    margin-top: auto;
    padding-top: 2px;
  }
.swnd-app .necker-style .from:empty { display: none; }
.swnd-app .necker-style.active-style {
    border-color: var(--brand);
    box-shadow: 0 0 0 2px color-mix(in oklab, var(--brand) 30%, transparent);
  }
.swnd-app .necker-style.active-style .label { color: var(--ink); font-weight: 500; }
.swnd-app .necker-style.active-style .from { color: var(--brand); }
.swnd-app /* ---------- Sections (all expanded) ---------- */
  .sections-list { display: flex; flex-direction: column; gap: 16px; }
.swnd-app .section-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 14px 14px 12px;
  }
.swnd-app .section-head {
    display: flex; align-items: center; gap: 12px;
    margin-bottom: 12px;
  }
.swnd-app .section-head .name {
    flex: 1; min-width: 0;
    font-size: 14px; font-weight: 600;
  }
.swnd-app .section-head .hint {
    font-size: 12px; color: var(--ink-3); font-weight: 400;
  }
.swnd-app .section-head .current-swatch {
    width: 22px; height: 22px;
    border-radius: 999px;
    border: 1px solid var(--line-2);
    background: var(--surface-2);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
    flex: 0 0 22px;
  }
.swnd-app .palette-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 8px;
  }
@media (max-width: 1100px) {
.swnd-app .palette-grid { grid-template-columns: repeat(10, 1fr); }
}
.swnd-app .palette-grid .swatch-btn {
    width: 100%; aspect-ratio: 1 / 1;
    border-radius: 999px;
    border: 1px solid var(--line-2);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 1px 2px rgba(20,20,18,0.06);
    position: relative;
    cursor: pointer;
    transition: transform 100ms ease, box-shadow 140ms ease;
  }
.swnd-app .palette-grid .swatch-btn:hover {
    transform: translateY(-2px) scale(1.06);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 4px 8px rgba(20,20,18,0.12);
  }
.swnd-app .palette-grid .swatch-btn.is-selected {
    box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--brand), inset 0 1px 0 rgba(255,255,255,0.4);
  }
.swnd-app .palette-grid .swatch-btn.is-selected::after {
    content: "";
    position: absolute; left: 50%; top: 50%;
    width: 32%; height: 17%;
    border-left: 2px solid #fff;
    border-bottom: 2px solid #fff;
    transform: translate(-50%, -65%) rotate(-45deg);
    filter: drop-shadow(0 0 1px rgba(0,0,0,0.45));
  }
.swnd-app .palette-grid .swatch-btn[data-light="true"].is-selected::after {
    border-color: #111;
    filter: none;
  }
.swnd-app .colour-tip {
    margin-top: 10px;
    font-size: 12px;
    color: var(--ink-3);
    display: flex; align-items: center; gap: 8px;
  }
.swnd-app .reset-link {
    color: var(--ink-2);
    text-decoration: underline;
    text-decoration-color: var(--line-2);
    text-underline-offset: 3px;
    font-size: 12px;
    cursor: pointer;
  }
.swnd-app .reset-link:hover { color: var(--ink); text-decoration-color: var(--ink-2); }
.swnd-app /* ---------- Sizes ---------- */
  .size-row {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
    margin-bottom: 10px;
    gap: 12px;
  }
.swnd-app .size-row:last-child { margin-bottom: 0; }
.swnd-app .size-row .info { flex: 1; min-width: 0; }
.swnd-app .size-row .info .name { font-size: 14px; font-weight: 600; }
.swnd-app .size-row .info .dims { font-size: 11px; color: var(--ink-3); }
.swnd-app .size-row .info .price { font-size: 12px; color: var(--ink-2); margin-top: 2px; }
.swnd-app .size-row .info .price b { color: var(--accent); font-weight: 700; }
.swnd-app .qty {
    display: flex; align-items: center;
    background: var(--surface-2);
    border-radius: 999px;
    padding: 3px;
  }
.swnd-app .qty button {
    width: 32px; height: 32px;
    border-radius: 999px;
    background: var(--surface);
    box-shadow: var(--shadow-1);
    font-size: 16px; font-weight: 500;
    color: var(--ink);
    display: grid; place-items: center;
    transition: background 100ms ease;
  }
.swnd-app .qty button:hover { background: var(--bg); }
.swnd-app .qty button:disabled { opacity: 0.4; box-shadow: none; background: transparent; }
.swnd-app .qty input {
    width: 42px; height: 32px;
    text-align: center;
    background: transparent; border: 0; outline: none;
    font-size: 14px; font-weight: 600;
    -moz-appearance: textfield;
  }
.swnd-app .qty input::-webkit-outer-spin-button, .swnd-app .qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.swnd-app .warn {
    display: none;
    margin-top: 10px;
    padding: 9px 12px;
    background: color-mix(in oklab, var(--warn) 10%, var(--surface));
    border: 1px solid color-mix(in oklab, var(--warn) 25%, var(--line));
    color: color-mix(in oklab, var(--warn) 70%, var(--ink));
    border-radius: 8px;
    font-size: 12px;
  }
.swnd-app .warn.show { display: block; }
.swnd-app /* ---------- Summary card ---------- */
  .swnd-summary {
    position: sticky; bottom: 0;
    background: color-mix(in oklab, var(--bg) 94%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-top: 1px solid var(--line);
    padding: 18px 26px 22px;
  }
.swnd-app .swnd-summary .row {
    display: flex; justify-content: space-between; align-items: baseline;
    font-size: 13px; color: var(--ink-2);
    margin-bottom: 4px;
  }
.swnd-app .swnd-summary .row.total {
    margin-top: 8px; padding-top: 10px;
    border-top: 1px dashed var(--line-2);
    font-size: 15px;
  }
.swnd-app .swnd-summary .row.total b { font-size: 20px; color: var(--accent); font-weight: 700; letter-spacing: -0.01em; }
.swnd-app .swnd-summary .row b { color: var(--ink); font-weight: 600; }
.swnd-app .cta {
    margin-top: 14px;
    width: 100%; height: 50px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--accent-ink);
    font-size: 15px; font-weight: 700; letter-spacing: -0.01em;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    box-shadow: 0 8px 20px -10px color-mix(in oklab, var(--accent) 70%, transparent);
    transition: transform 80ms ease, background 140ms ease;
  }
.swnd-app .cta:hover:not(:disabled) { background: color-mix(in oklab, var(--accent) 88%, #000); transform: scale(1.01); }
.swnd-app .cta:active { transform: scale(0.995); }
.swnd-app .cta:disabled { background: var(--surface-2); color: var(--ink-3); box-shadow: none; cursor: not-allowed; }
.swnd-app .cta .arrow { transition: transform 140ms ease; }
.swnd-app .cta:hover:not(:disabled) .arrow { transform: translateX(3px); }
.swnd-app .swnd-summary .micro {
    margin-top: 10px;
    font-size: 11px; color: var(--ink-3);
    display: flex; gap: 14px; flex-wrap: wrap; justify-content: center;
  }
.swnd-app .swnd-summary .micro span { display: inline-flex; align-items: center; gap: 5px; }
.swnd-app /* ---------- Toast ---------- */
  .toast {
    position: fixed; left: 50%; bottom: 28px;
    transform: translate(-50%, 12px);
    background: var(--toast-bg); color: var(--toast-ink);
    padding: 10px 16px; border-radius: 999px; font-size: 13px;
    opacity: 0; pointer-events: none;
    transition: opacity 200ms ease, transform 200ms ease;
    z-index: 50;
    box-shadow: var(--shadow-2);
  }
.swnd-app .toast.show { opacity: 1; transform: translate(-50%, 0); }
.swnd-app /* keyboard focus */
  button:focus-visible, .swnd-app input:focus-visible, .swnd-app .swatch-btn:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
  }
/* Short viewports: give the accordion room */
@media (max-height: 720px) {
    .swnd-app .swnd-summary .micro { display: none; }
    .swnd-app .swnd-summary { padding: 10px 26px 12px; }
    .swnd-app .swnd-summary .row { font-size: 12px; margin-bottom: 2px; }
    .swnd-app .swnd-summary .row.total { margin-top: 5px; padding-top: 7px; }
    .swnd-app .swnd-summary .row.total b { font-size: 17px; }
    .swnd-app .cta { height: 42px; margin-top: 8px; }
    .swnd-app .step-head { min-height: 46px; padding-top: 10px; padding-bottom: 10px; }
  }
/* ===== Mobile: horizontal step tabs, page scrolls, no sticky cart =====
 *
 * NOTE: data-mstep is set by designer.js on .swnd-app itself, not on <body>
 * (see openStep()). These selectors were written for the standalone prototype,
 * where the app WAS the document, and are retargeted here.
 */
@media (max-width: 960px) {
    .swnd-app .workspace { display: block; height: auto; overflow: visible; }
    .swnd-app .workspace .canvas-col { height: 44vh; min-height: 220px; padding: 0; border-bottom: 0; background: var(--surface); }
    .swnd-app .workspace .canvas-frame { width: 100%; max-width: none; height: 100%; aspect-ratio: auto; border-radius: 0; border: 0; box-shadow: none; }
    /* preview stays pinned in steps 1 & 2 so colour/style changes are visible live */
    .swnd-app[data-mstep="1"] .workspace .canvas-col,
    .swnd-app[data-mstep="2"] .workspace .canvas-col { position: sticky; top: var(--topbar-h, 0px); }
    .swnd-app .workspace .canvas-col { transition: none; }
    .swnd-app[data-mstep="1"].is-scrolled .workspace .canvas-col,
    .swnd-app[data-mstep="2"].is-scrolled .workspace .canvas-col { height: 35.2vh; }
    /* the step tab bar sticks directly beneath the pinned preview, so the
       current instruction is always legible while the cards scroll behind it */
    .swnd-app[data-mstep="1"] .step-head, .swnd-app[data-mstep="2"] .step-head { top: 44vh; }
    .swnd-app[data-mstep="1"].is-scrolled .step-head,
    .swnd-app[data-mstep="2"].is-scrolled .step-head { top: 35.2vh; }
    .swnd-app .main-image { padding: 4px 6px; }
    .swnd-app .canvas-chip { left: 10px; top: 10px; }
    .swnd-app .canvas-meta { right: 10px; bottom: 10px; }
    .swnd-app .workspace .rail { height: auto; overflow: visible; }
    .swnd-app .rail-scroll { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: auto auto; overflow: visible; }
    .swnd-app .step-block { display: contents; }
    .swnd-app .step-head {
      grid-row: 1; min-height: 66px; padding: 10px 6px; gap: 5px;
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      border-bottom: 2px solid var(--line); border-right: 1px solid var(--line);
      background: var(--surface-2);
      position: sticky; top: 0; z-index: 8;
    }
    .swnd-app .step-block:last-of-type .step-head { border-right: 0; }
    .swnd-app .step-block.is-open .step-head { background: var(--surface); border-bottom-color: var(--brand); }
    /* nudge: step 2 tab glows briefly after a style is picked */
    .swnd-app .step-block[data-step="2"]:not(.is-open) .step-head.is-nudged {
      background: color-mix(in oklab, var(--accent, #f07c1e) 20%, var(--surface));
      border-bottom-color: var(--accent, #f07c1e);
      transition: background 240ms ease, border-color 240ms ease;
    }
    .swnd-app .step-title { font-size: 12px; font-weight: 600; text-align: center; line-height: 1.2; text-wrap: balance; max-width: 100%; padding: 0 2px; }
    .swnd-app .step-status, .swnd-app .step-chev { display: none; }
    .swnd-app .step-num { width: 22px; height: 22px; font-size: 11px; }
    .swnd-app .step-panel { grid-row: 2; grid-column: 1 / -1; min-height: 0; }
    .swnd-app .step-block.is-open .step-body { overflow: visible; }
    .swnd-app .step-body-inner { padding: 14px 14px 20px; }
    .swnd-app .step-next { margin-top: 14px; }
    /* 2 across on mobile so the longer style names stay readable */
    .swnd-app .styles-grid { grid-template-columns: repeat(2, 1fr); }
    .swnd-app .necker-style .label { font-size: 12px; min-height: 0; }
    .swnd-app .necker-style .from { font-size: 12px; }
    /* step 2: one panel open at a time — pick a panel, pick a colour, move on */
    .swnd-app .step-block[data-step="2"] .step-body-inner { padding: 12px 12px 18px; }
    .swnd-app .step-block[data-step="2"] .step-body-inner > .sub { margin: 0 0 10px !important; font-size: 12px; }
    .swnd-app .sections-list { gap: 8px; }
    .swnd-app .section-card { padding: 0; border-radius: 10px; overflow: hidden; }
    .swnd-app .section-head { margin: 0; padding: 12px 14px; min-height: 48px; gap: 10px; cursor: pointer; }
    .swnd-app .section-head .name { font-size: 14px; }
    .swnd-app .section-head .hint { font-size: 12px; }
    .swnd-app .section-head .current-swatch { width: 20px; height: 20px; flex-basis: 20px; }
    .swnd-app .section-card:not(.is-active) .palette-grid { display: none; }
    .swnd-app .section-card.is-active { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
    .swnd-app .section-card.is-active .section-head { border-bottom: 1px solid var(--line); }
    .swnd-app .section-card.is-active .palette-grid {
      grid-template-columns: repeat(8, 1fr) !important; gap: 8px !important;
      padding: 12px 14px 14px;
    }
    .swnd-app .palette-grid .swatch-btn { border-radius: 7px; }
    .swnd-app .swnd-summary { position: static; box-shadow: none; }
  }


/* ============================================================================
 * EMBED ADAPTATION
 *
 * The prototype was a standalone full-viewport application: .workspace was
 * 100vh with overflow:hidden, and .canvas-col / .rail each scrolled internally.
 * Inside a WordPress page — with your header, nav and footer around it — that
 * clips content and produces a scroll-within-a-scroll.
 *
 * These overrides convert the shell to normal in-flow layout. Nothing visual
 * changes: same grid, same proportions, same sticky canvas and sticky summary.
 * The page scrolls instead of the rail.
 * ========================================================================== */

.swnd-app {
	min-height: 0;              /* was 100dvh — it is a section now, not a screen */
	background: transparent;    /* let the page background show through */
	max-width: 1440px;
	margin-inline: auto;
}

.swnd-app .workspace {
	height: auto;
	overflow: visible;
	/* stretch, not start: the preview column runs the full height of the rail so
	   the two columns end level. With `start` the preview stopped at its own
	   height and the options column visibly spilled past it. */
	align-items: stretch;
}

.swnd-app .canvas-col {
	height: auto;
	align-self: stretch;
	border-radius: var(--radius-lg, 16px);
}

.swnd-app .canvas-frame {
	aspect-ratio: 1 / 1;
	width: 100%;
}

/* Desktop only: the column fills the row, and the artwork inside it is what
   sticks. Pinning the column itself cannot work once it is full height — there
   is no slack for it to move in.
   MUST come after the `.canvas-frame { width: 100% }` rule above: same
   specificity, so source order decides, and a media query adds none. */
@media (min-width: 961px) {
	.swnd-app .canvas-col {
		position: static;
		align-items: flex-start;
		/* No padding at all. Horizontal padding is dead space beside an artwork that
		   is already capped to the column; the 32px of TOP padding started the
		   preview block lower than the options block beside it, so the two cards
		   did not line up. Both now begin at the top of the row. */
		padding: 0;
	}

	.swnd-app .canvas-frame {
		position: sticky;
		top: 16px;
		/* The frame is square, so on a wide column it can end up taller than the
		   screen — and an element taller than the viewport cannot stay pinned, it
		   drifts. Capping the WIDTH keeps it square while guaranteeing it fits. */
		width: min(100%, calc(100dvh - 48px));
		margin-inline: auto;
	}
}

.swnd-app .rail,
.swnd-app .rail-scroll {
	height: auto;
	overflow: visible;
}

.swnd-app .swnd-summary {
	position: sticky;
	bottom: 0;
	z-index: 3;
	background: var(--surface);
}

@media (max-width: 900px) {
	.swnd-app .canvas-col {
		position: sticky;
		top: 0;
		height: 46vh;
		min-height: 240px;
		z-index: 2;
	}
	.swnd-app .workspace { grid-template-columns: 1fr; }
	.swnd-app .rail { border-left: 0; }
}


/* Reflective is border-and-stripe only: shown but struck through, so the rule
   is legible rather than the swatch mysteriously missing. */
.swnd-app .swatch-btn:disabled { cursor: not-allowed; opacity: .28; }

.swnd-app .swatch-btn:disabled::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(to top left, transparent calc(50% - 1px), rgba(0,0,0,.6) 50%, transparent calc(50% + 1px));
}

/* The prototype's style thumbnails were <img>; these are inline SVG, so the same
   sizing rules are mirrored onto the svg element. */
.swnd-app .necker-style .thumb svg {
	width: 100%;
	height: 100%;
	display: block;
	object-fit: contain;
	pointer-events: none;
}

/* Busy state while the add-to-cart request is in flight. */
.swnd-app .cta.is-busy { opacity: .65; pointer-events: none; }


/* ============================================================================
 * PROGRESSIVE DISCLOSURE  (2026-08-11)
 *
 * The basket summary — the two size lines, the subtotal and Add to cart — is
 * only meaningful once sizes are being chosen. Shown at step 1 it reads as
 * £0.00 / £0.00 / disabled button and eats the most valuable vertical space
 * on the page, which on mobile is the space the style cards need.
 *
 * data-mstep is written to .swnd-app by designer.js openStep().
 * ========================================================================== */

.swnd-app .swnd-summary { display: none; }
.swnd-app[data-mstep="3"] .swnd-summary { display: block; }

/* Step 1 and 2 carry their own CTA instead, so there is always exactly one
   forward action on screen. Step 1's does not exist until a style is chosen. */
.swnd-app .step-next.is-hidden { display: none; }


/* ---------------------------------------------------------------------------
 * DOCKED STEP CTA
 *
 * The style grid is 20 cards tall. With the CTA as a normal last child, choosing
 * anything in row 1 meant scrolling past all 20 cards to reach Continue.
 *
 * position:sticky + bottom pins it to the bottom of the screen while there is
 * still grid below it, then lets it come to rest in the flow at the end. No
 * fixed positioning, so it stays inside the rail on desktop, cannot cover the
 * site footer, and needs no JS to place it.
 *
 * The gradient pad behind it stops cards showing through the rounded corners as
 * they scroll under.
 * ------------------------------------------------------------------------- */

.swnd-app .step-block[data-step="1"] .step-next,
.swnd-app .step-block[data-step="2"] .step-next {
	position: sticky;
	bottom: 12px;
	z-index: 7;
	box-shadow: 0 6px 20px -6px color-mix(in oklab, var(--brand) 55%, transparent),
	            0 0 0 12px var(--surface);
}

/* The pad is the point of the second shadow: the CTA sits over scrolling cards
   and swatches, so it needs opaque surface around it, not just behind it. When
   disabled it keeps the pad but loses the brand glow, which would read as
   "active". */
.swnd-app .step-block[data-step="1"] .step-next:disabled,
.swnd-app .step-block[data-step="2"] .step-next:disabled {
	box-shadow: 0 0 0 12px var(--surface);
}


/* The designer scrolls to its own top on every step change (scrollToApp() in
   designer.js). This is the offset it lands at — raise it if a sticky site
   header ever overlaps the preview. */
.swnd-app { scroll-margin-top: 8px; }


/* ============================================================================
 * QUANTITY STEPPER  (2026-08-11)
 *
 * Was white buttons on a near-white pill on a white card — three tones of white,
 * so the single most important control on step 3 read as decoration. It is now a
 * bordered well with brand-tinted circular buttons.
 * ========================================================================== */

.swnd-app .qty {
	background: var(--surface);
	border: 1.5px solid var(--line-2);
	box-shadow: inset 0 1px 3px color-mix(in oklab, var(--ink) 7%, transparent);
	padding: 4px;
	gap: 2px;
}

.swnd-app .qty button {
	background: color-mix(in oklab, var(--brand) 12%, var(--surface));
	border: 1px solid color-mix(in oklab, var(--brand) 28%, transparent);
	color: var(--brand);
	font-size: 19px;
	font-weight: 700;
	line-height: 1;
	box-shadow: none;
}

.swnd-app .qty button:hover:not(:disabled) {
	background: color-mix(in oklab, var(--brand) 22%, var(--surface));
	border-color: color-mix(in oklab, var(--brand) 45%, transparent);
}

.swnd-app .qty button:active:not(:disabled) { transform: scale(0.94); }

.swnd-app .qty button:disabled {
	background: var(--surface-2);
	border-color: transparent;
	color: var(--ink-3);
	opacity: 1;
}

.swnd-app .qty input {
	font-size: 16px;
	font-weight: 700;
	color: var(--ink);
	width: 46px;
}

/* NB: no `input[value="0"]` rule here. The attribute selector matches the markup
   attribute, which never changes — designer.js sets the value *property* — so it
   would mute the number at every quantity, not just zero. */


/* ============================================================================
 * ADD TO CART — BUSY SPINNER
 *
 * The request takes a while on this host (~3s while OPcache is off), and the
 * button previously just dimmed. It now shows a conventional spinner so it is
 * obviously working rather than broken.
 *
 * addToCart() sets disabled AND .is-busy, so the busy rules have to win over
 * :disabled or the button would go grey mid-request and read as dead.
 * ========================================================================== */

.swnd-app .cta { position: relative; }

.swnd-app .cta.is-busy,
.swnd-app .cta.is-busy:disabled {
	background: var(--accent);
	color: transparent;
	opacity: 1;
	cursor: progress;
	pointer-events: none;
}

.swnd-app .cta.is-busy .arrow { opacity: 0; }

.swnd-app .cta.is-busy::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 20px;
	height: 20px;
	margin: -10px 0 0 -10px;
	border: 2.5px solid color-mix(in oklab, var(--accent-ink) 35%, transparent);
	border-top-color: var(--accent-ink);
	border-radius: 50%;
	animation: swnd-spin 700ms linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
	.swnd-app .cta.is-busy::after {
		animation-duration: 2s;
	}
}


/* ============================================================================
 * MOBILE SURFACES  (2026-08-11)
 *
 * The preview panel, the step tabs and the panel body were all plain --surface,
 * so the whole thing read as one undifferentiated white sheet with a faint grid
 * floating in it. The preview now sits on a tinted gradient and both blocks are
 * rounded cards with a visible edge.
 *
 * No `overflow: hidden` on .rail to round it — that would make the rail a scroll
 * container and kill the sticky step tabs. Corners are rounded on the tab cells
 * themselves instead.
 * ========================================================================== */

@media (max-width: 960px) {

	/* --- preview --------------------------------------------------------- */

	.swnd-app .workspace .canvas-col {
		background: transparent;
		padding: 10px 12px 12px;
	}

	.swnd-app .workspace .canvas-frame {
		border-radius: 16px;
		border: 1px solid var(--line);
		box-shadow: 0 2px 10px -6px color-mix(in oklab, var(--ink) 30%, transparent);
		/* the tint the grid lines sit on, so the panel reads as its own surface */
		background:
			linear-gradient(170deg,
				color-mix(in oklab, var(--brand) 7%, var(--surface)) 0%,
				color-mix(in oklab, var(--brand) 3%, var(--surface)) 45%,
				var(--surface) 100%);
	}

	/* --- step block ------------------------------------------------------ */

	.swnd-app .workspace .rail {
		border: 1px solid var(--line);
		border-radius: 16px;
		background: var(--surface);
		margin: 0 12px 16px;
	}

	.swnd-app .step-block:first-of-type .step-head { border-top-left-radius: 15px; }
	.swnd-app .step-block:last-of-type  .step-head { border-top-right-radius: 15px; }

	/* the open panel is the bottom of the card, so it carries the bottom curve */
	.swnd-app .step-panel { border-bottom-left-radius: 15px; border-bottom-right-radius: 15px; }

	/* the tab bar sticks — it needs the card's own background behind it, not the
	   page's, or content shows through the rounded corners as it scrolls under */
	.swnd-app .step-head { background: var(--surface-2); }
}


/* ============================================================================
 * ROUND SEVEN  (2026-08-11)
 * ========================================================================== */

/* --- Desktop: no dead space beside the preview ----------------------------
 *
 * The grid was `1fr var(--rail-w)` with a fixed 380–460px rail, so the preview
 * column took every remaining pixel while the artwork inside it was capped at
 * `100dvh - 48px` — the difference showed as empty margin either side of the
 * artwork. The left column is now capped at the artwork's own maximum and the
 * rail takes ALL the remainder, so the space goes to the options instead.
 * ------------------------------------------------------------------------- */

@media (min-width: 961px) {
	.swnd-app .workspace {
		/* Two caps, both needed:
		   - `100dvh - 48px` keeps the square artwork inside the screen so it can
		     stay pinned.
		   - `52%` stops it eating the row on a short, narrow desktop. At 1024×768
		     the height cap alone gave the preview 720px and left the options 264px,
		     which is too narrow for three style cards.
		   The rail then takes everything that is left, so no width is wasted. */
		grid-template-columns: minmax(320px, min(calc(100dvh - 48px), 52%)) minmax(0, 1fr);
	}

	/* the column is already capped, so the frame simply fills it */
	.swnd-app .canvas-frame { width: 100%; }
}

/* --- Desktop: denser, more legible step 3 ---------------------------------
 *
 * On a now-wider rail the size rows stretched the full width, throwing the name
 * and the stepper to opposite edges with a void between them.
 * ------------------------------------------------------------------------- */

@media (min-width: 961px) {
	.swnd-app .step-block[data-step="3"] .step-body-inner { max-width: 620px; }

	.swnd-app .size-row {
		padding: 16px 18px;
		gap: 20px;
		border-radius: 12px;
	}

	.swnd-app .size-row .info .name { font-size: 16px; }
	.swnd-app .size-row .info .dims { font-size: 12px; margin-top: 1px; }
	.swnd-app .size-row .info .price { font-size: 14px; margin-top: 4px; }
	.swnd-app .size-row .info .price b { font-size: 16px; }

	.swnd-app .qty button { width: 38px; height: 38px; font-size: 21px; }
	.swnd-app .qty input { width: 54px; height: 38px; font-size: 17px; }
}

/* --- Mobile ---------------------------------------------------------------
 *
 * One variable drives the pinned preview's height and the offset the step tabs
 * stick at. They MUST agree — the tabs sit directly beneath the preview — and
 * previously the same two numbers were hardcoded in four places.
 *
 * 36vh (was 44vh) with the artwork box overhanging 11% top and bottom: the
 * drawing keeps the size it had at 44vh, and the empty space above and below it
 * is cropped instead of scrolled past. That is ~8vh of the screen handed back,
 * which is what stopped the quantity buttons being reachable without scrolling.
 * ------------------------------------------------------------------------- */

@media (max-width: 960px) {
	.swnd-app {
		--preview-h: 36vh;
		--preview-h-scrolled: 28.8vh;
	}

	.swnd-app .workspace .canvas-col {
		height: var(--preview-h);
		min-height: 180px;
		/* Transparent, and no radius.
		 *
		 * This column used to be tinted because it masked the style cards scrolling
		 * under the sticky preview. That was wrong: it is 12px wider than the frame
		 * on each side and carries its own radius, so it rendered as a second
		 * rounded card around the first, with its outer edges 12px off from the
		 * step block below.
		 *
		 * The mask is the FRAME, which is opaque and exactly the step block's width.
		 * Nothing ever scrolls through the 12px gutters — the cards live inside the
		 * step block — so there is nothing there to mask.
		 */
		background: transparent;
		border-radius: 0;
	}

	.swnd-app[data-mstep="1"].is-scrolled .workspace .canvas-col,
	.swnd-app[data-mstep="2"].is-scrolled .workspace .canvas-col {
		height: var(--preview-h-scrolled);
	}

	.swnd-app[data-mstep="1"] .step-head,
	.swnd-app[data-mstep="2"] .step-head { top: var(--preview-h); }

	.swnd-app[data-mstep="1"].is-scrolled .step-head,
	.swnd-app[data-mstep="2"].is-scrolled .step-head { top: var(--preview-h-scrolled); }

	/* Crop the dead space above and below the artwork. The neckerchief occupies
	   only the middle band of a 500×500 viewBox, so the box is grown past the
	   frame and the frame's overflow:hidden clips the surplus. The drawing does
	   not shrink — only the panel does. */
	.swnd-app .main-image {
		inset: -11% 0;
		padding: 8px 6px;
	}

	/* the rail card must paint over anything scrolling beneath it */
	.swnd-app .workspace .rail { background: var(--surface); }
}


/* ============================================================================
 * ROUND EIGHT  (2026-08-11)
 * ========================================================================== */

@media (min-width: 961px) {

	/* Breathing room at the page edges on a small desktop. Round seven took the
	   column padding to 0 to kill the dead space *inside* the preview column;
	   this puts a margin back at the outside edge, where it belongs. */
	.swnd-app { padding-inline: 20px; }

	/* ...and a gap between the two blocks, which the grid had at 0. */
	.swnd-app .workspace { gap: 20px; }

	/* The preview column was painting its own pale panel behind the artwork —
	   a second box around the block. The frame is the block; the column is just
	   the space it lives in. (Mobile is different: there the column has to stay
	   opaque because it masks the cards scrolling under the sticky preview.) */
	.swnd-app .canvas-col { background: transparent; }

	/* Match the preview's rounded card treatment on the options side. */
	.swnd-app .rail {
		border: 1px solid var(--line);
		border-radius: 16px;
		background: var(--surface);
		overflow: clip;
	}
}

@media (max-width: 960px) {

	/* Drop the top/bottom band around the preview — the frame fills the column
	   and only the side gutters remain, which line up with the rail card's own
	   margins so it reads as one consistent gutter rather than a box. */
	.swnd-app .workspace .canvas-col { padding: 0 12px; }

	/* Gap between the preview block and the step block. */
	.swnd-app .workspace .rail { margin-top: 12px; }
}


/* ============================================================================
 * CANVAS META — PROGRESS  (2026-08-11)
 *
 * Was: style name | n colours | Reset colours. The style name duplicated the
 * chip sitting top-left of the same artwork, so it is gone; what is left tells
 * the customer how far through the design they are.
 * ========================================================================== */

.swnd-app .meta-progress {
	display: flex;
	align-items: center;
	gap: 9px;
	min-width: 0;
}

.swnd-app .progress-track {
	position: relative;
	width: 64px;
	height: 6px;
	flex: none;
	border-radius: 999px;
	background: color-mix(in oklab, var(--ink) 12%, var(--surface));
	overflow: hidden;
}

.swnd-app .progress-fill {
	display: block;
	width: 0;
	height: 100%;
	border-radius: inherit;
	background: var(--brand);
	transition: width 260ms cubic-bezier(0.16, 1, 0.3, 1), background 200ms ease;
}

.swnd-app .meta-progress.is-complete .progress-fill { background: var(--color-success, #1f8a5b); }

.swnd-app .progress-label {
	font-variant-numeric: tabular-nums;   /* stops the bar jittering as digits change */
	white-space: nowrap;
	color: var(--ink-2);
}

.swnd-app .meta-progress.is-complete .progress-label {
	color: var(--color-success, #1f8a5b);
	font-weight: 600;
}

@media (max-width: 960px) {
	.swnd-app .progress-track { width: 52px; }
}

@media (prefers-reduced-motion: reduce) {
	.swnd-app .progress-fill { transition: none; }
}


/* ============================================================================
 * DESKTOP: STICKY STEP HEADER  (2026-08-11)
 *
 * The instruction ("1 Choose a style") scrolled away with the options, so once
 * you were into the style grid nothing on screen said what you were doing. It
 * now pins to the top of the screen and the options scroll underneath it —
 * the same behaviour the mobile tab bar already had.
 *
 * The rail carries `overflow: clip`, NOT `hidden`: clip rounds the card's
 * corners without making the rail a scroll container, so sticky descendants
 * still resolve against the viewport. `hidden` here would silently un-stick
 * both this header and the docked step CTA.
 * ========================================================================== */

@media (min-width: 961px) {
	.swnd-app .step-head {
		position: sticky;
		top: 0;
		z-index: 9;
		/* opaque: the style cards scroll directly beneath it */
		background: var(--surface);
		border-bottom: 1px solid var(--line);
	}

	.swnd-app .step-block.is-open .step-head {
		box-shadow: 0 6px 14px -12px color-mix(in oklab, var(--ink) 60%, transparent);
	}

	/* Closed steps stack beneath the open one; keeping them all at top:0 would
	   pile them on top of each other, so they sit in document order instead. */
	.swnd-app .step-block:not(.is-open) .step-head { position: static; }
}


/* ============================================================================
 * ROUND ELEVEN  (2026-08-11)
 * ========================================================================== */

/* The CTA is always present now, so `.is-hidden` is no longer applied by the JS.
   Kept as a no-op guard rather than deleted, in case markup elsewhere sets it. */


/* --- Desktop: clearance under the sticky step header ---------------------- */

@media (min-width: 961px) {
	.swnd-app .step-body-inner { padding-top: 16px; }

	/* softened: it was reading as a hard edge right above the first line */
	.swnd-app .step-block.is-open .step-head {
		box-shadow: 0 4px 10px -10px color-mix(in oklab, var(--ink) 45%, transparent);
	}
}

/* --- Delivery estimate ---------------------------------------------------- */

.swnd-app .delivery-note {
	margin: -6px 0 14px;
	font-size: 12px;
	line-height: 1.4;
	color: var(--ink-2);
	display: flex;
	align-items: center;
	gap: 6px;
}

.swnd-app .delivery-note::before {
	content: '';
	width: 6px;
	height: 6px;
	flex: none;
	border-radius: 50%;
	background: var(--color-success, #1f8a5b);
}


/* ============================================================================
 * ROUND TWELVE  (2026-08-11)
 * ========================================================================== */

/* --- Mobile step CTA: sticky INSIDE its container -------------------------
 *
 * Reverted from `position: fixed`. Sticky is the behaviour actually wanted: the
 * button holds at the bottom of the screen while there is still content below it
 * in the step, and once you reach the end of the step it releases and scrolls
 * away with the page. Fixed could not do that — it hovered over everything,
 * which is what put a sliver of the next section above it.
 *
 * The `.is-away` guard and the gradient scrim are both gone with it: a sticky
 * element cannot escape its own container, so there is nothing to hide and
 * nothing to fade. Two moving parts removed.
 *
 * Step 3 is deliberately untouched — flat scrolling there.
 * ------------------------------------------------------------------------- */

@media (max-width: 960px) {
	.swnd-app .step-block[data-step="1"] .step-next,
	.swnd-app .step-block[data-step="2"] .step-next {
		position: sticky;
		bottom: calc(12px + env(safe-area-inset-bottom, 0px));
		left: auto;
		right: auto;
		width: 100%;
		z-index: 7;
	}

	/* the flow reserve the fixed bar needed is no longer required — sticky
	   occupies its own space at the end of the content */
	.swnd-app .step-block[data-step="1"] .step-body-inner,
	.swnd-app .step-block[data-step="2"] .step-body-inner {
		padding-bottom: 20px;
	}
}

/* --- Fact pills: minimum quantity + delivery ------------------------------ */

.swnd-app .fact-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0 0 14px;
}

.swnd-app .fact-pills .pill {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 6px 12px;
	border-radius: 999px;
	font-size: 12px;
	font-weight: 600;
	line-height: 1;
	background: var(--surface-2);
	color: var(--ink-2);
	border: 1px solid var(--line);
	white-space: nowrap;
}

/* Delivery carries more weight than the minimum — it answers "when do we get
   them", which is the question that stalls a group order. */
.swnd-app .fact-pills .pill-delivery {
	background: color-mix(in oklab, var(--color-success, #1f8a5b) 10%, var(--surface));
	border-color: color-mix(in oklab, var(--color-success, #1f8a5b) 28%, transparent);
	color: color-mix(in oklab, var(--color-success, #1f8a5b) 80%, var(--ink));
}

.swnd-app .fact-pills .pill-delivery::before {
	content: '';
	width: 7px;
	height: 7px;
	flex: none;
	border-radius: 50%;
	background: var(--color-success, #1f8a5b);
	animation: swnd-pulse 2.4s ease-in-out infinite;
}

@keyframes swnd-pulse {
	0%, 100% { opacity: 1;   box-shadow: 0 0 0 0 color-mix(in oklab, var(--color-success, #1f8a5b) 55%, transparent); }
	50%      { opacity: .75; box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-success, #1f8a5b) 0%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
	.swnd-app .fact-pills .pill-delivery::before { animation: none; }
}

/* --- Back to designer ----------------------------------------------------- */

.swnd-app .back-to-designer {
	position: fixed;
	right: 16px;
	bottom: calc(16px + env(safe-area-inset-bottom, 0px));
	z-index: 40;
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 11px 16px;
	border-radius: 999px;
	background: var(--brand);
	color: var(--brand-ink);
	font-size: 13px;
	font-weight: 700;
	box-shadow: 0 8px 22px -8px color-mix(in oklab, var(--ink) 55%, transparent);
	animation: swnd-rise 180ms ease-out;
}

.swnd-app .back-to-designer[hidden] { display: none; }

@keyframes swnd-rise {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
	.swnd-app .back-to-designer { animation: none; }
}

/* ===========================================================================
   Desktop: even columns, and the PAGE scrolls the options
   ---------------------------------------------------------------------------
   Two requirements that pull against each other:
     1. Both blocks the same height — no tall rail beside a short preview.
     2. Scrolling the page must move through all the style options before the
        page carries on past the designer.

   v1.21.0 solved (1) by containing the rail and giving it its own scrollbar.
   That broke (2): the designer became one short section the page slid straight
   past, and the options scrolled only when the pointer was over the rail.

   This solves both without either. The rail keeps its natural height, so the
   options ARE page content and the page has to travel through them. The preview
   PANEL is the column rather than the square frame, so it is exactly as tall as
   the rail beside it, and the artwork stays sticky inside it.

   Measured on /product/design-scout-neckerchief at 1200x745:
   column 1765, rail 1765, frame 593 pinned at top 16 through a 769px scroll.

   Do NOT reintroduce overflow-y on .rail-scroll — that is what took the page
   scroll away. And .canvas-col uses overflow: clip, never hidden, or the frame
   inside it stops being sticky.
   =========================================================================== */
@media (min-width: 961px) {
	/* Undo the containment: the page scrolls the options again. */
	.swnd-app .rail {
		height: auto;
		min-height: 0;
		display: flex;
		flex-direction: column;
		overflow: clip;
	}
	.swnd-app .rail-scroll {
		flex: 0 0 auto;
		min-height: 0;
		overflow: visible;
	}

	/* Step blocks keep their natural height. .rail-scroll is a flex column, so
	   without this the open block is allowed to SHRINK, and its style grid paints
	   straight over the closed step heads below it. */
	.swnd-app .rail-scroll > .step-block { flex: 0 0 auto; }

	/* The preview panel is the COLUMN, pinned at viewport height.
	   
	   Round eighteen made the column stretch to the rail's full height so the two
	   sides matched. They did — 1765 and 1765 — but the artwork is only 593 tall,
	   so the panel carried 1,171px of empty white below it. "Same height" has to
	   mean level ON SCREEN, not equal document height.
	   
	   Pinned at exactly one viewport instead: the panel is always full, always
	   level with the options beside it, and the options still scroll the page.
	   Measured at 1200x744: column 712 (= 744 - 32), artwork 593 centred in it.
	   
	   align-self: start is required. The grid stretches items by default, and an
	   item stretched to the row height has no slack left to stick in.
	   
	   Specificity note: this needs .workspace in the selector to beat an earlier
	   `.swnd-app .canvas-col { height: auto; align-self: stretch }`, which would
	   otherwise win on source order and silently undo the whole rule. */
	.swnd-app .workspace .canvas-col {
		position: sticky;
		top: 16px;
		align-self: start;
		height: calc(100dvh - 32px);
		min-height: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		padding: 0;
		background: var(--surface);
		border: 1px solid var(--line);
		border-radius: 16px;
		overflow: clip;
	}

	/* The frame is no longer the panel — the column is — so it goes transparent,
	   and is capped to fit inside the pinned panel while staying square. */
	.swnd-app .workspace .canvas-frame {
		position: static;
		background: transparent;
		border: 0;
		box-shadow: none;
		width: min(100%, calc(100dvh - 72px));
	}

	/* Clearance for the docked CTA.
	   
	   The button stays docked while ANY content remains below it in the step, so
	   it sits over the style grid. With only 22px of padding the bottom row could
	   never be scrolled clear of it — measured 54px of permanent overlap, which
	   made the last two styles impossible to see properly.
	   
	   96px is the button (42) + its offset (12) + its pad (12) + a visible gap.
	   Re-measured after: the last card clears the button by 16px. */
	.swnd-app .step-block.is-open .step-body-inner {
		padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
	}

	/* Fade cards into the docked button instead of slicing them mid-row.
	   On ::before at bottom:100% it sits ABOVE the button, outside its box — a
	   pseudo-element positioned OVER the button would paint on top of its own
	   background, which is why round fifteen put the scrim on the rail. */
	.swnd-app .step-next::before {
		content: '';
		position: absolute;
		left: 0;
		right: 0;
		bottom: 100%;
		height: 28px;
		background: linear-gradient(to top, var(--surface), rgba(255, 255, 255, 0));
		pointer-events: none;
	}

	/* Step 3: .swnd-summary sits outside .step-body-inner, so the 620px cap never
	   reached it and the subtotal and Add to cart overhung the size cards. */
	.swnd-app .swnd-summary {
		position: static;
		max-width: 620px;
	}
}
