/* components.css
   Standalone UI components consolidated from style.css, index.html, app.js
   Caselet aside panel, lead capture, continuation/approach/diagnosis blocks,
   session indicator, domain cards, intent prompts */

/* --- Caselet aside panel (from style.css) --- */
/* ─── CASELET PANEL (right column) ─── */

.response-aside {
    position: sticky;
    top: 90px;
    /* The column pins as ONE piece, so a column taller than the viewport pins
       its own bottom off-screen — which is what buried the handwritten note
       under the shelf and made it a thing you had to scroll for. Capping the
       column keeps the whole invitation (our card → their card → the note) in
       view; the card below gives up the height rather than the note.
       `display: flex` is set inline by app.js, which also hides the column, so
       it cannot be declared here without fighting that inline value. */
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 108px);
}

/* "Below the waterline" proof card — whitish glass, the same overlay as the
   About drawer's CTA band (.about-cta-band): flat translucent white + light
   blur, no saturation boost, so it stays clean over the gradient. Keeps the
   brand top-edge, dotted waterline, and green motion. */
.caselet-panel-inner {
    position: relative;
    /* A column inside the pinned column: the header, the waterline and the
       proof are fixed, and only the body gives way when the viewport is short. */
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius);
    overflow: hidden;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow:
        0 16px 42px rgba(0, 0, 0, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
    animation: slideInRight 0.4s ease forwards;
}

/* Bright brand top-edge — same accent language as the contact card strip. */
.caselet-panel-inner::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--purple-light), var(--teal-light));
    z-index: 2;
}

/* The waterline — a refined dotted luminous divider (rail-style) between the
   surface (domain + engagement count) and the depth (the surfaced proof). */
.caselet-waterline {
    height: 0;
    margin: 0 22px 11px;
    border-top: 1px dotted rgba(255, 255, 255, 0.34);
}

@keyframes slideInRight {
    from {
        opacity: 0;
        transform: translateX(16px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* Header band — the domain identity. Sits as its own row with the dotted
   waterline directly beneath it, so the firm reads as a clear header (see the
   reference: firm → divider → engagement subtitle → proof). */
/* Eyebrow — names what the card is (echoes the mobile proof button), so the
   firm name reads as the subject rather than the headline. Kept a quiet muted
   grey so it labels without competing; only the small dot carries a live tint. */
.caselet-panel-eyebrow {
    margin: 14px 22px 4px;
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 0.95rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: white;
}

.caselet-panel-eyebrow-dot {
    flex: none;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--teal-light);
    box-shadow: 0 0 6px rgba(20, 184, 166, 0.9);
    animation: dotBlink 2s ease infinite;
}

.caselet-panel-header {
    padding: 7px 22px 12px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.caselet-panel-tag {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: none;
    color: #f2ecff;
    text-shadow: 0 1px 2px rgba(15, 10, 30, 0.35);
}

.caselet-panel-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--teal-light);
    margin-left: auto;
    animation: dotBlink 2s ease infinite;
}

@keyframes dotBlink {

    0%,
    100% {
        opacity: 1;
    }

    50% {
        opacity: 0.3;
    }
}

.caselet-panel-body {
    padding: 12px 22px 14px;
    /* Yields first, and only when it has to: on a tall enough window this
       scrolls nothing and looks exactly as it always did. */
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    /* A line of prose cut clean in half by the scroll edge reads as a rendering
       fault rather than as more text below. The fade is exactly the depth of
       the bottom padding, so it lands on empty space both when the card fits
       and when it is scrolled to the end — it only ever softens a real cut. */
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent);
}

/* Nothing follows it, so the body carries the card's bottom padding itself. */
.caselet-panel-body:last-child {
    padding-bottom: 22px;
}

/* Surfaced numbers carry the emphasis through colour alone (bright neon --iws
   purple on the dark teal/blue panel) — no glow/shadow, no reveal pulse. */

.caselet-panel-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--white);
    margin-bottom: 10px;
    line-height: 1.4;
    letter-spacing: -0.01em;
}

/* The pair reads as one short paragraph, so nothing sits between the two lines
   — no rule, no gap, no label. The join is the word that points back. */
.caselet-panel-pair {
    margin-top: 14px;
    border-top: 1px solid rgba(255,255,255,0.14);
    padding-top: 14px;
}
.caselet-panel-line {
    font-size: 0.86rem;
    color: rgba(255,255,255,0.76);
    line-height: 1.7;
    margin: 0;
}
.caselet-panel-solution {
    color: rgba(255,255,255,0.92);
}
.caselet-panel-pain {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.45);
    font-style: italic;
    margin-bottom: 14px;
    line-height: 1.5;
}

.caselet-panel-summary {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.75);
    line-height: 1.7;
    margin-bottom: 16px;
}

.caselet-panel-signals {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.caselet-panel-signals li {
    font-size: 12px;
    color: var(--pux);
    padding-left: 16px;
    position: relative;
    line-height: 1.5;
}

.caselet-panel-signals li::before {
    content: '→';
    position: absolute;
    left: 0;
    color: var(--teal);
    font-size: 11px;
}


/* --- Caselet aside panel — V2 credible rendering (from index.html inline <style>) --- */
/* The surfaced proof: crisp white prose, with highlight() spans supplying the
   colour pops (green motion, purple stats, teal vocabulary). */
.caselet-panel-number {
    font-size: 1.05rem;
    font-weight: 700;
    color: #ffffff;
    line-height: 1.5;
    letter-spacing: -0.01em;
    margin-bottom: 4px;
}
.caselet-panel-pain {
    font-size: 0.78rem;
    color: rgba(255,255,255,0.6);
    font-style: italic;
    line-height: 1.5;
    margin-bottom: 8px;
}
/* The single line of setup under the number. Unlabelled and quiet — the number
   above it is the claim, this only says whose situation it was. */
.caselet-panel-primer {
    font-size: 0.86rem;
    color: rgba(255,255,255,0.76);
    line-height: 1.7;
    margin-top: 14px;
    border-top: 1px solid rgba(255,255,255,0.14);
    padding-top: 14px;
}
.caselet-panel-contribution {
    font-size: 0.9rem;
    color: rgba(255,255,255,0.74);
    line-height: 1.72;
    margin-top: 16px;
    border-top: 1px solid rgba(255,255,255,0.14);
    padding-top: 16px;
}
.caselet-panel-domain {
    font-size: 0.72rem;
    color: #e0d3ff;
    margin-top: 8px;
    font-style: italic;
}
/* Deeper-cut caselet — the progressive-disclosure layers (1 = how it moved,
   2 = why it fits) carry a prose paragraph, not a crisp stat. Rendering that
   paragraph in the bold proof-number style produced an unstructured wall of
   text. Instead give it the same header hierarchy as a stat card: a teal
   eyebrow label + readable supporting prose, so every caselet reads structured. */
.caselet-panel-deepcut .caselet-panel-cut-label {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #7ff2dc;
    text-shadow: 0 1px 2px rgba(10, 25, 22, 0.4);
    margin-bottom: 10px;
}
.caselet-panel-deepcut .caselet-panel-cut-prose {
    font-size: 0.92rem;
    color: rgba(255, 255, 255, 0.86);
    line-height: 1.72;
}
/* engagement count — a muted subtitle just under the header divider: the
   evidence surfaced from the depths, secondary to the firm name above it. */
.caselet-eng-wrap {
    padding: 0 22px 2px;
}
.caselet-eng-count {
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.6);
    text-shadow: 0 1px 2px rgba(15, 10, 30, 0.3);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Caselet highlight system: bright amber. Numbers and before→after movement
   read in a vivid orange-amber that pops off the purple panel — no yellow.
   A soft same-hue glow lifts the digits so the proof numbers own the eye. */
.caselet-panel-inner .tm-stat,
.caselet-story-content .tm-stat,
.block-proof-wall .tm-stat,
.caselet-panel-inner .tm-move,
.caselet-story-content .tm-move,
.block-proof-wall .tm-move {
    color: #ffa023;
    font-weight: 800;
    text-shadow: 0 0 14px rgba(255, 145, 20, 0.45);
}

/* The brand is the one word in the solution beat that says who did it, so it
   takes the lit blue the proof surfaces reserve for glass over purple→teal —
   legible on both halves of the gradient and clear of the orange stats. */
.caselet-panel-inner .tm-brand,
.caselet-story-content .tm-brand,
.block-proof-wall .tm-brand {
    color: var(--sky-light);
    font-weight: 700;
    text-shadow: 0 0 14px rgba(56, 189, 248, 0.35);
}

/* Vocabulary carries no accent inside the caselet — proof numbers only, so the
   prose stays plain white and the green numbers own the eye. */
.caselet-panel-inner .tm-term,
.caselet-story-content .tm-term,
.block-proof-wall .tm-term {
    color: #fff;
    font-weight: 600;
    text-shadow: none;
}

/* --- Caselet "See the full story" trigger --- */
/* Outside the scrolling body on purpose. The pinned column caps our card's
   height on a short window, and the way into the full story is the one thing on
   it that must never end up below a scroll — a proof card whose proof you have
   to find is a card that failed. The body loses the bottom padding this row now
   carries, so a card that fits still looks exactly as it did. */
.caselet-panel-foot {
    flex: 0 0 auto;
    padding: 0 22px 22px;
}

.caselet-panel-more {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-top: 16px;
    padding: 8px 16px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 999px;
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--white);
    cursor: pointer;
    transition: color var(--transition), gap var(--transition),
        background var(--transition), border-color var(--transition);
}
.caselet-panel-more:hover {
    color: var(--white);
    background: rgba(20, 184, 166, 0.18);
    border-color: rgba(45, 212, 191, 0.6);
    gap: 11px;
}

/* --- Caselet "full story" modal --- */
.caselet-story-overlay {
    position: fixed;
    inset: 0;
    z-index: 260;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    background: rgba(5, 7, 18, 0.62);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    transition: opacity 0.28s ease, visibility 0.28s ease;
}
.caselet-story-overlay.open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}
.caselet-story-panel {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(720px, calc(100vw - 34px));
    max-height: calc(100vh - 48px);
    overflow: auto;
    border-radius: 20px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    /* Branded surface — matches the page's purple→teal gradient (slightly
       deeper for white-text contrast) instead of the old dark-navy modal. */
    background:
        radial-gradient(circle at 12% 0%, rgba(159, 103, 245, 0.50), transparent 46%),
        radial-gradient(circle at 100% 100%, rgba(20, 184, 166, 0.40), transparent 46%),
        linear-gradient(150deg, #6d28d9 0%, #0f766e 100%);
    box-shadow: 0 34px 90px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.14);
    transform: translate(-50%, -50%) scale(0.94);
    transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.32) transparent;
}
.caselet-story-overlay.open .caselet-story-panel {
    transform: translate(-50%, -50%) scale(1);
}
.caselet-story-panel::-webkit-scrollbar {
    width: 10px;
}
.caselet-story-panel::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.28);
    border-radius: 99px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.caselet-story-close {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 2;
    width: 36px;
    height: 36px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 99px;
    font-size: 22px;
    line-height: 1;
    color: var(--white);
    background: rgba(255, 255, 255, 0.14);
    cursor: pointer;
    transition: background var(--transition), transform var(--transition);
}
.caselet-story-close:hover {
    background: rgba(255, 255, 255, 0.16);
    transform: rotate(90deg);
}
.caselet-story-header {
    padding: 18px 22px 12px;
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
}
.caselet-story-header .caselet-panel-tag {
    font-size: 11px;
    padding-right: 44px;
}
.caselet-story-eng {
    padding: 10px 22px 0;
    font-size: 0.7rem;
    color: rgba(236, 220, 255, 0.92);
    text-shadow: 0 1px 2px rgba(15, 10, 30, 0.4);
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}
.caselet-story-body {
    padding: 18px 22px 24px;
}
.caselet-story-section {
    margin-top: 22px;
}
.caselet-story-section:first-child {
    margin-top: 6px;
}
.caselet-story-section + .caselet-story-section {
    padding-top: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.caselet-story-label {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #7ff2dc;
    text-shadow: 0 1px 2px rgba(10, 25, 22, 0.4);
    margin-bottom: 10px;
}
/* The four beats, two-up. The DOM order is the reading order in both layouts,
   so problem → solution → achievement → unusual survives the grid — `unusual`
   is derived from the three above it and can only ever read last.
   `solution` runs ~2.5x the other beats, so it sets the height of its row;
   giving each beat a card of its own makes that read as deliberate. */
/* One beat per row. At the panel's width a full row runs long, but it is what
   lets `solution` fold from six lines to three, which is where the height the
   two-up layout was spending actually went. */
.caselet-story-beats {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    margin-top: 6px;
}
.caselet-story-beat {
    padding: 14px 16px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.07);
}

.caselet-story-prose {
    font-size: 0.78rem;
    line-height: 1.7;
    color: rgba(255, 255, 255, 0.9);
    /* Never a blanket transform — it would upper-case the whole beat. Only the
       opening letter is touched, and only in the grid, by the rule below. */
    text-transform: none;
}

/* The beats are authored lower-case so they read on from their own label. In
   the grid that label sits in its own block inside a bordered card, so the
   read-on is gone and the lower-case only looks like a fault. Lift the first
   letter here, at render, rather than rewriting 200 authored beats. */
.caselet-story-beat .caselet-story-prose p:first-child::first-letter {
    text-transform: uppercase;
}
.caselet-story-section.caselet-story-changed,
.caselet-story-section.caselet-story-numbers {
    padding: 14px 16px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.07);
    margin-bottom: 12px;
}
/* Every block is already its own card, so the rule that divides bare stacked
   sections would draw a second line inside one. */
.caselet-story-body .caselet-story-section + .caselet-story-section {
    padding-top: 14px;
    border-top: none;
}
/* Before and After are a sequence, not a list of features, so each run is
   labelled and indented under the move it belongs to. */
.caselet-story-steps {
    margin-top: 12px;
}
.caselet-story-steps-label {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.52);
    margin-bottom: 6px;
}
/* The part that is not obvious from the three above it, so it reads after them
   and apart from them. */
.caselet-story-unusual {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
    font-style: italic;
    color: rgba(255, 255, 255, 0.82);
}
/* The lesson is the one block that is a claim rather than a retelling, so it
   sits in its own card at the foot of the story instead of reading as a fifth
   beat. */
.caselet-story-section.caselet-story-lesson {
    padding: 16px 18px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.10);
}
.caselet-story-lesson .caselet-story-prose {
    font-weight: 600;
    color: #ffffff;
    font-size: 0.92rem;
    line-height: 1.6;
}
.caselet-story-prose p {
    margin: 0 0 12px;
}
.caselet-story-prose p:last-child {
    margin-bottom: 0;
}
.caselet-story-points {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 12px 0;
    padding: 0;
}
.caselet-story-points:last-child {
    margin-bottom: 0;
}
.caselet-story-points li {
    position: relative;
    padding-left: 18px;
    line-height: 1.65;
    /* Without this the list inherits the panel's 16px and outsizes the prose
       it sits under. */
    font-size: 0.78rem;
}
.caselet-story-points li::before {
    content: '▸';
    position: absolute;
    left: 2px;
    top: 0;
    color: var(--iws);
}

.caselet-story-numbers .caselet-story-points li {
    padding: 9px 12px;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.18);
    line-height: 1.55;
}
.caselet-story-numbers .caselet-story-points li::before {
    content: none;
}

/* --- Closing invitation --- */
/* The offer card from the response flow (.block-cta.leads-close in blocks.css)
   spoken at modal scale: brand wash, hairline, teal spine down the left edge.
   Same job in both places — the canvas offering the next step rather than
   continuing the answer — so it is that card, not a second invention. Mirrored
   rather than shared because .leads-close means something specific over there
   (mountClose sets it only when a follow-up trails the offer).

   The spine is also what earns the small footprint: the fill only has to tint,
   not fence, so the card can be the ask plus the button over the tightest
   padding that still reads as a surface. Here the two share a ROW and the ask
   is uncapped, so the whole close costs about the height of the ask — the
   response-flow card stacks them because its column is narrower than this
   panel. Below ~210px of ask the row wraps back to that stack on its own. */
.caselet-story-invite {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 18px;
    margin-top: 20px;
    padding: 14px 16px;
    background: linear-gradient(135deg,
            rgba(124, 58, 237, 0.18) 0%,
            rgba(13, 148, 136, 0.20) 100%);
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-left: 3px solid var(--teal-light);
    border-radius: var(--radius-sm);
}

.caselet-story-invite-line {
    flex: 1 1 210px;
    margin: 0;
    font-size: 0.84rem;
    /* Tightened from 1.55: the generous body-prose leading read as loose on a
       one-or-two-line prompt; 1.4 sets it as a deliberate ask, not spillover. */
    line-height: 1.4;
    /* Medium, not bold. The lit CTA beside it is the row's one hot element;
       500 gives the ask quiet presence without a second focal point competing
       with the button — restraint is what reads as premium here. */
    font-weight: 500;
    color: rgba(255, 255, 255, 0.96);
}

/* Seated in the card rather than dropped on it: the card's own radius, since a
   child rounder than the thing containing it reads as unseated. Sizing is
   scoped through the card to outrank buttons.css's own block, which loads
   later; the lit-up skin itself still comes from .btn-primary. */
.caselet-story-invite .caselet-story-cta {
    flex: 0 0 auto;
    padding: 12px 24px;
    font-size: 13.5px;
    line-height: 1.15;
    letter-spacing: 0.015em;
    border-radius: var(--radius-sm);
}

/* Held at hover too: buttons.css's shadows are tuned to lift a page-scale
   button off the background, and at this size inside a tint they bloom into a
   halo instead of a lift. Hover keeps its brightness and rise from there. */
.caselet-story-invite .caselet-story-cta,
.caselet-story-invite .caselet-story-cta:hover {
    box-shadow:
        0 5px 16px rgba(0, 0, 0, 0.2),
        0 2px 8px rgba(124, 58, 237, 0.34),
        inset 0 1px 0 rgba(255, 255, 255, 0.34);
}

/* ── Phones: proof button + caselet-card popup ──
   ≤768px the aside card is hidden entirely (home.css); app.js renders this
   button directly after the visitor's submitted response. Tapping
   it opens the full story modal directly (z 260) — one tap, no detour
   through the compact popup. The popup/backdrop pieces stay as a fallback
   for caselets with no full story (see mountMobileProofBtn). All pieces
   are desktop-invisible. */
.caselet-proof-btn,
.caselet-popup-backdrop,
.caselet-popup-close {
    display: none;
}

@media (max-width: 768px) {
    .caselet-proof-btn {
        display: flex;
        align-items: center;
        gap: 15px;
        width: 100%;
        margin: 4px 0 26px;
        padding: 16px 16px 16px 20px;
        position: relative;
        overflow: hidden;
        /* Layered brand glass — a faint diagonal wash off the accent gradient
           over the white sheen, so the card reads as lit rather than a flat
           translucent panel. */
        background:
            linear-gradient(135deg, rgba(159, 103, 245, 0.16), rgba(20, 184, 166, 0.10) 60%, rgba(255, 255, 255, 0.02)),
            rgba(255, 255, 255, 0.07);
        border: 1px solid rgba(255, 255, 255, 0.22);
        border-radius: 16px;
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        box-shadow:
            0 14px 34px rgba(10, 6, 30, 0.24),
            0 2px 8px rgba(124, 58, 237, 0.14),
            inset 0 1px 0 rgba(255, 255, 255, 0.22),
            inset 0 -1px 0 rgba(0, 0, 0, 0.10);
        font-family: inherit;
        text-align: left;
        color: var(--white);
        cursor: pointer;
        transition: transform 0.18s ease, border-color var(--transition), box-shadow var(--transition);
    }

    .caselet-proof-btn:active {
        transform: scale(0.985);
        box-shadow:
            0 8px 20px rgba(10, 6, 30, 0.22),
            0 1px 5px rgba(124, 58, 237, 0.12),
            inset 0 1px 0 rgba(255, 255, 255, 0.18);
    }

    /* Same brand top-edge as the card it opens — the button reads as that
       card in compressed form. Feathered at the ends so it sits inside the
       rounded corners instead of butting flat against them. */
    .caselet-proof-btn::before {
        content: '';
        position: absolute;
        top: 0;
        left: 10%;
        right: 10%;
        height: 2px;
        background: linear-gradient(90deg, transparent, var(--purple-light) 20%, var(--teal-light) 80%, transparent);
        opacity: 0.9;
    }

    /* Soft diagonal sheen sweeping across the glass — the top-left catch of
       light that reads as a real, physical surface. */
    .caselet-proof-btn::after {
        content: '';
        position: absolute;
        top: -60%;
        left: -20%;
        width: 55%;
        height: 220%;
        background: linear-gradient(100deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0));
        transform: rotate(8deg);
        pointer-events: none;
    }

    /* Structured two-line text stack — eyebrow (what this is) over the
       domain name (which one), so the label reads instead of blaring as a
       single uppercase blob. */
    .caselet-proof-btn-text {
        display: flex;
        flex-direction: column;
        gap: 5px;
        min-width: 0;
        flex: 1;
    }

    .caselet-proof-btn-eyebrow {
        display: flex;
        align-items: center;
        gap: 7px;
        font-size: 0.95rem;
        font-weight: 800;
        letter-spacing: 0.12em;
        text-transform: uppercase;
        color: white;
    }

    .caselet-proof-btn-dot {
        flex: none;
        width: 5px;
        height: 5px;
        border-radius: 50%;
        background: var(--teal-light);
        box-shadow: 0 0 6px rgba(20, 184, 166, 0.9);
        animation: dotBlink 2s ease infinite;
    }

    .caselet-proof-btn-domain {
        font-size: 0.95rem;
        font-weight: 700;
        letter-spacing: 0.005em;
        line-height: 1.35;
        color: var(--white);
    }

    /* Premium arrow badge — a transparent frosted-glass orb, not a solid disc:
       a whisper of white fill over the card's own tint, a bright hairline rim
       and a crisp inset top-light, so it reads as a polished glass pearl. A
       thin outer halo ring (::before) floats it off the card; a slim specular
       crescent (::after) is the catch of light on the dome. The bold SVG chevron
       glides gently right-and-back forever, inviting the tap. */
    .caselet-proof-btn-arrow {
        flex: none;
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 42px;
        height: 42px;
        border-radius: 50%;
        color: #fff;
        background:
            radial-gradient(130% 130% at 30% 22%, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0.05) 55%),
            rgba(255, 255, 255, 0.06);
        border: 1px solid rgba(255, 255, 255, 0.38);
        backdrop-filter: blur(3px);
        -webkit-backdrop-filter: blur(3px);
        box-shadow:
            0 8px 20px rgba(10, 6, 30, 0.22),
            0 0 16px rgba(159, 103, 245, 0.22),
            inset 0 1.5px 1px rgba(255, 255, 255, 0.55),
            inset 0 -4px 8px rgba(0, 0, 0, 0.12);
        transition: transform 0.18s ease, box-shadow 0.22s ease, border-color 0.22s ease;
    }

    .caselet-proof-btn-arrow svg {
        width: 19px;
        height: 19px;
        display: block;
        filter: drop-shadow(0 1px 2px rgba(20, 8, 50, 0.45));
        animation: proofArrowGlide 2.2s ease-in-out infinite;
    }

    /* Gentle forward invitation — the chevron drifts right, eases back, forever.
       Small travel + slow tempo keeps it premium, never fidgety. */
    @keyframes proofArrowGlide {
        0%, 100% { transform: translateX(-1px); }
        50% { transform: translateX(3px); }
    }

    /* Faint outer halo ring — a hairline of brand light around the orb that
       lifts it off the glass. */
    .caselet-proof-btn-arrow::before {
        content: '';
        position: absolute;
        inset: -4px;
        border-radius: 50%;
        border: 1px solid rgba(255, 255, 255, 0.16);
        box-shadow: 0 0 18px rgba(159, 103, 245, 0.35);
        pointer-events: none;
    }

    /* Glossy top sheen — a slim crescent of light across the upper dome, the
       specular catch that reads as polished glass. */
    .caselet-proof-btn-arrow::after {
        content: '';
        position: absolute;
        top: 3px;
        left: 9px;
        right: 9px;
        height: 38%;
        border-radius: 50%;
        background: linear-gradient(180deg, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0));
        opacity: 0.75;
        pointer-events: none;
    }

    .caselet-proof-btn:active .caselet-proof-btn-arrow {
        transform: scale(0.92);
        border-color: rgba(255, 255, 255, 0.5);
        box-shadow:
            0 4px 12px rgba(10, 6, 30, 0.2),
            inset 0 1.5px 1px rgba(255, 255, 255, 0.5),
            inset 0 -3px 6px rgba(0, 0, 0, 0.12);
    }

    /* Respect reduced-motion — hold the chevron still for users who ask. */
    @media (prefers-reduced-motion: reduce) {
        .caselet-proof-btn-arrow svg {
            animation: none;
            transform: translateX(1px);
        }
    }

    body.caselet-popup-open {
        overflow: hidden;
    }

    body.caselet-popup-open .caselet-popup-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 240;
        background: rgba(10, 8, 24, 0.55);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
    }

    /* The aside card itself, relocated: fixed and centered. display needs
       !important because app.js shows the panel with an inline style and
       home.css hides it on phones with one. Scrolls inside when taller than
       the viewport. */
    body.caselet-popup-open .response-aside {
        display: block !important;
        position: fixed;
        z-index: 245;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: min(460px, calc(100vw - 26px));
        max-height: min(84vh, 660px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        border-radius: var(--radius);
    }

    /* Close chip — top-right inside the card; the header clears it. */
    body.caselet-popup-open .caselet-popup-close {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 10px;
        right: 10px;
        z-index: 3;
        width: 30px;
        height: 30px;
        border-radius: 50%;
        background: rgba(255, 255, 255, 0.12);
        border: 1px solid rgba(255, 255, 255, 0.28);
        color: var(--white);
        font-size: 1.05rem;
        line-height: 1;
        cursor: pointer;
    }

    body.caselet-popup-open .caselet-panel-eyebrow,
    body.caselet-popup-open .caselet-panel-header {
        padding-right: 52px;
    }
}

/* ── Real-world examples ─────────────────────────────────────────────────────
   Other companies' public post-mortems for the turn's pain. One surface in two
   orientations: a left-edge drawer on desktop, a bottom sheet on phones.

   It takes the edge the signals rail vacates. home.css:3291 hides
   .signal-drawer-tab under body.in-conversation and home.css:2929 hides
   .signal-fab the same way, so both landing affordances stand down the moment
   an answer renders — this one is their exact inverse and appears only then.

   Layer 232: above the answer, below the mobile caselet popup (240/245) and the
   caselet story overlay (260), so opening a full story over this layers right. */
.realworld {
    position: fixed;
    inset: 0;
    z-index: 232;
    /* Only the scrim and panel take clicks — the answer behind stays live while
       the panel is shut, and the rung that opens it lives in the answer's own
       column, not in here. */
    pointer-events: none;
}

.realworld[hidden],
body:not(.in-conversation) .realworld {
    display: none;
}

/* ── The way back to us, in the head beside the close ────────────────────────
   Header scale, not page scale. The site's lit gradient says "this is the
   action" — but .btn-primary's full skin is sized for a page, and at 15px with
   a 28px throw next to a 36px close button it reads as a button that fell into
   the title bar. So this takes the gradient and the light edge and leaves the
   size and the shadow behind: a control sitting in a row of controls, that
   still looks like every other way to us.

   Not the close button's glass, deliberately. Two glass pills in one corner
   read as two ways to dismiss the panel, and only one of them is. */
.realworld-cta[hidden] {
    display: none;
}

.realworld-return-cta {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 7px 8px 7px 16px;
    color: var(--white);
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.005em;
    line-height: 1.25;
    text-align: left;
    cursor: pointer;
    background: linear-gradient(135deg, #8b5cf6 0%, #14b8a6 100%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 999px;
    box-shadow:
        0 6px 20px rgba(12, 10, 40, 0.32),
        inset 0 1px 0 rgba(255, 255, 255, 0.38);
    transition: filter 0.22s ease, transform 0.22s ease, box-shadow 0.22s ease;
}

.realworld-return-cta:hover {
    filter: brightness(1.07);
    transform: translateY(-1px);
    box-shadow:
        0 10px 24px rgba(0, 0, 0, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.42);
}

.realworld-return-cta:active {
    transform: translateY(0);
    filter: brightness(0.98);
}

/* The arrow rides its own disc, so a long sentence ends on a mark rather than
   trailing off at the pill's edge. */
.realworld-return-cta-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.20);
}

.realworld-return-cta-arrow svg {
    width: 14px;
    height: 14px;
    transition: transform 0.22s ease;
}

.realworld-return-cta:hover .realworld-return-cta-arrow svg {
    transform: translateX(2px);
}


.realworld-scrim {
    position: absolute;
    inset: 0;
    /* The caselet story modal's scrim, verbatim. It dims the answer enough to
       hand the panel the screen without draining the colour out of it — the
       saturate() this drops was greying the page behind the glass. */
    background: rgba(14, 20, 44, 0.5);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(10px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

/* Dealt to the centre, not slid in from an edge: the click happens on the deck
   in the right-hand column, and a panel arriving from the far side of the
   window read as a different surface answering. It grows into place from a
   card's proportions instead. */
.realworld-panel {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) scale(0.94) rotate(-1.4deg);
    opacity: 0;
    /* Wider than it was, because width is what buys back scroll here: the three
       beats sit side by side, so every extra column inch is prose that stops
       wrapping and a card that gets shorter. min() keeps it fluid — the window
       is the smaller of a comfortable maximum and whatever the viewport can
       actually spare, so nothing has to change at a breakpoint for it to fit. */
    width: min(1440px, calc(100vw - 80px));
    max-height: calc(100vh - 40px);
    /* A fixed head and a scrolling body, and only the body moves — the panel
       itself no longer scrolls, so the offer in the head cannot be scrolled off
       it. `hidden` here is what keeps the stories inside the rounded corners. */
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* No bottom padding: the scroll band's own fade depth supplies it. */
    padding: 24px 28px 0;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 20px;
    /* .caselet-story-panel's surface, verbatim — the window a visitor already
       reads a long-form story on, so the two long-form windows on this site are
       one material. It is vivid rather than deep: the muted slate-blue middle a
       three-stop page ramp puts at 52% is what was reading as darkness, and
       dropping it for a straight violet → teal run lifts the whole panel
       without brightening a single stop past the design system.

       No noise layer with it. That is a page-scale dither for banding across a
       whole viewport; inside a window it only takes the polish off the glass.

       Not attachment:fixed: the panel carries a transform, so a fixed wash
       would resolve to the panel box anyway.

       One adaptation, and only one: a radial sized as a fraction of its box
       grows with the box, and this window is 1440px against that one's 880. At
       the source alphas the top-left glow reached far enough to sit under a
       whole beat and wash it out, so both are pulled in to light the corner
       they are for rather than a third of the panel. Same hues, same anchors. */
    background:
        radial-gradient(circle at 12% 0%, rgba(159, 103, 245, 0.44), transparent 38%),
        radial-gradient(circle at 100% 100%, rgba(20, 184, 166, 0.38), transparent 40%),
        linear-gradient(150deg, #6d28d9 0%, #0f766e 100%);
    /* Every authored heading on the panel, in one place: the wall row on a
       collapsed card and the beat headline in an open one are the same string
       and must not drift apart. Sky rather than --sky-light, which goes pale
       enough on this ground to read as disabled text. */
    --rw-heading: rgb(148, 220, 255);
    /* Closed, this is an invisible sheet more than half the viewport wide,
       centred over the answer — and opacity:0 does NOT stop it hit-testing.
       Left live it swallowed every click that landed on the aside column
       behind it, which is where the deck that opens this panel lives. Only
       .realworld.open turns it back on, the way the scrim already works. */
    pointer-events: none;
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.28s ease,
        box-shadow 0.4s ease;
}

/* The stories, and the only band that moves. It is bled back out into the
   panel's side padding and given that padding back as its own, for two reasons:
   the scrollbar rides near the panel's edge instead of cutting through the
   cards, and a card's drop shadow has room to fall rather than being clipped
   flat against the edge of a scroll box. */
.realworld-scroll {
    flex: 1 1 auto;
    /* Without this the flex item refuses to shrink below its content and the
       panel grows past max-height, taking the foot off screen with it. */
    min-height: 0;
    margin: 0 -20px;
    /* The bottom padding is the fade's own depth, so the fade only ever bites
       content that is genuinely mid-scroll: scrolled to the end, this padding
       is what sits in the fade zone and the last card stays crisp, and a panel
       short enough not to scroll at all shows no fade anywhere. */
    padding: 0 20px 22px;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* The band dissolves into the panel's own wash at its foot instead of being
       cut off square above the button. A hairline was tried here first and it
       cannot work: the divider is brightest exactly where the centred button
       covers it, and a flat scrim cannot be colour-matched to a ground that is
       three gradients deep. Masking the band lets the real ground show through,
       so the fade is correct at every point across a 1180px panel.

       Mask only — no fade at the top, where the head's own rule already draws
       the boundary. */
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22px),
        transparent 100%);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 22px),
        transparent 100%);
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.32) transparent;
}

.realworld-scroll::-webkit-scrollbar {
    width: 10px;
}

.realworld-scroll::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.03);
}

.realworld-scroll::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.28);
    border: 2px solid transparent;
    border-radius: 99px;
    background-clip: padding-box;
}

.realworld-scroll::-webkit-scrollbar-thumb:hover {
    background-color: rgba(255, 255, 255, 0.4);
}

.realworld.open .realworld-panel {
    transform: translate(-50%, -50%) scale(1) rotate(0deg);
    opacity: 1;
    pointer-events: auto;
    /* The branded surface's own throw: one drop to lift it off the scrim and a
       top-edge sheen so it catches light. The ring the ink version needed is
       gone — a lit ground draws its own edge against the dimmed page. */
    box-shadow:
        0 34px 90px rgba(0, 0, 0, 0.42),
        inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.realworld.open .realworld-scrim {
    opacity: 1;
    pointer-events: auto;
}

.realworld-collapse {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    color: var(--white);
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 99px;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition),
        color var(--transition);
}

.realworld-collapse:hover {
    color: var(--white);
    background: rgba(255, 255, 255, 0.22);
    border-color: rgba(255, 255, 255, 0.38);
}

.realworld-collapse svg {
    width: 18px;
    height: 18px;
    transition: transform var(--transition);
}

.realworld-collapse:hover svg {
    transform: rotate(90deg);
}

.realworld-head {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    /* The right margin is still the close button's berth — the offer parks
       beside it, never under it. */
    margin: 2px 48px 16px 2px;
    padding-bottom: 13px;
}

/* The rule is the panel's only full-width line, so it carries the light rather
   than boxing the title in: bright where the eyebrow starts, gone by the far
   edge. A hairline of even weight read as a table border. */
.realworld-head::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.34),
        rgba(255, 255, 255, 0.1) 55%, transparent 100%);
}

.realworld-title {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    /* Held back deliberately: this names the surface and nothing else, and the
       company under it is the line to be read first. On the lit ground 0.55 sank
       into the wash, so it comes up just far enough to stay legible. */
    color: rgba(255, 255, 255, 0.82);
}

/* The brand pair, at the one size where both hues fit in a single mark. */
.realworld-title::before {
    content: '';
    flex: 0 0 auto;
    width: 22px;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--purple-bright), var(--teal-light));
}
/* One row holds the title, the offer and the close only while the panel is at
   its full width. Below that both halves start wrapping and the head reads as
   two ragged columns, so it becomes two rows instead — the name of the surface,
   then the way out of it — and the close keeps its own corner above both. */
@media (max-width: 1080px) {
    .realworld-head {
        flex-direction: column;
        align-items: flex-start;
        gap: 13px;
    }
}

/* ── One card per example, collapsed to the three rows that identify it ── */
.realworld-cards {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* The proof card, verbatim: .caselet-panel-inner's fill, border, blur, radius
   and drop, with its 2px brand top edge. These cards carry a caselet, so they
   take the surface the system already has for one rather than inventing a
   dimmer cousin of it — and now that the panel is painted with the real page
   canvas, this glass is sitting on exactly the ground it was drawn against. */
.realworld-card {
    position: relative;
    /* Up from the proof card's .22: that alpha is tuned for the answer
       column, where a busy canvas draws the card's edge for it. A full-width
       card lying along the panel's own ramp gets no such help. */
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--radius);
    /* Thinner than the proof card's .10, not thicker. On the answer column's
       busy canvas a white wash reads as glass; on a smooth ramp it reads as
       haze, and the more of it there is the flatter the panel gets. So the fill
       is barely there and the card is drawn by its edge, its top accent and the
       shadow under it — which is what keeps the ground's own colour running
       through the card instead of being washed out of it. */
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow:
        0 18px 46px rgba(0, 0, 0, 0.26),
        inset 0 1px 0 rgba(255, 255, 255, 0.14);
    transition: background var(--transition), border-color var(--transition),
        box-shadow var(--transition), transform var(--transition);
}

/* Full strength closed as well as open. The proof card's edge is never dimmed,
   and holding it back was one more thing washing this stack out. */
.realworld-card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 2;
    background: linear-gradient(90deg, var(--purple-light), var(--teal-light));
}

.realworld-card:hover {
    border-color: rgba(255, 255, 255, 0.40);
    background: rgba(255, 255, 255, 0.09);
    transform: translateY(-1px);
}

.realworld-card.open {
    border-color: rgba(255, 255, 255, 0.38);
    background: rgba(255, 255, 255, 0.06);
    box-shadow:
        0 22px 54px rgba(0, 0, 0, 0.24),
        inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

.realworld-card-head {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    width: 100%;
    padding: 15px 20px 14px;
    text-align: left;
    color: inherit;
    font-family: inherit;
    background: none;
    border: none;
    cursor: pointer;
    transition: padding var(--transition), background var(--transition);
}

.realworld-card.open .realworld-card-head {
    padding: 15px 18px 13px;
    margin-bottom: 14px;
    /* The caselet's waterline draws this seam — the same dotted rule that splits
       the firm from its proof there splits the firm from its story here. */
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.06),
        rgba(255, 255, 255, 0));
    border-bottom: 1px dotted rgba(255, 255, 255, 0.34);
}

.realworld-card-rows {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

/* Held back. It sorts the card, it is not read: at full sky-blue it was the
   brightest thing in a stack of cards and the eye landed on the sector before
   the company. It stays a white whisper — just brought up off the floor, since
   the ground under it went back down to the page canvas. */
.realworld-card-industry {
    font-size: 0.57rem;
    font-weight: 600;
    letter-spacing: 0.17em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.62);
}

.realworld-card-company {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    margin-top: 3px;
    font-size: 1rem;
    letter-spacing: -0.01em;
    color: #8df6e1;
    text-shadow: 0 1px 2px rgba(12, 30, 28, 0.35);
}

/* The proof card's waterline, in the row it holds there: everything above it
   says whose story this is, everything below it is the proof. Inset to the
   text column rather than bled across the card, so it stops where the rows it
   divides stop and never runs under the chevron. */
.realworld-card-waterline {
    height: 0;
    margin: 9px 0 9px;
    border-top: 1px dotted rgba(255, 255, 255, 0.34);
}

/* Open, it gains a hair of size and nothing else: the colour above already
   carries it, and the story below is what the visitor came for. */
.realworld-card.open .realworld-card-company {
    font-size: 1.02rem;
    line-height: 1.25;
}

.realworld-card-company strong {
    font-weight: 700;
}

/* The setting the wall happened to, in the proof card's engagement-count row:
   small caps under the waterline, saying what the story is measured over
   before the number lands. It gives the wall a subject — "it broke" needs to
   say what "it" was — and the case treatment is what keeps a whole sentence
   here from competing with the line under it. */
.realworld-card-context {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    line-height: 1.6;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.68);
    text-shadow: 0 1px 2px rgba(15, 10, 30, 0.3);
}

/* The line the card is for, set as the proof card's number row: the wall, in
   the words that beat was headed with. The visitor either recognises this
   sentence as theirs or the card is not for them, so it is the biggest thing in
   the collapsed card — and it is the same authored heading beat 02 carries when
   the card opens, in the same blue. */
.realworld-card-wall {
    margin-top: 8px;
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: -0.01em;
    color: var(--rw-heading);
}

/* The proof card's "what we changed" row, in its place and its treatment: one
   hairline, no fill. A second tinted box inside a card is a third surface, and
   the card is already glass on glass. */
.realworld-card-result {
    display: block;
    margin-top: 11px;
    padding-top: 11px;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
    font-size: 0.9rem;
    line-height: 1.72;
    color: rgba(255, 255, 255, 0.8);
}

.realworld-card-result-mark {
    margin-right: 6px;
    font-size: 0.58rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(255, 196, 122, 0.92);
}

/* The caselet's colour discipline, applied to the collapsed rows: the proof
   number is the only thing on the card carrying colour. The scene line runs
   figures too, and in amber it pulled the eye above the waterline — so up
   there they keep the emphasis and drop the hue. */
.realworld-card-context .realworld-figure {
    color: rgba(255, 255, 255, 0.84);
    text-shadow: none;
}

/* Open, the story below says all of this at length, so the head steps back to
   the two rows that name whose story it is — and the waterline goes with them,
   since the open head draws that seam across the whole card itself. */
.realworld-card.open .realworld-card-waterline,
.realworld-card.open .realworld-card-context,
.realworld-card.open .realworld-card-wall,
.realworld-card.open .realworld-card-result {
    display: none;
}

/* The expand control, on the right-hand edge of the card. */
.realworld-card-chevron {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    margin-top: 1px;
    color: var(--sky-light);
    background: rgba(56, 189, 248, 0.08);
    border: 1px solid rgba(125, 211, 252, 0.22);
    border-radius: 99px;
    transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), background var(--transition),
        border-color var(--transition);
}

.realworld-card-head:hover .realworld-card-chevron {
    background: rgba(56, 189, 248, 0.26);
    border-color: rgba(125, 211, 252, 0.5);
}

.realworld-card.open .realworld-card-chevron {
    transform: rotate(180deg);
}

.realworld-card-chevron svg {
    width: 15px;
    height: 15px;
}

/* The beats answer to the CARD's width, not the window's: the panel is fluid,
   so a viewport breakpoint would flip them at the wrong moment. */
.realworld-card-body {
    padding: 0 18px 18px;
    container-type: inline-size;
}

/* ── The three steps, side by side ────────────────────────────────────────────
   The story is a run: what they tried, what broke, what fixed it. Read one at a
   time they are three cards; read across the row they are one arc, which is the
   only thing the beats are here to say.

   Each step is the caselet card's own material — white glass, one hairline, one
   radius — and takes its hue as an accent rather than a fill. Three coloured
   panels made three products out of one story; a token per beat keeps the rules
   below identical and lets the beat set only its colour. The tints are pitched
   light because they sit on lit glass, not on ink. */
.realworld-beat {
    --rw-accent: 154, 220, 253;
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 17px 18px 18px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    /* Black again, not the panel's blue. The blue tint was an adaptation to a
       lit ground; on the page canvas a black drop is what reads as depth. */
    box-shadow:
        0 10px 26px rgba(0, 0, 0, 0.16),
        inset 0 1px 0 rgba(255, 255, 255, 0.20);
}

.realworld-beat--production_reality {
    --rw-accent: 255, 196, 122;
}

.realworld-beat--recovery {
    --rw-accent: 143, 228, 210;
}

/* The hue at full strength, and ONLY here — with the step number and the mark.
   The border stays neutral: a hairline in each beat's own colour turned one
   story into three coloured products sitting in a row, which is the thing this
   accent language exists to avoid. One lit edge along the top says which beat
   this is from across the card, at the width of a hairline. Inset from the
   corners so it reads as light caught on the surface rather than as a second
   border drawn over the first. */
.realworld-beat::after {
    content: '';
    position: absolute;
    top: 0;
    left: 15px;
    right: 15px;
    height: 2px;
    border-radius: 0 0 2px 2px;
    background: rgba(var(--rw-accent), 0.92);
}

.realworld-beats {
    display: grid;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Past this the card is wide enough to hold the run across its width. Below it
   the steps stack, and the numbers carry the order the row was carrying.

   880, not 700: three columns out of 700px are 200px each, and at that width
   the prose fragments to three or four words a line while the tallest beat
   drags the two beside it into a tall empty box. The threshold is the width at
   which three columns are still readable, not the width at which three
   columns fit. It answers to the CARD, so a wider panel reaches it sooner. */
@container (min-width: 880px) {
    .realworld-beats {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        /* The gap is the connector's room. */
        gap: 30px;
        /* The three are one run, so they bottom out on the same line — a ragged
           edge read as the shortest one being unfinished. */
        align-items: stretch;
    }

    /* The handoff, drawn in the gap rather than inside either card: a chevron
       of two hairlines, on the step number's own line so it never floats in the
       middle of a paragraph. Nothing is drawn around it — a chip in a 30px gap
       is a third surface, and one you can try to press. */
    .realworld-beat + .realworld-beat::before {
        content: '';
        position: absolute;
        top: 27px;
        left: -19px;
        width: 7px;
        height: 7px;
        border-top: 1.5px solid rgba(255, 255, 255, 0.55);
        border-right: 1.5px solid rgba(255, 255, 255, 0.55);
        transform: rotate(45deg);
    }
}

/* Number and beat name, the row that makes the order visible. */
.realworld-beat-top {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.realworld-beat-step {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    font-size: 0.58rem;
    font-weight: 800;
    color: rgb(var(--rw-accent));
    border: 1px solid rgba(var(--rw-accent), 0.55);
    border-radius: 99px;
    background: rgba(255, 255, 255, 0.12);
}

.realworld-beat-mark {
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgb(var(--rw-accent));
}

/* The authored one-liner, and the first thing read in the step. Uniform across
   the three beats: the accent lives in the top rule, the step number and the
   mark, so the headline can be the sentence rather than a third signpost.

   Sky blue, which is what an authored heading is set in everywhere on this
   panel — the collapsed card's wall row is the same authored string as beat
   02's headline here, so the two are one colour by definition. It sits above
   the prose and below the amber: the figures inside a heading stay the
   brightest mark in it. */
.realworld-beat-headline {
    margin: 0 0 9px;
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1.45;
    letter-spacing: -0.012em;
    color: var(--rw-heading);
}

.realworld-beat-prose {
    margin: 0;
    font-size: 0.81rem;
    line-height: 1.7;
    /* Under the headline in rank, never level with it — that is what gives the
       step its shape. */
    color: rgba(255, 255, 255, 0.86);
}

/* Outcome runs 57-100 characters against the 237-538 of the beats, so it is a
   line inside the last step rather than a fourth tile: it is what came of that
   step, and a band across all three would claim the two before it as well.
   `margin-top: auto` seats it on the foot of its card, so it reads as the run's
   closing line however tall the three end up.
   It is drawn as the card's FOOT, not as a panel inside it: a bordered, filled
   box sitting inside a bordered, filled card was the one place the run put a
   container inside a container. All the separation it needs is one hairline run
   the full width of the card — which is why the negative margin is exactly the
   card's own side padding — and the amber it is already carrying in its mark
   and its figures. */
.realworld-outcome {
    margin: 16px -17px 0;
    padding: 12px 17px 0;
    border-top: 1px solid rgba(255, 255, 255, 0.22);
    font-size: 0.8rem;
    line-height: 1.55;
    color: rgba(255, 255, 255, 0.95);
}

/* The prose eats the card's free space, which is what seats the foot rule on
   the bottom of a stretched card. Done from the prose rather than as an auto
   top margin on the outcome, because an auto margin resolves to nothing on a
   card that is already full — and the rule would then be drawn hard against
   the last line of the paragraph above it. */
.realworld-beat .realworld-beat-prose {
    margin-bottom: auto;
}

/* A run-in heading, in the eyebrow's own case: the beat is named where the eye
   lands — the start of the line — and with the box gone this label is what says
   the line is a different kind of thing from the prose above the rule. */
.realworld-outcome-mark {
    margin-right: 2px;
    font-size: 0.62rem;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #ffc477;
}

/* Set by withFigures(), which marks up the numerals and nothing else. */
/* The caselet's proof-number treatment, verbatim: amber at 800 with a same-hue
   glow. These figures ARE the proof, so they read the way one does on a
   caselet card rather than inventing a second number colour. */
.realworld-figure {
    font-weight: 800;
    color: #ffa023;
    text-shadow: 0 0 14px rgba(255, 145, 20, 0.45);
}

/* Their conclusion in their own words — the one field on the card that is not
   our retelling. It closes the run from underneath rather than standing in it:
   the three steps are what happened, this is what it meant, and a fourth column
   would have made it a fourth thing that happened. Never clamped, truncated or
   reflowed: sized for the longest one, not the median. */
.realworld-lesson {
    --rw-accent: 154, 220, 253;
    position: relative;
    margin-top: 14px;
    padding: 15px 17px 16px;
    border: 1px solid rgba(255, 255, 255, 0.24);
    border-radius: 14px;
    /* Lit from the two opposite corners the panel itself is lit from, so the
       story closes on the same light it opened with. */
    background:
        radial-gradient(120% 170% at 0% 0%, rgba(125, 211, 252, 0.16), transparent 62%),
        radial-gradient(120% 170% at 100% 100%, rgba(45, 212, 191, 0.14), transparent 62%),
        rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow:
        0 14px 34px rgba(0, 0, 0, 0.24),
        inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

/* Still the label on the lesson, which keeps its eyebrow: it has no headline
   to hand the accent to. */
.realworld-beat-label {
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgb(var(--rw-accent));
    margin: 0;
}

.realworld-lesson .realworld-beat-prose {
    /* Full card width, on purpose. A measure cap was tried here and reads as a
       fault rather than as typography: the lesson is the one full-width band in
       the card, so text stopping two thirds of the way across looks like the
       line broke early, not like a column. It is three or four lines either
       way — the cap only changed where they broke. */
    font-weight: 500;
    font-size: 0.83rem;
    color: rgba(255, 255, 255, 0.94);
}

/* ── Phones: the panel becomes a sheet ────────────────────────────────────────
   The deck still opens it, but a centred modal on a 390px screen is a sheet in
   all but name, so it docks to the bottom edge and rises from there. That edge
   is free — .signal-fab stands down under body.in-conversation. */
@media (max-width: 768px) {
    .realworld-panel {
        left: 0;
        right: 0;
        top: auto;
        bottom: 0;
        width: auto;
        /* Rises to the top edge, less a sliver of page: the sheet still reads
           as a sheet over the answer rather than a second screen, and that
           sliver stays a tap target for dismissing it. dvh so the browser's
           own chrome does not push the foot of the sheet out of reach. */
        max-height: calc(100vh - 18px);
        max-height: calc(100dvh - 18px);
        transform: translateY(100%);
        border: 1px solid rgba(255, 255, 255, 0.24);
        border-bottom: none;
        border-radius: 22px 22px 0 0;
        /* The sheet's inset is narrower than the desktop panel's, so the bands
           re-cut to it: the scroll bleeds 10px instead of 20, and the safe area
           is the scroll band's to clear, since it is now what stands on the
           bottom edge. */
        padding: 18px 16px 0;
    }

    .realworld-scroll {
        margin: 0 -10px;
        padding: 0 10px calc(22px + env(safe-area-inset-bottom));
    }

    /* The title, the close and a sentence-long offer will not share one row at
       390px. The head becomes two rows instead — the name of the surface, then
       the one way out of it — and the close keeps its own corner above both. */
    .realworld-head {
        flex-direction: column;
        align-items: stretch;
        gap: 13px;
        margin-right: 44px;
        padding-bottom: 14px;
    }

    /* Full width, because a pill sized to three lines of wrapped text reads as
       a mis-sized pill rather than a chosen one. */
    .realworld-return-cta {
        width: 100%;
        padding: 11px 11px 11px 16px;
        line-height: 1.35;
    }

    .realworld.open .realworld-panel {
        transform: translateY(0);
        opacity: 1;
        box-shadow:
            0 -20px 56px rgba(0, 0, 0, 0.42),
            inset 0 1px 0 rgba(255, 255, 255, 0.16);
    }

    .realworld-beat,
    .realworld-lesson {
        padding: 12px 13px 13px;
    }

    /* The foot rule spans the card, so its pull-out has to track the padding
       the card takes here rather than the desktop one. */
    .realworld-outcome {
        margin: 13px -13px 0;
        padding: 11px 13px 0;
    }

    .realworld-beat-top {
        margin-bottom: 6px;
    }
}
