/* ==========================================================================
   OLLILY — base layer
   --------------------------------------------------------------------------
   Design tokens and the shared component primitives, in one file on purpose.

   They used to be sf-tokens.css + sf-ui.css, referenced separately by four
   surfaces (dw-init for the site, and each builder's own <head>). The version
   strings drifted: three surfaces were still pinned to sf-ui.css?v=2 while the
   newsletter builder had moved to ?v=3, so most of the product was serving a
   stale copy of the shared layer. One file, one version, cannot drift.

   Load order everywhere: this file first, then whatever that surface adds.
   ========================================================================== */

/* ---------- 1 · Design tokens ---------- */
:root{
  /* ======================================================================
     Carbon Design System v11 — Gray 10 (g10) theme.
     Values are Carbon's own token values, expressed under the --sf-*
     names the product already reads. Changing them here restyles every
     surface: shell, dashboards, features and builders.
     ====================================================================== */

  /* ---- neutral ramp ----------------------------------- Carbon greys --- */
  --sf-c-ink:#161616;          /* text-primary                              */
  --sf-c-text:#525252;         /* text-secondary                            */
  --sf-c-muted:#6f6f6f;        /* text-helper                               */
  --sf-c-faint:#a8a8a8;        /* text-placeholder, disabled                */
  --sf-c-line:#e0e0e0;         /* border-subtle-01                          */
  --sf-c-line-soft:#e8e8e8;    /* border-subtle-00                          */
  --sf-c-hover:#e8e8e8;        /* layer-hover-01                            */
  --sf-c-soft:#f4f4f4;         /* layer-02 / field-02                       */
  --sf-c-canvas:#f4f4f4;       /* background                                */
  --sf-c-surface:#ffffff;      /* layer-01                                  */
  --sf-c-bg-soft:#f4f4f4;      /* background — the ground a surface sits on */
  --sf-c-strong:#8d8d8d;       /* border-strong-01                          */

  /* ---- brand → Carbon interactive blue ---------------------------------
     Carbon has no decorative brand colour: blue IS the interactive colour. */
  --sf-c-brand:#0f62fe;        /* interactive / link-primary                */
  --sf-c-brand-2:#0043ce;      /* button-primary-hover                      */
  --sf-c-maroon:#002d9c;       /* blue-80, for deep brand fills             */
  --sf-c-blush:#edf5ff;        /* blue-10, tinted surface                   */
  --sf-c-grad:linear-gradient(#0f62fe,#0f62fe);  /* flat: Carbon has no gradients */

  /* ---- accent (interactive text, selection, focus) ---------------------- */
  --sf-c-accent:#0f62fe;
  --sf-c-accent-ink:#0043ce;   /* link-primary-hover / support-info         */
  --sf-c-accent-soft:#edf5ff;
  --sf-c-accent-line:#a6c8ff;  /* blue-30                                   */

  /* ---- status ------------------------------------------ Carbon support - */
  --sf-c-ok:#24a148;      --sf-c-ok-soft:#defbe6;   --sf-c-ok-line:#a7f0ba;
  --sf-c-warn:#8e6a00;    --sf-c-warn-soft:#fcf4d6; --sf-c-warn-line:#f1c21b;
  --sf-c-danger:#da1e28;  --sf-c-danger-ink:#a2191f;
  --sf-c-danger-soft:#fff1f1; --sf-c-danger-line:#ffd7d9;
  --sf-c-dark:#161616;    /* primary buttons: Carbon uses blue, this is the
                             neutral/ghost-inverse fill                     */

  /* ---- spacing ------------------------------------ Carbon spacing scale -
     01 2px · 02 4px · 03 8px · 04 12px · 05 16px · 06 24px · 07 32px
     08 40px · 09 48px · 10 64px                                           */
  --sf-s-1:4px;  --sf-s-2:8px;  --sf-s-3:12px; --sf-s-4:16px;
  --sf-s-5:24px; --sf-s-6:24px; --sf-s-8:32px; --sf-s-10:40px;
  --sf-s-05:2px; --sf-s-9:48px; --sf-s-12:64px;

  /* ---- radius ------------------------------------------------------------
     Carbon is square. Only tags and avatars are round.                     */
  --sf-r-xs:0; --sf-r-sm:0; --sf-r-md:0; --sf-r-lg:0;
  --sf-r-xl:0; --sf-r-2xl:0; --sf-r-pill:999px;

  /* ---- elevation ---------------------------------------------------------
     Carbon separates with borders, not shadows. Only floating layers cast. */
  --sf-e-raised:none;
  --sf-e-overlay:0 2px 6px rgba(0,0,0,.2);
  --sf-e-modal:0 4px 12px rgba(0,0,0,.25);
  --sf-e-focus:0 0 0 2px #0f62fe;      /* Carbon focus is a solid 2px ring  */
  --sf-e-focus-brand:0 0 0 2px #0f62fe;

  /* ---- motion ------------------------------------------- Carbon motion --
     Productive easing and durations.                                       */
  --sf-ease:cubic-bezier(.2,0,.38,.9);        /* standard, productive       */
  --sf-ease-entrance:cubic-bezier(0,0,.38,.9);
  --sf-ease-exit:cubic-bezier(.2,0,1,.9);
  --sf-t-fast:.11s;   /* fast-02:    hover, colour        */
  --sf-t-base:.15s;   /* moderate-01: menus, fades        */
  --sf-t-slow:.24s;   /* moderate-02: layout, panel width */

  /* ---- typography ---------------------------------------- IBM Plex Sans -
     Carbon type scale: label-01 12/16 · body-compact-01 14/18
     heading-02 16/22 · heading-03 20/28 · heading-04 28/36                 */
  --sf-font:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
  --sf-font-mono:"IBM Plex Mono",ui-monospace,monospace;
  --sf-fs-xs:12px; --sf-fs-sm:12px; --sf-fs-md:14px;
  --sf-fs-lg:16px; --sf-fs-xl:20px;  --sf-fs-2xl:28px;
  --sf-lh-tight:1.4; --sf-lh-body:1.43;
  --sf-fw-med:400; --sf-fw-semi:600; --sf-fw-bold:600;
  --sf-track-tight:0; --sf-track-caps:.32px;

  /* ---- icons (Lucide) ----------------------------------------------------
     Carbon's icon sizes are 16/20/24/32 with a 1.5px optical stroke.       */
  --sf-icon-sm:16px; --sf-icon-md:16px; --sf-icon-lg:20px; --sf-icon-xl:24px;
  --sf-icon-stroke:1.5;

  /* ---- breakpoints -------------------------------------------------------
     Two, and only two. The product had reached twenty-two distinct max-width
     values between 520px and 1560px — ten of them inside the 900–1180 band
     alone — which is not a responsive system, it is twenty-two independent
     guesses. Everything now moves at one of these:

       md 900px  a two-column layout becomes one; a table stops being a table
       sm 640px  a row becomes a stack; controls go full-width

     A media query cannot read a custom property, so these are declarations of
     intent that `node tools/ds-lint.mjs` enforces against the stylesheets.
     Anything that genuinely needs a third value states why in a comment on
     the query, which is what the lint reads.                               */
  --sf-bp-md:900px;
  --sf-bp-sm:640px;

  /* ---- dark scheme, opted into ------------------------------------------
     The ramp above is light and the product does not flip wholesale: the
     dashboard stays light in dark mode while the events workspace and the
     socials studio go dark, because they are canvases rather than pages.

     That is a real product decision, but it was implemented by copying the
     same fourteen declarations into events.css and again — twice, against two
     selectors — into studio.css. Three copies of one palette, and a comment in
     events.css saying so.

     The values now live here once. A surface opts in by adding `sf-scheme-dark`
     to its root element, and the rebinding follows the theme rather than the
     surface deciding what dark means.                                       */
  /* ======================================================================
     Carbon Design System v11 — Gray 100 (g100), for the navigation chrome.
     --------------------------------------------------------------------
     The app runs a dark sidebar and top bar over a light canvas, so the
     chrome needs its own theme rather than the page's. These are Carbon's
     own g100 values; the whole navigation reads them and nothing else, so
     retheming the chrome means editing this block alone.

     Declared on :root, not on the nav, because the rail tooltip mounts on
     <body> — a nav-scoped variable is invisible to it.

     **Brand black — 18 August 2026.** The navigation ground is the brand's
     own black, read from `--sf-c-ink` rather than written here as a literal.
     `app/shared/brand.css` maps `--brand-ink` to the same token, so the rail
     and the wordmark are the same black by construction — and a future brand
     palette moves both together instead of leaving one behind.

     The fallback is #161616, Carbon gray-100, which is what the token
     resolves to today. Everything else is the g100 scale unchanged: those
     text and layer values were tuned against exactly this ground.

     The variable names never change. Every rule that reads them — forty in
     shell.css alone — is untouched by a retheme, which is the whole reason
     this block exists.

     Contrast on --sf-nav-bg (#161616):
       ink #f4f4f4 16.1:1 · text #c6c6c6 10.0:1 · muted #8d8d8d 4.7:1
       link #78a9ff 7.4:1 · focus #fff 18.1:1
     Every value clears AA. `audit-a11y` checks this mechanically — it is not
     a claim, it is enforced.
     ====================================================================== */
  --sf-nav-bg:var(--sf-c-ink, #161616);     /* brand black                  */
  --sf-nav-layer:#161616;          /* layer-01: fields, menus               */
  --sf-nav-layer-2:#262626;        /* layer-02: tooltips, raised surfaces   */
  --sf-nav-hover:#262626;          /* layer-hover-01                        */
  --sf-nav-pressed:#393939;        /* layer-active-01                       */
  --sf-nav-selected:#262626;       /* layer-selected-01                     */
  --sf-nav-line:#262626;           /* border-subtle-01                      */
  --sf-nav-line-strong:#6f6f6f;    /* border-strong-01                      */
  --sf-nav-ink:#f4f4f4;            /* text-primary, icon-primary            */
  --sf-nav-text:#c6c6c6;           /* text-secondary, icon-secondary        */
  --sf-nav-muted:#8d8d8d;          /* text-helper                           */
  --sf-nav-placeholder:#6f6f6f;    /* text-placeholder                      */
  --sf-nav-disabled:rgba(244,244,244,.25);  /* text/icon-disabled           */
  --sf-nav-link:#78a9ff;           /* link-primary (blue-40)                */
  --sf-nav-focus:#ffffff;          /* focus — white on dark, per Carbon     */
  --sf-nav-on-brand:#ffffff;       /* text-on-color                         */

  /* Brand blue stays the primary action colour: white on #0f62fe is 4.6:1.
     As a mark ON the dark surface it is only 2.4:1, so indicators and
     selected text step up to blue-50, which is the same hue at 5.1:1.     */
  --sf-nav-brand:#0f62fe;          /* button-primary                        */
  --sf-nav-brand-hover:#0353e9;    /* button-primary-hover                  */
  --sf-nav-brand-active:#002d9c;   /* button-primary-active                 */
  --sf-nav-accent:#4589ff;         /* border-interactive (blue-50)          */
  --sf-nav-accent-soft:rgba(69,137,255,.16);
  --sf-nav-overlay:rgba(0,0,0,.65);
  --sf-nav-shadow:0 18px 42px -18px rgba(0,0,0,.7);

  /* ----------------------------------------------------------------------
     Top bar — Carbon g10, white.
     The two chrome surfaces are themed separately on purpose: the sidebar is
     g100, the top bar stays white, and each one's controls read the set that
     matches the surface they sit on. A menu takes the tokens of the surface
     it hangs off, so the sidebar's New menu is dark and the top bar's profile
     menu is light.

     Contrast on --sf-top-bg (#ffffff):
       ink #161616 16.1:1 · text #525252 7.6:1 · muted #6f6f6f 5.0:1
       brand #0f62fe 4.6:1 · focus #0f62fe 4.6:1
     ---------------------------------------------------------------------- */
  --sf-top-bg:#ffffff;             /* layer-01                              */
  --sf-top-layer:#f4f4f4;          /* layer-02: fields, menus, pills        */
  --sf-top-hover:#e8e8e8;          /* layer-hover-01                        */
  --sf-top-pressed:#d1d1d1;        /* layer-active-01                       */
  --sf-top-selected:#e0e0e0;       /* layer-selected-01                     */
  --sf-top-line:#e0e0e0;           /* border-subtle-01                      */
  --sf-top-line-strong:#8d8d8d;    /* border-strong-01                      */
  --sf-top-ink:#161616;            /* text-primary, icon-primary            */
  --sf-top-text:#525252;           /* text-secondary, icon-secondary        */
  --sf-top-muted:#6f6f6f;          /* text-helper                           */
  --sf-top-disabled:rgba(22,22,22,.25);
  --sf-top-focus:#0f62fe;          /* focus — blue on light, per Carbon     */
  --sf-top-brand:#0f62fe;
  --sf-top-brand-hover:#0353e9;
  --sf-top-brand-active:#002d9c;
  --sf-top-on-brand:#ffffff;
  --sf-top-shadow:0 20px 46px -20px rgba(0,0,0,.28);
}

/* Carbon g90, expressed under the same names the light ramp uses, so every
   rule written against a token keeps working rather than needing a twin. */
:root[data-theme="dark"] .sf-scheme-dark{
  --sf-c-surface:#262626;      /* layer-01                                  */
  --sf-c-canvas:#161616;       /* background                                */
  --sf-c-soft:#393939;         /* layer-02                                  */
  --sf-c-hover:#353535;        /* layer-hover-01                            */
  --sf-c-line:#393939;         /* border-subtle-01                          */
  --sf-c-line-soft:#333333;    /* border-subtle-00                          */
  --sf-c-ink:#f4f4f4;          /* text-primary                              */
  --sf-c-text:#c6c6c6;         /* text-secondary                            */
  --sf-c-muted:#a8a8a8;        /* text-helper                               */
  --sf-c-faint:#8d8d8d;        /* text-placeholder                          */
  --sf-c-blush:#001d6c;        /* blue-90, tinted surface                   */
  --sf-c-accent:#78a9ff;       /* blue-40: 7.4:1 on #262626                 */
  --sf-c-accent-soft:#001d6c;
  --sf-c-accent-ink:#a6c8ff;
  --sf-c-danger-soft:#520408;
  --sf-c-danger-ink:#ff8389;
  --sf-c-ok:#42be65;
  --sf-c-warn:#fddc69;
  --sf-c-strong:#6f6f6f;
}


/* ==========================================================================
   Carbon base layer
   The compiled bundle in /_next still declares Inter and the old Ollily
   ink on the document elements. It loads before this file, so restating the
   base here is what makes the Carbon typeface and greys apply site-wide.
   ========================================================================== */
html,body{
  font-family:var(--sf-font);
  color:var(--sf-c-ink);
  background:var(--sf-c-surface);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
body{
  font-size:var(--sf-fs-md);      /* body-compact-01 · 14px            */
  line-height:var(--sf-lh-body);  /* 1.43                              */
  letter-spacing:.16px;           /* Carbon body tracking              */
  font-weight:400;
}
/* Carbon headings are semibold with no negative tracking. */
h1,h2,h3,h4,h5,h6{
  font-family:var(--sf-font);
  font-weight:var(--sf-fw-semi);
  letter-spacing:0;
  color:var(--sf-c-ink);
}
h1{font-size:var(--sf-fs-2xl);line-height:1.29}   /* heading-04 28/36 */
h2{font-size:var(--sf-fs-xl);line-height:1.4}     /* heading-03 20/28 */
h3{font-size:var(--sf-fs-lg);line-height:1.375}   /* heading-02 16/22 */
h4,h5,h6{font-size:var(--sf-fs-md);line-height:1.29}
button,input,select,textarea{font-family:var(--sf-font);letter-spacing:.16px}

/* Carbon focus: a solid 2px ring, never a soft glow. */
:focus-visible{outline:2px solid var(--sf-c-accent);outline-offset:-2px}

/* Carbon tags keep their pill; everything else is square. */
.sfnl-badge,.sfnl-pill,.st-chip,.st-meta-badge,.sfct-tag,.sf-tag{
  border-radius:var(--sf-r-pill);
}


/* ==========================================================================
   Lucide baseline — every icon in the product is one of these, drawn the
   same way. Component CSS only ever overrides the size.
   ========================================================================== */
.lucide{
  width:var(--sf-icon-md);
  height:var(--sf-icon-md);
  flex:none;
  fill:none;
  stroke:currentColor;
  stroke-width:var(--sf-icon-stroke);
  stroke-linecap:round;
  stroke-linejoin:round;
  vertical-align:middle;
}
.lucide-sm{width:var(--sf-icon-sm);height:var(--sf-icon-sm)}
.lucide-lg{width:var(--sf-icon-lg);height:var(--sf-icon-lg)}
.lucide-xl{width:var(--sf-icon-xl);height:var(--sf-icon-xl)}
/* a few Lucide glyphs carry intentional solid dots — keep them filled */
.lucide [fill="currentColor"]{fill:currentColor;stroke:none}

@media (prefers-reduced-motion:reduce){
  :root{--sf-t-fast:0s;--sf-t-base:0s;--sf-t-slow:0s}
}


/* ---------- 2 · Shared component primitives ---------- */
/* ==========================================================================
   1 · Colour picker — ONE component, used by the studio, the builders and
   Creator. Previously: .st-color plus two bare input[type=color] treatments.
   ========================================================================== */
.sf-color,
.st-color,
html.sfb .fld .sf-color,
html.sfb .field .sf-color{
  display:flex;
  align-items:center;
  gap:var(--sf-s-2);
}
.sf-color > input[type=color],
.st-color > input[type=color],
html.sfb .fld input[type=color],
html.sfb .field input[type=color],
html.sfb .inp[type=color]{
  width:34px;
  height:34px;
  flex:none;
  padding:0;
  border:1px solid var(--sf-c-line);
  border-radius:0;
  background:var(--sf-c-surface);
  cursor:pointer;
  transition:border-color var(--sf-t-fast) var(--sf-ease),box-shadow var(--sf-t-fast) var(--sf-ease);
}
.sf-color > input[type=color]:hover,
.st-color > input[type=color]:hover,
html.sfb .fld input[type=color]:hover,
html.sfb .field input[type=color]:hover{border-color:var(--sf-c-faint)}
.sf-color > input[type=color]::-webkit-color-swatch-wrapper,
.st-color > input[type=color]::-webkit-color-swatch-wrapper,
html.sfb input[type=color]::-webkit-color-swatch-wrapper{padding:3px}
.sf-color > input[type=color]::-webkit-color-swatch,
.st-color > input[type=color]::-webkit-color-swatch,
html.sfb input[type=color]::-webkit-color-swatch{border:0;border-radius:0}
/* the hex field beside the swatch reads as one control */
.sf-color > input[type=text],
.st-color .st-in{
  flex:1;
  min-width:0;
  font-family:var(--sf-font-mono);
  font-size:var(--sf-fs-sm);
  text-transform:uppercase;
}

/* ==========================================================================
   2 · Focus — one visible ring everywhere. This was previously inconsistent:
   some controls had none, which is the accessibility gap that mattered most.
   ========================================================================== */
.sf-appnav a:focus-visible,
.sf-appnav button:focus-visible,
.sf-appnav input:focus-visible,
.sf-appnav select:focus-visible,
/* tabindex="-1" is "focusable by script, not by tab" — the roving-heading
   pattern, where a flow moves focus to the new heading so a screen reader
   announces it. Ringing a heading nobody tabbed to reads as a rendering
   fault, so the ring applies to genuinely tabbable elements only. */
.sf-appnav [tabindex]:not([tabindex="-1"]):focus-visible,
.st a:focus-visible,
.st button:focus-visible,
.st input:focus-visible,
.st select:focus-visible,
.st-modal button:focus-visible,
.st-menu button:focus-visible,
.sfnl-menu button:focus-visible,
html.sfb .top button:focus-visible,
html.sfb .topbar button:focus-visible,
html.sfb .left button:focus-visible,
html.sfb .right button:focus-visible{
  outline:none;
  box-shadow:var(--sf-e-focus);
  border-radius:0;
}
/* brand surfaces keep the brand ring so it reads as deliberate */
.sf-pn-row:focus-visible,
.sfnl-railrow:focus-visible,
.st-railbtn:focus-visible{
  outline:none;
  box-shadow:var(--sf-e-focus-brand);
}

/* ==========================================================================
   3 · Disabled — one treatment, previously three different opacities
   ========================================================================== */
.sf-appnav button:disabled,
.st button:disabled,
.st-btn:disabled,
.st-icon:disabled,
.sfnl-primary[aria-disabled="true"],
html.sfb .tbtn:disabled,
html.sfb .tb-btn[disabled]{
  opacity:.4;
  cursor:default;
  pointer-events:none;
}

/* ==========================================================================
   4 · Loading — a single spinner + a busy state any button can adopt
   ========================================================================== */
.sf-spinner,
.st-spinner{
  width:16px;height:16px;flex:none;
  border:2px solid currentColor;
  border-top-color:transparent;
  border-radius:50%;
  opacity:.55;
  animation:sfSpin .7s linear infinite;
}
@keyframes sfSpin{to{transform:rotate(360deg)}}
[data-busy="true"]{position:relative;pointer-events:none;color:transparent!important}
[data-busy="true"]::after{
  content:"";
  position:absolute;
  left:50%;top:50%;
  width:16px;height:16px;
  margin:-8px 0 0 -8px;
  border:2px solid rgba(0,0,0,.25);
  border-top-color:var(--sf-c-accent);
  border-radius:50%;
  animation:sfSpin .7s linear infinite;
}
.st-btn.pri[data-busy="true"]::after,
.sfnl-primary[data-busy="true"]::after{border-color:rgba(255,255,255,.35);border-top-color:#fff}

/* ==========================================================================
   5 · Skeleton — one shimmer, previously three
   ========================================================================== */
.sf-sk,
.sfnl-skeleton .sk,
.sfnl-tsk .sk,
.st-sk{
  display:block;
  border-radius:0;
  background:linear-gradient(90deg,var(--sf-c-line-soft) 25%,var(--sf-c-soft) 37%,var(--sf-c-line-soft) 63%);
  background-size:400% 100%;
  animation:sfShimmer 1.4s ease infinite;
}
@keyframes sfShimmer{from{background-position:100% 50%}to{background-position:0 50%}}

/* ==========================================================================
   6 · Tooltip — one look, three call sites (nav rail, builder chrome, tables)
   ========================================================================== */
.sf-tip,.sfb-tip,.sfnl-tip{
  position:fixed;
  z-index:999;
  max-width:264px;
  padding:7px 10px;
  border-radius:0;
  background:var(--sf-c-ink);
  color:#fff;
  font-family:var(--sf-font);
  font-size:var(--sf-fs-sm);
  font-weight:var(--sf-fw-med);
  line-height:1.45;
  pointer-events:none;
  opacity:0;
  box-shadow:var(--sf-e-overlay);
  transition:opacity var(--sf-t-fast) var(--sf-ease),transform var(--sf-t-fast) var(--sf-ease);
}
.sf-tip.on,.sfb-tip.on,.sfnl-tip.on{opacity:1;transform:none}

/* ==========================================================================
   7 · Toast — one look, three call sites
   ========================================================================== */
.sf-toast,.sfnl-toast,.st-toast,html.sfb .toast{
  position:fixed;
  z-index:500;
  display:flex;
  align-items:center;
  gap:var(--sf-s-2);
  padding:11px 18px;
  border-radius:var(--sf-r-pill);
  background:var(--sf-c-ink);
  color:#fff;
  font-family:var(--sf-font);
  font-size:12px;
  font-weight:var(--sf-fw-med);
  box-shadow:var(--sf-e-overlay);
  transition:opacity var(--sf-t-base) var(--sf-ease),transform var(--sf-t-base) var(--sf-ease);
}

/* ==========================================================================
   8 · Overlay surfaces — menus and dialogs share two elevations, no others
   ========================================================================== */
.sfnl-menu,.st-menu,html.sfb .menu .pop{
  border:1px solid var(--sf-c-line);
  border-radius:0;
  background:var(--sf-c-surface);
  box-shadow:var(--sf-e-overlay);
}
.sfnl-modal-card,.st-card,html.sfb .modal .box,html.sfb .modal .card{
  border:1px solid var(--sf-c-line);
  border-radius:0;
  background:var(--sf-c-surface);
  box-shadow:var(--sf-e-modal);
}
/* cards that merely sit on the page never get more than the raised level */
.sfnl-tablewrap,.sfnl-tcard,.sfnl-card,.st-bcard,.st-scard{box-shadow:var(--sf-e-raised)}

/* ==========================================================================
   9 · Switch — one control (studio had one, the dashboard used a checkbox)
   ========================================================================== */
.sf-switch,.st-sw{
  position:relative;
  width:38px;height:22px;flex:none;
  border:0;
  border-radius:var(--sf-r-pill);
  background:#d0e2ff;
  transition:background var(--sf-t-base) var(--sf-ease);
}
.sf-switch::after,.st-sw::after{
  content:"";
  position:absolute;left:3px;top:3px;
  width:16px;height:16px;
  border-radius:50%;
  background:#fff;
  box-shadow:0 1px 3px rgba(0,0,0,.3);
  transition:transform var(--sf-t-base) var(--sf-ease);
}
.sf-switch.on,.st-sw.on{background:var(--sf-c-accent)}
.sf-switch.on::after,.st-sw.on::after{transform:translateX(16px)}

/* ==========================================================================
   10 · Empty / error states — one shape for all three call sites
   ========================================================================== */
.sf-state,.sfnl-state,.st-empty,.st-props-empty{
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
}
.sf-state-ic,.sfnl-state-ic{
  display:grid;
  place-items:center;
  width:52px;height:52px;
  margin-bottom:var(--sf-s-4);
  border-radius:0;
  background:var(--sf-c-accent-soft);
  color:var(--sf-c-accent);
}
.sf-state-ic .lucide,.sfnl-state-ic .lucide{width:24px;height:24px}
.sf-state.is-error .sf-state-ic,.sfnl-state.is-error .sfnl-state-ic{
  background:var(--sf-c-danger-soft);
  color:var(--sf-c-danger);
}

/* ==========================================================================
   11 · Icon sizing by context — set once instead of per component
   ========================================================================== */
.sf-top-icon .lucide,.st-icon .lucide,.sfb-btn .lucide{width:var(--sf-icon-lg);height:var(--sf-icon-lg)}
.sf-pn-ic .lucide,.sfnl-icon .lucide,.st-bcard .lucide{width:var(--sf-icon-lg);height:var(--sf-icon-lg)}
.sfnl-menu .mi .lucide,.st-menu .lucide,.st-bar .lucide{width:var(--sf-icon-sm);height:var(--sf-icon-sm)}
.sfnl-info .lucide{width:14px;height:14px}
.sfnl-filter .lucide,.st-seg .lucide,.sfnl-bulk .lucide{width:var(--sf-icon-sm);height:var(--sf-icon-sm)}

/* ==========================================================================
   12 · Motion — one duration scale; anything not listed inherits it
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .sf-sk,.sfnl-skeleton .sk,.sfnl-tsk .sk,.st-sk,
  .sf-spinner,.st-spinner,[data-busy="true"]::after{animation:none}
  .sf-tip,.sfb-tip,.sfnl-tip,.sf-toast,.sfnl-toast,.st-toast,
  .sf-switch,.st-sw,.sf-switch::after,.st-sw::after{transition:none}
}

/* ---- the colour component, in full ---------------------------------------
   Brand presets + a free picker + a hex field. The builders previously had
   presets only and the studio a free picker only; one control now does both. */
.sf-color{flex-wrap:wrap}
.sf-color-sw{
  width:22px;height:22px;flex:none;
  padding:0;
  border:1px solid rgba(0,0,0,.12);
  border-radius:0;
  cursor:pointer;
  transition:transform var(--sf-t-fast) var(--sf-ease),box-shadow var(--sf-t-fast) var(--sf-ease);
}
.sf-color-sw:hover{transform:scale(1.12)}
.sf-color-sw.on{box-shadow:0 0 0 2px var(--sf-c-surface),0 0 0 4px var(--sf-c-accent)}
.sf-color-hex{
  flex:1 1 90px;
  min-width:78px;
  height:34px;
  padding:0 9px;
  border:1px solid var(--sf-c-line);
  border-radius:0;
  background:var(--sf-c-surface);
  color:var(--sf-c-ink);
  font-family:var(--sf-font-mono);
  font-size:var(--sf-fs-sm);
  text-transform:uppercase;
}
.sf-color-hex:focus{outline:none;border-color:var(--sf-c-accent);box-shadow:var(--sf-e-focus)}
/* builders render this row inside .swatches — keep that selector working */
html.sfb .swatches{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
html.sfb .swatches .sw{
  width:22px;height:22px;
  border:1px solid rgba(0,0,0,.12);
  border-radius:0;
  cursor:pointer;
  transition:transform var(--sf-t-fast) var(--sf-ease),box-shadow var(--sf-t-fast) var(--sf-ease);
}
html.sfb .swatches .sw:hover{transform:scale(1.12)}
html.sfb .swatches .sw.on{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--sf-c-accent)}
html.sfb .swatches .hexin{
  flex:1 1 84px;min-width:74px;height:34px;padding:0 9px;
  border:1px solid var(--sf-c-line);border-radius:0;
  font-family:var(--sf-font-mono);font-size:var(--sf-fs-sm);text-transform:uppercase;
}

/* ==========================================================================
   Shared colour picker (see /design-system/components/colorpicker.js)
   The Creator builder's interaction model, in the product's own light chrome.
   ========================================================================== */
.sf-cp{
  position:fixed;z-index:9800;
  width:264px;padding:12px;
  border:1px solid var(--sf-c-line);
  border-radius:0;
  background:var(--sf-c-surface);
  box-shadow:var(--sf-e-overlay);
  font-family:var(--sf-font);
  color:var(--sf-c-ink);
  opacity:0;transform:translateY(-6px) scale(.985);
  transition:opacity var(--sf-t-base) var(--sf-ease),transform var(--sf-t-base) var(--sf-ease);
}
.sf-cp.on{opacity:1;transform:none}
.sf-cp-h{
  margin:2px 0 6px;
  color:var(--sf-c-muted);
  font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-bold);
  letter-spacing:var(--sf-track-caps);text-transform:uppercase;
}
.sf-cp-h + .sf-cp-h{margin-top:10px}
.sf-cp-row{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px;min-height:20px}
.sf-cp-sw{
  width:20px;height:20px;padding:0;
  border:0;border-radius:0;
  background-image:linear-gradient(45deg,#e0e0e0 25%,transparent 25%),linear-gradient(-45deg,#e0e0e0 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#e0e0e0 75%),linear-gradient(-45deg,transparent 75%,#e0e0e0 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;
  cursor:pointer;transition:transform var(--sf-t-fast) var(--sf-ease);
}
.sf-cp-sw > span{display:block;width:100%;height:100%;border-radius:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12)}
.sf-cp-sw:hover{transform:scale(1.14)}
.sf-cp-sw:focus-visible{outline:2px solid var(--sf-c-accent);outline-offset:2px}
.sf-cp-none{color:var(--sf-c-muted);font-size:var(--sf-fs-xs);line-height:20px}

.sf-cp-top{display:flex;gap:9px}
.sf-cp-sv{
  position:relative;flex:1;height:132px;
  border-radius:0;overflow:hidden;
  cursor:crosshair;touch-action:none;
}
.sf-cp-sv i{position:absolute;inset:0;pointer-events:none}
.sf-cp-sv i.w{background:linear-gradient(to right,#fff,rgba(255,255,255,0))}
.sf-cp-sv i.b{background:linear-gradient(to top,#000,rgba(0,0,0,0))}
.sf-cp-cur{
  position:absolute;width:13px;height:13px;
  border:2px solid #fff;border-radius:50%;
  transform:translate(-6.5px,-6.5px);
  box-shadow:0 0 0 1px rgba(0,0,0,.5);pointer-events:none;
}
.sf-cp-hue{
  position:relative;flex:none;width:15px;height:132px;
  border-radius:0;cursor:ns-resize;touch-action:none;
  background:linear-gradient(to bottom,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00);
}
.sf-cp-hh{
  position:absolute;left:-3px;right:-3px;height:4px;
  border:2px solid #fff;border-radius:0;transform:translateY(-4px);
  box-shadow:0 0 0 1px rgba(0,0,0,.45);pointer-events:none;
}
.sf-cp-alpha{
  position:relative;height:15px;margin-top:9px;
  border-radius:0;cursor:ew-resize;touch-action:none;
  background-image:linear-gradient(45deg,#e0e0e0 25%,transparent 25%),linear-gradient(-45deg,#e0e0e0 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#e0e0e0 75%),linear-gradient(-45deg,transparent 75%,#e0e0e0 75%);
  background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0;
}
.sf-cp-alpha i{position:absolute;inset:0;border-radius:0;pointer-events:none}
.sf-cp-ah{
  position:absolute;top:-2px;bottom:-2px;width:4px;
  border:2px solid #fff;border-radius:0;transform:translateX(-4px);
  box-shadow:0 0 0 1px rgba(0,0,0,.45);pointer-events:none;
}
.sf-cp-sv:focus-visible,.sf-cp-hue:focus-visible,.sf-cp-alpha:focus-visible{
  outline:2px solid var(--sf-c-accent);outline-offset:2px;
}

.sf-cp-line{display:flex;align-items:center;gap:7px;margin-top:10px}
.sf-cp-prev{
  flex:none;width:30px;height:30px;border-radius:0;
  background-image:linear-gradient(45deg,#e0e0e0 25%,transparent 25%),linear-gradient(-45deg,#e0e0e0 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#e0e0e0 75%),linear-gradient(-45deg,transparent 75%,#e0e0e0 75%);
  background-size:9px 9px;background-position:0 0,0 4.5px,4.5px -4.5px,-4.5px 0;
}
.sf-cp-prev i{display:block;width:100%;height:100%;border-radius:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.14)}
.sf-cp-hex{
  flex:1;display:flex;align-items:center;gap:6px;
  height:30px;padding:0 9px;
  border:1px solid var(--sf-c-line);border-radius:0;
  background:var(--sf-c-soft);
}
.sf-cp-hex span{color:var(--sf-c-muted);font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-semi)}
.sf-cp-hex input{
  width:100%;min-width:0;border:0;background:none;outline:none;
  color:var(--sf-c-ink);
  font-family:var(--sf-font-mono);font-size:var(--sf-fs-sm);text-transform:uppercase;
}
.sf-cp-hex:focus-within{border-color:var(--sf-c-accent);box-shadow:var(--sf-e-focus)}
.sf-cp-icon{
  flex:none;display:grid;place-items:center;
  width:30px;height:30px;
  border:1px solid var(--sf-c-line);border-radius:0;
  background:var(--sf-c-surface);color:var(--sf-c-text);cursor:pointer;
  transition:background var(--sf-t-fast) var(--sf-ease),color var(--sf-t-fast) var(--sf-ease);
}
.sf-cp-icon:hover{background:var(--sf-c-hover);color:var(--sf-c-ink)}
.sf-cp-icon.on{background:var(--sf-c-brand);border-color:var(--sf-c-brand);color:#fff}
.sf-cp-icon:disabled{opacity:.4;cursor:default}
.sf-cp-icon svg{width:15px;height:15px}

.sf-cp-nums{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;margin-top:7px}
.sf-cp-nums label{
  display:flex;align-items:center;gap:3px;
  height:28px;padding:0 5px;
  border:1px solid var(--sf-c-line);border-radius:0;
  background:var(--sf-c-soft);
}
.sf-cp-nums span{color:var(--sf-c-muted);font-size:12px;font-weight:var(--sf-fw-bold)}
.sf-cp-nums input{
  width:100%;min-width:0;border:0;background:none;outline:none;
  color:var(--sf-c-ink);font-size:var(--sf-fs-sm);-moz-appearance:textfield;
}
.sf-cp-nums input::-webkit-outer-spin-button,.sf-cp-nums input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.sf-cp-nums label:focus-within{border-color:var(--sf-c-accent);box-shadow:var(--sf-e-focus)}

.sf-cp-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:11px}
.sf-cp-clear,.sf-cp-done{
  height:32px;padding:0 14px;
  border-radius:0;
  font-size:var(--sf-fs-md);font-weight:var(--sf-fw-semi);cursor:pointer;
  transition:background var(--sf-t-fast) var(--sf-ease),border-color var(--sf-t-fast) var(--sf-ease);
}
.sf-cp-clear{border:1px solid var(--sf-c-line);background:var(--sf-c-surface);color:var(--sf-c-text)}
.sf-cp-clear:hover{background:var(--sf-c-hover);color:var(--sf-c-ink)}
.sf-cp-done{border:1px solid var(--sf-c-accent);background:var(--sf-c-accent);color:#fff}
.sf-cp-done:hover{background:var(--sf-c-accent-ink);border-color:var(--sf-c-accent-ink)}
.sf-cp-clear:focus-visible,.sf-cp-done:focus-visible{outline:2px solid var(--sf-c-accent);outline-offset:2px}

/* the field that opens it */
.sf-cptrigger{
  display:flex;align-items:center;gap:8px;
  width:100%;height:34px;padding:0 9px;
  border:1px solid var(--sf-c-line);border-radius:0;
  background:var(--sf-c-surface);cursor:pointer;
  transition:background var(--sf-t-fast) var(--sf-ease),border-color var(--sf-t-fast) var(--sf-ease);
}
.sf-cptrigger:hover{background:var(--sf-c-hover);border-color:#c6c6c6}
.sf-cptrigger:focus-visible{outline:none;border-color:var(--sf-c-accent);box-shadow:var(--sf-e-focus)}
.sf-cptrigger[aria-expanded="true"]{border-color:var(--sf-c-accent);box-shadow:var(--sf-e-focus)}
.sf-cptrigger .sw{
  flex:none;width:18px;height:18px;border-radius:0;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.14);
  background-image:linear-gradient(45deg,#e0e0e0 25%,transparent 25%),linear-gradient(-45deg,#e0e0e0 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#e0e0e0 75%),linear-gradient(-45deg,transparent 75%,#e0e0e0 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;
}
.sf-cptrigger .sw i{display:block;width:100%;height:100%;border-radius:0}
.sf-cptrigger .hex{
  flex:1;min-width:0;text-align:left;
  font-family:var(--sf-font-mono);font-size:var(--sf-fs-sm);
  color:var(--sf-c-text);letter-spacing:.02em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sf-cptrigger .hex.is-none{font-family:var(--sf-font);color:var(--sf-c-muted)}

@media (prefers-reduced-motion:reduce){
  .sf-cp,.sf-cp-sw,.sf-cptrigger{transition:none}
}


/* ==========================================================================
   3 · Loading — one shimmer, one table skeleton
   --------------------------------------------------------------------------
   The same animated gradient was written three times: the newsletter template
   cards, the studio's boot placeholder and the table skeleton. One definition
   now, and every existing class is wired to it rather than restating it.
   ========================================================================== */
.sf-shimmer,
.sf-sk-c,
.sfnl-skeleton .sk,
.sfnl-tsk .sk,
.st-sk{
  background:linear-gradient(90deg,#e8e8e8 25%,#f4f4f4 37%,#e8e8e8 63%);
  background-size:400% 100%;
  animation:sfShimmer 1.4s ease infinite;
}
@keyframes sfShimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}

/* A skeleton shaped like the table it stands in for — same columns, same
   widths — so nothing jumps when the rows arrive. Built by SFTable.skeleton(). */
.sf-sk{padding:2px}
.sf-sk-head,.sf-sk-row{
  display:flex;align-items:center;gap:18px;
  height:52px;padding:0 16px;
  border-bottom:1px solid var(--sf-c-line-soft);
}
.sf-sk-head{height:46px;background:var(--sf-c-soft);border-radius:0}
.sf-sk-c{display:block;height:11px;border-radius:0;flex:none}
.sf-sk-head .sf-sk-c{height:9px;opacity:.8}
.sf-sk-c.is-check{width:18px;height:18px;border-radius:0}

@media (prefers-reduced-motion:reduce){
  .sf-shimmer,.sf-sk-c,.sfnl-skeleton .sk,.sfnl-tsk .sk,.st-sk{animation:none}
}

/* Light swatches need an outline or they read as a gap in the row rather than
   a colour — white against a white panel is nothing at all. Dark ones carry
   their own contrast and keep the quieter ring. */
.sf-cp-sw.is-light > span{box-shadow:inset 0 0 0 1px rgba(0,0,0,.34)}
/* the applied colour, marked where it sits */
.sf-cp-sw.is-on{transform:scale(1.08)}
.sf-cp-sw.is-on > span{box-shadow:inset 0 0 0 1px rgba(0,0,0,.28)}
.sf-cp-sw.is-on::after{
  content:"";
  position:absolute;inset:-3px;
  border:2px solid var(--sf-c-accent);
  pointer-events:none;
}
.sf-cp-sw{position:relative}
.sf-cp-sw.is-on:hover{transform:scale(1.14)}
/* The trigger's fill covered the ring its parent was drawing, so a white text
   colour showed as an empty box in the properties panel. */
.sf-cptrigger .sw i{box-shadow:inset 0 0 0 1px rgba(0,0,0,.22)}
.sf-cp-prev i{box-shadow:inset 0 0 0 1px rgba(0,0,0,.22)}

/* ---- gradient editing ----------------------------------------------------
   The stop bar and its controls. Stops sit on a checkerboard so a white or a
   part-transparent stop reads as a stop rather than a hole in the track. */
.sf-cp-mode{display:flex;gap:2px;margin:0 0 10px;padding:2px;background:var(--sf-c-soft,#f4f4f4)}
.sf-cp-mode button{
  flex:1;height:26px;border:0;border-radius:0;background:none;
  color:var(--sf-c-text);font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-bold);
  cursor:pointer;transition:background var(--sf-t-fast) var(--sf-ease);
}
.sf-cp-mode button.on{background:var(--sf-c-surface,#fff);color:var(--sf-c-ink)}
.sf-cp-grad{margin:0 0 10px}
.sf-cp-gbar{
  position:relative;height:26px;margin:0 0 22px;
  background-image:linear-gradient(45deg,#e0e0e0 25%,transparent 25%),linear-gradient(-45deg,#e0e0e0 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,#e0e0e0 75%),linear-gradient(-45deg,transparent 75%,#e0e0e0 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;
  cursor:copy;touch-action:none;
}
.sf-cp-gbar:focus-visible{outline:2px solid var(--sf-c-accent);outline-offset:2px}
.sf-cp-gbar > i{position:absolute;inset:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.16)}
.sf-cp-stop{
  position:absolute;top:100%;width:14px;height:14px;margin:4px 0 0 -7px;padding:0;
  border:0;border-radius:0;background:none;cursor:grab;
}
.sf-cp-stop i{
  display:block;width:100%;height:100%;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.2),0 0 0 1px rgba(255,255,255,.9);
}
.sf-cp-stop.is-light i{box-shadow:inset 0 0 0 1px rgba(0,0,0,.38),0 0 0 1px rgba(255,255,255,.9)}
.sf-cp-stop.on{z-index:2}
.sf-cp-stop.on i{box-shadow:inset 0 0 0 1px rgba(0,0,0,.25),0 0 0 2px var(--sf-c-accent)}
.sf-cp-stop:focus-visible{outline:2px solid var(--sf-c-accent);outline-offset:3px}
.sf-cp-grow{display:flex;align-items:center;gap:6px;margin:0 0 8px}
.sf-cp-seg{display:flex;gap:2px;padding:2px;background:var(--sf-c-soft,#f4f4f4)}
.sf-cp-seg button{
  height:24px;padding:0 10px;border:0;background:none;
  color:var(--sf-c-text);font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-bold);cursor:pointer;
}
.sf-cp-seg button.on{background:var(--sf-c-surface,#fff);color:var(--sf-c-ink)}
.sf-cp-gsp{flex:1}
.sf-cp-ang{display:flex;align-items:center;gap:7px;margin:0 0 8px}
.sf-cp-ang span{flex:none;color:var(--sf-c-muted);font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-bold)}
.sf-cp-ang em{flex:none;color:var(--sf-c-muted);font-style:normal;font-size:var(--sf-fs-xs)}
.sf-cp-ang input[type=range]{flex:1;min-width:0;height:20px;accent-color:var(--sf-c-accent)}
.sf-cp-ang input[type=number]{
  width:52px;flex:none;height:26px;padding:0 6px;
  border:1px solid var(--sf-c-line);background:var(--sf-c-surface);
  font-family:var(--sf-font-mono);font-size:var(--sf-fs-sm);color:var(--sf-c-ink);
}
.sf-cp-fb{display:flex;align-items:center;gap:6px;margin:0 0 6px}
.sf-cp-fb span{color:var(--sf-c-muted);font-size:var(--sf-fs-xs);font-weight:var(--sf-fw-bold)}
.sf-cp-fb input{
  flex:1;min-width:0;height:26px;padding:0 6px;
  border:1px solid var(--sf-c-line);background:var(--sf-c-surface);
  font-family:var(--sf-font-mono);font-size:var(--sf-fs-sm);color:var(--sf-c-ink);
  text-transform:uppercase;
}
.sf-cp-fb i{
  width:22px;height:22px;flex:none;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.22);
}
.sf-cp-fb i.is-light{box-shadow:inset 0 0 0 1px rgba(0,0,0,.34)}
.sf-cp-note{margin:0;color:var(--sf-c-muted);font-size:var(--sf-fs-xs);line-height:1.45}
/* the preview splits when a fallback is in play: gradient left, fallback right */
.sf-cp-prev u{display:none}
.sf-cp-prev.has-fb i{width:66%}
.sf-cp-prev.has-fb u{
  display:block;position:absolute;right:0;top:0;bottom:0;width:34%;
  box-shadow:inset 1px 0 0 rgba(0,0,0,.18);
}
.sf-cp-prev{position:relative;overflow:hidden}
