/*
 * Unidy SDK — Auth Overlay
 *
 * A single stylesheet drives all three render modes. Modifier classes on the
 * root element (.unidy-overlay--modal, --panel, --inline) branch the layout;
 * every other rule is shared so light/dark themes and CSS custom-properties
 * flow through consistently.
 *
 * Custom properties can be overridden per-site via the SDK config-attrs filter.
 */

/* ============================================================
 * Unidy SDK — Design Tokens (2026-07-17 handoff, Neutral / Sport preset)
 *
 * Components reference SEMANTIC ROLES (--u-accent, --u-surface, --u-radius-lg),
 * never raw hex. A preset writes color + radius only; everything else is fixed.
 *
 * The legacy --unidy-overlay-* names below are aliases mapped to the new
 * --u-* system so any operator custom-CSS that overrides them still works.
 * Prefer --u-* in new rules.
 * ============================================================ */
:root {
    /* Color — Towers / Neutral */
    --u-accent:         #111827;
    --u-accent-hover:   #1f2937;
    --u-text:           #0f172a;
    --u-text-muted:     #64748b;
    --u-text-inverse:   #ffffff;
    --u-surface:        #ffffff;
    --u-surface-sunken: #f8fafc;
    --u-border:         #e2e8f0;
    --u-border-strong:  #cbd5e1;

    /* Semantic status */
    --u-success:      #16a34a; --u-success-tint: #f0fdf4;
    --u-warning:      #d97706; --u-warning-tint: #fffbeb;
    --u-danger:       #dc2626; --u-danger-tint:  #fef2f2;
    --u-info:         #2563eb; --u-info-tint:    #eff6ff;

    /* Type */
    --u-font: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    --u-text-display:  700 30px/34px var(--u-font);
    --u-text-h2:       700 22px/28px var(--u-font);
    --u-text-h3:       600 18px/24px var(--u-font);
    --u-text-body-lg:  400 16px/24px var(--u-font);
    --u-text-body:     400 14px/20px var(--u-font);
    --u-text-label:    600 13px/16px var(--u-font);
    --u-text-caption:  500 12px/16px var(--u-font);

    /* Radius */
    --u-radius-sm:   6px;
    --u-radius-md:   8px;
    --u-radius-lg:  12px;
    --u-radius-full: 999px;

    /* Elevation */
    --u-shadow-card:      0 1px 2px rgba(15,23,42,.04), 0 2px 8px rgba(15,23,42,.06);
    --u-shadow-elevated:  0 4px 12px rgba(15,23,42,.08), 0 2px 4px rgba(15,23,42,.04);
    --u-shadow-modal:     0 24px 48px -12px rgba(15,23,42,.28), 0 8px 24px rgba(15,23,42,.12);
    --u-backdrop:         rgba(9,14,26,.55);

    /* Motion */
    --u-ease:         cubic-bezier(.16, 1, .3, 1);
    --u-ease-panel:   cubic-bezier(.32, .72, 0, 1);
    --u-dur-fast:     120ms;
    --u-dur-base:     180ms;
    --u-dur-panel:    220ms;
    --u-dur-backdrop: 160ms;

    /* Spacing (4px base) */
    --u-space-1: 2px;  --u-space-2: 4px;  --u-space-3: 8px;  --u-space-4: 12px;
    --u-space-5: 16px; --u-space-6: 20px; --u-space-7: 24px; --u-space-8: 32px;
    --u-space-9: 40px; --u-space-10: 48px;

    /* Layout */
    --u-modal-width: 360px;
    --u-panel-width: 320px;
    --u-focus-ring:  0 0 0 3px rgba(17, 24, 39, .12);

    /* ── Legacy aliases (backward compat with operator overrides) ── */
    --unidy-overlay-bg:         var(--u-surface);
    --unidy-overlay-surface:    var(--u-surface-sunken);
    --unidy-overlay-fg:         var(--u-text);
    --unidy-overlay-muted:      var(--u-text-muted);
    --unidy-overlay-border:     var(--u-border);
    --unidy-overlay-accent:     var(--u-accent);
    --unidy-overlay-accent-fg:  var(--u-text-inverse);
    --unidy-overlay-backdrop:   var(--u-backdrop);
    --unidy-overlay-radius:     var(--u-radius-lg);
    --unidy-overlay-shadow:     var(--u-shadow-modal);
    --unidy-overlay-width:      var(--u-modal-width);
    --unidy-overlay-panel-width: var(--u-panel-width);
    --unidy-overlay-transition: var(--u-dur-panel) var(--u-ease-panel);
    --unidy-overlay-font:       var(--u-font);
}

/* ── Preset overrides — one attribute on the SDK root re-skins everything ── */
[data-u-preset="warm"] {    /* Editorial */
    --u-accent: #b4530f; --u-accent-hover: #93430c;
    --u-radius-sm: 8px; --u-radius-md: 10px; --u-radius-lg: 14px;
    --u-focus-ring: 0 0 0 3px rgba(180, 83, 15, .14);
}
[data-u-preset="bold"] {    /* Institutional */
    --u-accent: #1d4ed8; --u-accent-hover: #1741ad;
    --u-radius-sm: 3px; --u-radius-md: 4px; --u-radius-lg: 6px;
    --u-focus-ring: 0 0 0 3px rgba(29, 78, 216, .16);
}
[data-u-preset="rounded"] { /* Playful */
    --u-accent: #15803d; --u-accent-hover: #116330;
    --u-radius-sm: 10px; --u-radius-md: 14px; --u-radius-lg: 18px;
    --u-focus-ring: 0 0 0 3px rgba(21, 128, 61, .16);
}

/* ── Dark-mode scope — for inline modules embedded on a dark host page.
 * NOT a user light/dark toggle; not tied to prefers-color-scheme. Set
 * data-u-theme="dark" on the SDK root via overlay.js luminance-detect
 * or via the Admin → Design manual override. Admin SPA + modal/panel
 * ignore this scope (they render on their own surface). ── */
[data-u-theme="dark"] {
    --u-surface:        #0f172a;
    --u-surface-sunken: #1e293b;
    --u-border:         #334155;
    --u-border-strong:  #475569;
    --u-text:           #f1f5f9;
    --u-text-muted:     #94a3b8;
    --u-accent:         #ffffff;
    --u-text-inverse:   #0f172a;
}

/* ── Icon defaults (from 2026-07-17 design handoff) ──
 * 24×24 by default, inherits color from parent via `currentColor`.
 * Callers set explicit width/height via <svg width=… height=…> to override.
 * `display:block` avoids inline-baseline gap inside flex row buttons. */
.u-icon {
    width: 24px;
    height: 24px;
    display: block;
    flex-shrink: 0;
}

/* ── Empty-state component (2026-07-17 design handoff) ──
 * 60px muted circle (or rounded-square for tickets) holds a 30px module
 * icon, then title + short body copy + a single primary/secondary CTA.
 * Illustration-free by design so operators don't wait on art and every
 * module reads consistent. Used everywhere a module has to say "nothing
 * to see here" (loaded-empty + signed-out variants). */
.u-empty {
    background: var(--u-surface);
    border-radius: var(--u-radius-lg);
    box-shadow: var(--u-shadow-card);
    padding: 36px 28px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    color: var(--u-text);
    font-family: var(--u-font);
}
.u-empty__icon {
    width: 60px;
    height: 60px;
    background: var(--u-surface-sunken);
    color: var(--u-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.u-empty__icon--circle { border-radius: 50%; }
.u-empty__icon--square { border-radius: 14px; }
.u-empty__icon svg { width: 30px; height: 30px; stroke-width: 1.6; }
.u-empty__text { max-width: 32ch; }
/* Host themes (Towers uses a massive display font on `body h3`, `.entry-content h3`)
 * reach into the empty-state with high specificity. Force the design-spec font
 * so title stays 18px regardless of surrounding page CSS. */
.u-empty__title {
    font: var(--u-text-h3) !important;
    color: var(--u-text) !important;
    margin: 0 0 6px !important;
    letter-spacing: -0.005em;
    text-transform: none;
}
.u-empty__body {
    font: var(--u-text-body) !important;
    color: var(--u-text-muted) !important;
    margin: 0 !important;
}
.u-empty__cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 44px;
    padding: 0 20px;
    border-radius: var(--u-radius-md);
    font: var(--u-text-body);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--u-dur-fast) var(--u-ease),
                border-color var(--u-dur-fast) var(--u-ease);
}
.u-empty__cta--primary,
.unidy-overlay a.u-empty__cta--primary,
.unidy-overlay .u-empty__cta--primary {
    background: var(--u-accent);
    /* !important + higher-specificity variants because two other cascade
     * layers compete for the label color:
     *   1. Customer themes set `.entry-content a { color: … }` — beaten
     *      by !important on the base rule.
     *   2. Our own `.unidy-overlay a { color: inherit !important }` also
     *      wins on specificity (class+tag > single class). We match that
     *      selector with `.unidy-overlay .u-empty__cta--primary` (two
     *      classes) so our declaration comes out on top when the empty
     *      state is inside the auth overlay body.
     * Without both variants the "Anmelden" label rendered dark-on-dark.
     */
    color: var(--u-text-inverse) !important;
    border: 1px solid var(--u-accent);
}
.u-empty__cta--primary:hover,
.unidy-overlay a.u-empty__cta--primary:hover,
.unidy-overlay .u-empty__cta--primary:hover {
    background: var(--u-accent-hover);
    border-color: var(--u-accent-hover);
    color: var(--u-text-inverse) !important;
}
.u-empty__cta--secondary,
.unidy-overlay a.u-empty__cta--secondary,
.unidy-overlay .u-empty__cta--secondary {
    background: var(--u-surface);
    color: var(--u-text) !important;
    border: 1px solid var(--u-border);
}
.u-empty__cta--secondary:hover,
.unidy-overlay a.u-empty__cta--secondary:hover,
.unidy-overlay .u-empty__cta--secondary:hover {
    background: var(--u-surface-sunken);
    border-color: var(--u-border-strong);
    color: var(--u-text) !important;
}
.u-empty__cta:focus-visible {
    outline: none;
    box-shadow: var(--u-focus-ring);
}

.unidy-overlay[hidden] { display: none !important; }

.unidy-overlay {
    position: fixed;
    inset: 0;
    z-index: 100000;
    color: var(--unidy-overlay-fg);
    font-family: var(--unidy-overlay-font);
    font-size: 15px;
    line-height: 1.4;
}
/* Beat host themes that put a display font on h1-h6 via `body h3` etc.
 * We scope this to the overlay so nothing else on the page shifts. */
.unidy-overlay h1,
.unidy-overlay h2,
.unidy-overlay h3,
.unidy-overlay h4,
.unidy-overlay h5,
.unidy-overlay h6 {
    font-family: var(--unidy-overlay-font) !important;
}
/*
 * Force dark text on all inline content inside the dialog. Host themes
 * (Towers uses `.page-content h3`, `body h3` etc.) reach into our modal with
 * higher specificity and paint everything white; we counter with !important
 * scoped to the overlay so no non-modal element on the page is affected.
 * Buttons/inputs get their own explicit colors below.
 */
.unidy-overlay__dialog,
.unidy-overlay__dialog h1,
.unidy-overlay__dialog h2,
.unidy-overlay__dialog h3,
.unidy-overlay__dialog h4,
.unidy-overlay__dialog p,
.unidy-overlay__dialog span,
.unidy-overlay__dialog label,
.unidy-overlay__dialog div {
    /* Descendant selector: nested SDK markup (u-registration-step >
     * u-raw-field > label, u-signed-in > .unidy-signed-in__body > label…)
     * needs the forced color too, otherwise `.entry-content label` /
     * `body div` in the host theme wins and text goes invisible.
     * Interactive elements are exempt below. */
    color: var(--unidy-overlay-fg) !important;
}
/*
 * Interactive elements manage their own text color (primary CTA needs
 * white-on-dark, secondary needs inherit, back-button needs muted…).
 * The rule above was painting spans/divs inside buttons dark navy, which
 * hid the primary CTA label because the button's own color: white didn't
 * cascade past an explicit rule on a child span. Exempt them here.
 */
.unidy-overlay button,
.unidy-overlay button *,
.unidy-overlay u-submit-button,
.unidy-overlay u-submit-button *,
.unidy-overlay u-registration-resend,
.unidy-overlay u-registration-resend *,
.unidy-overlay u-send-magic-code-button,
.unidy-overlay u-send-magic-code-button *,
.unidy-overlay u-registration-passkey,
.unidy-overlay u-registration-passkey *,
.unidy-overlay u-newsletter-toggle-subscription-button,
.unidy-overlay u-newsletter-toggle-subscription-button *,
.unidy-overlay u-logout-button,
.unidy-overlay u-logout-button *,
.unidy-overlay a {
    color: inherit !important;
}
.unidy-overlay .unidy-reg-title {
    color: var(--unidy-overlay-fg) !important;
    font-size: 20px !important;
    font-weight: 700 !important;
    line-height: 1.3 !important;
    margin: 0 0 6px !important;
    padding: 0 !important;
    letter-spacing: normal !important;
    text-transform: none !important;
}
.unidy-overlay .unidy-reg-hint {
    color: var(--unidy-overlay-muted) !important;
    font-size: 14px !important;
    line-height: 1.4 !important;
    margin: 0 0 16px !important;
    padding: 0 !important;
}

.unidy-backdrop {
    position: absolute;
    inset: 0;
    background: var(--unidy-overlay-backdrop);
    /* Blur + saturation dim the underlying page even when the host theme
     * is already dark (Towers is nearly black — a 45%-black backdrop on top
     * is invisible without this). Falls back gracefully on old browsers to
     * the plain rgba() background above. */
    -webkit-backdrop-filter: blur(4px) saturate(80%);
    backdrop-filter: blur(4px) saturate(80%);
    opacity: 0;
    transition: opacity var(--unidy-overlay-transition);
    pointer-events: auto;
}
.unidy-backdrop.is-visible { opacity: 1; }

.unidy-overlay__dialog {
    position: relative;
    background: var(--unidy-overlay-bg);
    box-shadow: var(--unidy-overlay-shadow);
    overflow-y: auto;
    max-height: 100vh;
}

.unidy-overlay__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 24px;
    border-bottom: 1px solid var(--unidy-overlay-border);
    font-weight: 600;
    gap: 12px;
    /* Header defaults to transparent (=body bg). Customers with a
     * dark-branded logo set --unidy-overlay-header-bg to a solid color;
     * --unidy-overlay-header-fg then flips the title + close-X to match.
     * Falls back to overlay-fg so text stays readable when the customer
     * sets bg but forgets fg. */
    background: var(--unidy-overlay-header-bg, transparent);
    color: var(--unidy-overlay-header-fg, var(--unidy-overlay-fg));
}
/* Close-X inherits from the header so it stays visible against a dark bg
 * without a separate variable. */
.unidy-overlay__header .unidy-overlay__close {
    color: inherit !important;
}
/* When the header has a solid background, drop the divider line — it
 * reads noisy against a color-block header. Body still separates
 * visually via the bg contrast. */
.unidy-overlay__header:where([style*='background'], .unidy-overlay__header--dark) {
    border-bottom-color: transparent;
}

/* ── Center alignment: logo (or title) sits centered, close-X in its own
 * right-hand lane so it doesn't fight the center. 3-col grid keeps the
 * visual centering true even when the title has a long word.            */
.unidy-overlay__header--center {
    display: grid;
    grid-template-columns: 32px 1fr 32px;
    align-items: center;
    padding: 24px 20px 20px;
}
.unidy-overlay__header--center .unidy-overlay__logo,
.unidy-overlay__header--center .unidy-overlay__title {
    grid-column: 2;
    justify-self: center;
    text-align: center;
}
.unidy-overlay__header--center .unidy-overlay__close {
    grid-column: 3;
    justify-self: end;
    align-self: start;
}

/* ── Logo styling ─────────────────────────────────────────────────────
 * Sized to be recognisable but not dominant. `max-height` beats `height`
 * so a very-wide SVG stays wide but shrinks to the height cap; a very-
 * tall PNG hits the height cap first. The block+auto width keeps native
 * proportions intact — no distortion.                                    */
.unidy-overlay__logo {
    display: block;
    max-height: 56px;
    max-width: min(200px, 70%);
    width: auto;
    height: auto;
    object-fit: contain;
    margin: 0;
}

/* ── When a logo AND a title are both set, the logo takes over as the
 * primary identity. Suppress the title in center-mode so we don't stack
 * a tiny "Willkommen" under a mark that already says who you are. Users
 * who want text-only should just leave the logo empty. Left-align mode
 * keeps the title inline next to the logo (side-by-side "logo + brand
 * name" pattern).                                                        */
.unidy-overlay__header--center:has(.unidy-overlay__logo) .unidy-overlay__title {
    display: none;
}
/* Default (left-align) header with a logo — logo first, title inline
 * with normal weight; close on the far right. */
.unidy-overlay__header:not(.unidy-overlay__header--center) .unidy-overlay__logo {
    order: -1;
    margin-right: 4px;
}
.unidy-overlay__close {
    background: transparent;
    border: 0;
    cursor: pointer;
    color: currentColor;
    padding: 4px;
    line-height: 0;
    border-radius: 6px;
}
.unidy-overlay__close:focus-visible {
    outline: 2px solid var(--unidy-overlay-accent);
    outline-offset: 2px;
}

.unidy-overlay__body   { padding: 24px; }
/*
 * Intro line rendered between header and form body. Small, centered by
 * default, muted color — it's context, not a call to action. Customers
 * write short copy here like "Melde dich mit deiner E-Mail an, um dabei
 * zu sein." — one line, two at most.
 */
.unidy-overlay__intro {
    margin: 0 !important;
    padding: 16px 24px 4px !important;
    font-size: 14px !important;
    line-height: 1.5 !important;
    color: var(--unidy-overlay-muted) !important;
    text-align: center;
    font-family: var(--unidy-overlay-font) !important;
}
/* Vertical rhythm inside a signin step — one gap value for input →
 * button → divider → social-button so nothing hugs a neighbour. */
.unidy-overlay u-signin-step,
.unidy-overlay u-signin-step > * {
    box-sizing: border-box;
}
.unidy-overlay u-signin-step {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
/* Divider owns its own top/bottom air via the gap above; kill the
 * hard-coded margin so we don't double-space around "ODER". */
.unidy-overlay u-signin-step > .u-divider {
    margin: 0;
}
/* Error messages sit tight against the field that produced them. */
.unidy-overlay u-signin-step > .u-error {
    margin-top: -8px;
}
.unidy-overlay__header:not(.unidy-overlay__header--center) + .unidy-overlay__intro {
    text-align: left;
}
.unidy-overlay__footer { padding: 16px 24px; border-top: 1px solid var(--unidy-overlay-border); }
.unidy-overlay__status {
    padding: 12px 16px;
    margin: 12px 24px;
    border-radius: 8px;
    background: #fef2f2;
    color: #b91c1c;
    font-size: 14px;
}

/* ── Modal mode: centered card with backdrop ─────────────────────────── */

.unidy-overlay--modal { display: flex; align-items: center; justify-content: center; }
.unidy-overlay--modal .unidy-overlay__dialog {
    width: min(var(--unidy-overlay-width), 92vw);
    max-height: 90vh;
    border-radius: var(--unidy-overlay-radius);
    transform: translateY(12px) scale(.98);
    opacity: 0;
    transition: transform var(--unidy-overlay-transition), opacity var(--unidy-overlay-transition);
}
.unidy-overlay--modal.is-open .unidy-overlay__dialog {
    transform: translateY(0) scale(1);
    opacity: 1;
}

/* ── Panel mode: right-side slide-in ─────────────────────────────────── */

.unidy-overlay--panel { display: block; }
.unidy-overlay--panel .unidy-overlay__dialog {
    position: absolute;
    top: 0;
    right: 0;
    height: 100vh;
    width: min(var(--unidy-overlay-panel-width), 92vw);
    transform: translateX(100%);
    transition: transform var(--unidy-overlay-transition);
    border-top-left-radius: var(--unidy-overlay-radius);
    border-bottom-left-radius: var(--unidy-overlay-radius);
    /* Sharp left-edge shadow so the panel visually detaches from the page
     * even when the host theme is dark and the tinted backdrop alone can't
     * carry the layering. Rounded corners only on the left (visible) side. */
    box-shadow: -12px 0 32px rgba(0, 0, 0, 0.28), -1px 0 0 rgba(0, 0, 0, 0.06);
}
.unidy-overlay--panel.is-open .unidy-overlay__dialog {
    transform: translateX(0);
}

/* ── Inline mode: no overlay chrome, meant to be embedded on a page ── */

.unidy-overlay--inline {
    position: static;
    inset: auto;
    z-index: auto;
}
.unidy-overlay--inline .unidy-backdrop  { display: none; }
.unidy-overlay--inline .unidy-overlay__close { display: none; }
.unidy-overlay--inline .unidy-overlay__dialog {
    max-height: none;
    box-shadow: none;
    border: 1px solid var(--unidy-overlay-border);
    border-radius: var(--unidy-overlay-radius);
    width: 100%;
}

/* ── Body scroll-lock while overlay is open ──────────────────────────── */

body.unidy-overlay-open { overflow: hidden; }
body.unidy-overlay-open .unidy-overlay--inline { /* inline mode never locks scroll */
    /* no-op; the class exists so JS can toggle it uniformly */
}

/* ── Form elements ────────────────────────────────────────────────────── */

/*
 * We select `input`/`textarea`/`select` at element level in addition to the
 * class-based `.u-input` because `<u-raw-field>` in some SDK versions doesn't
 * forward `class-name` to the internal input — resulting in unstyled inputs
 * that inherit the host theme's dark-mode `color: #fff` and render invisible.
 * The element-level selector is scoped to `.unidy-overlay` so it can't leak.
 */
.unidy-overlay .u-input,
.unidy-overlay input:not([type='hidden']):not([type='checkbox']):not([type='radio']):not([type='submit']):not([type='button']),
.unidy-overlay textarea,
.unidy-overlay select {
    display: block;
    width: 100%;
    /* Design spec: h 44 (42 in dense), pad 0 14, radius --u-radius-md */
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--u-border);
    border-radius: var(--u-radius-md);
    font-size: 15px;
    line-height: 1.4;
    background: var(--u-surface);
    color: var(--u-text);
    margin-bottom: 10px;
    box-sizing: border-box;
    appearance: none;
    -webkit-appearance: none;
    box-shadow: none;
    transition: border-color var(--u-dur-fast) var(--u-ease),
                box-shadow var(--u-dur-fast) var(--u-ease);
}
.unidy-overlay textarea { height: auto; min-height: 80px; padding: 12px 14px; }
.unidy-overlay .u-input:hover,
.unidy-overlay input:not([type='hidden']):not([type='checkbox']):not([type='radio']):not([type='submit']):not([type='button']):hover,
.unidy-overlay textarea:hover,
.unidy-overlay select:hover {
    border-color: var(--u-border-strong);
}
.unidy-overlay .u-input:focus,
.unidy-overlay input:not([type='hidden']):not([type='checkbox']):not([type='radio']):not([type='submit']):not([type='button']):focus,
.unidy-overlay textarea:focus,
.unidy-overlay select:focus {
    outline: none;
    border-color: var(--u-accent);
    box-shadow: var(--u-focus-ring);
}
.unidy-overlay .u-input:disabled,
.unidy-overlay input:disabled,
.unidy-overlay textarea:disabled,
.unidy-overlay select:disabled {
    background: var(--u-surface-sunken);
    color: var(--u-text-muted);
    cursor: not-allowed;
}
.unidy-overlay .u-input::placeholder,
.unidy-overlay input::placeholder,
.unidy-overlay textarea::placeholder {
    color: #9ca3af;
    opacity: 1;
}
.unidy-overlay .u-btn-primary,
.unidy-overlay .u-btn-secondary,
.unidy-overlay .u-btn-provider,
.unidy-overlay .u-btn-back,
.unidy-overlay .u-btn-link,
.unidy-overlay .unidy-sso-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    /* Design spec: h 44, pad 0 20, radius --u-radius-md, weight 600, font 15 */
    height: 44px;
    padding: 0 20px;
    border-radius: var(--u-radius-md);
    border: 1px solid var(--u-border);
    background: var(--u-surface);
    color: var(--u-text);
    font-weight: 600;
    font-size: 15px;
    cursor: pointer;
    width: 100%;
    box-sizing: border-box;
    text-decoration: none;
    margin-top: 6px;
    transition: background var(--u-dur-fast) var(--u-ease),
                border-color var(--u-dur-fast) var(--u-ease);
}
.unidy-overlay .u-btn-primary,
.unidy-overlay .unidy-sso-btn {
    background: var(--u-accent);
    color: var(--u-text-inverse);
    border-color: var(--u-accent);
}
.unidy-overlay .u-btn-primary:hover,
.unidy-overlay .unidy-sso-btn:hover {
    background: var(--u-accent-hover);
    border-color: var(--u-accent-hover);
}
.unidy-overlay .u-btn-secondary:hover,
.unidy-overlay .u-btn-provider:hover {
    background: var(--u-surface-sunken);
    border-color: var(--u-border-strong);
}
.unidy-overlay .u-btn-primary:focus-visible,
.unidy-overlay .u-btn-secondary:focus-visible,
.unidy-overlay .u-btn-provider:focus-visible,
.unidy-overlay .unidy-sso-btn:focus-visible {
    outline: none;
    box-shadow: var(--u-focus-ring);
}
.unidy-overlay .u-btn-primary[disabled],
.unidy-overlay .u-btn-primary:disabled {
    background: var(--u-border) !important;
    border-color: var(--u-border) !important;
    /* !important on color too — the general .u-btn-primary rule further
     * down declares `color: var(--unidy-overlay-accent-fg) !important` on
     * ALL states (including disabled, since :disabled doesn't add
     * specificity). Without matching !important here the enabled-state
     * white text bled through onto the disabled grey background,
     * rendering the label invisible (WCAG contrast fail, ~2.9:1 target
     * with #94a3b8/#e2e8f0). Reported by Burkhard on UD-3168. */
    color: var(--u-text-muted) !important;
    cursor: not-allowed;
}
.unidy-overlay .u-btn-link {
    border: 0;
    background: transparent;
    text-decoration: underline;
    padding: 6px 0;
    width: auto;
}
.unidy-overlay .u-btn-back { width: auto; padding: 6px 8px; border: 0; background: transparent; }
.unidy-overlay .u-error {
    color: #b91c1c;
    font-size: 14px;
    margin: 4px 0 8px;
    display: block;
}
.unidy-overlay .u-divider {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--unidy-overlay-muted);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0;
    margin: 12px 0;
}
.unidy-overlay .u-divider::before,
.unidy-overlay .u-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--unidy-overlay-border);
}
.unidy-overlay .u-step-desc, .unidy-overlay .u-legal-hint {
    color: var(--unidy-overlay-muted);
    font-size: 14px;
    margin: 6px 0 10px;
}

/* ── SDK profile/newsletter components ───────────────────────────────── */

.unidy-overlay u-profile,
.unidy-profile u-profile,
.unidy-overlay u-full-profile {
    display: grid;
    gap: 14px;
}

.unidy-overlay u-field,
.unidy-profile u-field {
    display: block;
    margin: 0 0 12px;
}

.unidy-overlay u-field::part(field_label),
.unidy-profile u-field::part(field_label),
.unidy-overlay u-raw-field::part(label) {
    display: block;
    color: var(--unidy-overlay-muted);
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 6px;
}

.unidy-overlay u-field::part(input_field),
.unidy-profile u-field::part(input_field),
.unidy-overlay u-field::part(select_field),
.unidy-profile u-field::part(select_field),
.unidy-overlay u-field::part(textarea_field),
.unidy-profile u-field::part(textarea_field),
.unidy-overlay u-raw-field::part(input),
.unidy-overlay u-magic-code-field::part(input),
.unidy-overlay u-registration-email-verification::part(input) {
    width: 100%;
    min-height: 44px;
    padding: 12px 14px;
    border: 1.5px solid var(--unidy-overlay-border);
    border-radius: 10px;
    background: #fff;
    color: var(--unidy-overlay-fg);
    box-sizing: border-box;
    font: inherit;
}

.unidy-overlay u-field::part(input_field):focus,
.unidy-profile u-field::part(input_field):focus,
.unidy-overlay u-field::part(select_field):focus,
.unidy-profile u-field::part(select_field):focus,
.unidy-overlay u-field::part(textarea_field):focus,
.unidy-profile u-field::part(textarea_field):focus,
.unidy-overlay u-raw-field::part(input):focus,
.unidy-overlay u-magic-code-field::part(input):focus,
.unidy-overlay u-registration-email-verification::part(input):focus {
    outline: none;
    border-color: var(--unidy-overlay-accent);
    box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.1);
}

.unidy-overlay u-field::part(readonly-indicator),
.unidy-profile u-field::part(readonly-indicator),
.unidy-overlay u-field::part(input_field--readonly),
.unidy-profile u-field::part(input_field--readonly),
.unidy-overlay u-field::part(select_field--readonly),
.unidy-profile u-field::part(select_field--readonly),
.unidy-overlay u-field::part(textarea_field--readonly),
.unidy-profile u-field::part(textarea_field--readonly) {
    display: block;
    min-height: 44px;
    padding: 11px 0;
    color: var(--unidy-overlay-fg);
    font-size: 15px;
}

.unidy-overlay u-field::part(radio-group_field),
.unidy-profile u-field::part(radio-group_field),
.unidy-overlay .u-radio-group,
.unidy-profile .u-radio-group {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 14px;
    align-items: center;
}

.unidy-overlay input[type='radio'],
.unidy-overlay input[type='checkbox'],
.unidy-profile input[type='radio'],
.unidy-profile input[type='checkbox'] {
    /* !important beats host themes that reset `input { margin: 0 }` at
     * higher specificity (Towers has `.entry-content input`). Without it
     * the radio circle glues to its own label — reads as "unclickable
     * decoration" not "one of three options". */
    inline-size: 18px !important;
    block-size: 18px !important;
    accent-color: var(--unidy-overlay-accent);
    margin: 0 10px 0 0 !important;
    vertical-align: middle;
    flex: 0 0 18px;
}
/*
 * Spacing between adjacent radio-label pairs. The SDK renders `<u-field
 * field="salutation">` as a flat sequence of `<input><label>Herr</label>
 * <input><label>Frau</label>…` — the label has no wrapping element, so the
 * next radio bumps right into it. Give each label a right-margin, and add
 * a small left-margin to the following input as a belt+braces cushion.
 * Wrap the group inline-flex so it doesn't stack when it fits on one line
 * but wraps gracefully when the panel is narrow.
 */
.unidy-overlay input[type='radio'] + label,
.unidy-overlay input[type='checkbox'] + label,
.unidy-profile input[type='radio'] + label,
.unidy-profile input[type='checkbox'] + label {
    display: inline-block;
    /* padding-left is belt to the input's margin-right braces — CSS
     * whitespace collapsing between an inline input and its label can
     * eat part of the margin. Padding on the label side always survives. */
    padding-left: 4px !important;
    margin-right: 22px !important;
    line-height: 1.5;
    vertical-align: middle;
    cursor: pointer;
    color: var(--unidy-overlay-fg) !important;
}
.unidy-overlay label + input[type='radio'],
.unidy-overlay label + input[type='checkbox'],
.unidy-profile label + input[type='radio'],
.unidy-profile label + input[type='checkbox'] {
    margin-left: 6px !important;
}
/*
 * Radio-group container. Regardless of whether the SDK renders as
 *   <input><label>Herr</label><input><label>Frau</label>...  (siblings)
 * or
 *   <label><input>Herr</label><label><input>Frau</label>...  (wrapped)
 * we want a healthy gap between each option AND between each radio circle
 * and its own label text. `word-spacing` adds inline-level spacing that
 * survives even when the SDK gives us no wrapper to flex on — it's the
 * one CSS lever that pushes label text away from a preceding inline
 * radio input reliably.
 */
.unidy-overlay u-field[field='salutation'],
.unidy-profile u-field[field='salutation'],
.unidy-overlay u-field[field='gender'],
.unidy-profile u-field[field='gender'] {
    display: block;
    padding: 6px 0 2px;
    line-height: 1.9;
    word-spacing: 8px;
}
/* Wrapper-label pattern: `<label><input type="radio">Herr</label>`.
 * Make each label an inline-flex row so the radio circle sits centered
 * relative to the label text with a fixed gap, and give the whole option
 * a right-margin that separates it from the next one. */
.unidy-overlay u-field:has(input[type='radio']) label:has(> input[type='radio']),
.unidy-profile u-field:has(input[type='radio']) label:has(> input[type='radio']),
.unidy-overlay label:has(> input[type='radio']),
.unidy-profile label:has(> input[type='radio']) {
    display: inline-flex !important;
    align-items: center;
    gap: 10px !important;
    margin-right: 24px !important;
    padding: 4px 0 !important;
    cursor: pointer;
    color: var(--unidy-overlay-fg) !important;
    word-spacing: normal;
}
.unidy-overlay label:has(> input[type='radio']) > input[type='radio'],
.unidy-profile label:has(> input[type='radio']) > input[type='radio'] {
    margin: 0 !important; /* flex gap handles it inside the wrapper */
}

/*
 * OTP / magic-code layout — 4-6 single-digit inputs in a row, not stacked
 * full-width text fields. The SDK emits an internal flex/grid container
 * around the digits; we style the host + any inputs it renders inside
 * (including shadow-DOM ::part(input) fallbacks) as square tiles.
 */
/* SDK 1.9's <u-registration-email-verification> renders (light DOM):
 *   <fieldset class="u-otp-wrap"> <input> <input> <input> <input> </fieldset>
 * so we need the fieldset ITSELF to be flex-row, with the four native
 * inputs as square tiles. Earlier CSS had a flex-column rule on the
 * same class which is what produced the "4 giant stacked boxes" bug. */
.unidy-overlay .u-otp-wrap,
.unidy-overlay u-magic-code-field,
.unidy-overlay u-registration-email-verification {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 8px;
    justify-content: center;
    align-items: center;
    margin: 12px 0;
    padding: 0;
    border: 0;
    max-width: 100%;
}
/* Legacy shadow-DOM path (older SDK / u-magic-code-field): if the SDK
 * ever wraps its inputs in an inner container, keep it flex-row too. */
.unidy-overlay u-magic-code-field::part(container),
.unidy-overlay u-registration-email-verification::part(container) {
    display: flex;
    flex-direction: row;
    gap: 8px;
    justify-content: center;
    align-items: center;
}

/* Digit input — overrides the generic `.unidy-overlay input {…}` rule
 * that would otherwise stretch each digit to 100% width. */
.unidy-overlay u-magic-code-field input,
.unidy-overlay u-registration-email-verification input,
.unidy-overlay .u-otp-wrap input,
.unidy-overlay u-magic-code-field::part(input),
.unidy-overlay u-registration-email-verification::part(input) {
    width: 44px !important;
    min-width: 44px;
    height: 52px;
    min-height: 52px;
    padding: 0 !important;
    margin: 0 !important;
    text-align: center;
    font-size: 22px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
    border: 1.5px solid var(--unidy-overlay-border);
    border-radius: 10px;
    background: #fff;
    color: var(--unidy-overlay-fg);
    box-sizing: border-box;
    display: inline-block !important;
}
.unidy-overlay u-magic-code-field input:focus,
.unidy-overlay u-registration-email-verification input:focus,
.unidy-overlay .u-otp-wrap input:focus,
.unidy-overlay u-magic-code-field::part(input):focus,
.unidy-overlay u-registration-email-verification::part(input):focus {
    outline: none;
    border-color: var(--unidy-overlay-accent);
    box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.1);
}

.unidy-overlay .u-newsletter-step,
.unidy-overlay u-registration-newsletter,
.unidy-overlay u-registration-newsletter-preference {
    display: grid;
    gap: 10px;
}

.unidy-overlay .u-newsletter-choice,
.unidy-overlay .u-newsletter-pref {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 10px 12px;
    border: 1px solid var(--unidy-overlay-border);
    border-radius: 8px;
    background: var(--unidy-overlay-surface);
}

.unidy-overlay .u-newsletter-pref {
    margin-left: 18px;
}

.unidy-overlay .u-newsletter-choice__name {
    display: block;
    font-weight: 600;
}

.unidy-overlay .u-newsletter-choice__desc {
    display: block;
    color: var(--unidy-overlay-muted) !important;
    font-size: 13px;
    margin-top: 2px;
}

.unidy-overlay u-registration-passkey {
    display: block;
}

.unidy-overlay u-registration-passkey + .u-error,
.unidy-overlay .u-newsletter-step + .u-error {
    margin-top: 8px;
}

.unidy-nl-prefs {
    display: grid;
    gap: 10px;
    margin: 16px 0;
}

.unidy-nl-prefs__label {
    color: var(--unidy-overlay-muted) !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    margin: 0 !important;
}

.unidy-nl-pref {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 10px 12px;
    border: 1px solid var(--unidy-overlay-border);
    border-radius: 8px;
    background: var(--unidy-overlay-surface);
}

.unidy-nl-pref__name {
    color: var(--unidy-overlay-fg) !important;
    font-size: 14px;
    line-height: 1.4;
}

/* ── Signed-in header / avatar (minimal — Profile module extends) ────── */

.unidy-signed-in--minimal .unidy-profile-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
}
.unidy-avatar {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: var(--unidy-overlay-accent);
    color: var(--unidy-overlay-accent-fg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 15px;
}
.unidy-profile-name  { font-weight: 600; }
.unidy-profile-email { color: var(--unidy-overlay-muted); font-size: 14px; }

/* ── wp-login button wrap ─────────────────────────────────────────────── */

.unidy-sso-wrap { margin: 16px 0; }
.unidy-sso-btn  { color: var(--unidy-overlay-accent-fg); }

/* ── SDK submit/action buttons (custom elements) ─────────────────────────
 *
 * The SDK ships buttons as its own tags (`<u-submit-button>`,
 * `<u-registration-resend>`, `<u-newsletter-toggle-subscription-button>` …).
 * They accept `class-name="u-btn-primary"` in most versions — but not all,
 * and never for the internal `<button>` inside their shadow tree. Style at
 * both levels so the primary CTA is never invisible: element-level for the
 * host, ::part(button) for the shadow-DOM child.
 */
.unidy-overlay u-submit-button,
.unidy-overlay u-registration-resend,
.unidy-overlay u-send-magic-code-button,
.unidy-overlay u-registration-passkey,
.unidy-overlay u-newsletter-toggle-subscription-button,
.unidy-overlay u-logout-button {
    display: block;
    width: 100%;
    margin-top: 8px;
}

.unidy-overlay u-submit-button::part(button),
.unidy-overlay u-registration-resend::part(button),
.unidy-overlay u-send-magic-code-button::part(button),
.unidy-overlay u-registration-passkey::part(button),
.unidy-overlay u-newsletter-toggle-subscription-button::part(button),
.unidy-overlay u-logout-button::part(button),
.unidy-overlay u-submit-button::part(cta),
.unidy-overlay u-registration-resend::part(cta),
.unidy-overlay u-send-magic-code-button::part(cta) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    padding: 12px 18px;
    border-radius: 10px;
    border: 1px solid var(--unidy-overlay-accent);
    background: var(--unidy-overlay-accent);
    color: var(--unidy-overlay-accent-fg);
    font: inherit;
    font-weight: 600;
    font-size: 15px;
    cursor: pointer;
    box-sizing: border-box;
}
.unidy-overlay u-submit-button::part(button):hover,
.unidy-overlay u-registration-resend::part(button):hover,
.unidy-overlay u-logout-button::part(button):hover {
    filter: brightness(0.92);
}
.unidy-overlay u-submit-button::part(button):disabled,
.unidy-overlay u-submit-button[disabled]::part(button),
.unidy-overlay u-registration-resend::part(button):disabled {
    opacity: 0.55;
    cursor: not-allowed;
    filter: none;
}
/* Secondary intent — resend, send-magic-code, passkey, and logout are
 * visually less-loud than the primary submit. */
.unidy-overlay u-registration-resend::part(button),
.unidy-overlay u-send-magic-code-button::part(button),
.unidy-overlay u-registration-passkey::part(button),
.unidy-overlay u-logout-button::part(button) {
    background: var(--unidy-overlay-bg);
    color: var(--unidy-overlay-fg);
    border-color: var(--unidy-overlay-border);
}

/*
 * Class-based logout fallback. Older SDK versions don't expose
 * part="button" on <u-logout-button>, so ::part() misses. But every
 * version DOES forward the `class-name` attribute onto the internal
 * `<button>`, so `.unidy-overlay__logout` (or plain
 * .unidy-signed-in__body button) is a reliable second path. Style the
 * same way as the secondary ::part(button) block above. Scoped broadly
 * to catch the button inside the auth-overlay footer, the profile
 * signed-in body, and the standalone profile page.
 */
.unidy-overlay .unidy-overlay__logout,
.unidy-profile .unidy-overlay__logout,
.unidy-signed-in .unidy-overlay__logout,
.unidy-profile button[type='button'][class*='logout'],
.unidy-profile u-logout-button > button,
.unidy-overlay u-logout-button > button {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    min-height: 44px;
    padding: 10px 18px !important;
    background: var(--unidy-overlay-bg) !important;
    color: var(--unidy-overlay-fg) !important;
    border: 1px solid var(--unidy-overlay-border) !important;
    border-radius: var(--unidy-overlay-radius, 10px) !important;
    font-family: var(--unidy-overlay-font) !important;
    font-size: 15px !important;
    font-weight: 500 !important;
    line-height: 1.2 !important;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
    transition: background 150ms ease, border-color 150ms ease;
    margin-top: 12px;
}
.unidy-overlay .unidy-overlay__logout:hover,
.unidy-profile .unidy-overlay__logout:hover,
.unidy-signed-in .unidy-overlay__logout:hover,
.unidy-profile u-logout-button > button:hover,
.unidy-overlay u-logout-button > button:hover {
    background: var(--unidy-overlay-surface, #f8fafc) !important;
    border-color: var(--unidy-overlay-fg) !important;
}
.unidy-overlay .unidy-overlay__logout svg,
.unidy-profile .unidy-overlay__logout svg,
.unidy-signed-in .unidy-overlay__logout svg {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    stroke-width: 1.8;
}
/*
 * The signed-in profile view: put the logout in its own footer row,
 * right-aligned, narrower — the primary intent on that page is "edit
 * your data", not "get out". Full-width was overwhelming.
 */
.unidy-profile--standalone u-logout-button,
.unidy-signed-in .unidy-overlay__footer {
    display: block;
    text-align: right;
    padding-top: 20px;
    margin-top: 16px;
    border-top: 1px solid var(--unidy-overlay-border);
}
.unidy-profile--standalone u-logout-button > button,
.unidy-signed-in .unidy-overlay__footer .unidy-overlay__logout {
    width: auto !important;
    min-width: 140px;
}

/* Step description / small headline inside a step body. `.u-step-title`
 * is what registration.php puts above the OTP input; `.u-step-desc` is
 * the paragraph beneath. Both scoped so they don't inherit the theme's
 * display font or margins. */
.unidy-overlay .u-step-title {
    font-size: 17px !important;
    font-weight: 600 !important;
    line-height: 1.3 !important;
    margin: 0 0 4px !important;
    padding: 0 !important;
    color: var(--unidy-overlay-fg) !important;
    font-family: var(--unidy-overlay-font) !important;
}
.unidy-overlay .u-step-desc {
    font-size: 14px !important;
    line-height: 1.5 !important;
    margin: 0 0 12px !important;
    padding: 0 !important;
    color: var(--unidy-overlay-muted) !important;
}

/* Belt-and-braces: also ensure the class-based primary keeps a visible
 * label even when the SDK does forward class-name — the earlier rules
 * inherited `color: currentColor`, and host themes sometimes drop that
 * to transparent. Restated with a locked color pair. */
.unidy-overlay .u-btn-primary,
.unidy-overlay .unidy-sso-btn {
    color: var(--unidy-overlay-accent-fg) !important;
    background: var(--unidy-overlay-accent);
    min-height: 48px;
    font-size: 15px;
    font-weight: 600;
}

/*
 * SDK-native social-login buttons (<u-signin-google>, <u-signin-apple>,
 * <u-signin-facebook>). They render a light-DOM button with
 * part="social-login-button" and hardcoded Tailwind-shaped utility
 * classes (`u:w-full u:h-10 u:border …`) that never make it to CSS
 * because the SDK's Tailwind namespace isn't part of our bundle. Result:
 * flat grey box on light grey — reads as unstyled. Restyle here with a
 * modern white-tile look that matches our other secondary buttons and
 * respects the overlay's radius/border tokens.
 */
.unidy-overlay button[part='social-login-button'],
.unidy-overlay [part='social-login-button'] {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 12px;
    width: 100%;
    min-height: 48px;
    padding: 10px 16px !important;
    background: var(--unidy-overlay-bg) !important;
    color: var(--unidy-overlay-fg) !important;
    border: 1px solid var(--unidy-overlay-border) !important;
    border-radius: var(--unidy-overlay-radius, 10px) !important;
    font-family: var(--unidy-overlay-font) !important;
    font-size: 15px !important;
    font-weight: 500 !important;
    line-height: 1.2 !important;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
    transition: background 150ms ease, border-color 150ms ease,
                box-shadow 150ms ease, transform 150ms ease;
    margin-top: 8px;
}
.unidy-overlay button[part='social-login-button']:hover {
    background: var(--unidy-overlay-surface, #f8fafc) !important;
    border-color: var(--unidy-overlay-fg) !important;
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.10);
}
.unidy-overlay button[part='social-login-button']:active {
    transform: translateY(1px);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
}
.unidy-overlay button[part='social-login-button']:focus-visible {
    outline: 2px solid var(--unidy-overlay-accent);
    outline-offset: 2px;
}
/* Provider mark (Google G, Apple, Facebook) — keep it a discreet 20px so
 * the label reads as the primary content of the button. */
.unidy-overlay button[part='social-login-button'] svg,
.unidy-overlay button[part='social-login-button'] img,
.unidy-overlay [part='social-login-button'] > svg,
.unidy-overlay [part='social-login-button'] > img {
    flex: 0 0 20px;
    width: 20px;
    height: 20px;
    object-fit: contain;
}
/* Duplicate disabled-state rule REMOVED (2026-07-21) — was setting only
 * `opacity: 0.55; cursor: not-allowed` and left color/bg to the earlier
 * declaration, which combined with `.u-btn-primary { color: white
 * !important }` above produced white-on-#e2e8f0 (invisible label).
 * The consolidated disabled rule earlier in this file now handles bg,
 * border-color, and color with matching !important discipline. */

/* ── Signed-in profile layout ─────────────────────────────────────────── */
/*
 * The profile module's signed-in body — a mix of `<u-field>` elements plus
 * name/email/avatar/logout — renders as a plain vertical stream by default,
 * which reads as "readonly text" to the user (see screenshots 2 + 3). Give
 * the body a 2-column grid so first_name/last_name, postal_code/city etc.
 * pair up naturally. Fields with `data-full-width` (address, salutation)
 * span both columns. Profile templates opt-in by wrapping their fields in
 * `.unidy-signed-in__body`.
 */
.unidy-signed-in__body {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 14px;
    row-gap: 12px;
    margin-top: 4px;
}
.unidy-signed-in__body [data-full-width],
.unidy-signed-in__body u-registration-newsletter,
.unidy-signed-in__body u-registration-passkey,
.unidy-signed-in__body .u-field-full,
.unidy-signed-in__body u-field[data-full-width],
.unidy-signed-in__body u-raw-field[data-full-width] {
    grid-column: 1 / -1;
}
/* Compact viewport: fall back to single-column so 2×small-inputs don't
 * force horizontal scroll in a 400px panel. */
@media (max-width: 480px) {
    .unidy-signed-in__body { grid-template-columns: 1fr; }
}

/* Logout row sits full-width below the grid, right-aligned so the primary
 * intent stays "edit your data", not "log out". */
.unidy-signed-in__actions {
    grid-column: 1 / -1;
    display: flex;
    justify-content: flex-end;
    padding-top: 12px;
    margin-top: 8px;
    border-top: 1px solid var(--unidy-overlay-border);
}
.unidy-signed-in__actions u-logout-button {
    width: auto;
}
.unidy-signed-in__actions u-logout-button::part(button) {
    width: auto;
    min-height: 40px;
    padding: 8px 16px;
    font-size: 14px;
}

/* ── Autosave status toast ────────────────────────────────────────────── */
/*
 * Slot for the profile-autosave indicator ("Saving…" / "Saved ✓"). The
 * Profile renderer emits a `<div class="unidy-autosave-status">` sibling
 * to the field grid; JS toggles `--is-saving` / `--is-saved` on it. Kept
 * subtle — this is confirmation, not a call to action.
 */
.unidy-autosave-status {
    grid-column: 1 / -1;
    justify-self: end;
    align-items: center;
    display: none;
    gap: 6px;
    font-size: 12px;
    color: var(--unidy-overlay-muted);
    padding: 4px 8px;
    border-radius: 999px;
    background: var(--unidy-overlay-surface);
    border: 1px solid var(--unidy-overlay-border);
    transition: opacity 200ms;
}
.unidy-autosave-status--is-saving,
.unidy-autosave-status--is-saved {
    display: inline-flex;
}
.unidy-autosave-status--is-saved {
    color: #047857;
    border-color: #a7f3d0;
    background: #ecfdf5;
}
.unidy-autosave-status__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    animation: unidy-autosave-pulse 1.2s infinite ease-in-out;
}
.unidy-autosave-status--is-saved .unidy-autosave-status__dot {
    animation: none;
}
@keyframes unidy-autosave-pulse {
    0%, 100% { opacity: 0.4; }
    50%      { opacity: 1; }
}

/* ── Panel: flex column so header/body/footer fill the height  ─────────── */
/*
 * Without this, `.unidy-overlay__body` stops at its content height and
 * leaves the bottom half of the panel empty white (see screenshot 3). Modal
 * doesn't need this (auto-height dialog centred in viewport).
 */
.unidy-overlay--panel .unidy-overlay__dialog {
    display: flex;
    flex-direction: column;
}
.unidy-overlay--panel .unidy-overlay__body {
    flex: 1 1 auto;
    overflow-y: auto;
}
.unidy-overlay--panel .unidy-overlay__header,
.unidy-overlay--panel .unidy-overlay__footer {
    flex: 0 0 auto;
}

/* ── Panel-header spec (2026-07-17 design handoff) ──
 * Panels get a compact sticky header (title-left + close-right) and a
 * bottom border that separates it from the scrollable body. The header
 * background matches the panel surface so scroll content doesn't bleed
 * through. Overrides the taller modal-style header padding above. */
.unidy-overlay--panel .unidy-overlay__header {
    padding: 18px 20px;
    border-bottom: 1px solid var(--u-border);
    background: var(--u-surface);
    /* Panel-header sits on --u-surface (white). Force dark text regardless
     * of legacy operator customization of --unidy-overlay-header-fg (used
     * in modal mode for dark-header brands). */
    color: var(--u-text);
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.unidy-overlay--panel .unidy-overlay__header .unidy-overlay__title {
    font: var(--u-text-h3);
    font-size: 16px;   /* h3-tightened for the panel header slot */
    color: var(--u-text);
    margin: 0;
}
.unidy-overlay--panel .unidy-overlay__header .unidy-overlay__close {
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    border-radius: var(--u-radius-md);
    color: var(--u-text-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--u-dur-fast) var(--u-ease),
                color var(--u-dur-fast) var(--u-ease);
}
.unidy-overlay--panel .unidy-overlay__header .unidy-overlay__close:hover {
    background: var(--u-surface-sunken);
    color: var(--u-text);
}
.unidy-overlay--panel .unidy-overlay__header .unidy-overlay__close:focus-visible {
    outline: none;
    box-shadow: var(--u-focus-ring);
}
/* The centered logo makes sense in the auth modal but reads awkward inside
 * a narrow slide-in panel. Suppress it and let the title carry the header. */
.unidy-overlay--panel .unidy-overlay__header .unidy-overlay__logo {
    display: none;
}
/* Neutralize the modal's center-align rules when we're rendering as a panel —
 * the panel-header spec is always title-left + close-right. Modal defaults
 * to `display:grid, grid-template-columns:32px 1fr 32px`, which centres the
 * title; we override back to flex-row so the title sits left. */
.unidy-overlay--panel .unidy-overlay__header.unidy-overlay__header--center {
    display: flex;
    flex-direction: row;
    grid-template-columns: none;
    gap: 12px;
    padding: 18px 20px;
    justify-content: space-between;
    align-items: center;
}
.unidy-overlay--panel .unidy-overlay__header--center .unidy-overlay__title {
    grid-column: auto;
    justify-self: start;
    text-align: left;
    margin: 0;
    /* Modal centre-mode hides the title in favour of the logo (line 321).
     * Panel mode suppresses the logo and needs the title back — un-hide. */
    display: inline;
}
.unidy-overlay--panel .unidy-overlay__header--center .unidy-overlay__close {
    grid-column: auto;
    justify-self: end;
    align-self: center;
    position: static;
    top: auto;
    right: auto;
}

/* Panel body: tighter side padding than modal, comfortable vertical rhythm. */
.unidy-overlay--panel .unidy-overlay__body {
    padding: 20px;
}

/* ── [unidy_user_menu] — header avatar + dropdown ─────────────────────
 *
 * Standalone widget, NOT scoped to `.unidy-overlay`. Lives in the site's
 * own header, so hosts theme resets don't reach the overlay's
 * !important text-color rules. We restate the necessary tokens here so
 * the widget looks the same regardless of where it lands.
 */
.unidy-user-menu {
    display: inline-flex;
    align-items: center;
    font-family: var(--unidy-overlay-font);
    font-size: 14px;
    line-height: 1.4;
    color: var(--unidy-overlay-fg);
}
.unidy-user-menu--right { justify-content: flex-end; margin-left: auto; }
.unidy-user-menu--left  { justify-content: flex-start; margin-right: auto; }

.unidy-user-menu__dropdown {
    position: relative;
    display: inline-block;
}

/* ── Signed-in trigger (2026-07-17 header-widget handoff) ──
 * Transparent outline wrapper — label "Mein Profil" + avatar + chevron.
 * NOT a filled button. Sits on the site's dark header, gets outline
 * from rgba white; hover strengthens the outline. */
.unidy-user-menu__trigger {
    display: inline-flex !important;
    flex-direction: row !important;
    align-items: center !important;
    gap: 9px;
    padding: 5px 7px 5px 15px;
    background: transparent !important;
    border: 1.5px solid rgba(255, 255, 255, 0.25) !important;
    border-radius: var(--u-radius-full, 999px);
    cursor: pointer;
    color: #ffffff;
    font-family: inherit;
    line-height: 1;
    transition: border-color var(--u-dur-fast, 120ms) var(--u-ease, ease),
                background var(--u-dur-fast, 120ms) var(--u-ease, ease);
}
.unidy-user-menu__trigger:hover,
.unidy-user-menu__trigger[aria-expanded="true"] {
    border-color: rgba(255, 255, 255, 0.5) !important;
}
.unidy-user-menu__trigger:focus-visible {
    outline: none;
    border-color: rgba(255, 255, 255, 0.9) !important;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.15);
}
.unidy-user-menu__trigger-label {
    color: #ffffff;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
}

.unidy-user-menu__avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: #ffffff;
    color: #0f172a;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0;
    line-height: 1;
    flex-shrink: 0;
}
/* Empty-initial fallback while JWT-decoder hasn't populated the initial —
 * render a subtle user-silhouette instead of the em-dash placeholder. */
.unidy-user-menu__avatar:empty::before,
.unidy-user-menu__avatar[data-empty="true"]::before {
    content: '\1F464';
    font-size: 15px;
    opacity: 0.7;
}

/* Chevron: rotates 180° when menu opens. Icon comes from HeaderMenu.php
 * as an inline SVG so we can flip it via transform without swapping. */
.unidy-user-menu__chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #94a3b8;
    transition: transform var(--u-dur-fast, 120ms) var(--u-ease, ease),
                color var(--u-dur-fast, 120ms) var(--u-ease, ease);
    line-height: 0;
}
.unidy-user-menu__trigger[aria-expanded="true"] .unidy-user-menu__chevron {
    transform: rotate(180deg);
    color: #ffffff;
}

/* ── Dropdown panel (250px card, right-aligned, hard shadow) ──
 * Positioned absolutely from the trigger. Right-edge anchored so the
 * card grows leftward on the header. Hidden by default; visible when
 * aria-expanded="true" via CSS attribute selector. */
.unidy-user-menu__panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 100000;
    width: 250px;
    background: #ffffff;
    color: #0f172a;
    border-radius: var(--u-radius-lg, 12px);
    box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.5);
    padding: 8px;
    opacity: 0;
    transform: translateY(-6px);
    transform-origin: top right;
    pointer-events: none;
    visibility: hidden;
    transition: opacity var(--u-dur-base, 180ms) var(--u-ease, ease),
                transform var(--u-dur-base, 180ms) var(--u-ease, ease),
                visibility 0s linear var(--u-dur-base, 180ms);
}
.unidy-user-menu--left .unidy-user-menu__panel {
    right: auto;
    left: 0;
    transform-origin: top left;
}
.unidy-user-menu__trigger[aria-expanded='true'] + .unidy-user-menu__panel {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
    visibility: visible;
    transition: opacity var(--u-dur-base, 180ms) var(--u-ease, ease),
                transform var(--u-dur-base, 180ms) var(--u-ease, ease),
                visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
    .unidy-user-menu__panel,
    .unidy-user-menu__trigger[aria-expanded='true'] + .unidy-user-menu__panel {
        transform: none;
        transition: opacity var(--u-dur-fast, 120ms) linear,
                    visibility 0s linear var(--u-dur-fast, 120ms);
    }
    .unidy-user-menu__chevron { transition: transform var(--u-dur-fast, 120ms) linear; }
}
@media (max-width: 480px) {
    /* On mobile the trigger sits inside a narrow header-slot (~180px on
     * Towers), so `position: absolute` inherits that narrow width. Break
     * out of the trigger's positioning context with `position: fixed`
     * anchored to the viewport, and cap max-width so tablets don't get
     * a full-width strip that looks unbalanced. */
    .unidy-user-menu__panel {
        position: fixed;
        top: auto;
        bottom: auto;
        left: 12px;
        right: 12px;
        width: auto;
        max-width: 380px;
        margin-inline: auto;
        transform-origin: top center;
    }
    .unidy-user-menu__email {
        word-break: break-all;
        line-height: 1.35;
    }
}

/* Identity header: avatar 38px + name + email, border-bottom separator */
.unidy-user-menu__identity {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px;
    border-bottom: 1px solid #f1f5f9;
    margin-bottom: 6px;
}
.unidy-user-menu__identity-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: #f1f5f9;
    color: #0f172a;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 14px;
    line-height: 1;
    flex-shrink: 0;
}
.unidy-user-menu__identity-avatar[data-empty="true"]::before,
.unidy-user-menu__identity-avatar:empty::before {
    content: '\1F464';
    font-size: 18px;
    opacity: 0.6;
}
.unidy-user-menu__identity-meta {
    min-width: 0;
    flex: 1;
}
.unidy-user-menu__name {
    font-weight: 600;
    color: #0f172a;
    font-size: 14px;
    line-height: 1.3;
    word-break: break-word;
}
.unidy-user-menu__email {
    color: var(--u-text-muted, #64748b);
    font-size: 12px;
    margin-top: 2px;
    word-break: break-all;
}
.unidy-user-menu__identity:empty,
.unidy-user-menu__identity:has(.unidy-user-menu__name:empty):has(.unidy-user-menu__email:empty) {
    display: none;
}

/* Item rows: icon 17px muted + label 14/500 */
.unidy-user-menu__items { display: flex; flex-direction: column; gap: 2px; }
.unidy-user-menu__item {
    display: flex !important;
    align-items: center;
    gap: 11px;
    padding: 10px 12px;
    border-radius: var(--u-radius-md, 8px);
    color: #334155;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    background: transparent;
    border: 0;
    text-align: left;
    width: 100%;
    cursor: pointer;
    font-family: inherit;
    line-height: 1.4;
    transition: background var(--u-dur-fast, 120ms) var(--u-ease, ease),
                color var(--u-dur-fast, 120ms) var(--u-ease, ease);
}
.unidy-user-menu__item:hover,
.unidy-user-menu__item:focus-visible {
    background: #f8fafc;
    color: #0f172a;
    outline: none;
}
.unidy-user-menu__item-icon {
    color: var(--u-text-muted, #64748b);
    line-height: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.unidy-user-menu__item-icon svg { width: 17px; height: 17px; }

/* Logout group: separated by border-top, danger tint */
.unidy-user-menu__logout-group {
    border-top: 1px solid #f1f5f9;
    margin-top: 6px;
    padding-top: 6px;
}
.unidy-user-menu__item--logout {
    color: var(--u-danger, #dc2626) !important;
}
.unidy-user-menu__item--logout:hover {
    background: color-mix(in srgb, var(--u-danger, #dc2626) 8%, transparent) !important;
    color: var(--u-danger, #dc2626) !important;
}

/* SDK's u-logout-button in this context — style like a normal menu item. */
.unidy-user-menu u-logout-button {
    display: block !important;
    width: 100% !important;
    margin: 0 !important;
}
.unidy-user-menu u-logout-button::part(button),
.unidy-user-menu u-logout-button > button {
    display: flex !important;
    align-items: center !important;
    gap: 11px !important;
    width: 100% !important;
    min-height: 0 !important;
    padding: 10px 12px !important;
    text-align: left !important;
    background: transparent !important;
    border: 0 !important;
    border-radius: var(--u-radius-md, 8px) !important;
    box-shadow: none !important;
    font-weight: 500 !important;
    color: var(--u-danger, #dc2626) !important;
    font-size: 14px !important;
    line-height: 1.4 !important;
    cursor: pointer;
}
.unidy-user-menu u-logout-button::part(button):hover,
.unidy-user-menu u-logout-button > button:hover {
    background: color-mix(in srgb, var(--u-danger, #dc2626) 8%, transparent) !important;
    filter: none !important;
}

/* Signed-out state: a proper login CTA — HARDCODED white-on-white
 * chrome so it reads on any host theme regardless of what accent
 * vars the operator has set. The avatar-menu widget sits in the
 * site header (Towers' navy bar, someone else's white bar, whatever)
 * and can't gamble on inheriting the right contrast pair. */
.unidy-user-menu__signin {
    /* !important on display + flex-direction because Towers mobile theme
     * rewrites `header a` to `display: block, text-align: center`, which
     * turned our inline-flex pill into a vertical stack (icon above text)
     * on mobile only. Beat the theme decisively — this pill must always
     * be a single row of icon + text, at every viewport width. */
    display: inline-flex !important;
    flex-direction: row !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 8px;
    padding: 10px 18px;
    background: #ffffff !important;
    color: #0f172a !important;
    border: 1.5px solid rgba(15, 23, 42, 0.12);
    border-radius: 999px;
    text-decoration: none;
    font-weight: 600;
    font-size: 14px;
    line-height: 16px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
    white-space: nowrap;
    width: auto !important;
}
/* Reset any host-theme text-transform / letter-spacing so the pill
 * reads exactly as configured — Towers-style headers sometimes apply
 * a display-font uppercase transform that pushes the pill off-center. */
.unidy-user-menu__signin,
.unidy-user-menu__signin * {
    text-transform: none !important;
    letter-spacing: normal !important;
}
/* Person-icon via inline SVG data-uri. Inherits currentColor (dark
 * slate) — visible against the white pill. */
.unidy-user-menu__signin::before {
    content: '';
    display: block;
    width: 16px;
    height: 16px;
    line-height: 0;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm-7 10a7 7 0 1 1 14 0Z'/%3E%3C/svg%3E") no-repeat center / contain;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm-7 10a7 7 0 1 1 14 0Z'/%3E%3C/svg%3E") no-repeat center / contain;
    flex-shrink: 0;
    align-self: center;
}
.unidy-user-menu__signin:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
    background: #f8fafc !important;
}
.unidy-user-menu__signin:active {
    transform: translateY(0);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}
.unidy-user-menu__signin:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 3px;
}


/* ── Newsletter widget ────────────────────────────────────────────────
 *
 * A self-contained card that owns its palette via widget-scoped CSS
 * custom properties. Falls back to the auth-overlay tokens when a host
 * has customised them, otherwise renders as a light card so it stays
 * legible even on aggressive dark themes (Towers) without inheriting
 * the theme's own text color.
 *
 * All interactive elements are sized for touch — inputs 44px+ tall,
 * toggle switches 24px thumb, checkboxes 20px. Consent + submit read
 * as first-class controls, not decoration.
 */

.unidy-newsletter-section {
    /* Bind widget-scoped --unidy-nl-* to the design-system --u-* so a
     * data-u-theme="dark" scope on the wrapper flips the widget with the
     * rest of the module family. Hard-coded fallbacks kept for the case
     * the design tokens weren't loaded (e.g. minimal admin renders). */
    --unidy-nl-bg:         var(--u-surface,        #ffffff);
    --unidy-nl-fg:         var(--u-text,           #0f172a);
    --unidy-nl-muted:      var(--u-text-muted,     #64748b);
    --unidy-nl-surface:    var(--u-surface-sunken, #f8fafc);
    --unidy-nl-border:     var(--u-border,         #e2e8f0);
    --unidy-nl-accent:     var(--u-accent,         #111827);
    --unidy-nl-accent-fg:  var(--u-text-inverse,   #ffffff);
    --unidy-nl-track-off:  var(--u-border-strong,  #cbd5e1);
    --unidy-nl-danger:     var(--u-danger,         #dc2626);

    background: var(--unidy-nl-bg);
    color:      var(--unidy-nl-fg);
    max-width:   640px;
    margin:      24px auto;
    padding:     28px;
    border:      1px solid var(--unidy-nl-border);
    border-radius: 12px;
    box-shadow:  0 1px 3px rgba(0, 0, 0, 0.08);
    font-family: inherit;
    line-height: 1.5;
}

/* Intro */
.unidy-nl-intro {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-bottom: 24px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--unidy-nl-border);
}
.unidy-nl-intro__icon {
    flex-shrink: 0;
    color: var(--unidy-nl-accent);
    margin-top: 2px;
}
.unidy-nl-intro__title {
    display: block;
    font-size: 18px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
    margin-bottom: 4px;
}
.unidy-nl-intro__text {
    margin: 0;
    font-size: 14px;
    color: var(--unidy-nl-muted);
    line-height: 1.55;
}

/* Signup wrapper */
.unidy-nl-signup {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

/* Email field */
.unidy-nl-signup__email {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.unidy-nl-signup__email-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
}
.unidy-nl-input {
    width: 100%;
    height: 48px;
    padding: 0 16px;
    font-size: 15px;
    font-family: inherit;
    line-height: 1.4;
    color: var(--unidy-nl-fg);
    background: var(--unidy-nl-bg);
    border: 1.5px solid #cbd5e1;
    border-radius: 8px;
    box-sizing: border-box;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: border-color 150ms, box-shadow 150ms;
}
.unidy-nl-input:hover {
    border-color: #94a3b8;
}
.unidy-nl-input:focus {
    outline: none;
    border-color: var(--unidy-nl-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--unidy-nl-accent) 18%, transparent),
                inset 0 1px 2px rgba(0, 0, 0, 0.04);
}
.unidy-nl-input::placeholder {
    color: #94a3b8;
    opacity: 1;
}

/* "Bereits abonniert? Zur Verwaltung" — inline link disguised as button */
.unidy-nl-manage-link {
    align-self: flex-start;
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
    margin: -8px 0 0 !important;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    color: var(--unidy-nl-accent) !important;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

/* Card list */
.unidy-nl-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.unidy-nl-cards__label {
    margin: 8px 0 4px;
    font-size: 12px;
    font-weight: 700;
    color: var(--unidy-nl-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* Individual card */
.unidy-nl-card {
    background: var(--unidy-nl-surface);
    border: 1px solid var(--unidy-nl-border);
    border-radius: 10px;
    /* Bumped from 14/16 to 18/20 — the tighter padding made small cards
     * (title + short description) feel cramped against the 36px button. */
    padding: 18px 20px;
    transition: border-color 150ms, background 150ms;
}
.unidy-nl-card:hover {
    border-color: color-mix(in srgb, var(--unidy-nl-accent) 40%, var(--unidy-nl-border));
}
.unidy-nl-card__row {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 16px;
    cursor: pointer;
}
.unidy-nl-card__meta {
    display: flex;
    flex-direction: column;
    /* Bumped from 3 to 5 — 3px reads as cramped label/description pair;
     * 5px opens the two lines up without breaking their visual grouping. */
    gap: 5px;
    min-width: 0;
}
.unidy-nl-card__name {
    font-size: 15px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
}
.unidy-nl-card__desc {
    font-size: 13px;
    color: var(--unidy-nl-muted);
    line-height: 1.4;
}
.unidy-nl-card__badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--unidy-nl-accent);
    color: var(--unidy-nl-accent-fg);
    text-transform: uppercase;
    white-space: nowrap;
    align-self: center;
    justify-self: end;
    margin-right: 8px;
}

/* Nested sub-preferences — clean list, no per-row boxes */
.unidy-nl-card__prefs {
    display: flex;
    flex-direction: column;
    /* Bumped: 4px between checkboxes felt cramped, 12/12 margin/padding
     * around the divider gave a hard step. 16px opens the separation so
     * meta-row → PRÄFERENZEN → list reads as a smooth stack. */
    gap: 6px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--unidy-nl-border);
}
.unidy-nl-pref,
.unidy-newsletter-section label.unidy-nl-pref {
    display: flex !important;
    align-items: center;
    gap: 12px;
    font-size: 14px;
    color: var(--unidy-nl-fg);
    cursor: pointer;
    padding: 6px 8px;
    margin: 0;
    background: transparent !important;
    border: none !important;
    border-radius: 6px;
    box-shadow: none !important;
    transition: background 120ms ease;
}
.unidy-nl-pref:hover { background: var(--unidy-nl-surface) !important; }
.unidy-nl-pref span { line-height: 1.3; }
.unidy-nl-pref u-newsletter-preference-checkbox {
    display: inline-flex;
    align-items: center;
    line-height: 0;
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
    margin: 0 !important;
}

/* ── Toggle switch (used for main card subscribe checkbox) ────────────
 * <u-newsletter-checkbox class-name="unidy-nl-toggle"> renders an
 * `input[type=checkbox]` with our class — we style it as a pill switch
 * with a sliding thumb (::after). Purely CSS, no JS.
 */
.unidy-nl-toggle {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex-shrink: 0;
    width: 44px;
    height: 24px;
    background: var(--unidy-nl-track-off);
    border: none;
    border-radius: 999px;
    cursor: pointer;
    transition: background 200ms ease;
    margin: 0;
}
.unidy-nl-toggle::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    transition: transform 200ms ease;
}
.unidy-nl-toggle:checked {
    background: var(--unidy-nl-accent);
}
.unidy-nl-toggle:checked::after {
    transform: translateX(20px);
}
.unidy-nl-toggle:focus-visible {
    outline: 2px solid var(--unidy-nl-accent);
    outline-offset: 3px;
}

/* ── Standard checkbox (used for prefs + consent) ─────────────────────
 * Bigger tap target (20px), accent color when checked, own visible
 * outline. Matches Chromium's own accent-color implementation where
 * available, falls back to background swap on older engines.
 */
.unidy-nl-checkbox {
    appearance: auto;
    -webkit-appearance: auto;
    width: 20px;
    height: 20px;
    accent-color: var(--unidy-nl-accent);
    cursor: pointer;
    flex-shrink: 0;
    margin: 0;
}

/* Sub-preference checkbox is exactly the same style; the <u-newsletter-
 * preference-checkbox> element renders a native checkbox that inherits
 * from the surrounding label. The 20px accent-color styling applies via
 * the label's implicit input target. */
.unidy-nl-pref u-newsletter-preference-checkbox,
.unidy-nl-pref input[type="checkbox"] {
    accent-color: var(--unidy-nl-accent);
    width: 20px;
    height: 20px;
    cursor: pointer;
    flex-shrink: 0;
    margin: 0;
}

/* Consent row — sits at the same visual weight as cards but slightly
 * more compact. Font-size matches prefs for consistency. */
.unidy-nl-consent {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    margin-top: 4px;
    background: var(--unidy-nl-surface);
    border: 1px solid var(--unidy-nl-border);
    border-radius: 10px;
    font-size: 13px;
    color: var(--unidy-nl-fg);
    cursor: pointer;
    line-height: 1.5;
}
.unidy-nl-consent .unidy-nl-checkbox { margin-top: 1px; }

/* Submit button — same 48px height as email input for vertical rhythm */
.unidy-nl-submit {
    display: inline-flex;
    width: 100%;
    height: 48px;
    justify-content: center;
    align-items: center;
    padding: 0 20px;
    margin-top: 4px;
    font-size: 15px;
    font-weight: 600;
    font-family: inherit;
    background: var(--unidy-nl-accent) !important;
    color: var(--unidy-nl-accent-fg) !important;
    border: none !important;
    border-radius: 8px;
    cursor: pointer;
    transition: filter 150ms ease, transform 100ms;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.unidy-nl-submit:hover {
    filter: brightness(0.94);
}
.unidy-nl-submit:active {
    transform: translateY(1px);
}
.unidy-nl-submit:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    filter: none;
}
.unidy-nl-submit:focus-visible {
    outline: 2px solid var(--unidy-nl-accent);
    outline-offset: 3px;
}

/* Errors */
.unidy-nl-error {
    display: block;
    color: var(--unidy-nl-danger);
    font-size: 12px;
    font-weight: 500;
    margin-top: 6px;
}
.unidy-nl-error:empty { display: none; }

/* Signed-in hint */
.unidy-nl-signedin {
    margin: 0;
    padding: 14px 16px;
    background: color-mix(in srgb, var(--unidy-nl-accent) 8%, var(--unidy-nl-bg));
    border: 1px solid color-mix(in srgb, var(--unidy-nl-accent) 30%, transparent);
    border-radius: 8px;
    font-size: 14px;
    color: var(--unidy-nl-fg);
    line-height: 1.4;
}

/* Small-screen tweaks */
@media (max-width: 480px) {
    .unidy-newsletter-section { padding: 20px; margin: 16px 0; border-radius: 10px; }
    .unidy-nl-intro { gap: 10px; margin-bottom: 20px; padding-bottom: 16px; }
    .unidy-nl-card__row { grid-template-columns: 1fr auto; gap: 12px; }
    .unidy-nl-card__badge { grid-column: 1 / -1; justify-self: start; margin-right: 0; }
}

/* ── Newsletter preference-center + signed-in states ─────────────────── */

/* Success banner shown at the top of the signed-in preference-center
 * view. Green accent, checkmark icon, one row height, ~48px like inputs. */
.unidy-nl-success {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: #dcfce7;
    border: 1px solid #86efac;
    border-radius: 8px;
    color: #14532d;
    font-size: 14px;
    line-height: 1.4;
    margin-bottom: 4px;
}
.unidy-nl-success__icon { flex-shrink: 0; color: #16a34a; }
.unidy-nl-success__text { font-weight: 500; }

/* Identified email row — the visitor's identified address, clearly
 * marked as non-editable via a label above ("Angemeldet als") + a lock
 * icon left of the value + a compact "Ändern" pill button to swap
 * identity. Presented as a read-only DISPLAY, not a disabled input;
 * removes the affordance conflict where a bordered input suggests
 * editability. */
.unidy-nl-identified {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 8px;
    padding: 12px 14px;
    background: var(--unidy-nl-surface);
    border: 1px solid var(--unidy-nl-border);
    border-radius: 8px;
}
.unidy-nl-identified__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--unidy-nl-muted);
}
.unidy-nl-identified__row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}
.unidy-nl-identified__icon {
    flex-shrink: 0;
    color: var(--unidy-nl-muted);
}
.unidy-nl-identified u-email-field {
    flex: 1 1 100%;
    min-width: 0;
    width: 100%;
    display: block;
    align-items: center;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Reach through the SDK's <u-email-field> to the actual native <input>
 * it renders and strip ALL input chrome — border, bg, shadow, padding.
 * We want the value to look like plain text, not a disabled form field. */
.unidy-nl-input--identified,
u-email-field.unidy-nl-input--identified,
.unidy-nl-identified u-email-field input,
.unidy-nl-identified u-email-field input[disabled],
u-email-field.unidy-nl-input--identified input {
    height: auto !important;
    padding: 0 !important;
    background: transparent !important;
    color: var(--unidy-nl-fg) !important;
    border: 0 !important;
    outline: 0 !important;
    box-shadow: none !important;
    font-size: 15px !important;
    font-weight: 500 !important;
    font-family: inherit !important;
    cursor: default !important;
    opacity: 1 !important;
    line-height: 1.3 !important;
    width: 100% !important;
    max-width: 100% !important;
    min-width: 240px !important;
    box-sizing: border-box !important;
    -webkit-text-fill-color: var(--unidy-nl-fg) !important;
    text-overflow: ellipsis;
    overflow: hidden;
}
/* Native <input size="N"> attribute (SDK sets this to constrain width
 * to ~180px) overrides width via a browser default. Force via all: sizing
 * on the actual input element inside u-email-field so long emails are
 * fully readable. Also nuke inline attributes that might block width. */
.unidy-nl-identified u-email-field input {
    field-sizing: content;
}
/* <u-email-field> may render its own <input> element inside — reach in
 * so the padding actually applies to the visible text. Uses attribute
 * selectors so we don't have to guess if the SDK exposes a class-name
 * pass-through or a shadow-DOM part. */
.unidy-nl-input--identified input,
u-email-field.unidy-nl-input--identified input,
u-email-field[disabled] input,
.unidy-nl-identified input,
.unidy-nl-identified u-email-field input {
    padding-left: 16px !important;
    padding-right: 44px !important;
    box-sizing: border-box;
}
/* Also cover the case where u-email-field IS the visible input itself. */
u-email-field.unidy-nl-input {
    padding-left: 16px !important;
    padding-right: 44px !important;
    display: block;
    box-sizing: border-box;
}
/* Standard (non-identified) email field: reach the inner input too so
 * the anonymous signup input isn't flush against the left edge either. */
.unidy-nl-input input,
u-email-field.unidy-nl-input input {
    padding-left: 16px !important;
    padding-right: 16px !important;
    box-sizing: border-box;
    height: 100%;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    width: 100%;
}
/* "Ändern" pill on the right of the identified row. Small pill, quiet
 * default state, activates on hover / focus. */
.unidy-nl-identified__logout {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
}
.unidy-nl-identified__logout-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 5px 12px;
    border-radius: 999px;
    background: transparent;
    border: 1px solid var(--unidy-nl-border);
    color: var(--unidy-nl-fg);
    font-family: inherit;
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: background 120ms, border-color 120ms, color 120ms;
    white-space: nowrap;
}
.unidy-nl-identified__logout-btn:hover {
    background: color-mix(in srgb, var(--unidy-nl-fg) 6%, transparent);
    border-color: color-mix(in srgb, var(--unidy-nl-fg) 30%, transparent);
}
.unidy-nl-identified__logout-btn:focus-visible {
    outline: 2px solid var(--unidy-nl-accent);
    outline-offset: 2px;
}

/* Double-opt-in banner — yellow warning band under a card that's
 * subscribed but not yet confirmed. Includes a resend button. */
.unidy-nl-doi {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding: 10px 12px;
    background: #fef3c7;
    border: 1px solid #fcd34d;
    border-radius: 8px;
    color: #78350f;
    font-size: 13px;
    line-height: 1.4;
}
.unidy-nl-doi__text { flex: 1; }
.unidy-nl-doi__resend {
    white-space: nowrap;
    padding: 6px 12px;
    font-size: 13px;
    font-weight: 500;
    background: transparent !important;
    color: #78350f !important;
    border: 1px solid #d97706 !important;
    border-radius: 6px;
    cursor: pointer;
    transition: background 120ms;
}
.unidy-nl-doi__resend:hover {
    background: #fde68a !important;
}

/* Toggle-subscription button — the primary action on each card in the
 * preference-center view. Two states via SDK's `subscribe-class-name` +
 * `unsubscribe-class-name`. The web-component wrapper is constrained to
 * button-sized dimensions so an empty state (icon-only render, missing
 * label) doesn't balloon into a huge block in the grid parent. */
.unidy-nl-card__row u-newsletter-toggle-subscription-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: 110px;
    max-width: 160px;
    height: 36px;
    align-self: center;
    justify-self: end;
}
.unidy-nl-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    border-radius: 6px;
    cursor: pointer;
    transition: filter 120ms, background 120ms, color 120ms;
    white-space: nowrap;
    line-height: 1;
    box-sizing: border-box;
}
.unidy-nl-btn--subscribe,
u-newsletter-toggle-subscription-button .unidy-nl-btn--subscribe {
    background: var(--unidy-nl-accent) !important;
    color: var(--unidy-nl-accent-fg) !important;
    border: 1px solid var(--unidy-nl-accent) !important;
}
/* The SDK renders its own label inside the button — reach descendants
 * so the text color follows the class, not whatever the SDK's default
 * cascade would give it (which on dark host themes produces black-on-
 * black or white-on-white invisibility bugs). */
.unidy-nl-btn--subscribe *,
u-newsletter-toggle-subscription-button.unidy-nl-btn--subscribe *,
.unidy-nl-btn--subscribe span,
.unidy-nl-btn--subscribe button {
    color: var(--unidy-nl-accent-fg) !important;
}
.unidy-nl-btn--subscribe:hover { filter: brightness(0.94); }

.unidy-nl-btn--unsubscribe {
    background: transparent !important;
    color: var(--unidy-nl-danger) !important;
    border: 1px solid color-mix(in srgb, var(--unidy-nl-danger) 40%, transparent) !important;
}
.unidy-nl-btn--unsubscribe *,
.unidy-nl-btn--unsubscribe span,
.unidy-nl-btn--unsubscribe button {
    color: var(--unidy-nl-danger) !important;
}
.unidy-nl-btn--unsubscribe:hover {
    background: color-mix(in srgb, var(--unidy-nl-danger) 8%, transparent) !important;
}

/* Preferences label above the checkbox list on preference-center cards */
.unidy-nl-card__prefs-label {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--unidy-nl-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Not-identified fallback text — sits inside <u-conditional-render
 * when="newsletter.loggedIn" not> in the preference center only. */
.unidy-nl-not-identified {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}

/* Compact signed-in fallback (link_to_pc + disabled_email_only modes) */
.unidy-nl-signedin-link {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 4px 0;
}
.unidy-nl-signedin-link__text {
    margin: 0;
    font-size: 14px;
    color: var(--unidy-nl-fg);
    line-height: 1.5;
}
.unidy-nl-signedin-link__cta {
    display: inline-flex;
    align-items: center;
    padding: 10px 16px;
    background: var(--unidy-nl-accent);
    color: var(--unidy-nl-accent-fg) !important;
    text-decoration: none;
    font-size: 14px;
    font-weight: 600;
    border-radius: 6px;
    transition: filter 120ms;
}
.unidy-nl-signedin-link__cta:hover {
    filter: brightness(0.94);
}
.unidy-nl-signedin-compact {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Preference-center variant of the newsletter section — no signup
 * padding above, since it's used inside modals + inline pages where
 * we want a tighter top rhythm. */
.unidy-newsletter-section--prefs {
    padding-top: 20px;
}
.unidy-newsletter-section--overlay {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    border-radius: 0;
    background: transparent;
}

/* ── Newsletter flash messages ────────────────────────────────────────
 *
 * <u-flash-message> is the SDK's native toast component (subscribe /
 * unsubscribe / resend-doi / error events all push into its store).
 * We position it as a fixed top-right stack so it stays visible even
 * when the widget is inside a modal / panel and the user's viewport
 * has scrolled elsewhere. z-index sits ABOVE the auth-overlay dialog
 * (1000) so success confirmations don't get eaten by an open modal.
 * Animation: slide-in from right + fade so each new message reads. */
.unidy-nl-flash {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 10000;
    max-width: 400px;
    pointer-events: none;
}
.unidy-nl-flash > div {
    pointer-events: auto;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.15);
    animation: unidy-nl-flash-in 200ms ease-out;
}
@keyframes unidy-nl-flash-in {
    from { opacity: 0; transform: translateX(20px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* On very narrow viewports, stretch to full width with side gutters
 * so long messages don't clip against the right edge. */
@media (max-width: 480px) {
    .unidy-nl-flash {
        top: 12px;
        right: 12px;
        left: 12px;
        max-width: none;
    }
}

/* ── Flash toast level tinting (2026-07-17 friendly-messages feature) ──
 * The JS interceptor in overlay.js adds .u-flash--success / --error /
 * --info / --warning based on the message level registered in
 * Support\Messages. Each tint reads via the shared design tokens so
 * presets and dark-scope automatically propagate. */
u-flash-message,
u-flash-message > div {
    /* Give the SDK's default toast container a sane baseline before our
     * level tints apply. Padding + radius + text scale match the frontend
     * design handoff's `toast` spec (14/16 padding, radius-md, gap 10). */
    padding: 14px 16px;
    border-radius: var(--u-radius-md, 8px);
    border: 1px solid transparent;
    font: var(--u-text-body, 400 14px/20px var(--u-font));
    background: var(--u-surface, #ffffff);
    color: var(--u-text, #0f172a);
    display: flex;
    align-items: center;
    gap: 10px;
}
u-flash-message.u-flash--success,
u-flash-message.u-flash--success > div {
    background: var(--u-success-tint, #f0fdf4);
    border-color: color-mix(in srgb, var(--u-success, #16a34a) 24%, transparent);
    color: color-mix(in srgb, var(--u-success, #16a34a) 65%, #000);
}
u-flash-message.u-flash--error,
u-flash-message.u-flash--error > div {
    background: var(--u-danger-tint, #fef2f2);
    border-color: color-mix(in srgb, var(--u-danger, #dc2626) 24%, transparent);
    color: color-mix(in srgb, var(--u-danger, #dc2626) 70%, #000);
}
u-flash-message.u-flash--info,
u-flash-message.u-flash--info > div {
    background: var(--u-info-tint, #eff6ff);
    border-color: color-mix(in srgb, var(--u-info, #2563eb) 24%, transparent);
    color: color-mix(in srgb, var(--u-info, #2563eb) 70%, #000);
}
u-flash-message.u-flash--warning,
u-flash-message.u-flash--warning > div {
    background: var(--u-warning-tint, #fffbeb);
    border-color: color-mix(in srgb, var(--u-warning, #d97706) 24%, transparent);
    color: color-mix(in srgb, var(--u-warning, #d97706) 70%, #000);
}
/* Inline form errors (.u-error) — subtle red text, no background. */
.u-error {
    color: var(--u-danger, #dc2626);
    font-size: 13px;
    line-height: 1.4;
    margin: 4px 0 8px;
    display: block;
}

/* ── Profile widget (matches Newsletter card shell) ───────────────────
 *
 * <u-profile> + <u-field render-default-label="true"> render their own
 * label + input; we style the surrounding card + spacing + save button
 * to match the newsletter widget for visual consistency across modules.
 * Widget-scoped tokens fall back to the newsletter tokens (which fall
 * back to the overlay tokens) so a single design change propagates
 * everywhere.
 */
.unidy-profile-section {
    /* Same design-system binding as .unidy-newsletter-section — the
     * widget-scoped --unidy-nl-* names are shared between Profile and
     * Newsletter so both re-skin from one place. Bound to --u-* so
     * data-u-theme="dark" on the section flips the widget in step. */
    --unidy-nl-bg:         var(--u-surface,        #ffffff);
    --unidy-nl-fg:         var(--u-text,           #0f172a);
    --unidy-nl-muted:      var(--u-text-muted,     #64748b);
    --unidy-nl-surface:    var(--u-surface-sunken, #f8fafc);
    --unidy-nl-border:     var(--u-border,         #e2e8f0);
    --unidy-nl-accent:     var(--u-accent,         #111827);
    --unidy-nl-accent-fg:  var(--u-text-inverse,   #ffffff);
    --unidy-nl-danger:     var(--u-danger,         #dc2626);

    background:    var(--unidy-nl-bg);
    color:         var(--unidy-nl-fg);
    max-width:     640px;
    margin:        24px auto;
    padding:       28px;
    border:        1px solid var(--unidy-nl-border);
    border-radius: 12px;
    box-shadow:    0 1px 3px rgba(0, 0, 0, 0.08);
    font-family:   inherit;
    line-height:   1.5;
}
.unidy-profile-section--overlay {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    border-radius: 0;
    background: transparent;
}

/* Optional avatar header (when show_avatar is on) */
.unidy-profile-section .unidy-profile-header {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 20px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--unidy-nl-border);
}
.unidy-profile-section .unidy-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--unidy-nl-accent) 15%, transparent);
    color: var(--unidy-nl-accent);
    font-weight: 700;
    font-size: 18px;
    flex-shrink: 0;
}
.unidy-profile-section .unidy-profile-name  { font-weight: 600; }
.unidy-profile-section .unidy-profile-email { font-size: 13px; color: var(--unidy-nl-muted); }

/* Field grid — 2 columns on wider screens for the pairs (first/last
 * name, date_of_birth/phone_number), single column stacked on narrow.
 * `--half` fields participate in the 2-col grid; `--full` span both. */
.unidy-profile-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px 16px;
}
.unidy-profile-field           { display: block; min-width: 0; }
.unidy-profile-field--half     { grid-column: span 1; }
.unidy-profile-field--full     { grid-column: 1 / -1; }
@media (max-width: 480px) {
    .unidy-profile-grid { grid-template-columns: 1fr; }
    .unidy-profile-field--half { grid-column: 1 / -1; }
}

/* Custom-attributes block sits below the core grid with its own quiet
 * heading so users can tell "here are the required base fields, and
 * here are the fan-interest extras". */
.unidy-profile-custom {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--unidy-nl-border);
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.unidy-profile-section-label {
    margin: 0;
    font-size: 12px;
    font-weight: 700;
    color: var(--unidy-nl-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* SDK <u-field> uses Shadow DOM (shadow: true in Stencil), so descendant
 * selectors like `u-field input` DO NOT reach the inner elements — only
 * ::part() crosses the shadow boundary. All chrome below therefore
 * targets the SDK-exposed parts (see field.tsx JSDoc header for the
 * full catalogue). Field labels are rendered in the shadow tree and
 * exposed as ::part(field_label). */
.unidy-profile-section u-field {
    display: block;
    width: 100%;
}
.unidy-profile-section u-field::part(field_label) {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
    margin-bottom: 6px;
}

/* Text inputs (first_name, last_name, email, phone, date_of_birth, …),
 * selects (country_code, salutation-as-select fallback), and textareas
 * all share the same newsletter-email chrome for cross-widget
 * consistency. min-height 44px hits the mobile tap-target minimum. */
.unidy-profile-section u-field::part(input_field),
.unidy-profile-section u-field::part(select_field),
.unidy-profile-section u-field::part(textarea_field) {
    width: 100%;
    min-height: 44px;
    padding: 10px 14px;
    font-size: 15px;
    font-family: inherit;
    color: var(--unidy-nl-fg);
    background: var(--unidy-nl-bg);
    border: 1.5px solid #cbd5e1;
    border-radius: 8px;
    box-sizing: border-box;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: border-color 150ms, box-shadow 150ms;
}
.unidy-profile-section u-field::part(input_field):hover,
.unidy-profile-section u-field::part(select_field):hover,
.unidy-profile-section u-field::part(textarea_field):hover {
    border-color: #94a3b8;
}
.unidy-profile-section u-field::part(input_field):focus,
.unidy-profile-section u-field::part(select_field):focus,
.unidy-profile-section u-field::part(textarea_field):focus {
    outline: none;
    border-color: var(--unidy-nl-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--unidy-nl-accent) 18%, transparent),
                inset 0 1px 2px rgba(0, 0, 0, 0.04);
}
/* Readonly-value display (rendered as a <span> when a field is locked
 * by admin). Neutral surface so it doesn't masquerade as an editable
 * input. */
.unidy-profile-section u-field::part(input_field--readonly),
.unidy-profile-section u-field::part(select_field--readonly),
.unidy-profile-section u-field::part(textarea_field--readonly) {
    background: var(--unidy-nl-surface);
    color: var(--unidy-nl-muted);
    cursor: not-allowed;
}
/* Disabled state (during save, or admin-locked fields). */
.unidy-profile-section u-field::part(input_field--disabled),
.unidy-profile-section u-field::part(select_field--disabled),
.unidy-profile-section u-field::part(textarea_field--disabled) {
    background: var(--unidy-nl-surface);
    color: var(--unidy-nl-muted);
    cursor: not-allowed;
    opacity: 0.75;
}

/* Multi-select (custom_attributes.fan_interests etc.) styled as
 * clickable chips. Field-name-scoped selector so single-select
 * dropdowns (which use ::part(select_field) above) are unaffected. */
.unidy-profile-section u-field[field^="custom_attributes."]::part(multi-select-group_field) {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 0;
    border: none;
    background: transparent;
}
.unidy-profile-section u-field[field^="custom_attributes."]::part(multi-select-item_label) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 90px;
    height: 40px;
    padding: 0 14px;
    border: 1px solid var(--unidy-nl-border);
    border-radius: 999px;
    background: var(--unidy-nl-bg);
    font-size: 14px;
    cursor: pointer;
    transition: border-color 150ms, background 150ms;
}
.unidy-profile-section u-field[field^="custom_attributes."]::part(multi-select-item_label):hover {
    border-color: var(--unidy-nl-accent);
    background: color-mix(in srgb, var(--unidy-nl-accent) 6%, var(--unidy-nl-bg));
}
.unidy-profile-section u-field[field^="custom_attributes."]::part(multi-select-item_checkbox) {
    width: 16px;
    height: 16px;
    margin: 0 8px 0 0;
    accent-color: var(--unidy-nl-accent);
    cursor: pointer;
}

/* Salutation as a segmented-pill selector (Herr / Frau / Divers in a
 * rounded rail). Shadow DOM means only ::part selectors reach the
 * radio-group internals — RadioGroup.tsx exposes:
 *   • radio-group_field          → the wrapping <div> (rail)
 *   • radio-group-item_label     → each option pill (<label>)
 *   • radio_checked              → an *additional* part on the checked
 *                                   label — targetable via ::part()
 *                                   because ::part matches any token
 *                                   in the part attribute
 *   • radio-group-item_radio     → the native <input type="radio">
 *
 * The visible "pill" is the label; the native radio is visually hidden
 * (accessibility preserved: label click-target + focus-visible ring on
 * the pill via :focus-within). */
.unidy-profile-section u-field[field="salutation"]::part(radio-group_field) {
    display: flex;
    width: 100%;
    padding: 4px;
    border: 1px solid var(--unidy-nl-border);
    border-radius: 999px;
    background: var(--unidy-nl-surface);
    gap: 0;
    box-sizing: border-box;
}
.unidy-profile-section u-field[field="salutation"]::part(radio-group-item_label) {
    display: inline-flex;
    flex: 1 1 0;
    align-items: center;
    justify-content: center;
    height: 40px;
    padding: 0 18px;
    font-size: 14px;
    font-weight: 500;
    color: var(--unidy-nl-fg);
    background: transparent;
    border: none;
    border-radius: 999px;
    cursor: pointer;
    transition: background 150ms, color 150ms;
    line-height: 1;
    margin: 0;
}
.unidy-profile-section u-field[field="salutation"]::part(radio-group-item_label):hover {
    background: color-mix(in srgb, var(--unidy-nl-accent) 8%, transparent);
}
/* Hide the native radio input — the pill IS the affordance. Kept in
 * the DOM (not display:none) so screen-reader semantics survive. */
.unidy-profile-section u-field[field="salutation"]::part(radio-group-item_radio) {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
    opacity: 0;
    pointer-events: none;
}
/* Checked pill — ::part(radio_checked) matches because the SDK
 * concatenates `radio_checked` onto the label's part attribute when
 * the option is selected (RadioGroup.tsx line 58). */
.unidy-profile-section u-field[field="salutation"]::part(radio_checked) {
    background: var(--unidy-nl-accent);
    color: var(--unidy-nl-accent-fg);
}

/* Save-indicator: a green checkmark that appears for ~2s after a
 * field autosaves. Reassures the user their edit landed without a
 * global toast. field-input-wrapper positions the indicator inside
 * the field row. */
.unidy-profile-section u-field::part(field-input-wrapper) {
    position: relative;
    display: block;
}
.unidy-profile-section u-field::part(field-save-indicator) {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    pointer-events: none;
}
.unidy-profile-section u-field::part(field-save-indicator--saved) {
    color: #16a34a;
    animation: unidy-profile-saved-fade 400ms ease-out;
}
.unidy-profile-section u-field::part(field-save-indicator--saving) {
    color: var(--unidy-nl-muted);
}
@keyframes unidy-profile-saved-fade {
    from { opacity: 0; transform: translateY(-50%) scale(0.6); }
    to   { opacity: 1; transform: translateY(-50%) scale(1); }
}

/* Save button — same 48px height + accent styling as newsletter submit. */
.unidy-profile-submit {
    display: inline-flex;
    width: 100%;
    height: 48px;
    justify-content: center;
    align-items: center;
    padding: 0 20px;
    margin-top: 8px;
    font-size: 15px;
    font-weight: 600;
    font-family: inherit;
    background: var(--unidy-nl-accent) !important;
    color: var(--unidy-nl-accent-fg) !important;
    border: none !important;
    border-radius: 8px;
    cursor: pointer;
    transition: filter 150ms ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.unidy-profile-submit *,
.unidy-profile-submit span,
.unidy-profile-submit button {
    color: var(--unidy-nl-accent-fg) !important;
}
.unidy-profile-submit:hover    { filter: brightness(0.94); }
.unidy-profile-submit:disabled { opacity: 0.55; cursor: not-allowed; }

/* Signed-out fallback */
.unidy-profile-signin-hint {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}
/* ── Tickets widget (`.unidy-tk-*`) ───────────────────────────────────
 *
 * SDK 1.8 <u-ticketable-list ticketable-type="ticket"> surface. Card
 * shell matches `.unidy-newsletter-section` so all Unidy widgets read
 * as one system on any host theme. The `--unidy-nl-*` tokens are
 * redeclared here so the widget is self-contained even when a page
 * only ships `[unidy_tickets]` (no newsletter widget to inherit
 * from). `.unidy-tk-section--overlay` strips the card chrome so the
 * same template renders flush inside a modal / panel body.
 */
.unidy-tk-section {
    /* Bound to design-system --u-* — dark-scope on wrapper flips widget. */
    --unidy-nl-bg:         var(--u-surface,        #ffffff);
    --unidy-nl-fg:         var(--u-text,           #0f172a);
    --unidy-nl-muted:      var(--u-text-muted,     #64748b);
    --unidy-nl-surface:    var(--u-surface-sunken, #f8fafc);
    --unidy-nl-border:     var(--u-border,         #e2e8f0);
    --unidy-nl-accent:     var(--u-accent,         #111827);
    --unidy-nl-accent-fg:  var(--u-text-inverse,   #ffffff);
    --unidy-nl-danger:     var(--u-danger,         #dc2626);

    background: var(--unidy-nl-bg);
    color:      var(--unidy-nl-fg);
    max-width:   640px;
    margin:      24px auto;
    padding:     28px;
    border:      1px solid var(--unidy-nl-border);
    border-radius: 12px;
    box-shadow:  0 1px 3px rgba(0, 0, 0, 0.08);
    font-family: inherit;
    line-height: 1.5;
}
.unidy-tk-section--overlay {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    border-radius: 0;
    background: transparent;
}
/* Row-based list per 2026-07-17 design handoff. One item per row, spine
 * on the left, 52px date chip, main content flexes, actions right. */
.unidy-tk-list {
    display: flex;
    flex-direction: column;
}
.unidy-tk-item {
    display: grid;
    grid-template-columns: 4px 52px 1fr auto;
    align-items: stretch;
    gap: 14px;
    padding: 14px 4px 14px 0;
    border-bottom: 1px solid color-mix(in srgb, var(--unidy-nl-border) 60%, transparent);
    background: transparent;
    transition: background var(--u-dur-fast, 120ms) var(--u-ease, ease);
}
.unidy-tk-item:last-child { border-bottom: none; }
.unidy-tk-item:hover { background: var(--unidy-nl-surface); }

/* Spine — color-coded by next-up vs archival. `--u-accent` is the
 * default because most rendered tickets are upcoming; specialisation
 * to a past/stale color happens once we wire `data-past` from the SDK. */
.unidy-tk-item__spine {
    grid-column: 1;
    background: var(--u-accent, var(--unidy-nl-accent));
    border-radius: 2px;
    align-self: stretch;
    min-height: 44px;
}

/* Date chip — day 22px bold, month 11px uppercase muted. */
.unidy-tk-item__date {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding-top: 2px;
    border-right: 1px solid var(--unidy-nl-border);
    padding-right: 12px;
    line-height: 1;
}
.unidy-tk-item__date-day {
    font-size: 22px;
    font-weight: 700;
    color: var(--unidy-nl-fg);
    font-family: var(--u-font, inherit);
    letter-spacing: -0.02em;
}
.unidy-tk-item__date-month {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--unidy-nl-muted);
    margin-top: 3px;
}

.unidy-tk-item__main {
    grid-column: 3;
    min-width: 0; /* enables text-overflow ellipsis inside flex */
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.unidy-tk-item__title {
    /* Customer themes (Towers, upscale, others) frequently define
     * `h3 { font-family: <display-font>; font-size: 60px; }` which
     * blows the ticket-row layout apart. `!important` on all three
     * font props (family + size + weight + line-height) is the only
     * reliable way to hold the row height stable across themes. */
    margin: 0 !important;
    padding: 0 !important;
    font-family: var(--u-font, inherit) !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    line-height: 1.3 !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    color: var(--unidy-nl-fg) !important;
    display: flex;
    align-items: center;
    gap: 8px;
    /* One-line ellipsis for tight rows. Multi-line titles still wrap
     * inside the main block; ellipsis is only the last-resort truncation. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.unidy-tk-item__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    font-size: 13px;
    color: var(--unidy-nl-muted);
    line-height: 1.4;
}
.unidy-tk-item__meta-item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.unidy-tk-item__meta-item svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    opacity: 0.9;
}
.unidy-tk-item__extras {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    font-size: 12px;
    color: var(--unidy-nl-muted);
    margin-top: 2px;
}
.unidy-tk-item__category {
    padding: 2px 8px;
    background: var(--unidy-nl-surface);
    border-radius: var(--u-radius-full, 999px);
    color: var(--unidy-nl-fg);
    font-weight: 500;
    font-size: 11px;
}
.unidy-tk-item__price {
    font-weight: 600;
    color: var(--unidy-nl-fg);
    font-variant-numeric: tabular-nums;
    align-self: center;
}

.unidy-tk-badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: 999px;
    flex-shrink: 0;
}
.unidy-tk-badge--vip {
    background: #fef3c7;
    color: #78350f;
}

.unidy-tk-item__actions {
    grid-column: 4;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.unidy-tk-item__chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--u-radius-md, 8px);
    color: var(--unidy-nl-muted);
    text-decoration: none;
    background: transparent;
    transition: background var(--u-dur-fast, 120ms), color var(--u-dur-fast, 120ms);
}
.unidy-tk-item__chevron:hover {
    background: var(--unidy-nl-surface);
    color: var(--unidy-nl-fg);
}
.unidy-tk-item__chevron:focus-visible {
    outline: none;
    box-shadow: var(--u-focus-ring, 0 0 0 3px rgba(17,24,39,.12));
}

/* Narrow viewport / panel — collapse the horizontal layout, stack the
 * actions full-width. Trigger at 480px OR when we're in the overlay
 * scope (panel-mode, 320px). */
@media (max-width: 480px) {
    .unidy-tk-item {
        grid-template-columns: 4px auto 1fr;
        grid-template-areas:
            'spine date main'
            '.     .    actions';
        row-gap: 10px;
    }
    .unidy-tk-item__spine { grid-area: spine; }
    .unidy-tk-item__date { grid-area: date; }
    .unidy-tk-item__main { grid-area: main; }
    .unidy-tk-item__actions {
        grid-area: actions;
        justify-content: flex-start;
        flex-wrap: wrap;
        width: 100%;
    }
    .unidy-tk-item__title { white-space: normal; }
}
.unidy-tk-section--overlay .unidy-tk-item {
    grid-template-columns: 4px auto 1fr;
    grid-template-areas:
        'spine date main'
        '.     .    actions';
    row-gap: 10px;
}
.unidy-tk-section--overlay .unidy-tk-item__spine { grid-area: spine; }
.unidy-tk-section--overlay .unidy-tk-item__date { grid-area: date; }
.unidy-tk-section--overlay .unidy-tk-item__main { grid-area: main; }
.unidy-tk-section--overlay .unidy-tk-item__actions {
    grid-area: actions;
    justify-content: flex-start;
    flex-wrap: wrap;
    width: 100%;
}
.unidy-tk-section--overlay .unidy-tk-item__title { white-space: normal; }
.unidy-tk-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 36px;
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    border-radius: 6px;
    border: none;
    cursor: pointer;
    text-decoration: none;
    transition: filter 120ms, background 120ms, border-color 120ms;
}
.unidy-tk-btn--primary {
    background: var(--unidy-nl-accent);
    color: var(--unidy-nl-accent-fg) !important;
}
.unidy-tk-btn--primary:hover { filter: brightness(0.94); }
.unidy-tk-btn--secondary {
    background: transparent;
    border: 1px solid var(--unidy-nl-border);
    color: var(--unidy-nl-fg) !important;
}
.unidy-tk-btn--secondary:hover {
    background: color-mix(in srgb, var(--unidy-nl-fg) 6%, transparent);
}
.unidy-tk-btn--dark {
    background: var(--unidy-nl-fg);
    color: var(--unidy-nl-bg) !important;
}
.unidy-tk-btn--dark:hover { filter: brightness(1.1); }
.unidy-tk-empty {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}
.unidy-tk-signin-hint {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}

/* ── Transactions widget (`.unidy-tx-*`) ──────────────────────────────
 *
 * SDK 1.8 <u-transaction-list> surface. Same shell language as the
 * tickets widget; row layout is flex-between with meta on the left and
 * amount + status pill on the right. Filter row uses a native <select>
 * styled to match the newsletter email input.
 */
.unidy-tx-section {
    /* Bound to design-system --u-* — dark-scope on wrapper flips widget. */
    --unidy-nl-bg:         var(--u-surface,        #ffffff);
    --unidy-nl-fg:         var(--u-text,           #0f172a);
    --unidy-nl-muted:      var(--u-text-muted,     #64748b);
    --unidy-nl-surface:    var(--u-surface-sunken, #f8fafc);
    --unidy-nl-border:     var(--u-border,         #e2e8f0);
    --unidy-nl-accent:     var(--u-accent,         #111827);
    --unidy-nl-accent-fg:  var(--u-text-inverse,   #ffffff);

    background: var(--unidy-nl-bg);
    color:      var(--unidy-nl-fg);
    max-width:   640px;
    margin:      24px auto;
    padding:     28px;
    border:      1px solid var(--unidy-nl-border);
    border-radius: 12px;
    box-shadow:  0 1px 3px rgba(0, 0, 0, 0.08);
    font-family: inherit;
    line-height: 1.5;
}
.unidy-tx-section--overlay {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    border-radius: 0;
    background: transparent;
}
.unidy-tx-filter-row {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 14px;
}
.unidy-tx-filter {
    min-height: 48px;
    padding: 0 32px 0 14px;
    font-size: 14px;
    font-family: inherit;
    color: var(--unidy-nl-fg);
    background: var(--unidy-nl-bg);
    border: 1.5px solid #cbd5e1;
    border-radius: 8px;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: border-color 150ms, box-shadow 150ms;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 12px center;
}
.unidy-tx-filter:hover { border-color: #94a3b8; }
.unidy-tx-filter:focus {
    outline: none;
    border-color: var(--unidy-nl-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--unidy-nl-accent) 18%, transparent);
}
.unidy-tx-grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.unidy-tx-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 14px;
    background: var(--unidy-nl-surface);
    border: 1px solid var(--unidy-nl-border);
    border-radius: 8px;
    transition: border-color 150ms;
}
.unidy-tx-row:hover {
    border-color: color-mix(in srgb, var(--unidy-nl-accent) 40%, var(--unidy-nl-border));
}
.unidy-tx-row__meta {
    flex: 1 1 auto;
    min-width: 0;
}
.unidy-tx-row__reference {
    margin: 0 0 2px;
    font-size: 14px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
    line-height: 1.3;
}
.unidy-tx-row__source {
    margin: 0;
    font-size: 12px;
    color: var(--unidy-nl-muted);
    line-height: 1.35;
}
.unidy-tx-row__amount {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    flex-shrink: 0;
}
.unidy-tx-row__total {
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--unidy-nl-fg);
}
.unidy-tx-state {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: 999px;
    background: #e2e8f0;
    color: #475569;
}
.unidy-tx-state[data-state="paid"] {
    background: #dcfce7;
    color: #14532d;
}
.unidy-tx-state[data-state="pending"] {
    background: #fef3c7;
    color: #78350f;
}
.unidy-tx-state[data-state="refunded"] {
    background: #e2e8f0;
    color: #475569;
}
.unidy-tx-empty {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}
.unidy-tx-signin-hint {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}

/* ── Subscriptions widget (`.unidy-sub-*`) ────────────────────────────
 *
 * SDK 1.8 <u-ticketable-list ticketable-type="subscription"> surface.
 * Card shape mirrors `.unidy-tk-card`; state pill uses the same colour
 * language as `.unidy-tx-state` so paid/active/pending/refunded/canceled
 * feel like one visual vocabulary.
 */
.unidy-sub-section {
    /* Bound to design-system --u-* — dark-scope on wrapper flips widget. */
    --unidy-nl-bg:         var(--u-surface,        #ffffff);
    --unidy-nl-fg:         var(--u-text,           #0f172a);
    --unidy-nl-muted:      var(--u-text-muted,     #64748b);
    --unidy-nl-surface:    var(--u-surface-sunken, #f8fafc);
    --unidy-nl-border:     var(--u-border,         #e2e8f0);
    --unidy-nl-accent:     var(--u-accent,         #111827);
    --unidy-nl-accent-fg:  var(--u-text-inverse,   #ffffff);

    background: var(--unidy-nl-bg);
    color:      var(--unidy-nl-fg);
    max-width:   640px;
    margin:      24px auto;
    padding:     28px;
    border:      1px solid var(--unidy-nl-border);
    border-radius: 12px;
    box-shadow:  0 1px 3px rgba(0, 0, 0, 0.08);
    font-family: inherit;
    line-height: 1.5;
}
.unidy-sub-section--overlay {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    border-radius: 0;
    background: transparent;
}
.unidy-sub-grid {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.unidy-sub-card {
    background: var(--unidy-nl-surface);
    border: 1px solid var(--unidy-nl-border);
    border-radius: 10px;
    padding: 14px 16px;
    transition: border-color 150ms;
}
.unidy-sub-card:hover {
    border-color: color-mix(in srgb, var(--unidy-nl-accent) 40%, var(--unidy-nl-border));
}
.unidy-sub-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.unidy-sub-card__title {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 600;
    color: var(--unidy-nl-fg);
    line-height: 1.35;
}
.unidy-sub-card__meta,
.unidy-sub-card__price {
    margin: 0 0 2px;
    font-size: 13px;
    color: var(--unidy-nl-muted);
    line-height: 1.4;
}
.unidy-sub-card__price {
    font-weight: 600;
    color: var(--unidy-nl-fg);
}
.unidy-sub-state {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: 999px;
    background: #e2e8f0;
    color: #475569;
    flex-shrink: 0;
}
.unidy-sub-state[data-state="active"] {
    background: #dcfce7;
    color: #14532d;
}
.unidy-sub-state[data-state="paused"] {
    background: #fef3c7;
    color: #78350f;
}
.unidy-sub-state[data-state="canceled"],
.unidy-sub-state[data-state="expired"] {
    background: #e2e8f0;
    color: #475569;
}
.unidy-sub-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    padding: 8px 18px;
    font-size: 14px;
    font-weight: 600;
    font-family: inherit;
    background: var(--unidy-nl-accent);
    color: var(--unidy-nl-accent-fg) !important;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    text-decoration: none;
    transition: filter 120ms;
}
.unidy-sub-btn:hover { filter: brightness(0.94); }
.unidy-sub-empty {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}
.unidy-sub-signin-hint {
    margin: 0;
    padding: 16px 18px;
    background: var(--unidy-nl-surface);
    border: 1px dashed var(--unidy-nl-border);
    border-radius: 8px;
    color: var(--unidy-nl-muted);
    font-size: 14px;
    line-height: 1.5;
}

/* Small-screen tweaks for the ticketable + transaction widgets */
@media (max-width: 480px) {
    .unidy-tk-section,
    .unidy-tx-section,
    .unidy-sub-section {
        padding: 20px;
        margin: 16px 0;
        border-radius: 10px;
    }
    .unidy-tk-section--overlay,
    .unidy-tx-section--overlay,
    .unidy-sub-section--overlay {
        padding: 0;
        margin: 0;
    }
    .unidy-tx-row { flex-direction: column; align-items: stretch; }
    .unidy-tx-row__amount { align-items: flex-start; }
}

/* ============================================================
   Mobile refinement pass (2026-07-17)
   ============================================================
   Consolidated overrides across every Unidy widget for viewports
   ≤ 480px. Focus areas:
     1. Neutralize customer-theme h1/h2/h3 that inflate our section
        titles to 60-90px display fonts (Towers, upscale, others).
     2. Shrink card/section padding to give content more room.
     3. Force single-column layouts where grids stack awkwardly.
     4. Full-width primary CTAs so thumbs can reach the target.
   ============================================================ */
@media (max-width: 480px) {
    /* ── Section titles across widgets — reset the theme cascade
     * so operators don't need to write custom.css to fix h1/h2/h3
     * font-family + size in the ticket / newsletter / profile /
     * transactions containers. */
    .unidy-nl-section h1,
    .unidy-nl-section h2,
    .unidy-nl-section h3,
    .unidy-newsletter-section h1,
    .unidy-newsletter-section h2,
    .unidy-newsletter-section h3,
    .unidy-profile-section h1,
    .unidy-profile-section h2,
    .unidy-profile-section h3,
    .unidy-tk-section h1,
    .unidy-tk-section h2,
    .unidy-tk-section h3,
    .unidy-tx-section h1,
    .unidy-tx-section h2,
    .unidy-tx-section h3,
    .unidy-sub-section h1,
    .unidy-sub-section h2,
    .unidy-sub-section h3 {
        font-family: var(--u-font, inherit) !important;
        font-size: 18px !important;
        font-weight: 600 !important;
        line-height: 1.35 !important;
        letter-spacing: 0 !important;
        text-transform: none !important;
    }

    /* ── Widget container padding — tighter on mobile so content
     * gets more of the ~350px viewport. Preserves the light-card
     * shell but stops eating 56px total to L+R padding. */
    .unidy-nl-section,
    .unidy-newsletter-section,
    .unidy-profile-section,
    .unidy-tk-section,
    .unidy-tx-section,
    .unidy-sub-section {
        padding: 16px !important;
        margin: 12px auto !important;
    }

    /* ── Profile field grid → single column ────────────────── */
    .unidy-profile-fields {
        grid-template-columns: 1fr !important;
        gap: 12px !important;
    }

    /* ── Newsletter preference cards → less padding ─────────── */
    .unidy-nl-card {
        padding: 12px 14px !important;
    }

    /* ── Ticket-detail root — reduce outer padding, tighter QR */
    .uvt {
        margin: 8px 4px !important;
        padding: 16px 12px !important;
        border-radius: 12px !important;
    }
    .uvt-qr__frame {
        padding: 12px !important;
    }
    .uvt-qr__canvas {
        max-width: 220px !important;
    }
    .uvt-tiles {
        gap: 6px !important;
    }
    .uvt-tile {
        padding: 10px !important;
    }

    /* ── Empty-state buttons full-width so the tap target is clear */
    .uvt-empty__cta,
    .u-empty__cta {
        width: 100%;
        max-width: 320px;
        box-sizing: border-box;
    }

    /* ── Auth overlay — full-height sheet on mobile instead of a
     * floating modal centered vertically. Feels native. */
    .unidy-overlay--modal .unidy-overlay__panel {
        max-width: none !important;
        margin: 0 !important;
        border-radius: 16px 16px 0 0 !important;
        max-height: 92vh;
        align-self: flex-end;
    }

    /* ── Ticket-list row — Towers theme h3 blows up ticket titles
     * on Mobile too. The existing overrides on the class handle
     * .unidy-tk-item__title, but a stray theme rule like
     * `.entry-content h3 { font-size: 42px; }` beats our rule
     * unless we also anchor by container. Belt + braces here. */
    .unidy-tk-section h3.unidy-tk-item__title {
        font-size: 15px !important;
        line-height: 1.3 !important;
    }
}
