    /* ============================================================
       TRY-FOR-FREE MODAL (`tff-` = try-for-free)
       Reuses the landing-page .bkm-* modal chrome from vertical.css
       (overlay, close button, body padding, form fields, submit)
       and adds signup-specific components:
         - big phone-hero input
         - "or" divider
         - Google + email OAuth-style secondary buttons
         - sign-in footer link
       ============================================================ */

    /* Overlay / shell — mirror .bkm-overlay exactly so both modals
       have identical enter/exit behavior. */
    .tff-overlay {
        position: fixed; inset: 0;
        background: rgba(5, 5, 8, 0.78);
        backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
        display: flex; align-items: center; justify-content: center;
        padding: 24px;
        z-index: 2000;
        opacity: 0; pointer-events: none;
        transition: opacity 0.22s ease;
    }
    .tff-overlay[data-open="true"] { opacity: 1; pointer-events: auto; }

    .tff {
        position: relative;
        width: 100%;
        max-width: 480px;
        max-height: calc(100vh - 48px);
        background: var(--pk-bg-elevated, #111113);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.08));
        border-radius: 18px;
        box-shadow: 0 32px 80px rgba(0,0,0,0.55);
        overflow: hidden;
        transform: translateY(12px) scale(0.985);
        opacity: 0;
        transition: max-width 0.32s cubic-bezier(0.22, 1, 0.36, 1),
                    transform 0.28s cubic-bezier(0.22, 1, 0.36, 1),
                    opacity 0.24s ease;
        display: flex; flex-direction: column;
    }
    /* Voice-selection and test views need more room for their 2-column layouts.
       Test view is wider than voices (720 vs 640) because the 14-char mono
       phone-number placeholder at 24px/700 needs ~240px of inner text area
       inside the callme input to breathe (205px glyphs + both padding). */
    .tff[data-view="voices"] { max-width: 640px; }
    .tff[data-view="test"] { max-width: 720px; }
    .tff[data-view="calling"] { max-width: 520px; }
    .tff-overlay[data-open="true"] .tff {
        transform: translateY(0) scale(1);
        opacity: 1;
    }

    .tff-close {
        position: absolute; top: 16px; right: 16px;
        width: 36px; height: 36px;
        display: flex; align-items: center; justify-content: center;
        background: rgba(255,255,255,0.06);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.08));
        border-radius: 10px;
        color: var(--pk-fg);
        cursor: pointer; z-index: 4;
        transition: background 0.15s, color 0.15s;
    }
    @media (hover: hover) {
        .tff-close:hover { background: rgba(255,255,255,0.1); color: #fff; }
    }
    .tff-close svg { width: 16px; height: 16px; }

    /* Header pane — reuses .aud9-kicker + .aud9-title via inline classes */
    .tff-head {
        padding: 36px 36px 28px;
    }
    .tff-head .aud9-kicker {
        color: rgb(245, 158, 11);
        margin-bottom: 12px;
    }
    .tff-head .aud9-kicker .aud9-kicker-dot {
        background: rgb(239, 68, 68);
    }
    .tff-head .aud9-title {
        font-family: var(--pk-font-sans);
        font-size: 26px;
        font-weight: 800;
        color: var(--pk-fg);
        letter-spacing: -0.022em;
        line-height: 1.18;
        margin: 0 0 14px;
    }
    .tff-head .aud9-title em {
        font-style: normal;
        background: linear-gradient(135deg, #10B981, #34d399);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
    }
    /* Loading-dot pulse for "Check your phone..." — three dots fade+scale
       in sequence. The em's -webkit-text-fill-color cascade breaks across
       inline-block descendants, so we replay the green gradient on each
       dot span explicitly. */
    .tff-dots { letter-spacing: -0.01em; margin-left: 1px; }
    .tff-dots > span {
        display: inline-block;
        background: linear-gradient(135deg, #10B981, #34d399);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        opacity: 0.25;
        transform: translateY(0);
        animation: tff-dot-pulse 1.3s infinite ease-in-out both;
        will-change: opacity, transform;
    }
    .tff-dots > span:nth-child(1) { animation-delay: 0s; }
    .tff-dots > span:nth-child(2) { animation-delay: 0.18s; }
    .tff-dots > span:nth-child(3) { animation-delay: 0.36s; }
    @keyframes tff-dot-pulse {
        0%, 70%, 100% { opacity: 0.25; transform: translateY(0) scale(0.9); }
        35%           { opacity: 1;    transform: translateY(-3px) scale(1); }
    }
    @media (prefers-reduced-motion: reduce) {
        .tff-dots > span { animation: none; opacity: 1; transform: none; }
    }

    /* ────────────────────────────────────────────────────────────
       Building stall — "forge" animation
       ------------------------------------------------------------
       Direct port of the /hang-tight forge (shared/css/meta-postsubmit.css)
       adapted to live INSIDE the modal: smaller diameter, phase labels
       constrained inside the box (no negative-inset protrusion), and
       palette tuned to the modal's existing violet (--pk-accent #7c3aed)
       paired with cyan #22d3ee — same accents /hang-tight uses, just
       shifted slightly cooler so the green emerald em-accent in the
       title still pops. All ambient looping motion, no per-user data.
       ──────────────────────────────────────────────────────────── */
    .tff-building {
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 8px 0 4px;
    }

    /* "Continue anyway" skip affordance — fades in after 10s on a
       stuck tail-end. Styled to match the modal's primary CTA
       language (rounded, solid accent) so it reads as a legitimate
       action in the flow rather than a half-styled link. D31's
       "escape hatch" intent is preserved via the fade-in delay and
       reduced padding so it still doesn't upstage the forge. */
    .tff-building-skip {
        margin-top: 20px;
        padding: 12px 24px;
        border: none;
        border-radius: 12px;
        background: var(--pk-accent, #7c3aed);
        color: var(--pk-accent-fg, #fff);
        font: inherit;
        font-size: 14px;
        font-weight: 600;
        cursor: pointer;
        opacity: 0;
        animation: tff-building-skip-in 0.5s ease-out forwards;
        transition: background 0.2s, transform 0.2s;
    }
    @media (hover: hover) {
        .tff-building-skip:hover {
            background: var(--pk-accent-hover, #6D28D9);
            transform: translateY(-1px);
        }
    }
    @keyframes tff-building-skip-in {
        from { opacity: 0; transform: translateY(4px); }
        to   { opacity: 1; transform: translateY(0); }
    }
    .tff-forge {
        position: relative;
        width: 220px;
        height: 220px;
        margin: 0 auto;
        flex-shrink: 0;
    }
    .tff-forge-ring {
        position: absolute;
        inset: 0;
        border-radius: 50%;
        border: 1px solid rgba(192, 132, 252, 0.20);
    }
    .tff-forge-ring-1 { animation: tff-spin-cw 22s linear infinite; }
    .tff-forge-ring-1::before,
    .tff-forge-ring-1::after {
        content: '';
        position: absolute;
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: #c084fc;
        box-shadow: 0 0 12px #c084fc;
    }
    .tff-forge-ring-1::before { top: -4px; left: 50%; transform: translateX(-50%); }
    .tff-forge-ring-1::after  { bottom: -4px; left: 50%; transform: translateX(-50%); opacity: 0.5; }

    .tff-forge-ring-2 {
        inset: 22px;
        border-color: rgba(34, 211, 238, 0.24);
        animation: tff-spin-ccw 16s linear infinite;
    }
    .tff-forge-ring-2::before,
    .tff-forge-ring-2::after {
        content: '';
        position: absolute;
        width: 6px;
        height: 6px;
        border-radius: 50%;
        background: #22d3ee;
        box-shadow: 0 0 10px #22d3ee;
    }
    .tff-forge-ring-2::before { top: 50%; left: -3px; transform: translateY(-50%); }
    .tff-forge-ring-2::after  { top: 50%; right: -3px; transform: translateY(-50%); opacity: 0.5; }

    .tff-forge-ring-3 {
        inset: 44px;
        border-color: rgba(244, 114, 182, 0.16);
        border-style: dashed;
        animation: tff-spin-cw 30s linear infinite;
    }

    @keyframes tff-spin-cw  { to { transform: rotate(360deg);  } }
    @keyframes tff-spin-ccw { to { transform: rotate(-360deg); } }

    .tff-forge-core {
        position: absolute;
        inset: 70px;
        border-radius: 50%;
        background:
            radial-gradient(circle at 50% 40%, rgba(192, 132, 252, 0.55), transparent 62%),
            linear-gradient(145deg, #1a0a2e, #0a0418);
        box-shadow:
            0 0 40px rgba(192, 132, 252, 0.4),
            inset 0 0 20px rgba(34, 211, 238, 0.28),
            inset 0 0 4px rgba(255, 255, 255, 0.22);
        display: flex;
        align-items: center;
        justify-content: center;
        animation: tff-core-pulse 3.2s ease-in-out infinite;
    }
    @keyframes tff-core-pulse {
        0%, 100% {
            box-shadow:
                0 0 40px rgba(192, 132, 252, 0.4),
                inset 0 0 20px rgba(34, 211, 238, 0.28),
                inset 0 0 4px rgba(255, 255, 255, 0.22);
        }
        50% {
            box-shadow:
                0 0 70px rgba(192, 132, 252, 0.65),
                inset 0 0 30px rgba(34, 211, 238, 0.42),
                inset 0 0 6px rgba(255, 255, 255, 0.32);
        }
    }

    .tff-forge-wave {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 3px;
        height: 30px;
    }
    .tff-forge-wave span {
        display: block;
        width: 3px;
        background: linear-gradient(180deg, #c084fc, #22d3ee);
        border-radius: 2px;
        animation: tff-wave-bar 1.2s ease-in-out infinite;
    }
    .tff-forge-wave span:nth-child(1) { height:  9px; animation-delay: 0s;   }
    .tff-forge-wave span:nth-child(2) { height: 16px; animation-delay: 0.1s; }
    .tff-forge-wave span:nth-child(3) { height: 24px; animation-delay: 0.2s; }
    .tff-forge-wave span:nth-child(4) { height: 30px; animation-delay: 0.3s; }
    .tff-forge-wave span:nth-child(5) { height: 24px; animation-delay: 0.4s; }
    .tff-forge-wave span:nth-child(6) { height: 16px; animation-delay: 0.5s; }
    .tff-forge-wave span:nth-child(7) { height:  9px; animation-delay: 0.6s; }
    @keyframes tff-wave-bar {
        0%, 100% { transform: scaleY(0.5); opacity: 0.5; }
        50%      { transform: scaleY(1);   opacity: 1;   }
    }

    /* Phase labels orbit the forge perimeter. Each fades in for ~1.8s out
       of a 9s loop with a 1.5s offset between siblings — at any given
       moment one or two are visible, never the whole set. Constrained to
       the forge box so they never escape the modal frame. */
    .tff-forge-phase {
        position: absolute;
        font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 9px;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: #d4d4d8;
        padding: 4px 8px;
        background: rgba(8, 4, 16, 0.78);
        border: 1px solid rgba(192, 132, 252, 0.28);
        border-radius: 4px;
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
        opacity: 0;
        animation: tff-phase-fade 9s ease-in-out infinite;
        white-space: nowrap;
    }
    .tff-forge-phase-1 { top: 0;      left: 8%;     animation-delay: 0s;   }
    .tff-forge-phase-2 { top: 16%;    right: -4%;   animation-delay: 1.5s; }
    .tff-forge-phase-3 { top: 50%;    left: 100%;   animation-delay: 3s;   margin-left: 12px; transform: translateY(-50%); }
    .tff-forge-phase-4 { bottom: 16%; right: -4%;   animation-delay: 4.5s; }
    .tff-forge-phase-5 { bottom: 0;   left: 14%;    animation-delay: 6s;   }
    .tff-forge-phase-6 { top: 50%;    right: 100%;  animation-delay: 7.5s; margin-right: 12px; transform: translateY(-50%); }
    @keyframes tff-phase-fade {
        0%, 80%, 100% { opacity: 0;   transform: translateY(4px); }
        8%, 20%       { opacity: 1;   transform: translateY(0);   }
        30%           { opacity: 0.6; }
    }
    /* The two side-anchored labels (phase-3 right, phase-6 left) sit
       outside the forge box at vertical center, so their transform
       must preserve the -50% y-shift throughout the fade. */
    .tff-forge-phase-3,
    .tff-forge-phase-6 {
        animation-name: tff-phase-fade-side;
    }
    @keyframes tff-phase-fade-side {
        0%, 80%, 100% { opacity: 0;   transform: translateY(-50%) translateX(2px); }
        8%, 20%       { opacity: 1;   transform: translateY(-50%) translateX(0);   }
        30%           { opacity: 0.6; }
    }

    /* Sub-copy under the forge — small, muted, single line. */
    .tff-building-sub {
        margin: 22px 0 0;
        font-size: 13px;
        color: var(--pk-fg-muted, rgba(255,255,255,0.62));
        text-align: center;
        line-height: 1.5;
    }

    @media (prefers-reduced-motion: reduce) {
        .tff-forge-ring-1,
        .tff-forge-ring-2,
        .tff-forge-ring-3,
        .tff-forge-core,
        .tff-forge-wave span,
        .tff-forge-phase { animation: none; }
        .tff-forge-phase { opacity: 0.9; }
    }

    /* Promise list — reuses .vp-hero-points green checkmark pattern */
    .tff-head .vp-hero-points {
        margin: 0;
        width: 100%;
        align-items: flex-start;
    }
    /* When the list follows a lede paragraph (verify-failed head), give
       the checkmarks breathing room from the prose above them. */
    .tff-head .tff-head-lede + .vp-hero-points { margin-top: 14px; }
    /* Forward / feedback sub-view heads: lede sits above the
       `.tff-test-context` callout. The `test` head variant has no lede
       so the 14px title bottom-margin is enough there; when there IS a
       lede, give the callout a more generous 22px top gap so the two
       blocks read as distinct sections rather than a continuous wall of
       text (matches the spacing in the feedback-modal reference). */
    .tff-head .tff-head-lede + .tff-test-context { margin-top: 22px; }
    .tff-head .vp-hero-points li { font-size: 13.5px; gap: 10px; }
    .tff-head .vp-hero-points li::before {
        width: 18px; height: 18px; font-size: 10px;
    }

    /* Body */
    .tff-body {
        padding: 0 36px 28px;
        overflow-y: auto;
    }
    /* Inset divider between the promise list and the phone form.
       Matches the width + tone of the `or` divider below. */
    .tff-body::before {
        content: '';
        display: block;
        height: 1px;
        background: rgba(255,255,255,0.08);
        margin-bottom: 24px;
    }
    /* Verifying view has no body content — drop the divider and bottom
       padding so the modal doesn't hang with an empty chunk under the
       checkmark list. */
    .tff[data-view="verifying"] .tff-body { padding-bottom: 16px; }
    .tff[data-view="verifying"] .tff-body::before { display: none; }
    /* Building view — pure ambient stall. No promise list, no divider,
       no controls. The forge animation is the entire body. */
    .tff[data-view="building"] .tff-body { padding-bottom: 28px; overflow: hidden; }
    .tff[data-view="building"] .tff-body::before { display: none; }
    .tff[data-view="building"] { max-width: 520px; }
    /* Name step has no promise bullets, so the body divider would sit
       directly under the title and read as decoration. Drop it. */
    .tff[data-view="name"] .tff-body::before { display: none; }

    .tff-error {
        padding: 10px 12px;
        margin-bottom: 14px;
        border-radius: 10px;
        font-size: 13px;
        color: #FCA5A5;
        background: rgba(239, 68, 68, 0.08);
        border: 1px solid rgba(239, 68, 68, 0.25);
        display: none;
    }
    .tff-error[data-show="true"] { display: block; }

    /* Phone-hero block: the primary account-creation path.
       Large input + large purple button, matching the login page's
       hero-sized phone entry but tuned to the landing-page palette. */
    /* Subhead above the phone form on the primary view — frames the
       flow as account creation, not just a free-trial signup. Matches
       the header title's display face (weight, letter-spacing, color)
       at a smaller size so it reads as a secondary heading. */
    .tff-primary-intro {
        margin: 0 0 16px;
        font-family: var(--pk-font-sans);
        font-size: 18px;
        font-weight: 800;
        line-height: 1.25;
        letter-spacing: -0.022em;
        color: var(--pk-fg);
    }

    .tff-phone-form { display: flex; flex-direction: column; gap: 12px; }
    .tff-phone-label {
        font-size: 12px; font-weight: 600; color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    .tff-phone-wrap { position: relative; }
    .tff-phone-input {
        width: 100%;
        padding: 16px 16px 16px 44px;
        background-color: rgba(255,255,255,0.03);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        color: var(--pk-fg);
        font: inherit; font-size: 18px; font-weight: 500;
        letter-spacing: 0.01em;
        transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
    }
    .tff-phone-input::placeholder { color: rgba(255,255,255,0.32); font-weight: 400; }
    .tff-phone-input:focus {
        outline: none;
        border-color: rgba(124,58,237,0.55);
        background-color: rgba(124,58,237,0.04);
        box-shadow: 0 0 0 3px rgba(124,58,237,0.15);
    }
    .tff-phone-icon {
        position: absolute;
        left: 16px; top: 50%; transform: translateY(-50%);
        width: 18px; height: 18px;
        color: var(--pk-fg-muted);
        pointer-events: none;
    }
    .tff-phone-input:focus ~ .tff-phone-icon { color: var(--pk-accent, #7c3aed); }

    .tff-primary {
        margin-top: 4px;
        padding: 15px 20px;
        background: var(--pk-accent, #7c3aed);
        color: var(--pk-accent-fg, #fff);
        border: none;
        border-radius: 12px;
        font: inherit; font-size: 15px; font-weight: 600;
        cursor: pointer;
        transition: background 0.2s, transform 0.2s;
        display: inline-flex; align-items: center; justify-content: center; gap: 8px;
        width: 100%;
    }
    @media (hover: hover) {
        .tff-primary:hover:not(:disabled) {
            background: var(--pk-accent-hover, #6D28D9);
            transform: translateY(-1px);
        }
    }
    .tff-primary:disabled { opacity: 0.5; cursor: not-allowed; }
    .tff-primary svg { width: 16px; height: 16px; }

    /* "or" divider */
    .tff-or {
        display: flex; align-items: center; gap: 12px;
        margin: 20px 0;
        font-size: 11px; font-weight: 600;
        text-transform: uppercase; letter-spacing: 0.14em;
        color: var(--pk-fg-muted);
    }
    .tff-or::before, .tff-or::after {
        content: ''; flex: 1; height: 1px;
        background: rgba(255,255,255,0.08);
    }
    /* Vertical orientation — stacks the two line segments above/below
       the word so the divider can sit between side-by-side cards. */
    .tff-or-vertical {
        flex-direction: column;
        gap: 8px;
        align-self: stretch;
    }
    .tff-or-vertical::before, .tff-or-vertical::after {
        width: 1px;
        height: auto;
        min-height: 14px;
    }

    /* ── Sub-view toggling ── */
    .tff-view[hidden] { display: none; }
    .tff-head-variant[hidden] { display: none; }

    /* Subtitle/lede that replaces the bullet list in secondary steps. */
    .tff-head-lede {
        font-size: 13.5px; line-height: 1.55;
        color: var(--pk-fg-muted);
        margin: 0;
    }
    .tff-head-lede strong {
        color: var(--pk-fg);
        font-weight: 600;
        white-space: nowrap;
    }

    /* ── OTP sub-view ─────────────────────────────────────────── */
    .tff-otp { display: flex; flex-direction: column; align-items: stretch; }
    .tff-otp-digits {
        display: flex; justify-content: center;
        gap: 8px;
        margin: 4px 0 18px;
    }
    .tff-otp-digit {
        width: 44px; height: 52px;
        flex: 0 0 auto;
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        background: rgba(255,255,255,0.03);
        color: var(--pk-fg);
        font-family: 'JetBrains Mono', ui-monospace, monospace;
        font-size: 22px; font-weight: 600;
        text-align: center;
        caret-color: var(--pk-accent, #7c3aed);
        outline: none;
        transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
    }
    .tff-otp-digit:focus {
        border-color: rgba(124,58,237,0.55);
        background-color: rgba(124,58,237,0.04);
        box-shadow: 0 0 0 3px rgba(124,58,237,0.15);
    }
    .tff-otp-digit.is-filled { border-color: rgba(16,185,129,0.45); }

    .tff-resend {
        text-align: center;
        font-size: 13px;
        color: var(--pk-fg-muted);
        margin-bottom: 16px;
    }
    .tff-resend-link {
        background: none; border: none;
        font: inherit; font-size: 13px;
        color: var(--pk-accent, #7c3aed);
        cursor: pointer;
        padding: 0 0 0 4px;
    }
    @media (hover: hover) {
        .tff-resend-link:hover:not(:disabled) { text-decoration: underline; }
    }
    .tff-resend-link:disabled {
        color: var(--pk-fg-dim, rgba(255,255,255,0.32));
        cursor: default;
    }

    /* ── Done / success placeholder view ──────────────────────── */
    .tff-done {
        display: flex; flex-direction: column; align-items: center;
        text-align: center;
        padding: 4px 0 8px;
    }
    .tff-done-check {
        width: 56px; height: 56px;
        border-radius: 999px;
        background: rgba(16,185,129,0.12);
        border: 1px solid rgba(16,185,129,0.28);
        display: flex; align-items: center; justify-content: center;
        color: #34d399;
        margin-bottom: 16px;
    }
    .tff-done-check svg { width: 28px; height: 28px; }
    .tff-done-title {
        font-size: 18px; font-weight: 700; color: var(--pk-fg);
        letter-spacing: -0.01em;
        margin: 0 0 6px;
    }
    .tff-done-sub {
        font-size: 13.5px; color: var(--pk-fg-muted); line-height: 1.55;
        margin: 0 0 18px; max-width: 320px;
    }
    .tff-done-spinner {
        width: 24px; height: 24px;
        border: 2px solid rgba(255,255,255,0.12);
        border-top-color: var(--pk-accent, #7c3aed);
        border-radius: 999px;
        animation: tff-spin 0.7s linear infinite;
    }
    @keyframes tff-spin { to { transform: rotate(360deg); } }

    /* ── Verify-failed state ───────────────────────────────────────
       Amber/warning tone — not red-alert, but a heads-up the user
       needs to respond to. */
    .tff-kicker-warning { color: rgb(245, 158, 11) !important; }
    .tff-kicker-warning .aud9-kicker-dot { background: rgb(239, 68, 68) !important; }
    .tff-head .aud9-title em.tff-em-warning {
        background: linear-gradient(135deg, #F59E0B, #FBBF24);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
    }
    .tff-fail-actions {
        display: flex; flex-direction: column; align-items: stretch;
        gap: 2px; margin-top: 18px; width: 100%;
    }
    .tff-fail-actions .tff-primary { margin: 0; }
    .tff-fail-actions .tff-back { margin: 10px auto 0; }
    /* URL-step skip link sits under its Continue button — mirrors the
       verify-failed spacing (2px gap + 10px margin = 12px). The parent
       form is a flex column with a 14px gap, so the negative top margin
       cancels the surplus gap to land at the same 12px. */
    #tff-url-skip { margin: -2px auto 0; }

    /* ── Email + password sub-view (triggered by "Continue with Email") ── */
    .tff-email-form { display: flex; flex-direction: column; gap: 14px; }
    .tff-field { display: flex; flex-direction: column; gap: 6px; }
    /* Two fields side-by-side (e.g. first + last name). Children split
       the row evenly; `min-width: 0` lets them shrink past the input's
       intrinsic width so long placeholders don't force an overflow. */
    .tff-field-row { display: flex; gap: 12px; }
    .tff-field-row > .tff-field { flex: 1; min-width: 0; }
    .tff-label {
        font-size: 12px; font-weight: 600; color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    .tff-input-wrap { position: relative; }
    .tff-input {
        width: 100%;
        padding: 13px 14px 13px 42px;
        background-color: rgba(255,255,255,0.03);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        color: var(--pk-fg);
        font: inherit; font-size: 15px; font-weight: 500;
        letter-spacing: 0.005em;
        transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
    }
    .tff-input::placeholder { color: rgba(255,255,255,0.32); font-weight: 400; }
    .tff-input:focus {
        outline: none;
        border-color: rgba(124,58,237,0.55);
        background-color: rgba(124,58,237,0.04);
        box-shadow: 0 0 0 3px rgba(124,58,237,0.15);
    }
    .tff-input-icon {
        position: absolute;
        left: 14px; top: 50%; transform: translateY(-50%);
        width: 16px; height: 16px;
        color: var(--pk-fg-muted);
        pointer-events: none;
        transition: color 0.15s;
    }
    .tff-input:focus ~ .tff-input-icon { color: var(--pk-accent, #7c3aed); }

    /* Invalid-field state + inline error message. Mirrors the focus
       ring so the field feels hot-to-touch, not broken. The border
       and glow are applied even when the input has focus — blur-based
       validation only flags invalid-on-leave, so a focused + invalid
       state is rare (only happens on submit-attempt focus-back). */
    .tff-input.is-invalid,
    .tff-input.is-invalid:focus {
        border-color: rgba(239,68,68,0.6);
        background-color: rgba(239,68,68,0.04);
        box-shadow: 0 0 0 3px rgba(239,68,68,0.15);
    }
    .tff-input.is-invalid ~ .tff-input-icon { color: #FCA5A5; }
    .tff-field-error {
        margin: 6px 2px 0;
        font-size: 12.5px;
        line-height: 1.4;
        color: #FCA5A5;
    }
    .tff-field-error[hidden] { display: none; }

    .tff-email-form .tff-primary { margin-top: 6px; }
    /* Progressive disclosure on the email step — password field only
       appears after the user confirms their email with Continue. The
       form's flex gap collapses when the child is display: none, so
       spacing between email and the button stays correct. */
    .tff-email-form[data-stage="email"] [data-field="password"] { display: none; }
    /* Name step collects whichever contact method wasn't used to sign up:
       phone-signup users see the email field, email-signup users see the
       phone field. CSS hides the channel that matches the signup method. */
    #tff-name-form[data-channel="phone"] [data-channel-field="phone"] { display: none; }
    #tff-name-form[data-channel="email"] [data-channel-field="email"] { display: none; }

    /* Small hint text that sits under a field. */
    .tff-field-hint {
        margin: 2px 2px 0;
        font-size: 11.5px; line-height: 1.5;
        color: var(--pk-fg-muted);
    }
    .tff-field-hint code {
        font-family: 'JetBrains Mono', ui-monospace, monospace;
        font-size: 11px;
        padding: 1px 5px;
        border-radius: 5px;
        background: rgba(255,255,255,0.05);
        color: var(--pk-fg);
    }

    /* "All sign-up options" back link — sits below the email form */
    .tff-back {
        display: inline-flex; align-items: center; gap: 6px;
        margin: 18px auto 0;
        padding: 6px 10px;
        background: none; border: none;
        color: var(--pk-fg-muted);
        font: inherit; font-size: 13px; font-weight: 500;
        cursor: pointer;
        transition: color 0.15s;
    }
    @media (hover: hover) {
        .tff-back:hover { color: var(--pk-fg); }
    }
    .tff-back svg { width: 14px; height: 14px; }
    /* `:not([hidden])` keeps this rule from overriding the hidden state. */
    .tff-view[data-view="email"]:not([hidden]) { display: flex; flex-direction: column; align-items: stretch; }

    /* OAuth / secondary auth buttons */
    .tff-oauth { display: flex; flex-direction: column; gap: 10px; }
    .tff-oauth-btn {
        display: flex; align-items: center; justify-content: center;
        gap: 10px;
        width: 100%;
        padding: 13px 16px;
        background: rgba(255,255,255,0.02);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        color: var(--pk-fg);
        font: inherit; font-size: 14px; font-weight: 500;
        cursor: pointer;
        transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
    }
    @media (hover: hover) {
        .tff-oauth-btn:hover {
            background: rgba(255,255,255,0.05);
            border-color: rgba(255,255,255,0.18);
            transform: translateY(-1px);
        }
    }
    .tff-oauth-btn svg { width: 18px; height: 18px; flex-shrink: 0; }

    /* ── Voice-selection sub-view ──────────────────────────────────
       Compact version of the .vp-persona-card pattern from the
       landing page — 8 cards visible by default, expand for the rest.
       Colors are per-card via --card-accent (pink = female, blue = male).
       ───────────────────────────────────────────────────────────── */
    .tff-view[data-view="voices"]:not([hidden]) { display: flex; flex-direction: column; }
    .tff-voices-form { display: flex; flex-direction: column; gap: 14px; }

    .tff-voices-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
    }
    /* Once the user expands to see the full roster, cap the grid so it
       stops growing the modal — 8 cards visible per column, with a
       scrollbar revealing the rest. 8 × (60px card + 8px gap) − 8px. */
    .tff-voices-grid.is-expanded {
        max-height: 540px;
        overflow-y: auto;
        padding-right: 6px;
        scrollbar-width: thin;
        scrollbar-color: rgba(255,255,255,0.14) transparent;
    }
    .tff-voices-grid.is-expanded::-webkit-scrollbar { width: 8px; }
    .tff-voices-grid.is-expanded::-webkit-scrollbar-track { background: transparent; }
    .tff-voices-grid.is-expanded::-webkit-scrollbar-thumb {
        background: rgba(255,255,255,0.12);
        border-radius: 999px;
    }
    @media (hover: hover) {
        .tff-voices-grid.is-expanded::-webkit-scrollbar-thumb:hover {
            background: rgba(255,255,255,0.22);
        }
    }
    .tff-voice-card {
        position: relative;
        display: flex; align-items: center; gap: 10px;
        padding: 9px 12px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
        cursor: pointer;
        transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
    }
    .tff-voice-card.is-hidden { display: none; }
    @media (hover: hover) {
        .tff-voice-card:hover {
            border-color: var(--card-accent, rgba(255,255,255,0.15));
            background: rgba(255,255,255,0.02);
        }
    }
    .tff-voice-card.is-selected {
        border-color: var(--card-accent);
        background: rgba(255,255,255,0.015);
        box-shadow: 0 0 0 2px color-mix(in srgb, var(--card-accent) 22%, transparent);
    }
    .tff-voice-avatar {
        width: 32px; height: 32px;
        border-radius: 50%;
        border: 1.5px solid;
        display: flex; align-items: center; justify-content: center;
        font-size: 13px; font-weight: 800;
        flex-shrink: 0;
    }
    .tff-voice-info { flex: 1; min-width: 0; }
    .tff-voice-name {
        display: flex; align-items: center; gap: 6px;
        font-size: 13.5px; font-weight: 700;
        color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    .tff-voice-name-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .tff-voice-meta {
        font-size: 11px; color: var(--pk-fg-muted);
        margin-top: 1px;
        text-transform: capitalize;
    }
    .tff-voice-play {
        width: 28px; height: 28px;
        border-radius: 50%;
        border: 2px solid var(--card-accent);
        background: transparent;
        color: var(--card-accent);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; flex-shrink: 0;
        transition: background 0.2s, color 0.2s, transform 0.2s;
    }
    @media (hover: hover) {
        .tff-voice-play:hover {
            background: var(--card-accent); color: #fff; transform: scale(1.08);
        }
    }
    .tff-voice-play[data-playing="true"] {
        background: var(--card-accent); color: #fff;
    }
    .tff-voice-play svg { width: 10px; height: 10px; }
    .tff-voice-play .tff-pause { display: none; }
    .tff-voice-play[data-playing="true"] .tff-play-icon { display: none; }
    .tff-voice-play[data-playing="true"] .tff-pause { display: block; }

    /* Selection checkmark — inline badge next to the voice name. Green
       (our universal "yes / confirmed" color) regardless of the card's
       per-voice accent, since the meaning is "you picked this one". */
    .tff-voice-check {
        flex-shrink: 0;
        width: 14px; height: 14px;
        border-radius: 999px;
        background: #10B981;
        display: none;
        align-items: center; justify-content: center;
        color: #fff;
    }
    .tff-voice-check svg { width: 9px; height: 9px; }
    .tff-voice-card.is-selected .tff-voice-check { display: inline-flex; }

    /* "Show more voices" expand button */
    .tff-voices-more {
        width: 100%;
        padding: 10px 12px;
        border: 1.5px dashed rgba(255,255,255,0.08);
        border-radius: 12px;
        background: transparent;
        color: var(--pk-fg-muted);
        font: inherit; font-size: 13px; font-weight: 500;
        cursor: pointer;
        transition: border-color 0.15s, color 0.15s, background 0.15s;
    }
    @media (hover: hover) {
        .tff-voices-more:hover {
            border-color: rgba(255,255,255,0.18);
            color: var(--pk-fg);
            background: rgba(255,255,255,0.015);
        }
    }
    .tff-voices-more.is-hidden { display: none; }

    /* ── Industry picker sub-view ─────────────────────────────────
       Asks the user what line of work they're in so the provisioner
       can seed the right starter playbook. Not yet wired into the
       flow — available via a jump trigger and will slot in later. */
    .tff-view[data-view="industry"]:not([hidden]) { display: flex; flex-direction: column; }
    .tff-industry-form { display: flex; flex-direction: column; gap: 14px; }

    .tff-industry-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
    }
    .tff-industry-tile {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 13px 14px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
        color: var(--pk-fg);
        font: inherit;
        font-size: 14px;
        font-weight: 600;
        letter-spacing: -0.005em;
        cursor: pointer;
        text-align: left;
        transition: border-color 0.2s, background 0.2s, box-shadow 0.2s, color 0.2s;
    }
    @media (hover: hover) {
        .tff-industry-tile:hover {
            border-color: rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.02);
        }
    }
    .tff-industry-tile.is-selected {
        border-color: rgba(16, 185, 129, 0.55);
        background: rgba(16, 185, 129, 0.06);
        color: #34d399;
        box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.22);
    }
    .tff-industry-icon {
        flex-shrink: 0;
        width: 22px; height: 22px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        color: var(--pk-fg-muted);
        transition: color 0.2s;
    }
    .tff-industry-icon svg { width: 20px; height: 20px; }
    @media (hover: hover) {
        .tff-industry-tile:hover .tff-industry-icon { color: var(--pk-fg); }
    }
    .tff-industry-tile.is-selected .tff-industry-icon { color: #34d399; }
    .tff-industry-label {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    /* "Something else" catchall sits on its own row, spanning both columns
       so it reads as a distinct pick from the specific verticals above.
       Content centered so it doesn't read as "left-aligned in an empty
       row" — the full-width tile looks intentional this way. */
    .tff-industry-tile.tff-industry-tile-wide {
        grid-column: 1 / -1;
        justify-content: center;
        text-align: center;
    }

    /* Stage 2: subcategory grid. Text-only tiles (no icons) since the user
       has already established the parent vertical — we're just refining.
       A subtle back chevron above the grid goes back to stage 1. */
    .tff-industry-stage { display: flex; flex-direction: column; gap: 12px; }
    /* The [hidden] attribute alone is overridden by the display: flex
       rule above — force display: none explicitly so the non-active
       stage is actually hidden. */
    .tff-industry-stage[hidden] { display: none; }
    .tff-industry-back {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 4px 8px;
        margin-left: -8px;
        align-self: flex-start;
        background: transparent;
        border: 0;
        color: var(--pk-fg-muted);
        font: inherit;
        font-size: 12px;
        font-weight: 600;
        letter-spacing: -0.005em;
        cursor: pointer;
        border-radius: 6px;
        transition: color 0.15s, background 0.15s;
    }
    .tff-industry-back svg { width: 14px; height: 14px; flex-shrink: 0; }
    @media (hover: hover) {
        .tff-industry-back:hover {
            color: var(--pk-fg);
            background: rgba(255,255,255,0.04);
        }
    }

    .tff-industry-subs { display: contents; }
    .tff-industry-subgrid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
    }
    .tff-industry-subgrid[hidden] { display: none; }
    .tff-industry-subtile {
        padding: 13px 14px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
        color: var(--pk-fg);
        font: inherit;
        font-size: 14px;
        font-weight: 600;
        letter-spacing: -0.005em;
        cursor: pointer;
        text-align: left;
        transition: border-color 0.2s, background 0.2s, box-shadow 0.2s, color 0.2s;
    }
    @media (hover: hover) {
        .tff-industry-subtile:hover {
            border-color: rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.02);
        }
    }
    .tff-industry-subtile.is-selected {
        border-color: rgba(16, 185, 129, 0.55);
        background: rgba(16, 185, 129, 0.06);
        color: #34d399;
        box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.22);
    }
    /* "Something else" sub always lives at the bottom of each subgrid;
       span both columns so it reads as a distinct catchall and the grid
       never ends on an orphaned odd tile. Carries the same centered
       icon+label layout as the parent-stage catchall so the two reads
       as the same affordance across stages. */
    .tff-industry-subtile[data-sub="other"] {
        grid-column: 1 / -1;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 12px;
        text-align: center;
    }
    @media (hover: hover) {
        .tff-industry-subtile:hover .tff-industry-icon { color: var(--pk-fg); }
    }
    .tff-industry-subtile.is-selected .tff-industry-icon { color: #34d399; }

    /* ── Agent setup sub-view ─────────────────────────────────────
       Name the agent + write the opening greeting. "Play" renders
       the greeting via the voice-preview edge function (same path
       /app/setup uses for its greeting preview).
       ───────────────────────────────────────────────────────── */
    .tff-view[data-view="agent"]:not([hidden]) { display: flex; flex-direction: column; }
    .tff-agent-form { display: flex; flex-direction: column; gap: 14px; }

    /* Plain (no left icon) variant of .tff-input — agent name doesn't
       need the globe/user/etc. glyph the URL & email fields carry. */
    .tff-input-plain { padding-left: 14px; padding-right: 14px; }

    .tff-textarea {
        width: 100%;
        padding: 12px 14px;
        background-color: rgba(255,255,255,0.03);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 10px;
        color: var(--pk-fg);
        font: inherit; font-size: 14px; line-height: 1.55;
        resize: vertical;
        min-height: 84px;
        transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
    }
    .tff-textarea::placeholder { color: rgba(255,255,255,0.32); }
    .tff-textarea:focus {
        outline: none;
        border-color: rgba(124,58,237,0.55);
        background-color: rgba(124,58,237,0.04);
        box-shadow: 0 0 0 3px rgba(124,58,237,0.15);
    }

    /* Full-width "Play your custom greeting" button — sized like .tff-primary
       so it feels like a peer action to Continue, but styled as a secondary
       (neutral translucent) button so Continue remains the committing action.
       Swaps between play / pause / spinner icons via hidden attrs on the
       inner SVGs. */
    .tff-greeting-play {
        margin-top: 4px;
        padding: 15px 20px;
        background: rgba(255,255,255,0.02);
        color: var(--pk-fg);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        font: inherit; font-size: 15px; font-weight: 600;
        cursor: pointer;
        transition: background 0.15s, border-color 0.15s, transform 0.15s;
        display: inline-flex; align-items: center; justify-content: center; gap: 8px;
        width: 100%;
    }
    @media (hover: hover) {
        .tff-greeting-play:hover:not(:disabled) {
            background: rgba(255,255,255,0.05);
            border-color: rgba(255,255,255,0.18);
            transform: translateY(-1px);
        }
    }
    .tff-greeting-play:disabled { opacity: 0.55; cursor: progress; }
    .tff-greeting-play[hidden] { display: none; }
    .tff-greeting-icon { width: 16px; height: 16px; flex-shrink: 0; }
    .tff-greeting-icon[hidden] { display: none; }
    .tff-greeting-icon-spinner { animation: tff-spin 0.7s linear infinite; }
    .tff-greeting-note {
        margin-top: 6px;
        color: var(--pk-muted);
        font-size: 13px;
        line-height: 1.45;
    }

    /* Thin divider separating the preview button from Continue. Matches the
       modal's subtle border tone so it feels like a section rule, not a field. */
    .tff-agent-divider {
        height: 1px;
        background: var(--pk-border-muted, rgba(255,255,255,0.08));
        margin: 4px 0;
    }

    /* ── Test / Launch sub-view ─────────────────────────────────────
       Final step. Agent is provisioned and live — user tests it either
       by dialing their new number (inbound) or requesting an outbound
       "call me" ring, then commits the trial with Launch.

       Mirrors the /app/setup Step 3 "two methods" pattern (call your
       number · your agent calls you) but stacked vertically and tuned
       to the landing-page palette (green = agent-is-live success,
       purple = action accent, matching the rest of this modal).
       ───────────────────────────────────────────────────────────── */
    .tff-view[data-view="test"]:not([hidden]) { display: flex; flex-direction: column; }
    .tff-view[data-view="calling"]:not([hidden]) { display: flex; flex-direction: column; }
    .tff-test-form { display: flex; flex-direction: column; gap: 14px; }
    /* Within the test view, rely on the form's flex gap for spacing;
       the default .tff-or margin would double-up with the gap. */
    .tff-test-form .tff-or { margin: 0; }

    /* Expectation-setting card above the test phones. Two variants (scraped
       vs unscraped) switch via `data-scraped` on the container — sets honest
       expectations so users don't judge the quick demo as the finished product. */
    .tff-test-context {
        background: rgba(124, 58, 237, 0.07);
        border: 1px solid rgba(124, 58, 237, 0.22);
        border-radius: 14px;
        padding: 14px 16px;
        display: flex;
        flex-direction: column;
        gap: 10px;
    }
    .tff-test-context-label {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 11.5px;
        font-weight: 700;
        letter-spacing: 0.12em;
        text-transform: uppercase;
        color: #c4b5fd;
        margin: 0;
    }
    .tff-test-context-label svg { width: 14px; height: 14px; }
    .tff-test-context-points {
        list-style: none;
        padding: 0;
        margin: 0;
        display: flex;
        flex-direction: column;
        gap: 6px;
    }
    .tff-test-context-points li {
        font-size: 13.5px;
        line-height: 1.5;
        color: rgba(255,255,255,0.78);
        padding-left: 16px;
        position: relative;
    }
    .tff-test-context-points li::before {
        content: '';
        position: absolute;
        left: 2px;
        top: 8px;
        width: 5px;
        height: 5px;
        border-radius: 999px;
        background: rgba(167, 139, 250, 0.7);
    }
    /* Green accent on the "real magic" bullet's opening phrase — echoes the
       "agent is live" palette and gives the closing point emphasis without
       needing a separate styled block. */
    .tff-test-context-points li strong {
        color: #34d399;
        font-weight: 600;
    }
    /* Variant switching — only the matching variant renders. */
    .tff-test-context[data-scraped="true"] [data-context-variant="unscraped"],
    .tff-test-context[data-scraped="false"] [data-context-variant="scraped"] {
        display: none;
    }

    /* Two test cards sit side-by-side in a flex row at desktop width.
       The modal widens to 640px for this view (see `.tff[data-view="test"]`
       above). On mobile the row collapses back to a vertical stack.

       Row-by-row alignment: the left card has (label · phone · copy) and
       the right has (label · input · call-me · status). To keep each row
       vertically aligned across cards:
         1. Content flows top-down (no justify-content:center).
         2. The phone display gets a `min-height` equal to the input so
            the "field" row is the same height on both sides.
         3. A ghost `.tff-test-status` is added to the left card so the
            status row is reserved on both sides too. */
    .tff-test-row {
        display: flex;
        gap: 10px;
        align-items: stretch;
    }
    .tff-test-row > .tff-test-card {
        flex: 1 1 0;
        min-width: 0;
        justify-content: flex-start;
    }
    /* Phone display in the row layout — becomes a same-height "ghost field"
       so its baseline row matches the input next to it. */
    .tff-test-row .tff-test-phone-display {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 51px;
        width: 100%;
    }

    .tff-test-card {
        padding: 20px 16px;
        background: rgba(255,255,255,0.02);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.08));
        border-radius: 14px;
        display: flex; flex-direction: column; align-items: center;
        text-align: center;
        gap: 12px;
    }
    .tff-test-card-label {
        font-size: 11px;
        font-weight: 700;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: var(--pk-fg-muted);
        margin: 0;
    }
    /* Inbound lead-in — small muted caption that sits above the phone
       number on the "Call the agent" tab. Uses negative bottom margin
       to tighten the gap to the number below (overriding the panel's
       default 12px flex gap) so the caption reads as a label, not as
       a peer element. */
    .tff-test-caption {
        margin: 0 0 -4px;
        font-size: 13px;
        line-height: 1.4;
        color: var(--pk-fg-muted);
        text-align: center;
    }

    /* Phone display — green success tone matching the "agent is live"
       kicker, with a soft pulsing glow so the number reads as alive /
       just-provisioned. */
    .tff-test-phone-display {
        font-family: 'JetBrains Mono', ui-monospace, monospace;
        font-size: 24px;
        font-weight: 700;
        color: #34d399;
        letter-spacing: 0.01em;
        font-variant-numeric: tabular-nums;
        line-height: 1.1;
        animation: tff-test-phone-pulse 3.2s ease-in-out infinite;
    }
    @keyframes tff-test-phone-pulse {
        0%, 100% { text-shadow: 0 0 22px rgba(16,185,129,0.22); }
        50%      { text-shadow: 0 0 34px rgba(16,185,129,0.40), 0 0 62px rgba(16,185,129,0.14); }
    }
    @media (prefers-reduced-motion: reduce) {
        .tff-test-phone-display {
            animation: none;
            text-shadow: 0 0 22px rgba(16,185,129,0.22);
        }
    }

    .tff-test-copy-btn {
        display: inline-flex; align-items: center; gap: 6px;
        padding: 8px 14px;
        background: rgba(16,185,129,0.08);
        border: 1px solid rgba(16,185,129,0.28);
        border-radius: 999px;
        color: #34d399;
        font: inherit; font-size: 12.5px; font-weight: 600;
        cursor: pointer;
        transition: background 0.15s, border-color 0.15s, color 0.15s;
    }
    @media (hover: hover) {
        .tff-test-copy-btn:hover {
            background: rgba(16,185,129,0.14);
            border-color: rgba(16,185,129,0.48);
        }
    }
    .tff-test-copy-btn[data-copied="true"] {
        background: rgba(16,185,129,0.22);
        border-color: rgba(16,185,129,0.55);
        color: #86efac;
    }
    .tff-test-copy-btn svg { width: 13px; height: 13px; }

    /* "Have us call you" — matches the Copy-number button (green pill) so
       both actions under the segmented toggle read as equivalent controls.
       Typography mirrors `.tff-test-phone-display` exactly (same mono font,
       size, weight, color) so the user's typed number reads identically
       to the provisioned number on the inbound panel. */
    .tff-test-callme-input {
        width: 100%;
        max-width: 300px;
        padding: 11px 14px;
        background-color: rgba(255,255,255,0.03);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.1));
        border-radius: 12px;
        color: #34d399;
        font-family: 'JetBrains Mono', ui-monospace, monospace;
        font-size: 24px;
        font-weight: 700;
        line-height: 1.1;
        letter-spacing: 0.01em;
        text-align: center;
        font-variant-numeric: tabular-nums;
        outline: none;
        transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
    }
    .tff-test-callme-input::placeholder {
        color: rgba(255,255,255,0.28);
        font-weight: 500;
        letter-spacing: 0.01em;
    }
    .tff-test-callme-input:focus {
        border-color: rgba(16,185,129,0.55);
        background-color: rgba(16,185,129,0.04);
        box-shadow: 0 0 0 3px rgba(16,185,129,0.15);
    }
    /* Bigger than the Copy-number button — now the primary action in
       the outbound panel since the "Launch your agent" CTA has been
       removed. Still green (so it pairs visually with Copy number in
       the sibling panel) but sized closer to a full button. */
    .tff-test-callme-btn {
        display: inline-flex; align-items: center; gap: 10px;
        padding: 14px 28px;
        background: rgba(16,185,129,0.1);
        border: 1px solid rgba(16,185,129,0.32);
        border-radius: 999px;
        color: #34d399;
        font: inherit; font-size: 15px; font-weight: 600;
        cursor: pointer;
        transition: background 0.15s, border-color 0.15s, color 0.15s;
    }
    @media (hover: hover) {
        .tff-test-callme-btn:hover:not(:disabled) {
            background: rgba(16,185,129,0.16);
            border-color: rgba(16,185,129,0.5);
        }
    }
    .tff-test-callme-btn:disabled { opacity: 0.5; cursor: not-allowed; }
    .tff-test-callme-btn svg { width: 16px; height: 16px; }

    /* Heading above the segmented toggle — sets the scene for the tabs.
       The sparkle icon reads as "AI / something magic is about to
       happen" and nudges the eye toward the CTAs below. */
    .tff-test-heading {
        display: flex; align-items: center; justify-content: center;
        gap: 8px;
        text-align: center;
        font-size: 16px;
        font-weight: 700;
        letter-spacing: -0.005em;
        color: var(--pk-fg, #fff);
        margin: 0 0 14px;
    }
    .tff-test-heading-sparkle {
        width: 18px; height: 18px;
        color: #a78bfa;
        flex: 0 0 auto;
    }

    /* Segmented toggle — single decision point, one active panel at a time.
       Purple accent mirrors the signup flow's primary-action color so the
       chosen mode reads as an active selection rather than a passive tab. */
    .tff-test-seg {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0;
        background: rgba(255,255,255,0.02);
        border: 1px solid rgba(255,255,255,0.1);
        border-radius: 12px;
        padding: 4px;
        margin-bottom: 18px;
    }
    .tff-test-seg-btn {
        display: inline-flex; align-items: center; justify-content: center; gap: 8px;
        padding: 10px 14px;
        background: transparent;
        border: none;
        border-radius: 8px;
        color: var(--pk-fg-muted);
        font: inherit; font-size: 13.5px; font-weight: 600;
        cursor: pointer;
        transition: background 0.15s, color 0.15s;
    }
    @media (hover: hover) {
        .tff-test-seg-btn:hover:not(.is-active) { color: var(--pk-fg); }
    }
    .tff-test-seg-btn svg { width: 14px; height: 14px; }
    .tff-test-seg-btn.is-active {
        background: rgba(124,58,237,0.12);
        color: #c4b5fd;
        box-shadow: 0 1px 0 rgba(255,255,255,0.06) inset;
    }

    .tff-test-seg-panel {
        display: flex; flex-direction: column; align-items: center;
        gap: 12px;
        padding: 8px 0 4px;
    }
    .tff-test-seg-panel[hidden] { display: none; }

    /* Wrapper for the prefilled callback number. Shrink-wraps the text
       so the absolutely-positioned edit icon can hang off the right
       edge without shifting layout. Hidden (via JS) when the user
       switches to input mode. */
    .tff-test-callme-display-wrap {
        position: relative;
        display: inline-flex;
        align-items: center;
    }
    .tff-test-callme-display-wrap[hidden] { display: none; }

    /* Icon-only edit affordance. Hangs just off the top-right corner
       of the number so it doesn't jostle the text, fades in on hover
       of the display wrap, and opens input mode on click. Keyboard
       users get an always-visible focus ring via :focus-visible.
       Hidden entirely for phone-OTP signups (number is already verified). */
    .tff-test-callme-change {
        position: absolute;
        top: -4px;
        right: -30px;
        display: inline-flex; align-items: center; justify-content: center;
        width: 24px; height: 24px;
        padding: 0;
        background: transparent;
        border: none;
        border-radius: 6px;
        color: var(--pk-fg-muted);
        cursor: pointer;
        opacity: 0;
        transition: opacity 0.15s, color 0.15s, background 0.15s;
    }
    .tff-test-callme-change svg { width: 14px; height: 14px; }
    @media (hover: hover) {
        .tff-test-callme-display-wrap:hover .tff-test-callme-change,
        .tff-test-callme-change:focus-visible {
            opacity: 1;
        }
    }
    @media (hover: hover) {
        .tff-test-callme-change:hover {
            color: var(--pk-fg);
            background: rgba(255,255,255,0.06);
        }
    }
    .tff-test-callme-change:focus-visible {
        outline: 2px solid rgba(124,58,237,0.55);
        outline-offset: 1px;
    }
    .tff-test-callme-change[hidden] { display: none; }

    /* Touch devices have no hover — leave the icon permanently visible
       at reduced opacity so the affordance is still discoverable. */
    @media (hover: none) {
        .tff-test-callme-change { opacity: 0.55; }
    }

    .tff-test-status {
        font-size: 12.5px;
        line-height: 1.5;
        color: var(--pk-fg-muted);
        min-height: 18px;
        margin-top: -2px;
    }
    .tff-test-status.is-success { color: #34d399; }
    .tff-test-status.is-error { color: #FCA5A5; }

    /* ─────────────────────────────────────────────────────────
       CALLING VIEW — after the user taps "Call me" we flip to a
       dedicated screen showing the ringing state. Three concentric
       ripples pulse out from a phone icon; below it, a state label
       (placing / ringing / connected / ended) and a purple-tinted
       "Try asking" hints card so the user knows what to try the
       moment they pick up. Hangup button at the bottom returns to
       the test view. Realtime call events from the phone system
       drive the state transitions (wired in JS).
       ───────────────────────────────────────────────────────── */
    .tff-calling {
        display: flex; flex-direction: column; align-items: center;
        gap: 16px;
        padding: 4px 0 4px;
    }
    .tff-calling-to {
        margin: 0;
        font-size: 11px;
        color: var(--pk-fg-muted);
        text-transform: uppercase;
        letter-spacing: 0.16em;
        font-weight: 700;
    }
    .tff-calling-phone {
        font-family: 'JetBrains Mono', ui-monospace, monospace;
        font-size: 26px;
        font-weight: 700;
        color: var(--pk-fg, #fff);
        letter-spacing: 0.01em;
        font-variant-numeric: tabular-nums;
    }

    /* Animated ringing indicator. Three expanding circles layered
       behind a solid phone icon. When the call connects, ripples
       stop and the icon core brightens. */
    .tff-calling-indicator {
        position: relative;
        width: 132px; height: 132px;
        display: flex; align-items: center; justify-content: center;
        margin: 4px 0;
    }
    .tff-calling-ripple {
        position: absolute;
        inset: 0;
        border-radius: 999px;
        border: 2px solid rgba(52, 211, 153, 0.42);
        opacity: 0;
        animation: tff-calling-pulse 2.4s cubic-bezier(0.22, 1, 0.36, 1) infinite;
    }
    .tff-calling-ripple:nth-child(2) { animation-delay: 0.65s; }
    .tff-calling-ripple:nth-child(3) { animation-delay: 1.3s; }
    @keyframes tff-calling-pulse {
        0%   { transform: scale(0.5);  opacity: 0; }
        12%  { opacity: 0.7; }
        100% { transform: scale(1.7);  opacity: 0; }
    }
    @media (prefers-reduced-motion: reduce) {
        .tff-calling-ripple { animation: none; opacity: 0.35; transform: scale(1); }
    }
    .tff-calling-icon {
        position: relative;
        z-index: 1;
        width: 60px; height: 60px;
        display: inline-flex; align-items: center; justify-content: center;
        background: rgba(16, 185, 129, 0.18);
        border: 1px solid rgba(16, 185, 129, 0.48);
        border-radius: 999px;
        color: #34d399;
        box-shadow: 0 0 32px rgba(16,185,129,0.28);
        transition: background 0.3s, border-color 0.3s, color 0.3s, box-shadow 0.3s;
    }
    .tff-calling-icon svg { width: 24px; height: 24px; }

    /* Connected state — ripples halt, icon glows brighter green. */
    .tff-calling-indicator[data-state="connected"] .tff-calling-ripple {
        animation: none;
        opacity: 0;
    }
    .tff-calling-indicator[data-state="connected"] .tff-calling-icon {
        background: rgba(16, 185, 129, 0.32);
        border-color: rgba(16, 185, 129, 0.72);
        color: #a7f3d0;
        box-shadow: 0 0 44px rgba(16, 185, 129, 0.55);
    }
    /* Ended/error state — ripples halt, icon shifts to muted red. */
    .tff-calling-indicator[data-state="ended"] .tff-calling-ripple,
    .tff-calling-indicator[data-state="failed"] .tff-calling-ripple {
        animation: none;
        opacity: 0;
    }
    .tff-calling-indicator[data-state="ended"] .tff-calling-icon,
    .tff-calling-indicator[data-state="failed"] .tff-calling-icon {
        background: rgba(239, 68, 68, 0.12);
        border-color: rgba(239, 68, 68, 0.45);
        color: #fca5a5;
        box-shadow: none;
    }

    .tff-calling-status {
        margin: 0;
        font-size: 14px;
        line-height: 1.45;
        color: var(--pk-fg-muted);
        text-align: center;
        min-height: 20px;
    }
    .tff-calling-status.is-success { color: #34d399; }
    .tff-calling-status.is-error   { color: #fca5a5; }

    /* On `connected`, keep the full preamble visible — the hints
       card is the reference for *what* to ask, and the phone number
       context reinforces "this is the live call on your real phone".
       Only the CTA changes on connected: it reveals below the status
       line (see `.tff-claim-cta`). */

    /* "Claim your agent" CTA — revealed on the calling view only
       once the call reaches `connected` state. Reuses .tff-primary
       shape/color so it reads as the same kind of "submit / move
       forward" action as every other primary in the modal; the
       only additions here are the auto-sized width (inline pill
       rather than full-bleed) and a subtle enter animation so the
       reveal has presence. */
    .tff-claim-cta {
        margin-top: 18px;
        padding: 13px 20px;
        background: var(--pk-accent, #7c3aed);
        color: var(--pk-accent-fg, #fff);
        border: none;
        border-radius: 12px;
        font: inherit; font-size: 15px; font-weight: 600;
        letter-spacing: -0.005em;
        cursor: pointer;
        display: inline-flex; align-items: center; justify-content: center; gap: 8px;
        transition: background 0.2s, transform 0.2s;
        animation: tff-claim-cta-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    @media (hover: hover) {
        .tff-claim-cta:hover {
            background: var(--pk-accent-hover, #6D28D9);
            transform: translateY(-1px);
        }
    }
    .tff-claim-cta svg { width: 16px; height: 16px; }
    @keyframes tff-claim-cta-in {
        0%   { opacity: 0; transform: translateY(8px); }
        100% { opacity: 1; transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
        .tff-claim-cta { animation: none; }
    }

    /* ──────────────────────────────────────────────────────────
       CLAIM VIEW — post-test-call celebration + guided next steps.
       Four equal-weight cards (Dashboard / Forward / Feedback /
       Plan) in a 2×2 grid; no primary CTA (D01). Close button is
       hidden across the entire claim flow (claim + forward +
       feedback + plan sub-views per D04) so every exit is a
       productive action. Kicker keeps the modal's default amber +
       red-dot treatment so each view reads as part of the same
       flow, not a separate celebration page.
       ────────────────────────────────────────────────────────── */
    .tff[data-view="claim"],
    .tff[data-view="forward"],
    .tff[data-view="feedback"],
    .tff[data-view="plan"] { max-width: 640px; }
    .tff[data-view="claim"] .tff-close,
    .tff[data-view="forward"] .tff-close,
    .tff[data-view="feedback"] .tff-close,
    .tff[data-view="plan"] .tff-close { display: none; }

    /* Agent number callout — green-tinted container wrapping the label,
       number, copy button, and a concierge-swap footnote. Mirrors the
       `.tff-test-context` callout pattern but uses the emerald palette
       (the same tokens the `.tff-test-phone-display` and
       `.tff-test-copy-btn` already use) so it reads as a celebratory
       "your number is live" block rather than a neutral info note. The
       footnote leads with the offer ("Prefer a local or toll-free
       number?") rather than framing the assigned number as a demo —
       many users keep the number they're given, so we avoid any copy
       that implies it's a throwaway. The swap is handled by us on
       request, not a self-serve control, so the CTA is "just ask". */
    .tff-claim-phone-callout {
        background: rgba(16, 185, 129, 0.06);
        border: 1px solid rgba(16, 185, 129, 0.22);
        border-radius: 14px;
        padding: 16px 18px 18px;
        margin: 18px 0 4px;
        display: flex;
        flex-direction: column;
        gap: 12px;
    }
    /* Inside the callout, the original phone block drops its outer
       margin and top-level gap so the callout's padding controls the
       frame. Alignment stays centered so the number remains the
       visual anchor. */
    .tff-claim-phone-callout .tff-claim-phone-block {
        margin: 0;
    }
    .tff-claim-phone-block {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        margin: 18px 0 4px;
    }
    .tff-claim-phone-label {
        margin: 0;
        font-size: 11px;
        color: var(--pk-fg-muted);
        text-transform: uppercase;
        letter-spacing: 0.16em;
        font-weight: 700;
    }
    /* Footnote under the number — small, muted, centered. Lives inside
       the green callout so it visually belongs to the number block
       (not the cards below). Line-height matches the test-context
       points so the two callout styles feel like siblings. */
    .tff-claim-phone-note {
        margin: 0;
        padding-top: 12px;
        border-top: 1px solid rgba(16, 185, 129, 0.16);
        text-align: center;
        font-size: 12.5px;
        line-height: 1.5;
        color: rgba(255, 255, 255, 0.72);
    }
    .tff-claim-phone-note strong {
        color: #86efac;
        font-weight: 600;
    }

    /* Claim 4-card grid: four equal-weight tiles in a 2×2 layout at
       desktop width, stacking vertically on narrow screens (D02).
       Reuses the .tff-industry-tile palette (elevated bg, subtle
       border, hover lifts the border) so they read as the same
       visual vocabulary as the industry picker — just in a vertical
       layout with a description line instead of a single label.
       Dashboard, Forward, Feedback, and Plan must stay visually
       equal — no card may dominate (D01). */
    .tff-claim-secondary {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
        margin-top: 4px;
    }
    .tff-claim-card {
        appearance: none;
        -webkit-appearance: none;
        text-align: left;
        font: inherit;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
        padding: 14px 14px 16px;
        color: var(--pk-fg);
        cursor: pointer;
        display: flex;
        flex-direction: column;
        gap: 8px;
        transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;
        position: relative;
    }
    @media (hover: hover) {
        .tff-claim-card:hover {
            border-color: rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.02);
        }
    }
    .tff-claim-card-icon {
        width: 22px; height: 22px;
        display: inline-flex; align-items: center; justify-content: center;
        color: var(--pk-fg-muted);
        transition: color 0.2s;
    }
    .tff-claim-card-icon svg { width: 20px; height: 20px; }
    @media (hover: hover) {
        .tff-claim-card:hover .tff-claim-card-icon { color: var(--pk-fg); }
    }
    .tff-claim-card-title {
        font-size: 14px;
        font-weight: 600;
        color: var(--pk-fg);
        letter-spacing: -0.005em;
        margin: 0;
    }
    .tff-claim-card-desc {
        font-size: 12.5px;
        line-height: 1.45;
        color: var(--pk-fg-muted);
        margin: 0;
    }
    /* Done-state treatment for cards whose action has a confirmable
       result (Forward = instructions viewed, Feedback = sent). The
       card adopts the modal's is-selected green palette (same tokens
       as .tff-industry-tile.is-selected). Dashboard and Plan never
       reach this state — they leave the modal (D13). */
    .tff-claim-card.is-done {
        border-color: rgba(16, 185, 129, 0.45);
        background: rgba(16, 185, 129, 0.05);
    }
    .tff-claim-card.is-done .tff-claim-card-icon { color: #34d399; }
    .tff-claim-card.is-done .tff-claim-card-title { color: #34d399; }

    /* Sub-view back link — sits at the bottom of forward/feedback/plan
       and is the only exit from those sub-views (D04). Mirrors the
       `.tff-back` "Enter a website instead" treatment used by other
       skip-confirm flows so the visual language stays consistent. */
    .tff-subview-back {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        margin: 18px auto 0;
        padding: 6px 10px;
        align-self: center;
        background: transparent;
        border: 0;
        color: var(--pk-fg-muted);
        font: inherit;
        font-size: 13px;
        font-weight: 500;
        cursor: pointer;
        transition: color 0.15s;
    }
    .tff-subview-back svg { width: 14px; height: 14px; flex-shrink: 0; }
    @media (hover: hover) {
        .tff-subview-back:hover { color: var(--pk-fg); }
    }

    /* Claim-flow sub-view bodies — flex columns so the back arrow
       stacks above the content. Matching the industry-stage layout
       so the visual rhythm is consistent across all modal pickers. */
    .tff[data-view="forward"] .tff-body,
    .tff[data-view="feedback"] .tff-body,
    .tff[data-view="plan"] .tff-body {
        display: flex;
        flex-direction: column;
    }
    /* Claim-flow sub-views drop the body divider — the sub-view has
       its own in-body controls (back arrow + picker/form), and a
       horizontal rule above them would read as decoration. */
    .tff[data-view="forward"] .tff-body::before,
    .tff[data-view="feedback"] .tff-body::before,
    .tff[data-view="plan"] .tff-body::before { display: none; }

    /* ── Forward sub-view ──────────────────────────────────────── */
    /* Carrier picker grid — 2-column at desktop width so each tile
       is wide enough for the label; stacks to 1 column on narrow
       screens alongside the rest of the claim flow. */
    .tff-forward-carriers {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
        margin-bottom: 16px;
    }
    .tff-forward-carrier {
        appearance: none;
        -webkit-appearance: none;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 8px;
        text-align: center;
        font: inherit;
        font-size: 14px;
        font-weight: 600;
        letter-spacing: -0.005em;
        padding: 14px 14px 12px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 10px;
        color: var(--pk-fg);
        cursor: pointer;
        transition: border-color 0.15s, background 0.15s, color 0.15s;
    }
    @media (hover: hover) {
        .tff-forward-carrier:hover {
            border-color: rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.02);
        }
    }
    /* Selection affordance is inverted: the picked carrier stays in its
       default state and the OTHERS dim out, so the user's focus falls
       naturally on the chosen row + the instructions panel below. No
       green border/bg on the selected tile (keeps the picker calm and
       matches the "reference, not action" framing of this sub-view). */
    .tff-forward-carriers:has(.tff-forward-carrier[aria-checked="true"]) .tff-forward-carrier:not([aria-checked="true"]) {
        opacity: 0.15;
    }
    @media (hover: hover) {
        .tff-forward-carriers:has(.tff-forward-carrier[aria-checked="true"]) .tff-forward-carrier:not([aria-checked="true"]):hover {
            opacity: 0.4;
        }
    }
    /* Logo wrapper — sized to match `/app/setup` provider tiles. The
       icon markup itself comes from EchoCarrierData.getProviderLogo()
       (40x40 native), so we cap to 32 for the smaller modal tile. */
    .tff-forward-carrier-icon {
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--pk-fg);
    }
    .tff-forward-carrier-icon img,
    .tff-forward-carrier-icon svg {
        max-width: 32px;
        max-height: 32px;
    }

    /* Instructions panel — renders the picked carrier's forwardAll
       code + step list. Only one carrier is visible at a time (D06);
       swapping carriers replaces the panel contents, it does not
       stack or accordion. */
    .tff-forward-instructions {
        display: flex;
        flex-direction: column;
        gap: 12px;
        padding: 16px 16px 18px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
    }
    .tff-forward-instructions[hidden] { display: none; }
    .tff-forward-code-label {
        margin: 0;
        font-size: 11px;
        color: var(--pk-fg-muted);
        text-transform: uppercase;
        letter-spacing: 0.16em;
        font-weight: 700;
    }
    .tff-forward-code {
        margin: 0;
        font-family: var(--pk-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
        font-size: 22px;
        font-weight: 700;
        color: #34d399;
        letter-spacing: -0.01em;
        word-break: break-all;
    }
    /* Click-to-copy variant of `.tff-forward-code` — same green-mono
       treatment, but rendered as a button with a copy icon and brief
       "Copied!" feedback (mirrors the `.tff-test-copy-btn` pattern). */
    .tff-forward-code-copy {
        appearance: none;
        -webkit-appearance: none;
        display: inline-flex;
        align-items: center;
        gap: 12px;
        margin: 0;
        padding: 10px 14px;
        background: rgba(16, 185, 129, 0.06);
        border: 1px solid rgba(16, 185, 129, 0.22);
        border-radius: 10px;
        color: #34d399;
        cursor: pointer;
        font: inherit;
        font-family: var(--pk-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
        font-size: 22px;
        font-weight: 700;
        letter-spacing: -0.01em;
        text-align: left;
        transition: background 0.15s, border-color 0.15s, color 0.15s;
        align-self: flex-start;
        max-width: 100%;
    }
    @media (hover: hover) {
        .tff-forward-code-copy:hover {
            background: rgba(16, 185, 129, 0.12);
            border-color: rgba(16, 185, 129, 0.4);
        }
    }
    .tff-forward-code-copy[data-copied="true"] {
        background: rgba(16, 185, 129, 0.18);
        border-color: rgba(16, 185, 129, 0.55);
        color: #86efac;
    }
    .tff-forward-code-copy-text {
        word-break: break-all;
        flex: 1 1 auto;
    }
    .tff-forward-code-copy-icon {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        width: 16px;
        height: 16px;
    }
    .tff-forward-code-copy-icon svg {
        width: 16px;
        height: 16px;
    }
    .tff-forward-code-copy-icon-default { display: inline-block; }
    .tff-forward-code-copy-icon-done { display: none; }
    .tff-forward-code-copy[data-copied="true"] .tff-forward-code-copy-icon-default { display: none; }
    .tff-forward-code-copy[data-copied="true"] .tff-forward-code-copy-icon-done { display: inline-block; }
    .tff-forward-steps {
        margin: 4px 0 0;
        padding: 0 0 0 20px;
        font-size: 13.5px;
        line-height: 1.5;
        color: var(--pk-fg);
    }
    .tff-forward-steps li + li { margin-top: 6px; }
    .tff-forward-other {
        margin: 0;
        font-size: 13.5px;
        line-height: 1.5;
        color: var(--pk-fg);
    }
    .tff-forward-other a {
        color: #34d399;
        text-decoration: underline;
        text-underline-offset: 2px;
    }
    @media (hover: hover) {
        .tff-forward-other a:hover { color: #6ee7b7; }
    }

    /* Enable / Disable split — mirrors the `/app/setup` Step 4 layout:
       one section for "turn it on" (forwardAll code + steps) and another
       for "turn it off" (one or more turnOff {label, code} entries from
       EchoCarrierData). The divider + labeled sections make it obvious
       which code does what, so users don't accidentally copy the wrong
       one when they come back to disable forwarding. */
    .tff-forward-section {
        display: flex;
        flex-direction: column;
        gap: 12px;
    }
    .tff-forward-section-title {
        margin: 0;
        font-size: 13px;
        font-weight: 700;
        color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    /* Muted treatment for the disable section so the primary "turn it
       on" block reads as the main action and disable sits as reference. */
    .tff-forward-section-title[data-kind="disable"] {
        color: rgba(255,255,255,0.7);
    }
    .tff-forward-divider {
        margin: 2px 0;
        height: 1px;
        border: 0;
        background: rgba(255,255,255,0.08);
    }
    /* 2-column grid so carriers with multiple disable codes (T-Mobile
       has 4) don't become a tall vertical stack. Single-code carriers
       (Verizon: *73) leave the right column empty — that's fine; the
       layout reads as a compact reference table either way. Stacks
       back to one column at the mobile breakpoint below. */
    .tff-forward-turnoff-items {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 14px;
        row-gap: 12px;
    }
    .tff-forward-turnoff-item {
        display: flex;
        flex-direction: column;
        gap: 6px;
    }
    .tff-forward-turnoff-label {
        margin: 0;
        font-size: 12.5px;
        line-height: 1.4;
        color: var(--pk-fg-muted);
        font-weight: 500;
    }
    /* Compact size for disable codes — carriers like T-Mobile expose up
       to four turnOff codes, and stacking full-size 22px buttons would
       overwhelm the panel. 16px reads as secondary without losing the
       green mono-code affordance. */
    .tff-forward-code-copy.is-compact {
        font-size: 16px;
        padding: 8px 12px;
        gap: 10px;
    }
    .tff-forward-code-copy.is-compact .tff-forward-code-copy-icon,
    .tff-forward-code-copy.is-compact .tff-forward-code-copy-icon svg {
        width: 14px;
        height: 14px;
    }

    /* ── Feedback sub-view ─────────────────────────────────────── */
    .tff-feedback-form {
        display: flex;
        flex-direction: column;
        gap: 18px;
    }
    .tff-feedback-rating {
        border: 0;
        margin: 0;
        padding: 0;
        display: flex;
        flex-direction: column;
        gap: 8px;
    }
    .tff-feedback-label {
        font-size: 13px;
        font-weight: 600;
        color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    .tff-feedback-stars {
        display: inline-flex;
        gap: 6px;
    }
    .tff-feedback-star {
        appearance: none;
        -webkit-appearance: none;
        background: transparent;
        border: 0;
        padding: 4px;
        color: rgba(255,255,255,0.22);
        cursor: pointer;
        transition: color 0.15s, transform 0.15s;
        border-radius: 6px;
    }
    .tff-feedback-star svg { width: 28px; height: 28px; display: block; }
    @media (hover: hover) {
        .tff-feedback-star:hover { color: rgba(251, 191, 36, 0.7); }
    }
    .tff-feedback-star.is-active { color: #fbbf24; }
    .tff-feedback-star:focus-visible {
        outline: 2px solid rgba(124, 58, 237, 0.55);
        outline-offset: 2px;
    }
    .tff-feedback-field {
        display: flex;
        flex-direction: column;
        gap: 8px;
    }
    .tff-feedback-textarea {
        font: inherit;
        font-size: 14px;
        line-height: 1.5;
        padding: 12px 14px;
        background: var(--pk-bg-elevated, #18181b);
        color: var(--pk-fg);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.08));
        border-radius: 10px;
        resize: vertical;
        min-height: 96px;
    }
    .tff-feedback-textarea:focus {
        outline: none;
        border-color: rgba(124, 58, 237, 0.55);
    }
    /* Simple inline toast for the feedback success state. Lives in
       the same body as the form so we don't need the V2Toast runtime
       in the harness — disappears after ~1.8s and we return to the
       claim view. */
    .tff-feedback-toast {
        position: absolute;
        left: 50%;
        bottom: 20px;
        transform: translateX(-50%);
        padding: 10px 16px;
        background: rgba(16, 185, 129, 0.14);
        border: 1px solid rgba(16, 185, 129, 0.45);
        color: #34d399;
        font-size: 13px;
        font-weight: 600;
        border-radius: 10px;
        pointer-events: none;
        opacity: 0;
        transition: opacity 0.2s, transform 0.2s;
        z-index: 5;
    }
    .tff-feedback-toast[data-show="true"] {
        opacity: 1;
        transform: translateX(-50%) translateY(-4px);
    }

    /* ── Plan sub-view ─────────────────────────────────────────── */
    .tff-plan-cards {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
        /* Give the first row enough headroom so the "MOST POPULAR"
           badge (positioned at `top: -9px` on `.tff-plan-card`) isn't
           clipped by the scrollable `.tff-body`. */
        padding-top: 12px;
    }
    .tff-plan-card {
        position: relative;
        display: flex;
        flex-direction: column;
        gap: 12px;
        padding: 18px 16px 16px;
        background: var(--pk-bg-elevated, #18181b);
        border: 1px solid var(--pk-border-muted, rgba(255,255,255,0.06));
        border-radius: 12px;
        color: var(--pk-fg);
    }
    .tff-plan-card.is-recommended {
        border-color: rgba(124, 58, 237, 0.55);
        box-shadow: 0 0 0 1px rgba(124, 58, 237, 0.18);
    }
    .tff-plan-card-badge {
        position: absolute;
        top: -9px;
        left: 16px;
        padding: 2px 8px;
        background: var(--pk-accent, #7c3aed);
        color: var(--pk-accent-fg, #fff);
        font-size: 10.5px;
        font-weight: 700;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        border-radius: 999px;
    }
    .tff-plan-card-head {
        display: flex;
        flex-direction: column;
        gap: 4px;
    }
    .tff-plan-card-name {
        margin: 0;
        font-size: 14px;
        font-weight: 700;
        color: var(--pk-fg);
        letter-spacing: -0.005em;
    }
    .tff-plan-card-price {
        margin: 0;
        display: inline-flex;
        align-items: baseline;
        gap: 2px;
    }
    .tff-plan-card-price-amount {
        font-size: 24px;
        font-weight: 800;
        color: var(--pk-fg);
        letter-spacing: -0.015em;
    }
    .tff-plan-card-price-period {
        font-size: 12px;
        color: var(--pk-fg-muted);
    }
    /* Per-call overage rate — mirrors `.vp-plan-overage` from the
       vertical landing pages (green dollar amount + muted descriptor)
       but without the divider line that the larger landing-page cards
       use to separate price from features. */
    .tff-plan-card-overage {
        margin: 0;
        font-size: 12px;
        color: var(--pk-fg-muted);
    }
    .tff-plan-card-overage-price {
        color: #34d399;
        font-weight: 600;
    }
    .tff-plan-card-features {
        margin: 0;
        padding: 0;
        list-style: none;
        display: flex;
        flex-direction: column;
        gap: 6px;
        font-size: 12.5px;
        line-height: 1.45;
        color: var(--pk-fg-muted);
    }
    .tff-plan-card-features li {
        position: relative;
        padding-left: 16px;
    }
    .tff-plan-card-features li::before {
        content: '';
        position: absolute;
        top: 6px;
        left: 0;
        width: 8px;
        height: 8px;
        border-radius: 999px;
        background: rgba(16, 185, 129, 0.6);
    }
    .tff-plan-card-cta {
        margin-top: auto;
        width: 100%;
    }
    /* Loading / error / empty states for the plan sub-view. The
       container is `aria-live="polite"` so a screen reader picks up
       the status swap once plans resolve. */
    .tff-plan-loading,
    .tff-plan-error {
        grid-column: 1 / -1;
        margin: 0;
        padding: 16px 12px;
        text-align: center;
        font-size: 13px;
        color: var(--pk-fg-muted);
    }
    .tff-plan-error { color: var(--pk-danger, #ef4444); }

    /* Mobile */
    @media (max-width: 640px) {
        .tft-intro, .tft-variant { padding-left: 20px; padding-right: 20px; }
        .tff-head { padding: 28px 22px 22px; }
        .tff-body { padding: 0 22px 22px; }
        .tff-body::before { margin-bottom: 20px; }
        .tff-head .aud9-title { font-size: 22px; }
        .tff-phone-input { font-size: 16px; padding: 14px 14px 14px 40px; }
        .tff-input { font-size: 16px; padding: 12px 12px 12px 40px; }
        .tff-voices-grid { grid-template-columns: 1fr; }
        .tff[data-view="voices"],
        .tff[data-view="test"] { max-width: 480px; }
        .tff[data-view="claim"],
        .tff[data-view="forward"],
        .tff[data-view="feedback"],
        .tff[data-view="plan"] { max-width: 480px; }
        .tff-claim-secondary { grid-template-columns: 1fr; }
        .tff-forward-carriers { grid-template-columns: 1fr; }
        .tff-forward-turnoff-items { grid-template-columns: 1fr; }
        .tff-plan-cards { grid-template-columns: 1fr; }
        .tff-test-row { flex-direction: column; }
        .tff-or-vertical { flex-direction: row; align-self: auto; gap: 12px; }
        .tff-or-vertical::before, .tff-or-vertical::after {
            width: auto; height: 1px; min-height: 0;
        }
        /* Phone display + callme input share identical typography (mono
           24px bold green) at all breakpoints — no mobile size override. */
    }
