/* ============================================================
   Avatar Onboarding Wizard
   Single-page, Alpine-driven guided flow. Chrome + step layout.
   Colours follow the platform accent (--color-accent, set globally
   by Unfold's customization helper) and the shared card tokens.
   ============================================================ */

/* v21 tokens: the P3 blue (#3b6fed) is both the primary button fill and the
   accent; it follows the customizer's --color-accent inside the app and
   falls back to the design value on the bare auth pages. */
:root {
    --ob-primary: var(--color-accent, #3b6fed);
    --ob-accent: var(--color-accent, #3b6fed);
    --ob-ink-primary: #ffffff;
    --ob-card: var(--bg-card, #ffffff);
    --ob-surface: var(--bg-page, #f7f8fa);
    --ob-line: var(--border-color, #e7e8ec);
    --ob-ink: var(--text-primary, #0b0d14);
    --ob-muted: var(--text-secondary, #6b7280);
    --ob-ok: #eafaf1;
    --ob-ok-text: #1aa361;
}

.dark {
    --ob-card: #18181b;
    --ob-surface: #131316;
    --ob-line: #27272a;
    --ob-ink: #f4f4f5;
    --ob-muted: #a1a1aa;
    /* --ob-ok is a BACKGROUND tint, so the dark override has to stay a tint
       too — the solid #34d399 that used to sit here turned the "Chat is live"
       banner into a block of saturated green. --ob-ok-text (the readable
       green) is legible on both themes and needs no override. */
    --ob-ok: color-mix(in srgb, #34d399 12%, transparent);
}

/* Outer container keeps the flow focused and centred like the prototype. */
.ob-wrap {
    max-width: 74rem;
    margin: 0 auto;
    padding: 0 0 3rem;
}

/* --- Page shell -----------------------------------------------
   Same soft diagonal gradient as the auth pages' .auth-shell (see
   auth.css) so a user going signup → onboarding sees one continuous
   background feel rather than a hard cut to a plain white admin page.
   Scoped to this page only (via onboarding.html's `bodyclass` block
   override) — every other admin page keeps its default bg-white /
   dark:bg-gray-900 shell. `!important` is required to beat Tailwind's
   `bg-white`/`dark:bg-gray-900` utility classes, compiled `!important`
   under this project's `important: true` config. -------------------- */
.ob-onboarding-page {
    background: var(--bg-page, #f7f8fa) !important;
}

.dark .ob-onboarding-page {
    background: var(--bg-page, #111827) !important;
}

/* --- Step card ------------------------------------------------
   Wraps the active step section + footer nav in one frame so the
   wizard body reads as a card, matching the auth pages' .auth-card
   (1px border, shadow-lg, ~1rem radius — see auth.css). ------------ */
.ob-card {
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 1rem;
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.1),
        0 4px 6px -4px rgba(0, 0, 0, 0.1);
    padding: 1.75rem 2rem 2rem;
}

.dark .ob-card {
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.35),
        0 4px 6px -4px rgba(0, 0, 0, 0.35);
}

@media (max-width: 30rem) {
    .ob-card {
        padding: 1.5rem 1.25rem 1.75rem;
    }
}

/* --- Stepper ------------------------------------------------
   One node per step: an icon bullet + the step name, joined by a rail
   drawn as a ::before on every node but the first. A bare progress bar
   said "you are 2/4 through"; this says what each stop actually is,
   which is the difference between a progress meter and a map. --------- */
.ob-stepper {
    display: flex;
    align-items: flex-start;
    gap: 0;
    padding: 1rem 1.1rem 0.9rem;
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 1rem;
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.1),
        0 4px 6px -4px rgba(0, 0, 0, 0.1);
    margin-bottom: 1rem;
}

.dark .ob-stepper {
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.35),
        0 4px 6px -4px rgba(0, 0, 0, 0.35);
}

.ob-step-node {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.45rem;
    padding: 0 0.25rem;
    background: none;
    border: none;
    cursor: pointer;
    min-width: 0;
}

/* Connector rail — sits behind the bullets, at their vertical centre. */
.ob-step-node + .ob-step-node::before {
    content: "";
    position: absolute;
    top: 1.1rem;
    right: 50%;
    left: -50%;
    height: 2px;
    background: color-mix(in srgb, var(--ob-ink) 12%, transparent);
    transition: background 0.3s ease;
}

.ob-step-node.is-done::before,
.ob-step-node.is-current::before {
    background: var(--ob-primary);
}

.ob-step-bullet {
    position: relative;
    z-index: 1;
    width: 2.2rem;
    height: 2.2rem;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: var(--ob-surface);
    border: 2px solid color-mix(in srgb, var(--ob-ink) 12%, transparent);
    color: var(--ob-muted);
    transition: background 0.2s ease, border-color 0.2s ease,
                color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
}

.ob-step-bullet .material-symbols-outlined {
    font-size: 1.15rem;
}

.ob-step-node:hover .ob-step-bullet {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
}

.ob-step-node:focus-visible {
    outline: none;
}

.ob-step-node:focus-visible .ob-step-bullet {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 30%, transparent);
}

.ob-step-node.is-done .ob-step-bullet {
    background: color-mix(in srgb, var(--ob-accent) 14%, var(--ob-card));
    border-color: color-mix(in srgb, var(--ob-accent) 55%, transparent);
    color: var(--ob-accent);
}

.ob-step-node.is-current .ob-step-bullet {
    background: var(--ob-primary);
    border-color: var(--ob-primary);
    color: var(--ob-ink-primary);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--ob-primary) 18%, transparent);
}

.ob-step-name {
    font-size: 0.76rem;
    font-weight: 600;
    line-height: 1.25;
    text-align: center;
    color: var(--ob-muted);
    max-width: 9rem;
}

.ob-step-node.is-current .ob-step-name {
    color: var(--ob-ink);
    font-weight: 800;
}

.ob-step-node.is-done .ob-step-name {
    color: var(--ob-ink);
}

/* Compact read-out under the rail. Redundant with the names on wide
   screens, so it only appears once they're hidden. */
.ob-step-mobile {
    display: none;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.ob-step-count {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--ob-muted);
    white-space: nowrap;
    text-transform: uppercase;
}

.ob-step-label {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--ob-ink);
}

@media (max-width: 48rem) {
    .ob-step-name { display: none; }
    .ob-step-mobile { display: flex; }
    .ob-stepper { padding: 0.85rem 1rem; }
}

/* --- Step panel ------------------------------------------- */
.ob-panel {
    animation: obfade 0.32s ease;
}

@keyframes obfade {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* Steps 2 and 3 each render two stacked .ob-panel blocks (identity+
   personality, model+knowledge). The second one gets a rule above it and a
   smaller heading so the screen reads as two grouped ideas rather than two
   competing steps. */
.ob-panel-joined {
    margin-top: 2.25rem;
    padding-top: 1.75rem;
    border-top: 1px solid var(--ob-line);
}

/* Same header component as a full step, one notch quieter — the joined panel
   is the step's second half, not a competing step. */
.ob-panel-joined .ob-step-title {
    font-size: 1.12rem;
}

.ob-panel-joined .ob-panel-icon {
    width: 2.4rem;
    height: 2.4rem;
}

.ob-panel-joined .ob-panel-icon .material-symbols-outlined {
    font-size: 1.3rem;
}

.ob-step-title {
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--ob-ink);
}

.ob-step-sub {
    margin-top: 0.35rem;
    font-size: 0.92rem;
    color: var(--ob-muted);
    max-width: 34rem;
    line-height: 1.5;
}

/* --- Panel header -------------------------------------------
   Every step (and every stacked half-step) opens with the same
   icon-badge + title + one-line sub, so the eye always lands in the
   same place and the wizard reads as one system. ------------------- */
.ob-panel-head {
    display: flex;
    align-items: flex-start;
    gap: 0.9rem;
}

.ob-panel-head > div:first-of-type {
    flex: 1;
    min-width: 0;
}

.ob-panel-icon {
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 0.85rem;
    background: color-mix(in srgb, var(--ob-accent) 12%, transparent);
    color: var(--ob-accent);
}

.ob-panel-icon .material-symbols-outlined {
    font-size: 1.5rem;
}

/* --- Section header -----------------------------------------
   A divider that carries meaning: rule + icon + title + optional
   status pill. Deliberately a sibling, not a wrapper, so it can chunk
   a long panel without nesting every field group in a container. ---- */
.ob-section-head {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--ob-line);
    margin-bottom: 0.9rem;
}

.ob-section-icon {
    flex: none;
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 0.6rem;
    background: color-mix(in srgb, var(--ob-accent) 10%, transparent);
    color: var(--ob-accent);
}

.ob-section-icon .material-symbols-outlined {
    font-size: 1.15rem;
}

.ob-section-heading {
    flex: 1;
    min-width: 0;
}

.ob-section-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--ob-ink);
    line-height: 1.3;
}

.ob-section-sub {
    margin-top: 0.15rem;
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--ob-muted);
}

/* Status pills — "Optional" / "Required" said once, in a glance, instead
   of a sentence of hedging copy inside every hint. */
.ob-pill {
    flex: none;
    align-self: flex-start;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ob-muted);
    background: var(--ob-surface);
    border: 1px solid var(--ob-line);
}

.ob-pill-required {
    color: var(--ob-accent);
    background: color-mix(in srgb, var(--ob-accent) 10%, transparent);
    border-color: color-mix(in srgb, var(--ob-accent) 25%, transparent);
}

/* --- Disclosure row -----------------------------------------
   One-line "Show / Hide …" control for a block of settings that is
   already correct for most people (the brain step's provider + model +
   key). Reads as a quiet link, not a button, so it never competes with
   the step's real actions — and carries the current value on the right
   so the collapsed state still answers "what is it set to?". No
   `display` on the inner spans: x-show toggles inline display, and a
   class-level display would out-rank it. ------------------------------ */
.ob-disclosure {
    margin-top: 1.1rem;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.6rem 0.85rem;
    border: 1px dashed var(--ob-line);
    border-radius: 0.85rem;
    background: transparent;
    color: var(--ob-accent);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 650;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.ob-disclosure:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
    background: color-mix(in srgb, var(--ob-accent) 6%, transparent);
}

.ob-disclosure-caret {
    font-size: 1.15rem;
    line-height: 1;
}

.ob-disclosure-value {
    margin-left: auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    color: var(--ob-muted);
}

/* Label with a leading icon. Lighter than .ob-section-head: use it when a
   panel is ONE idea split into inputs (the personality step) rather than
   several distinct sections. A trailing .ob-pill floats to the far edge. */
.ob-label-inline {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.5rem;
}

.ob-label-inline .material-symbols-outlined {
    font-size: 1.05rem;
    color: var(--ob-accent);
}

.ob-label-inline .ob-pill {
    margin-left: auto;
}

/* --- Persona cards (step 1) -------------------------------
   Portrait-ONLY: this screen picks a look, nothing else. Names and roles
   used to ride on a scrim over each portrait, which read as though you
   were adopting the template's identity when the very next step asks you
   to write your own — so the tiles carry the image alone (the name stays
   in the title/aria-label) and are sized to be scanned as a contact
   sheet rather than studied one card at a time. Portraits are
   background-free cutouts, so the tile paints its own backdrop
   (.ob-persona-stage) for them to drop into. ------------------------ */
.ob-persona-grid {
    margin-top: 1.25rem;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
    gap: 0.65rem;
}

.ob-persona {
    position: relative;
    display: block;
    padding: 0;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    background: var(--ob-card);
    border: 1.5px solid var(--ob-line);
    border-radius: 1rem;
    cursor: pointer;
    transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}

.ob-persona:hover {
    transform: translateY(-3px);
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
    box-shadow: 0 12px 26px color-mix(in srgb, var(--ob-accent) 18%, transparent);
}

.ob-persona:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 30%, transparent);
}

.ob-persona.is-selected {
    border-color: var(--ob-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 22%, transparent);
}

/* The backdrop a transparent portrait stands in front of: a soft accent
   wash plus a spotlight roughly where a head sits. Uniform across the
   grid on purpose — varying it per card would read as noise, not as a
   cast of characters. */
.ob-persona-stage {
    position: absolute;
    inset: 0;
    display: block;
    background:
        radial-gradient(60% 45% at 50% 28%,
            color-mix(in srgb, var(--ob-accent) 22%, transparent) 0%,
            transparent 70%),
        linear-gradient(to bottom,
            color-mix(in srgb, var(--ob-accent) 9%, var(--ob-surface)) 0%,
            var(--ob-surface) 100%);
}

/* Bottom-anchored and slightly oversized so the portrait reads as a
   cutout standing in the card rather than a photo pasted into a box. */
.ob-persona-portrait {
    position: absolute;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    width: 108%;
    height: 100%;
    object-fit: contain;
    object-position: bottom center;
    transition: transform 0.25s ease;
}

.ob-persona:hover .ob-persona-portrait {
    transform: translateX(-50%) scale(1.04);
}

.ob-persona-fallback {
    position: absolute;
    top: 42%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* Sized against the smaller tile — the old 3.5rem nearly filled it. */
    font-size: 2.4rem;
    color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
}

@media (max-width: 30rem) {
    .ob-persona-grid {
        grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr));
        gap: 0.55rem;
    }
}

/* Small square thumbnail — the Onboarding Setup roster (a list, not a
   gallery) still wants a compact avatar rather than a portrait card. */
.ob-persona-thumb {
    width: 3rem;
    height: 3rem;
    border-radius: 0.7rem;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--ob-accent) 10%, transparent);
    color: var(--ob-accent);
    flex: none;
}

.ob-persona-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.ob-persona-thumb .material-symbols-outlined {
    font-size: 1.6rem;
}

.ob-empty-note {
    margin-top: 1rem;
    font-size: 0.85rem;
    color: var(--ob-muted);
}

/* Request-a-custom-persona banner */
.ob-custom-banner {
    margin-top: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1rem 1.25rem;
    border-radius: 0.85rem;
    border: 1px solid var(--ob-line);
    background: var(--ob-surface);
}

/* The text block takes the slack so space-between only ever pushes the
   CTA to the far edge — the icon stays glued to the copy it labels. */
.ob-custom-banner > div {
    flex: 1 1 18rem;
    min-width: 0;
}

.ob-custom-icon {
    flex: none;
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 0.65rem;
    background: color-mix(in srgb, var(--ob-accent) 12%, transparent);
    color: var(--ob-accent);
}

.ob-custom-icon .material-symbols-outlined {
    font-size: 1.3rem;
}

.ob-custom-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-custom-sub {
    margin-top: 0.2rem;
    font-size: 0.82rem;
    color: var(--ob-muted);
    max-width: 34rem;
    line-height: 1.45;
}

/* Modal */
.ob-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: rgba(15, 23, 42, 0.45);
    backdrop-filter: blur(2px);
}

.ob-modal {
    position: relative;
    width: 100%;
    max-width: 30rem;
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 1rem;
    padding: 1.75rem;
    box-shadow: 0 20px 50px rgba(15, 23, 42, 0.35);
    animation: obfade 0.2s ease;
}

.ob-modal-close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 1.9rem;
    height: 1.9rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 0.5rem;
    background: transparent;
    color: var(--ob-muted);
    cursor: pointer;
}

.ob-modal-close:hover {
    background: color-mix(in srgb, var(--ob-ink) 8%, transparent);
}

.ob-modal-title {
    font-size: 1.15rem;
    font-weight: 800;
    color: var(--ob-ink);
}

.ob-modal-sub {
    margin-top: 0.35rem;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--ob-muted);
}

.ob-modal-done {
    text-align: center;
    padding: 0.5rem 0;
}

.ob-modal-done .material-symbols-outlined {
    font-size: 2.6rem;
    /* --ob-ok is the pale success TINT (a background); the readable green is
       --ob-ok-text. Using the tint here rendered a near-white icon on a white
       modal. */
    color: var(--ob-ok-text);
}

/* Sits over the portrait, so it carries its own ring + shadow to stay
   legible against whatever happens to be behind it. */
.ob-persona-check {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 999px;
    background: var(--ob-accent);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow:
        0 0 0 2px var(--ob-card),
        0 2px 6px rgba(0, 0, 0, 0.25);
}

.ob-persona-check .material-symbols-outlined {
    font-size: 0.85rem;
}

/* --- Form fields (step 2: identity) ----------------------- */
.ob-field-grid {
    margin-top: 1.5rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1.25rem;
}

.ob-field {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.ob-label {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-input {
    width: 100%;
    padding: 0.65rem 0.8rem;
    border-radius: 0.6rem;
    border: 1px solid var(--ob-line);
    background: var(--ob-card);
    color: var(--ob-ink);
    font-size: 0.9rem;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.ob-input:focus {
    border-color: var(--ob-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 20%, transparent);
}

select.ob-input {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.7rem center;
    padding-right: 2.2rem;
}

.ob-hint {
    font-size: 0.75rem;
    color: var(--ob-muted);
    line-height: 1.4;
}

/* --- Voice picker ----------------------------------------- */
.ob-voice-block {
    margin-top: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.ob-voice-loading,
.ob-voice-empty {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--ob-muted);
    padding: 0.5rem 0;
}

.ob-spin {
    animation: obspin 0.9s linear infinite;
    font-size: 1.15rem;
}

@keyframes obspin {
    to { transform: rotate(360deg); }
}

.ob-voice-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.7rem;
}

.ob-voice {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    text-align: left;
    padding: 0.7rem 0.85rem;
    background: var(--ob-card);
    border: 1.5px solid var(--ob-line);
    border-radius: 0.7rem;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.ob-voice:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
}

.ob-voice:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 30%, transparent);
}

.ob-voice.is-selected {
    border-color: var(--ob-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ob-accent) 22%, transparent);
}

.ob-voice-icon {
    width: 2rem;
    height: 2rem;
    flex: none;
    border-radius: 0.55rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--ob-accent) 12%, transparent);
    color: var(--ob-accent);
}

.ob-voice-icon .material-symbols-outlined {
    font-size: 1.2rem;
}

.ob-voice-name {
    flex: 1;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--ob-ink);
}

.ob-voice-check {
    color: var(--ob-accent);
    font-size: 1.15rem;
    flex: none;
}

/* Custom voice ID + preview row */
.ob-voice-custom {
    margin-top: 0.9rem;
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}

.ob-voice-custom .ob-input { flex: 1; }

.ob-preview-btn {
    flex: none;
    white-space: nowrap;
}

.ob-preview-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* --- Personality (step 3) --------------------------------- */
.ob-safety-note {
    margin-top: 1.25rem;
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.8rem 1rem;
    border-radius: 0.7rem;
    background: color-mix(in srgb, var(--ob-accent) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--ob-accent) 20%, transparent);
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--ob-ink);
}

.ob-safety-note .material-symbols-outlined {
    color: var(--ob-accent);
    font-size: 1.2rem;
    flex: none;
}

/* --- Included-key panel + "use my own key" opt-out ----------------------- */
/* The default state of every credential step: a reassurance, not a form. It
   reads green (a resolved state) rather than accent-blue like ob-safety-note,
   so "nothing needed here" is distinguishable at a glance from "read this". */
.ob-included {
    margin-top: 1.25rem;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.85rem 1rem;
    border-radius: 0.85rem;
    background: color-mix(in srgb, var(--ob-ok-text) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--ob-ok-text) 30%, transparent);
}

.ob-included-icon {
    color: var(--ob-ok-text);
    font-size: 1.3rem;
    flex: none;
}

.ob-included-title {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-included-sub {
    margin: 0.15rem 0 0;
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--ob-muted);
}

/* The opt-out sits directly under the panel it replaces, indented like a form
   row so it reads as a control rather than more prose. */
.ob-own-key {
    margin-top: 0.9rem;
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    cursor: pointer;
}

.ob-own-key input[type="checkbox"] {
    margin-top: 0.15rem;
    width: 1rem;
    height: 1rem;
    flex: none;
    accent-color: var(--ob-accent);
    cursor: pointer;
}

.ob-own-key input[type="checkbox"]:disabled {
    cursor: not-allowed;
}

.ob-own-key-text {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.ob-own-key-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ob-ink);
}

.ob-own-key-sub {
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--ob-muted);
}

.ob-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.ob-chip {
    padding: 0.45rem 0.9rem;
    border-radius: 999px;
    border: 1px solid var(--ob-line);
    background: var(--ob-card);
    color: var(--ob-ink);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease;
}

.ob-chip:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
}

/* Selected state per the style guide: Accent Blue border over a pale blue
   tint, NOT a solid accent fill. Chips, cards and segmented controls all share
   that one recipe, so a screen full of picked traits reads as a set of quiet
   selections rather than a wall of saturated blue. */
.ob-chip.is-on {
    background: color-mix(in srgb, var(--ob-accent) 10%, var(--ob-card));
    border-color: var(--ob-accent);
    color: var(--ob-accent);
    box-shadow: 0 0 0 1px var(--ob-accent);
}

.ob-formality-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.7rem;
}

.ob-formality {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    text-align: left;
    padding: 0.8rem 0.95rem;
    border-radius: 0.7rem;
    border: 1.5px solid var(--ob-line);
    background: var(--ob-card);
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.ob-formality:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
}

.ob-formality.is-selected {
    border-color: var(--ob-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ob-accent) 22%, transparent);
    background: color-mix(in srgb, var(--ob-accent) 6%, var(--ob-card));
}

.ob-formality-label {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-formality-sub {
    font-size: 0.76rem;
    color: var(--ob-muted);
}

/* Advanced (generated prompt) */
/* Link-style buttons — one recipe shared by every bare accent "button that
   reads as a link" so they can't drift apart. Size overrides stay local. */
.ob-advanced-toggle,
.ob-writer-revert-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--ob-accent);
}

.ob-advanced-toggle:hover,
.ob-writer-revert-btn:hover { text-decoration: underline; }

.ob-advanced-toggle .material-symbols-outlined {
    font-size: 1.1rem;
    transition: transform 0.15s ease;
}

.ob-advanced-body {
    margin-top: 0.6rem;
}

.ob-prompt {
    margin: 0;
    padding: 0.9rem 1rem;
    border-radius: 0.7rem;
    background: var(--ob-surface);
    border: 1px solid var(--ob-line);
    color: var(--ob-muted);
    font-size: 0.8rem;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Editable twin of .ob-prompt — the step-2 instructions textarea. */
.ob-prompt-edit {
    width: 100%;
    font-size: 0.8rem;
    line-height: 1.55;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Label + "this runs your avatar" pill on one line above the prompt box. */
.ob-prompt-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
}

/* Switcher between the two retained prompt versions ("Yours" / "AI
   enhanced"). A segmented control rather than a checkbox: these are two
   alternatives to compare, and the shape should say so. Only rendered once
   an enhanced version has actually been accepted. */
.ob-prompt-variants {
    display: inline-flex;
    gap: 0.25rem;
    margin-bottom: 0.6rem;
    padding: 0.2rem;
    border: 1px solid var(--ob-line);
    border-radius: 999px;
    background: var(--ob-surface);
}

.ob-prompt-variant {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    border: none;
    border-radius: 999px;
    background: none;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--ob-muted);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.ob-prompt-variant .material-symbols-outlined { font-size: 0.95rem; }

.ob-prompt-variant:hover:not(.is-on) { color: var(--ob-ink); }

.ob-prompt-variant.is-on {
    background: var(--ob-card);
    color: var(--ob-accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

/* "What will your avatar do?" composer: description on the left, the button
   that commits it into the prompt box on the right. The button aligns to the
   bottom of the textarea so the pair reads as one control even when the
   description grows to several lines. */
.ob-role-row {
    display: flex;
    align-items: flex-end;
    gap: 0.6rem;
}

.ob-role-row > .ob-input {
    flex: 1 1 auto;
    min-width: 0;
}

.ob-role-add {
    flex: none;
    white-space: nowrap;
    font-size: 0.78rem;
}

@media (max-width: 34rem) {
    .ob-role-row { flex-direction: column; align-items: stretch; }
    .ob-role-add { justify-content: center; }
}

/* --- AI prompt writer (step 2) --- */
/* The button itself is .ob-btn-ai (full width, its own violet) — see the
   button system further down. What's left here is the surrounding copy. */
.ob-writer-hint {
    font-size: 0.76rem;
    line-height: 1.4;
    color: var(--ob-muted);
}

/* Confirmation that the writer ran — and, when documents fed it, which
   ones. Without it there's no way to tell an uploaded file was used. */
.ob-writer-done {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin-top: 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--ob-ok-text);
}

.ob-writer-done .material-symbols-outlined {
    font-size: 1rem;
    flex: none;
}

.ob-writer-revert {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 0.55rem;
}

/* Colours/shape inherited from the shared .ob-advanced-toggle link-button
   rule; only the smaller type is local. */
.ob-writer-revert-btn { font-size: 0.78rem; }

/* The staged "Enhanced version" card. Dashed border and a recessed fill so it
   reads as a proposal sitting beside the real prompt box rather than as
   another field that has already taken effect. */
.ob-proposal {
    margin-top: 1rem;
    padding: 1rem 1.1rem;
    border: 1.5px dashed var(--ob-line);
    border-radius: 0.9rem;
    background: var(--ob-surface);
}

.ob-proposal-note {
    margin-top: 0.5rem;
    font-size: 0.76rem;
    font-weight: 600;
    color: var(--ob-ok-text);
}

.ob-proposal-body {
    margin: 0.7rem 0 0;
    max-height: 16rem;
    overflow-y: auto;
    padding: 0.85rem 0.95rem;
    border-radius: 0.7rem;
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    color: var(--ob-ink);
    font-size: 0.79rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Equal-width pair, per the mockup: accepting and declining are two
   genuine options here, not a primary action with an escape hatch. */
.ob-proposal-actions {
    display: flex;
    gap: 0.6rem;
    margin-top: 0.9rem;
}

.ob-proposal-actions > .ob-btn {
    flex: 1 1 0;
    justify-content: center;
}

@media (max-width: 30rem) {
    .ob-proposal-actions { flex-wrap: wrap; }
    .ob-proposal-actions > .ob-btn { flex-basis: 100%; }
}

/* --- Knowledge base (step 4) ------------------------------ */
.ob-dropzone {
    margin-top: 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    padding: 2rem 1.5rem;
    border: 1.5px dashed color-mix(in srgb, var(--ob-accent) 35%, var(--ob-line));
    border-radius: 0.85rem;
    background: var(--ob-surface);
    cursor: pointer;
    text-align: center;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.ob-dropzone:hover,
.ob-dropzone.is-drag {
    border-color: var(--ob-accent);
    background: color-mix(in srgb, var(--ob-accent) 6%, var(--ob-surface));
}

/* Personality-document lane (step 2). Shorter and quieter than the
   knowledge-base dropzone: it's an optional shortcut sitting inside a
   step, not the main event of one. */
.ob-dropzone.is-compact {
    margin-top: 0;
    padding: 1.15rem 1.25rem;
    border-style: dashed;
    border-color: var(--ob-line);
    background: transparent;
}

.ob-dropzone.is-compact:hover,
.ob-dropzone.is-compact.is-drag {
    border-color: var(--ob-accent);
    background: color-mix(in srgb, var(--ob-accent) 5%, transparent);
}

.ob-dropzone.is-compact .ob-dropzone-icon {
    font-size: 1.5rem;
}

.ob-dropzone-icon {
    font-size: 2rem;
    color: var(--ob-accent);
}

.ob-dropzone-title {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.hidden { display: none !important; }

.ob-kb-error {
    margin-top: 0.5rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: #d14343;
}

/* Voice-audition failure. Louder than .ob-kb-error on purpose: the only other
   signal is silence, which reads as a broken button rather than a missing key.
   Wrapped in an x-show <p>, so the flex layout only applies when it's shown. */
.ob-voice-error {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin-top: 0.75rem;
    padding: 0.6rem 0.75rem;
    border-radius: 0.6rem;
    border: 1px solid color-mix(in srgb, #d14343 40%, transparent);
    background: color-mix(in srgb, #d14343 12%, transparent);
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.35;
    color: #f0a3a3;
}

.ob-voice-error .material-symbols-outlined {
    font-size: 1.05rem;
    flex-shrink: 0;
    color: #e06666;
}

/* --- Inline validation -------------------------------------------------- */
/* Wrapped in an x-show <p>/<div>, so the flex layout only applies when shown
   — same arrangement as .ob-voice-error above. Nothing here is !important, so
   x-show's inline display:none still wins. */
.ob-field-error {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin-top: 0.4rem;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.35;
    color: #d14343;
}

.ob-field-error .material-symbols-outlined {
    font-size: 0.95rem;
    flex-shrink: 0;
}

.dark .ob-field-error { color: #f0a3a3; }

/* The offending control itself. Colour is never the only signal — the message
   under the field carries the meaning — this just makes it findable. */
.ob-input.is-invalid,
.ob-consent.is-invalid,
.ob-approve.is-invalid {
    border-color: #d14343;
}

.ob-input.is-invalid:focus {
    border-color: #d14343;
    box-shadow: 0 0 0 3px color-mix(in srgb, #d14343 22%, transparent);
}

/* Reason the step is blocked, inside the sticky footer. Takes a full row of
   its own above Back/Continue (hence .ob-nav's flex-wrap + order:-1) rather
   than squeezing between them. */
.ob-nav-error {
    flex: 1 1 100%;
    order: -1;
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    margin-bottom: 0.15rem;
    font-size: 0.8rem;
    font-weight: 600;
    line-height: 1.35;
    color: #d14343;
}

.ob-nav-error .material-symbols-outlined {
    font-size: 1rem;
    flex-shrink: 0;
}

.dark .ob-nav-error { color: #f0a3a3; }

/* Continue stays clickable while the step is incomplete (that click is what
   surfaces the errors), so it borrows the disabled LOOK without the disabled
   behaviour. Matches .ob-btn-primary:disabled above. */
.ob-btn-primary.is-blocked {
    opacity: 0.45;
}

.ob-source-list {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.ob-source {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.6rem;
    background: var(--ob-card);
}

.ob-source.is-uploading {
    opacity: 0.7;
    border-style: dashed;
}

.ob-source.is-warn {
    border-color: #d9a441;
    background: rgba(217, 164, 65, 0.06);
}

.ob-source.is-warn .ob-source-icon {
    color: #d9a441;
}

.ob-source-warn {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8rem;
    line-height: 1.35;
    color: #9a6a12;
}

.ob-source-icon {
    color: var(--ob-accent);
    font-size: 1.25rem;
    flex: none;
}

.ob-source-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.ob-source-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ob-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ob-source-sub {
    font-size: 0.72rem;
    color: var(--ob-muted);
}

.ob-source-remove {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 0.4rem;
    border: none;
    background: transparent;
    color: var(--ob-muted);
    cursor: pointer;
    transition: background 0.14s ease, color 0.14s ease;
}

.ob-source-remove:hover {
    background: color-mix(in srgb, #d14343 12%, transparent);
    color: #d14343;
}

.ob-source-remove .material-symbols-outlined { font-size: 1.1rem; }

.ob-url-row {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}

.ob-url-row .ob-input { flex: 1; }

.ob-consent {
    margin-top: 1.5rem;
    width: 100%;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    text-align: left;
    padding: 0.85rem 1rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.7rem;
    background: var(--ob-card);
    cursor: pointer;
    transition: border-color 0.15s ease;
}

.ob-consent:hover { border-color: color-mix(in srgb, var(--ob-accent) 40%, transparent); }
.ob-consent.is-on { border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent); }

/* There is nothing to consent to until a source exists. The row stays on
   screen so the rule is discoverable up front, but it reads as inert rather
   than as a box you forgot to tick. */
.ob-consent:disabled { cursor: default; opacity: 0.55; }
.ob-consent:disabled:hover { border-color: var(--ob-line); }

.ob-consent-box {
    flex: none;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 0.4rem;
    border: 1.5px solid var(--ob-line);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    transition: background 0.14s ease, border-color 0.14s ease;
}

.ob-consent.is-on .ob-consent-box {
    background: var(--ob-accent);
    border-color: var(--ob-accent);
}

.ob-consent-box .material-symbols-outlined { font-size: 0.95rem; }

.ob-consent-text {
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--ob-ink);
}

.ob-consent-link {
    color: var(--ob-accent);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ob-consent-link:hover { text-decoration-thickness: 2px; }

.ob-required {
    font-size: 0.72rem;
    font-weight: 700;
    color: #d14343;
}

/* Layout only — colours come from .ob-btn-soft. */
.ob-approve {
    margin-top: 1rem;
    width: 100%;
    justify-content: center;
}

.ob-approve.is-approved {
    background: color-mix(in srgb, var(--ob-ok-text) 12%, transparent);
    border-color: color-mix(in srgb, var(--ob-ok-text) 40%, transparent);
    color: var(--ob-ok-text);
}

/* Must out-specify .ob-btn-soft:hover:not(:disabled) (0-3-0), or hovering an
   already-approved button flashes the accent tint over the green state. */
.ob-approve.is-approved:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ob-ok-text) 20%, transparent);
    border-color: color-mix(in srgb, var(--ob-ok-text) 55%, transparent);
}

/* --- Live preview pane ------------------------------------
   The real embedded widget (reagan-avatar widget.html) rendered
   beside the step card from step 2 onward. On wide screens the
   wizard grows into a two-column grid; below ~64rem the pane
   stacks above the card at a fixed height. ------------------------ */
.ob-wrap.has-preview {
    max-width: 88rem;
}

.ob-columns {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
}

/* The preview track is sized to the widget, not to a ratio. widget.html's open
   layout is a hard 576px — 272px avatar canvas + 280px chat panel + its 24px
   right offset — and it is position:fixed, so it cannot reflow. Add the pane's
   1rem padding either side and the frame's 1px border and the track must never
   drop below 610px; a proportional 5fr fell to ~544px here, which clipped the
   chat panel off the left edge. 40rem leaves ~30px of slack. */
.ob-wrap.has-preview .ob-columns {
    grid-template-columns: minmax(0, 1fr) minmax(40rem, 42rem);
}

.ob-preview-pane {
    position: sticky;
    top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 1rem;
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.1),
        0 4px 6px -4px rgba(0, 0, 0, 0.1);
    padding: 1rem;
}

.dark .ob-preview-pane {
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.45),
        0 4px 6px -4px rgba(0, 0, 0, 0.4);
}

.ob-preview-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.ob-preview-title {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-preview-title .material-symbols-outlined {
    font-size: 1.1rem;
    color: var(--ob-accent);
}

/* Right edge of the preview header. Holds the sync pill; the old
   "Voice only / Chat live" badge went with the widget chrome — the pane
   shows the avatar alone now, so there is no chat state to label. */
.ob-preview-head-right {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
}

/* Transient state for a draft change propagating into the widget:
   "Applying changes…" while the reload is in flight, then a brief
   "Avatar updated" once the widget reports ready. */
.ob-preview-sync {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    white-space: nowrap;
    border: 1px solid transparent;
}

.ob-preview-sync .material-symbols-outlined {
    font-size: 0.9rem;
}

.ob-preview-sync.is-working {
    background: var(--ob-surface);
    border-color: var(--ob-line);
    color: var(--ob-muted);
}

.ob-preview-sync.is-done {
    background: color-mix(in srgb, var(--ob-ok-text) 12%, transparent);
    border-color: color-mix(in srgb, var(--ob-ok-text) 40%, transparent);
    color: var(--ob-ok-text);
}

/* The widget iframe. The wizard's pane is always "open", so the frame gets
   the full pane height; the widget's own chrome lives inside it. */
.ob-preview-frame-wrap {
    position: relative;
    border-radius: 0.8rem;
    overflow: hidden;
    border: 1px solid var(--ob-line);
    background: var(--ob-surface);
    height: min(34rem, 62vh);
}

.ob-preview-frame {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    background: transparent;
}

/* Veil shown while the widget boots (or when no preview exists yet). */
.ob-preview-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem;
    text-align: center;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--ob-muted);
    background: var(--ob-surface);
}

.ob-preview-overlay .material-symbols-outlined {
    font-size: 1.6rem;
    color: color-mix(in srgb, var(--ob-accent) 70%, var(--ob-muted));
}

.ob-preview-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0;
    padding: 0.6rem 0.8rem;
    border-radius: 0.7rem;
    background: var(--ob-surface);
    border: 1px solid var(--ob-line);
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--ob-muted);
}

.ob-preview-note .material-symbols-outlined {
    font-size: 1.05rem;
    flex: none;
    color: var(--ob-muted);
}

/* The style guide's Success Tint (--ob-ok) is specified for exactly this
   banner — the "Chat is live" confirmation — and its checkmark. */
.ob-preview-note.is-live {
    background: var(--ob-ok);
    border-color: color-mix(in srgb, var(--ob-ok-text) 30%, transparent);
    color: color-mix(in srgb, var(--ob-ok-text) 75%, var(--ob-ink));
}

.ob-preview-note.is-live .material-symbols-outlined { color: var(--ob-ok-text); }

/* --- "Test your avatar" panel ---------------------------------
   Sits under the (deliberately chat-free) preview and unlocks with the
   language model. The wizard owns this transcript; the widget above just
   relays what was said. Styled as a distinct sub-card rather than more of
   the pane, so it reads as a tool you picked up, not chrome that was
   always there. ------------------------------------------------------- */
.ob-testchat {
    margin-top: 0.85rem;
    padding: 0.85rem 0.9rem 0.9rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.9rem;
    background: var(--ob-card);
}

.ob-testchat-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.ob-testchat-title {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-testchat-title .material-symbols-outlined {
    font-size: 1.05rem;
    color: var(--ob-accent);
}

.ob-testchat-clear {
    border: none;
    background: none;
    padding: 0;
    font-size: 0.74rem;
    font-weight: 700;
    color: var(--ob-muted);
    cursor: pointer;
}

.ob-testchat-clear:hover { color: var(--ob-ink); text-decoration: underline; }

.ob-testchat-hint { margin-top: 0.45rem; }

/* Scrolls internally so a long conversation can never push the composer
   off the bottom of the pane. */
.ob-testchat-log {
    margin-top: 0.6rem;
    max-height: 14rem;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding-right: 0.2rem;
}

.ob-testchat-msg {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    font-size: 0.79rem;
    line-height: 1.5;
    padding: 0.5rem 0.65rem;
    border-radius: 0.6rem;
    background: var(--ob-surface);
    overflow-wrap: anywhere;
}

.ob-testchat-msg.is-user {
    background: color-mix(in srgb, var(--ob-accent) 10%, transparent);
}

.ob-testchat-who {
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ob-muted);
}

.ob-testchat-text { color: var(--ob-ink); white-space: pre-wrap; }

/* Three-dot "thinking" indicator, shown between send and first token. */
.ob-testchat-dots {
    display: inline-flex;
    gap: 0.22rem;
    padding: 0.25rem 0;
}

.ob-testchat-dots span {
    width: 0.32rem;
    height: 0.32rem;
    border-radius: 999px;
    background: var(--ob-muted);
    animation: ob-testchat-blink 1.2s infinite ease-in-out;
}

.ob-testchat-dots span:nth-child(2) { animation-delay: 0.18s; }
.ob-testchat-dots span:nth-child(3) { animation-delay: 0.36s; }

@keyframes ob-testchat-blink {
    0%, 80%, 100% { opacity: 0.25; }
    40%           { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .ob-testchat-dots span { animation: none; opacity: 0.6; }
}

.ob-testchat-form {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.7rem;
}

.ob-testchat-form > .ob-input {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.82rem;
}

.ob-testchat-send { flex: none; font-size: 0.8rem; }

/* The pane is a narrow column — below ~26rem the word wins nothing the
   icon doesn't already say. */
@media (max-width: 26rem) {
    .ob-testchat-send-label { display: none; }
}

/* Escape hatch under the test panel: opens the same preview token in the
   full widget, in a new tab — for seeing the chrome a visitor gets, not
   for testing the answers. */
.ob-preview-test {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.55rem;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--ob-accent);
    text-decoration: none;
}

.ob-preview-test:hover { text-decoration: underline; }

.ob-preview-test .material-symbols-outlined { font-size: 1rem; }

/* Stack the pane above the card on narrow screens (sticky off).
   Breakpoint follows the 40rem preview track above. Because that track is a
   hard floor (the widget cannot reflow), too low a breakpoint squeezes the
   step card or overflows horizontally. 80rem rather than the ~72rem the track
   alone implies: this media query measures the VIEWPORT, but the grid lives
   inside Unfold's sidebar-constrained content area, so ~18rem of the viewport
   is not ours to spend. */
@media (max-width: 80rem) {
    .ob-wrap.has-preview .ob-columns {
        grid-template-columns: minmax(0, 1fr);
    }
    .ob-preview-pane {
        position: static;
        order: -1;
    }
    .ob-preview-frame-wrap { height: 22rem; }
}

/* --- Go live (step 6) ------------------------------------- */
/* Recap strip */
.ob-recap {
    margin-top: 1.5rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.7rem;
}

.ob-recap-item {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.7rem;
    background: var(--ob-card);
    min-width: 0;
}

/* Text column: must be allowed to shrink so the value can truncate
   instead of pushing the chip wider than its grid cell. */
.ob-recap-item > div {
    flex: 1 1 auto;
    min-width: 0;
}

.ob-recap-item .material-symbols-outlined {
    color: var(--ob-accent);
    font-size: 1.35rem;
    flex: none;
    margin-top: 0.1rem;
}

.ob-recap-label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ob-muted);
}

.ob-recap-value {
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--ob-ink);
    /* Wrap up to two lines, then ellipsis; break long unbroken tokens
       (voice IDs, model slugs) so they never overflow the chip. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.ob-recap-edit {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 0.4rem;
    border: none;
    background: transparent;
    color: var(--ob-muted);
    cursor: pointer;
    transition: background 0.14s ease, color 0.14s ease;
}

.ob-recap-edit:hover {
    background: color-mix(in srgb, var(--ob-accent) 12%, transparent);
    color: var(--ob-accent);
}

/* `color: inherit` matters: .ob-recap-item paints every icon inside it accent
   blue, which would otherwise outrank this button's muted colour and kill the
   hover transition. */
.ob-recap-edit .material-symbols-outlined {
    font-size: 1.1rem;
    color: inherit;
    margin-top: 0;
}

/* Plan cards */
.ob-plan-grid {
    margin-top: 1.5rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
}

.ob-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    text-align: left;
    padding: 1.25rem 1.1rem 1.1rem;
    background: var(--ob-card);
    border: 1.5px solid var(--ob-line);
    border-radius: 0.9rem;
    cursor: pointer;
    transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}

.ob-plan:hover {
    transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
    box-shadow: 0 8px 20px color-mix(in srgb, var(--ob-accent) 14%, transparent);
}

.ob-plan.is-selected {
    border-color: var(--ob-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 22%, transparent);
}

.ob-plan.is-recommended {
    border-color: color-mix(in srgb, var(--ob-accent) 50%, transparent);
}

.ob-plan-badge {
    position: absolute;
    top: -0.7rem;
    left: 1.1rem;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    background: var(--ob-accent);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.ob-plan-name {
    font-size: 1.05rem;
    font-weight: 800;
    color: var(--ob-ink);
}

.ob-plan-price {
    display: flex;
    align-items: baseline;
    gap: 0.2rem;
    margin-top: 0.15rem;
}

.ob-plan-price-amount {
    font-size: 1.7rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--ob-ink);
}

.ob-plan-price-suffix {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ob-muted);
}

.ob-plan-tagline {
    font-size: 0.8rem;
    color: var(--ob-muted);
}

.ob-plan-features {
    margin: 0.7rem 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.ob-plan-features li {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.82rem;
    color: var(--ob-ink);
}

.ob-plan-features .material-symbols-outlined {
    font-size: 1rem;
    color: var(--ob-accent);
    flex: none;
}

.ob-plan-check {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    color: var(--ob-accent);
    font-size: 1.25rem;
}

/* Success hero */
.ob-launch-hero {
    text-align: center;
    padding: 1rem 0 0.5rem;
}

.ob-launch-check {
    font-size: 3.2rem;
    color: var(--ob-ok-text);
    animation: obpop 0.4s ease;
}

@keyframes obpop {
    from { transform: scale(0.5); opacity: 0; }
    to   { transform: scale(1); opacity: 1; }
}

.ob-launch-actions {
    margin-top: 1.1rem;
    display: flex;
    gap: 0.6rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* Embed / key cards */
.ob-launch-card {
    margin-top: 1.25rem;
    padding: 1.1rem 1.2rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.85rem;
    background: var(--ob-card);
}

.ob-launch-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.4rem;
}

.ob-launch-card-title {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-launch-card-title .material-symbols-outlined {
    font-size: 1.2rem;
    color: var(--ob-accent);
}

.ob-copy-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.35rem 0.7rem;
    border-radius: 0.5rem;
    border: 1px solid var(--ob-line);
    background: var(--ob-surface);
    color: var(--ob-ink);
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.14s ease, color 0.14s ease;
}

.ob-copy-btn:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 45%, transparent);
    color: var(--ob-accent);
}

.ob-copy-btn .material-symbols-outlined { font-size: 1rem; }

.ob-key {
    color: var(--ob-ink);
    font-weight: 600;
    letter-spacing: 0.01em;
}

.ob-key-warn {
    margin-top: 0.5rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.76rem;
    font-weight: 600;
    color: #b45309;
}

.dark .ob-key-warn { color: #fbbf24; }

.ob-key-warn .material-symbols-outlined { font-size: 1rem; }

.ob-launch-note {
    margin-top: 1.1rem;
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.7rem 0.95rem;
    border-radius: 0.7rem;
    background: color-mix(in srgb, var(--ob-accent) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--ob-accent) 20%, transparent);
    font-size: 0.82rem;
    color: var(--ob-ink);
}

.ob-launch-note .material-symbols-outlined {
    font-size: 1.15rem;
    color: var(--ob-accent);
    flex: none;
}

.ob-launch-note-warn {
    background: color-mix(in srgb, #f59e0b 10%, transparent);
    border-color: color-mix(in srgb, #f59e0b 28%, transparent);
}

.ob-launch-note-warn .material-symbols-outlined { color: #d97706; }

/* --- Placeholder panels (steps not yet built) ------------- */
.ob-placeholder {
    margin-top: 1.5rem;
    padding: 2.5rem 1.5rem;
    text-align: center;
    border: 1.5px dashed var(--ob-line);
    border-radius: 0.85rem;
    background: var(--ob-surface);
    color: var(--ob-muted);
}

.ob-placeholder .material-symbols-outlined {
    font-size: 2.2rem;
    color: color-mix(in srgb, var(--ob-accent) 60%, var(--ob-muted));
}

/* --- Onboarding Setup (super-admin config) ---------------- */
.ob-admin-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.ob-admin-row {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--ob-line);
    border-radius: 0.7rem;
    background: var(--ob-card);
    cursor: pointer;
    transition: border-color 0.15s ease;
}

.ob-admin-row:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 40%, transparent);
}

.ob-admin-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.ob-admin-name {
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--ob-ink);
}

.ob-admin-sub {
    font-size: 0.76rem;
    color: var(--ob-muted);
}

/* Advisory, not an error — the character still works, its picker card
   just reads thinner without a title. */
.ob-admin-sub-missing {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: #b45309;
}

.dark .ob-admin-sub-missing { color: #fbbf24; }

.ob-admin-sub-missing .material-symbols-outlined { font-size: 0.95rem; }

/* Toggle switch — the native checkbox is hidden; the pill follows :checked. */
.ob-switch-input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.ob-switch {
    flex: none;
    position: relative;
    width: 2.5rem;
    height: 1.4rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--ob-ink) 18%, transparent);
    transition: background 0.18s ease;
}

.ob-switch::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 1.05rem;
    height: 1.05rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transition: transform 0.18s ease;
}

.ob-switch-input:checked ~ .ob-switch {
    background: var(--ob-accent);
}

.ob-switch-input:checked ~ .ob-switch::after {
    transform: translateX(1.1rem);
}

.ob-switch-input:focus-visible ~ .ob-switch {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 30%, transparent);
}

/* --- Footer nav ------------------------------------------- */
.ob-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--ob-line);
}

/* Fully rounded per the style guide's 100px primary-button radius. Applied to
   the base class rather than just .ob-btn-primary on purpose: Back and
   Continue sit side by side in the footer nav, and a pill next to a
   soft-cornered rectangle reads as two different components rather than one
   pair. */
.ob-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 1.3rem;
    border-radius: 100px;
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

.ob-btn-primary {
    background: var(--ob-primary);
    color: var(--ob-ink-primary);
}

.ob-btn-primary:hover {
    background: color-mix(in srgb, var(--ob-primary) 85%, black);
}

.ob-btn-primary:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.ob-btn-ghost {
    background: transparent;
    border-color: var(--ob-line);
    color: var(--ob-ink);
}

.ob-btn-ghost:hover {
    border-color: color-mix(in srgb, var(--ob-accent) 40%, transparent);
}

/* Outline — the style guide's second button role: transparent fill with
   Accent Blue text and border. Use it for a secondary action that still needs
   to look like an offer rather than a way back (Request a custom avatar), as
   opposed to .ob-btn-ghost, which is the neutral "Back / not now" treatment. */
.ob-btn-outline {
    background: transparent;
    border-color: var(--ob-accent);
    color: var(--ob-accent);
}

.ob-btn-outline:hover {
    background: color-mix(in srgb, var(--ob-accent) 8%, transparent);
}

/* Soft accent — the secondary CTA that still reads as "the accent action"
   (approve sources, write my prompt). THE single source of truth for that
   treatment: .ob-approve and .ob-writer-btn used to each carry their own
   near-miss recipe (different border widths, tint percentages and hover
   states) for the same visual role, so the two drifted apart. Those classes
   now only carry their layout deltas. */
.ob-btn-soft {
    background: color-mix(in srgb, var(--ob-accent) 10%, transparent);
    border-color: color-mix(in srgb, var(--ob-accent) 40%, transparent);
    color: var(--ob-accent);
}

.ob-btn-soft:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ob-accent) 18%, transparent);
    border-color: color-mix(in srgb, var(--ob-accent) 55%, transparent);
}

.ob-btn-soft:disabled { opacity: 0.65; cursor: not-allowed; }

/* "Enhance with AI" — the only button in the wizard that WRITES something for
   you, so it gets its own violet identity rather than the accent blue that
   everywhere else means "continue". Full width: it acts on the whole prompt
   box above it, and a small button floated beside a hint read as an aside. */
.ob-btn-ai {
    width: 100%;
    justify-content: center;
    background: linear-gradient(135deg, #f6f1ff 0%, #eef5ff 100%);
    border-color: #d6c6f7;
    color: #6d3fd1;
}

.ob-btn-ai:hover:not(:disabled) {
    background: linear-gradient(135deg, #f0e8ff 0%, #e5efff 100%);
    border-color: #c3aef2;
}

.ob-btn-ai:disabled { opacity: 0.65; cursor: not-allowed; }

/* The gradient is a light wash — on the dark theme it has to become a tint of
   the same violet instead, or the button turns into a white slab. */
.dark .ob-btn-ai {
    background: color-mix(in srgb, #a78bfa 14%, transparent);
    border-color: color-mix(in srgb, #a78bfa 45%, transparent);
    color: #c4b5fd;
}

.dark .ob-btn-ai:hover:not(:disabled) {
    background: color-mix(in srgb, #a78bfa 22%, transparent);
    border-color: color-mix(in srgb, #a78bfa 60%, transparent);
}

/* Autosave indicator in the header. */
.ob-saved {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--ob-ok-text);
}

.ob-saved-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--ob-ok-text);
}

/* --- Searchable model combobox (language-model step) ------------------- */
/* An Alpine-driven input + floating list, matching .ob-input's shape. The
   dropdown is absolutely positioned so opening it never reflows the step. */
.ob-combo { position: relative; }

.ob-combo-input-wrap { position: relative; }
.ob-combo-input-wrap > .ob-input { padding-right: 2.2rem; }
.ob-combo-caret {
    position: absolute;
    right: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--ob-muted);
    font-size: 1.25rem;
    pointer-events: none;
    transition: transform 0.15s;
}
.ob-combo.is-open .ob-combo-caret { transform: translateY(-50%) rotate(180deg); }

.ob-combo-list {
    position: absolute;
    z-index: 40;
    top: calc(100% + 0.4rem);
    left: 0;
    right: 0;
    max-height: 17rem;
    overflow-y: auto;
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 0.75rem;
    box-shadow: 0 18px 44px -10px rgba(0, 0, 0, 0.38), 0 4px 12px rgba(0, 0, 0, 0.14);
    padding: 0.35rem;
    scrollbar-width: thin;
    scrollbar-color: var(--ob-line) transparent;
}
.ob-combo-list::-webkit-scrollbar { width: 9px; }
.ob-combo-list::-webkit-scrollbar-thumb {
    background: var(--ob-line);
    border: 3px solid var(--ob-card);
    border-radius: 9999px;
}

.ob-combo-option {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    width: 100%;
    text-align: left;
    padding: 0.55rem 0.7rem;
    border: none;
    background: transparent;
    border-radius: 0.55rem;
    cursor: pointer;
    transition: background 0.12s;
}
.ob-combo-option + .ob-combo-option { margin-top: 1px; }
.ob-combo-option:hover {
    background: color-mix(in srgb, var(--ob-accent) 9%, transparent);
}
/* Selected model — accent tint + a left accent bar to distinguish it from a
   plain hover. */
.ob-combo-option.is-active {
    background: color-mix(in srgb, var(--ob-accent) 15%, transparent);
    box-shadow: inset 3px 0 0 var(--ob-accent);
}
.ob-combo-option-name {
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--ob-ink);
    line-height: 1.3;
}
.ob-combo-option.is-active .ob-combo-option-name {
    color: var(--ob-accent);
}
.ob-combo-option-id {
    font-size: 0.72rem;
    color: var(--ob-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ob-combo-option .material-symbols-outlined {
    font-size: 1.05rem;
    color: var(--ob-accent);
}
.ob-combo-custom {
    flex-direction: row;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--ob-accent);
    margin-top: 0.15rem;
    border-top: 1px solid var(--ob-line);
    border-radius: 0 0 0.55rem 0.55rem;
}
.ob-combo-custom:hover {
    background: color-mix(in srgb, var(--ob-accent) 12%, transparent);
}

.ob-combo-note {
    padding: 0.65rem 0.7rem;
    font-size: 0.8rem;
    color: var(--ob-muted);
}

/* ============================================================
   v21 in-shell wizard chrome (mockup 03): a white top strip with the
   title, autosave pill and Exit button, a numbered horizontal stepper
   with connector rails, and a footer nav that sticks to the bottom
   of the viewport while the step card is on screen. Appended so the
   rules below win every same-specificity tie against the originals.
   ============================================================ */
.ob-topbar {
    background: var(--ob-card);
    border: 1px solid var(--ob-line);
    border-radius: 14px;
    padding: 12px 20px 0;
    margin-bottom: 18px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 1px rgba(16, 24, 40, .04);
}
.ob-topbar-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--ob-line);
}
.ob-topbar-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    font-weight: 800;
    letter-spacing: -.01em;
    color: var(--ob-ink);
}
.ob-topbar-title .material-symbols-outlined { font-size: 18px; color: var(--ob-accent); }
.ob-topbar-right { display: inline-flex; align-items: center; gap: 12px; }
.ob-btn-sm { padding: 0.45rem 0.9rem; font-size: 0.82rem; border-radius: 9px; }

.ob-stepper {
    display: flex;
    align-items: center;
    gap: 0;
    padding: 12px 0;
    margin: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    overflow-x: auto;
}
.ob-step-node {
    flex: none;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 0;
    min-width: 0;
}
.ob-step-node + .ob-step-node::before { content: none; }
.ob-step-node[disabled] { cursor: not-allowed; }
.ob-step-node.is-locked .ob-step-bullet { border-style: dashed; }
.ob-step-bullet {
    width: 24px;
    height: 24px;
    border: 1.5px solid var(--ob-line);
    background: var(--ob-card);
    color: var(--ob-muted);
    font-size: 11px;
    font-weight: 700;
}
.ob-step-bullet .material-symbols-outlined { font-size: 14px; }
.ob-step-node:hover .ob-step-bullet { transform: none; }
.ob-step-node.is-done .ob-step-bullet {
    background: var(--ob-accent);
    border-color: var(--ob-accent);
    color: #fff;
}
.ob-step-node.is-current .ob-step-bullet {
    background: var(--ob-card);
    border-color: var(--ob-accent);
    color: var(--ob-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ob-accent) 14%, transparent);
}
.ob-step-name {
    font-size: 12.5px;
    font-weight: 600;
    text-align: left;
    max-width: none;
    white-space: nowrap;
    margin: 0 2px 0 0;
}
.ob-step-node.is-current .ob-step-name { font-weight: 700; }
.ob-step-rail {
    width: 36px;
    height: 1.5px;
    background: var(--ob-line);
    margin: 0 10px;
    flex: none;
}
.ob-step-node.is-done .ob-step-rail { background: var(--ob-accent); }
.ob-step-node:last-child .ob-step-rail { display: none; }
.ob-step-mobile { padding-bottom: 10px; margin-bottom: 0; }
@media (max-width: 48rem) {
    .ob-step-name { display: none; }
    .ob-step-rail { width: 16px; margin: 0 4px; }
    .ob-stepper { padding: 10px 0; }
}

/* Footer nav: sticks to the bottom edge while the card is in view. */
.ob-nav {
    position: sticky;
    bottom: 0;
    z-index: 5;
    margin: 2rem -2rem -2rem;
    padding: 14px 2rem;
    background: var(--ob-card);
    border-top: 1px solid var(--ob-line);
    border-radius: 0 0 1rem 1rem;
}
@media (max-width: 30rem) {
    .ob-nav { margin: 1.5rem -1.25rem -1.75rem; padding: 12px 1.25rem; }
}
.ob-btn { border-radius: 9px; }
.ob-btn-primary { box-shadow: 0 6px 16px color-mix(in srgb, var(--ob-accent) 28%, transparent); }
.ob-btn-primary:hover { background: color-mix(in srgb, var(--ob-primary) 82%, black); }
.ob-card, .ob-preview-pane {
    border-radius: 14px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 1px rgba(16, 24, 40, .04);
}

/* ============================================================
   Footer nav / primary CTA hardening
   ------------------------------------------------------------
   Two things were wrong with the wizard's Continue button.

   1. It rendered as a white pill with white text in light mode.
      Its fill is the only thing carrying contrast (the label is a
      flat #fff), so the moment `background` loses — either because
      the --ob-primary -> --color-accent chain fails to resolve
      (a var() that resolves to garbage is invalid at computed-value
      time and falls back to `transparent`, NOT to an earlier
      declaration), or because something later in the cascade wins —
      the control becomes literally invisible on the white card.
      Note that unfold/layouts/skeleton.html re-links the
      `important: true` Tailwind build AFTER {% block extrahead %},
      via unfold/helpers/customization.html in the <body>, so this
      file is not the last word on the cascade.

      So the fill is rebuilt to be unkillable: a literal colour floor
      on background-color, the accent token carried by a gradient
      layer painted over it, and !important on both. Worst case the
      button is P3 blue instead of a custom accent — it is never a
      white-on-white ghost.

   2. It sat at the very bottom of a card that can run several
      screens long (step 1 with a lot of avatars), so finding it
      meant scrolling. The bar was already position:sticky but read
      as part of the page; it now gets a lift shadow so it clearly
      floats above the content it covers.
   ============================================================ */
.ob-btn-primary {
    background-color: #3b6fed !important;
    background-image:
        linear-gradient(var(--ob-primary, #3b6fed), var(--ob-primary, #3b6fed)) !important;
    color: #fff !important;
}

/* The 2421 rule uses the `background` shorthand, which would reset the
   gradient layer above — hover has to be re-stated as a layer too. */
.ob-btn-primary:hover:not(:disabled) {
    background-image: linear-gradient(
        color-mix(in srgb, var(--ob-primary, #3b6fed) 82%, black),
        color-mix(in srgb, var(--ob-primary, #3b6fed) 82%, black)) !important;
}

/* Same treatment for the stepper's current bullet, the other place the
   accent is the only source of contrast against white ink. */
.ob-step-node.is-current .ob-step-bullet {
    background-color: #3b6fed;
    background-image:
        linear-gradient(var(--ob-primary, #3b6fed), var(--ob-primary, #3b6fed));
}

/* A sticky box is pinned by its MARGIN box, so the -2rem bottom margin the bar
   used to cancel the card's bottom padding with was pushing the bottom 32px of
   the bar — most of the button — below the viewport edge while it was stuck.
   The bar now ends where the card's content box ends and the card gives up its
   bottom padding instead, which is the same geometry with none of the offset.
   Once the avatar is live the nav is display:none, so the card takes its
   padding back (see .ob-wrap.is-launched). */
.ob-card {
    padding-bottom: 0;
}

.ob-wrap.is-launched .ob-card {
    padding-bottom: 2rem;
}

.ob-nav {
    margin: 2rem -2rem 0;
    /* Radius matches .ob-card's 14px (set above), not the older 1rem. */
    border-radius: 0 0 13px 13px;
    /* Reads as a floating bar over the step body instead of a flat strip. */
    box-shadow: 0 -10px 22px -14px rgba(16, 24, 40, .45);
}

@media (max-width: 30rem) {
    .ob-nav { margin: 1.5rem -1.25rem 0; }
}

.dark .ob-nav {
    box-shadow: 0 -10px 22px -12px rgba(0, 0, 0, .6);
}
