/* ---------------------------------------------------------------
         Tokens resolved from Figma variables (file WqbZ7IrGWguS3pm4RjWykS).
         Anthropic Sans / Serif are not installable here; the stacks below
         name them first so the page upgrades itself once they exist.
         --------------------------------------------------------------- */
      :root {
        --bg-000: #ffffff;
        --bg-100: #faf9f5;
        --bg-200: #242424;
        --bg-300: #f0efec;
        --background-primary: #ffffff;
        --bg-transparent: rgba(255, 255, 255, 0.6);

        --text-primary: #141413;
        --text-secondary: #3d3d3a;
        --text-tertiary: #73726c;
        --text-muted: #7b7974;
        --default-text-100: #131313;

        --border-primary: rgba(31, 30, 29, 0.4);
        --border-secondary: rgba(31, 30, 29, 0.3);
        --border-200: rgba(30, 30, 29, 0.3);
        --border-300: rgba(31, 30, 29, 0.15);

        --accent-100: #2a78d6;
        --accent-info: #2c84db;
        --accent-clay: #d97757;
        --brand-000: #c6613f;
        --secondary-fig: #c46686;

        --radius-md: 6px;
        --radius-lg: 10px;
        --radius-xl: 12px;
        --radius-2xl: 16px;
        --radius-xl-touch: 24px;
        --radius-full: 9999px;

        --shadow-panel: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
        --shadow-low: 0 1px 1px rgba(0, 0, 0, 0.05);

        /* The card's own chrome, mirrored here from the widgets' tokens.
           The fullscreen sheet is drawn by the host, not by the widget, so
           these have to exist on this side for the sheet and an inline card
           to be the same object rather than two things that resemble each
           other. Kept byte-identical to the widget's --card-shadow and
           --border-secondary; if either moves, both move. */
        --card-border: rgba(31, 30, 29, 0.3);
        --card-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.08),
          0 1px 3px -1px rgba(0, 0, 0, 0.06);
        /* The widgets' own --r-xl, restated here for the same reason the
           border and shadow are: the sheet has to be the card, not a copy of
           it that has drifted two pixels. */
        --card-radius: 20px;

        --size-text-xs: 12px;
        --lh-text-xs: 16.8px;
        --size-text-sm: 14px;
        --lh-text-sm: 19.6px;
        --size-text-md: 16px;
        --lh-text-md: 22.4px;

        --font-sans: "Anthropic Sans Text", "Anthropic Sans", -apple-system,
          BlinkMacSystemFont, "SF Pro Text", Inter, system-ui, sans-serif;
        --font-serif: "Anthropic Serif Text", "Anthropic Serif", "Tiempos Text",
          "Iowan Old Style", Charter, Georgia, serif;

        --lab-canvas: #e9e7e1;
        --glyph-bg: rgba(255, 255, 255, 0.8);
      }

      html[data-theme="dark"] {
        color-scheme: dark;
        --bg-000: #30302e;
        --bg-100: #141413;
        --bg-200: #faf9f5;
        --bg-300: #3a3a36;
        --background-primary: #30302e;
        --bg-transparent: rgba(48, 48, 46, 0.72);
        --text-primary: #faf9f5;
        --text-secondary: #c2c0b6;
        --text-tertiary: #9c9a92;
        --text-muted: #9c9a92;
        --default-text-100: #faf9f5;
        --border-primary: rgba(222, 220, 209, 0.4);
        --border-secondary: rgba(222, 220, 209, 0.3);
        --border-200: rgba(222, 220, 209, 0.3);
        --border-300: rgba(222, 220, 209, 0.15);
        --accent-100: #80aadd;
        --accent-info: #80aadd;
        --shadow-panel: 0 2px 8px 0 rgba(0, 0, 0, 0.45);
        --card-border: rgba(222, 220, 209, 0.3);
        /* Less light in the room, so a deeper drop — the widget's dark
           --card-shadow, unchanged. */
        --card-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.5),
          0 1px 3px -1px rgba(0, 0, 0, 0.4);
        --lab-canvas: #0f0f0e;
        --glyph-bg: rgba(255, 255, 255, 0.12);
      }

      * {
        box-sizing: border-box;
      }

      html,
      body {
        height: 100%;
        overflow: hidden;
      }

      body {
        margin: 0;
        background: var(--lab-canvas);
        font-family: var(--font-sans);
        font-feature-settings: "salt" 1;
        -webkit-font-smoothing: antialiased;
        display: flex;
        flex-direction: column;
      }

      /* Centred, and away unless it is wanted. The bar is scaffolding for
         judging the thing above it, and a permanent strip of lab chrome ends up
         being read as part of the design it is there to frame. Parked off the
         bottom edge it costs nothing until the pointer goes looking for it.
         Padding is even on all four sides. It was 8/12, which reads as a
         mistake at this size: the controls inside already carry their own
         horizontal padding, so the extra 4px only made the bar's ends look
         loose against a top and bottom that were tight. */
      .lab {
        position: fixed;
        bottom: 24px;
        /* Stretched edge to edge and centred with auto margins, not pinned to
           `left: 50%`. With only a left offset the width available to a
           shrink-to-fit box is what remains to its right — half the window — so
           the bar began wrapping at twice the width it should have. */
        left: 0;
        right: 0;
        width: fit-content;
        max-width: calc(100vw - 32px);
        margin-inline: auto;
        z-index: 40;
        display: flex;
        align-items: center;
        justify-content: center;
        /* Centred, a bar wider than the window overhangs both ends and neither
           end can be scrolled to, so a narrow window is the one case where it
           has to give and become two rows. Left-anchored this never came up,
           which is why it was not handled before. */
        flex-wrap: wrap;
        gap: 10px;
        padding: 8px;
        background: var(--bg-000);
        border: 0.5px solid var(--border-300);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-panel);
        color: var(--text-primary);
        /* Parked, not gone: a sliver stays on the bottom edge so the bar
           can still be found. 24px rest gap minus 12px of peek. */
        translate: 0 calc(100% + 12px);
        opacity: 0.42;
        transition: translate 0.26s cubic-bezier(0.32, 0.72, 0, 1),
          opacity 0.18s ease;
      }
      html[data-bar="on"] .lab {
        translate: 0 0;
        opacity: 1;
      }
      /* Nothing to reveal it with, so it cannot be allowed to hide. */
      @media (hover: none) {
        .lab {
          translate: 0 0;
          opacity: 1;
        }
      }
      @media (prefers-reduced-motion: reduce) {
        .lab {
          transition: none;
        }
      }
      /* The strip the pointer has to reach to bring the bar back. Deep enough
         to be found without aiming — the bar it summons is itself only 46px —
         and it sits under the bar rather than over it, so it never intercepts a
         click meant for a control.
         It has to be a real element rather than a pointermove watcher on the
         document: the shells are iframes, and pointer events inside an iframe
         never reach the parent, so a watcher would go dead over exactly the
         part of the window the pointer spends its time in. */
      .lab-hotzone {
        position: fixed;
        inset: auto 0 0 0;
        height: 96px;
        z-index: 39;
      }
      /* Standing down the moment the bar is up, so the strip is only ever in
         the way for the single movement that summons it. Otherwise it would
         swallow every click landing in the bottom 96px of the board — which on
         a shell taller than the window is live widget, not margin. */
      html[data-bar="on"] .lab-hotzone {
        pointer-events: none;
      }
      /* The bar never hides here, so nothing needs summoning. */
      @media (hover: none) {
        .lab-hotzone {
          display: none;
        }
      }
      .lab-brand {
        display: flex;
        flex-direction: column;
        gap: 1px;
        line-height: 1.2;
      }
      .lab strong {
        font-weight: 500;
        font-size: 13px;
        letter-spacing: -0.02em;
        color: var(--text-primary);
      }
      .lab em {
        font-style: normal;
        font-size: 11px;
        color: var(--text-tertiary);
      }
      .lab .grow {
        display: none;
      }
      /* display:flex below would otherwise beat the attribute. */
      .seg[hidden],
      .sel[hidden] {
        display: none;
      }
      .sel {
        display: flex;
        align-items: center;
        gap: 6px;
        font-size: 12px;
        font-weight: 600;
        color: var(--text-secondary);
      }
      .sel select {
        appearance: none;
        height: 30px;
        padding: 0 24px 0 10px;
        border: 0.5px solid var(--border-300);
        border-radius: var(--radius-lg);
        background: var(--bg-300)
          url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' viewBox='0 0 12 12'><path stroke='%2373726c' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.25' d='M2.5 4.25 6 7.75 9.5 4.25'/></svg>")
          no-repeat right 8px center;
        color: var(--text-primary);
        font: inherit;
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
      }
      .lab-scale {
        font-size: 11px;
        font-variant-numeric: tabular-nums;
        color: var(--text-tertiary);
        white-space: nowrap;
      }
      html[data-view="widget"] .lab-scale {
        display: none;
      }
      .seg {
        display: flex;
        gap: 2px;
        padding: 2px;
        background: var(--bg-300);
        border: 0.5px solid var(--border-300);
        border-radius: var(--radius-lg);
      }
      .seg button {
        appearance: none;
        border: 0;
        background: transparent;
        color: var(--text-secondary);
        font: inherit;
        font-size: 12px;
        font-weight: 600;
        padding: 5px 10px;
        border-radius: calc(var(--radius-lg) - 2px);
        cursor: pointer;
        transition: background 0.12s, color 0.12s, box-shadow 0.12s;
      }
      .seg button:hover:not(.is-on) {
        background: var(--bg-000);
        color: var(--text-primary);
      }
      .seg button.is-on {
        background: var(--bg-000);
        color: var(--text-primary);
        box-shadow: var(--shadow-low);
      }

      /* `safe center` centres a shell that fits and falls back to start-aligned
         when one does not. Plain `center` overflows equally in both directions,
         and the half that goes past the start edge cannot be scrolled back to —
         at 1:1 a 1440px shell in a smaller window would lose its left side for
         good.
         The bottom padding no longer reserves a lane for the toolbar: the bar
         hides itself now, and holding 88px open permanently for something
         usually not on screen cost the shells the room they needed. */
      .board {
        flex: 1;
        min-height: 0;
        display: flex;
        align-items: safe center;
        justify-content: safe center;
        padding: 24px;
        overflow: auto;
      }
      html[data-view="pc"] .m-wrap,
      html[data-view="pc"] .solo-wrap {
        display: none;
      }
      html[data-view="mobile"] .pc-wrap,
      html[data-view="mobile"] .solo-wrap {
        display: none;
      }
      html[data-view="widget"] .pc-wrap,
      html[data-view="widget"] .m-wrap {
        display: none;
      }

      .scene-select {
        appearance: none;
        height: 30px;
        padding: 0 26px 0 10px;
        border: 0.5px solid var(--border-300);
        border-radius: var(--radius-lg);
        background: var(--bg-300)
          url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' viewBox='0 0 12 12'><path stroke='%2373726c' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.25' d='M2.5 4.25 6 7.75 9.5 4.25'/></svg>")
          no-repeat right 8px center;
        color: var(--text-primary);
        font: inherit;
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
      }

      .widget-frame {
        display: block;
        width: 100%;
        height: 1px;
        min-height: 0;
        max-height: none;
        border: 0;
        overflow: hidden;
        background: transparent;
        vertical-align: top;
      }

      /* Fullscreen is a host overlay, not a column takeover. The
         conversation stays; this sheet sits on top of it with room to
         scroll. */
      .fs-bar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
      }
      .solo-wrap .fs-bar {
        display: none;
      }
      /* And in fullscreen it goes. This used to grow a border, take on
         padding and put a close button at its right end, so the sheet
         opened under a strip carrying an app name and an X — directly on
         top of the card's own top line, which carries the filters. Two
         bars, and the reader has to work out which one belongs to what
         they are looking at.
         The cards ask for this mode themselves now and each one keeps the
         button that asked, flipped, in the row it was already in. The way
         out is where the way in was, which is the one place nobody has to
         be told to look. Escape still works — see host.js.
         Inline the row stays exactly as it was: that is the attribution
         Claude puts above every MCP app, and it is not ours to drop. */
      html[data-display="fullscreen"] .fs-bar {
        display: none;
      }

      /* Fullscreen does not resize the shell.
         It used to: the PC frame was blown up to fill the lab board so the
         sheet had a full window to cover, which meant the one control that
         asks "what does this look like taken over the whole app" answered by
         changing what the whole app was. You could not compare the fullscreen
         card to the inline one, because the 1440px frame the inline one was
         measured in had gone.
         So the mockup holds its size and the sheet is drawn inside it — over
         the chat, up to the sidebar's edge and no further, which is where a
         real fullscreen MCP app stops. Everything below is scoped to the
         standalone widget view, which has no shell to sit inside and so still
         has to borrow the board. */
      html[data-display="fullscreen"][data-view="widget"] body {
        /* Otherwise the lab canvas shows under the sheet as a grey strip and
           reads as a footer rather than as the chat behind it. */
        background: var(--bg-100);
      }
      html[data-display="fullscreen"][data-view="widget"] .board {
        padding: 0;
        align-items: stretch;
        justify-content: stretch;
      }
      /* There is no scrim behind the sheet, and there was.
         A scrim is how a dialog says the thing underneath it is out of reach,
         and it earns that by being visible — you are meant to see the dimmed
         page and understand it is waiting. This sheet covers its column
         entirely except for a 16px margin, so all the scrim could dim was
         that margin. It did not read as "the conversation is behind this", it
         read as a grey line down the side of a white panel: the one strip of
         chat still on screen came out at rgb(199,198,194) against the
         sidebar's #faf9f5 immediately beside it, and two backgrounds that are
         the same surface do not get to be two colours.
         The sheet is opaque and fills the column. That is already the whole
         message. */
      /* Absolute, and the box it resolves against is .pc-chat — the column
         that starts where the sidebar ends. So `left` here is the sheet's
         inset from the sidebar, not from the window, and it is the same 16px
         the other three sides take. It was fixed at left: 68px, which only
         landed in the right place because the shell had been given a
         transform and had been blown up to the size of the window: two
         coincidences holding up one layout, and both are now gone.
         The same 16px on all four sides, and the fourth one was missing. It
         ran to bottom: 0 on the theory that a sheet which has come up should
         be attached to the edge it came from — but that is the argument for
         a sheet that arrives from below and can be pushed back down, and this
         one fades in over the column and is dismissed with an × in its own
         top corner. Nothing about it is anchored to the bottom of the window,
         so an inset panel with one side welded down just looked like a panel
         that had overrun. Three matching margins and one absent one is read
         as a mistake before it is read as an intention, every time. */
      html[data-display="fullscreen"][data-view="pc"] .pc-slot {
        position: absolute;
        inset: 16px;
        z-index: 5;
        width: auto !important;
        height: auto !important;
        max-width: none;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background: var(--bg-000);
        /* The same three materials an inline card is made of, because it is
           the same card — the widget in it has not become a different object
           by being given the column.
           This did without them for a while, on the argument that a shadow
           needs somewhere to fall and all it had was a 16px margin. That is
           true of the shadow that argument was written against, a 48px blur
           that turned the strip into a gradient. --card-shadow is not that:
           6px of blur pulled in 1px, reaching about 8px past the edge, which
           the margin holds with room to spare. The reason to want it is the
           same reason the card has one — a hairline alone gives an object a
           contour, a hairline and a shadow give it a position — and the
           sheet is a panel standing in front of the conversation, which is a
           position. */
        border: 0.5px solid var(--card-border);
        border-radius: var(--card-radius);
        box-shadow: var(--card-shadow);
      }
      html[data-display="fullscreen"][data-view="mobile"] .m-slot {
        position: absolute;
        inset: 8px 8px 8px;
        z-index: 5;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background: var(--bg-000);
        /* Same as the PC sheet. The margin here is 8 rather than 16, which
           was the objection when the shadow was a 32px blur; against an 8px
           reach it is a close fit rather than an impossible one, and a sheet
           that has the card's chrome on a desktop and not on a phone is two
           sheets again.
           The radius is the phone's own, not --card-radius: this one is
           bounded by the device's screen corners a few pixels outside it,
           and a panel inset 8px from a 20px screen corner has to be rounder
           than a card in free space or the two curves fight. */
        border: 0.5px solid var(--card-border);
        border-radius: 20px;
        box-shadow: var(--card-shadow);
      }
      html[data-display="fullscreen"][data-view="widget"] .solo-wrap {
        width: min(960px, 100%);
        height: 100%;
        max-height: 100%;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background: var(--bg-000);
        /* Same sheet, same chrome. The rule this replaces was right about the
           principle — a sheet that gains a shadow depending on which mockup
           you are looking at is not the same sheet — and settled it by taking
           the shadow off all three. The other two have it now, so this one
           does, and the principle is intact the other way up. */
        border: 0.5px solid var(--card-border);
        border-radius: var(--card-radius);
        box-shadow: var(--card-shadow);
      }
      html[data-display="fullscreen"][data-view="widget"] .board {
        align-items: stretch;
        justify-content: center;
      }
      html[data-display="fullscreen"][data-view="pc"] .pc-slot .widget-frame,
      html[data-display="fullscreen"][data-view="mobile"] .m-slot .widget-frame,
      html[data-display="fullscreen"][data-view="widget"] .solo-wrap .widget-frame {
        flex: 1 1 auto;
        height: auto !important;
        min-height: 0 !important;
        max-height: none !important;
      }
      .pc-slot {
        width: 100%;
        overflow: visible;
      }
      .m-slot {
        width: 100%;
        overflow: visible;
      }

      /* --- app attribution ---
         The line Claude puts above an MCP app to say whose it is. It belongs to
         the host, not to the widget: the guidelines are explicit that an app
         must not render its own logo as a response element, because the host
         appends attribution itself. Simulated here so the widgets can be judged
         with the same thing above them that production will put there — without
         it, every widget looks unlabelled in review and someone eventually
         "fixes" that by building a header into the card, which is the exact
         duplication the rule exists to prevent.
         Quiet on purpose: it identifies the source, it is not a title for the
         card. Tertiary text and a mark that reads as an app's icon rather than
         as branding — quiet is a matter of weight and colour, which this keeps,
         and it was being bought with size instead.
         Caption size put the row on the bottom step of the host's whole type
         scale (12 / 14 / 16), i.e. smaller than anything Claude sets around it,
         and a 16px tile holding a 10px glyph is below a favicon. One step up on
         both. Provisional: Claude publishes no measurement for this row, so
         these are still the lab's numbers, not the host's. The one artifact
         that would settle it is Anthropic's MCP Apps Figma kit. */
      .app-attrib {
        display: flex;
        align-items: center;
        gap: 7px;
        padding: 0 2px 8px;
      }
      /* The tile flips with the theme rather than holding one brand colour.
         A fixed dark tile vanishes into the dark-mode thread — same ink, same
         surface — and what is left reads as a bare floating logo instead of an
         app's icon. So the tile takes the inverse-surface token and the glyph
         rides the same invert the host's own monochrome glyphs use, which keeps
         mark-on-tile contrast identical in both themes.
         This is also the one place a brand colour could legitimately go, and
         where it should go once OpenArt's pink is settled. */
      .app-attrib-mark {
        width: 20px;
        height: 20px;
        display: grid;
        place-items: center;
        /* 5px, not the 4px this had: the glyph grew with the tile, and a
           radius left behind starts to read as a square. */
        border-radius: 5px;
        background: var(--bg-200);
        flex-shrink: 0;
      }
      .app-attrib-mark img {
        width: 12px;
        height: auto;
      }
      html[data-theme="dark"] .app-attrib-mark img {
        filter: invert(1) brightness(0.97);
      }
      .app-attrib-name {
        font-size: var(--size-text-sm);
        line-height: 1.4;
        font-weight: 500;
        color: var(--text-tertiary);
      }
      .solo-wrap {
        width: min(760px, 100%);
        max-height: 100%;
        overflow: auto;
      }
      /* Each shell is laid out at the client's real frame size — 720px of
         message column, 16px of phone gutter — rather than reflowed to whatever
         the lab window happens to be. That distinction matters because these
         widgets have breakpoints: a shell allowed to reflow would silently
         preview the wrong one. fitView() writes the px on both boxes. */
      .fit {
        flex-shrink: 0;
      }

      img {
        display: block;
      }

      /* Figma exports every glyph as a positioned box inside a fixed square.
         The per-icon left/top/width/height percentages below are the node's
         own inset values — without them the glyph stretches to the full box. */
      .icon {
        position: relative;
        flex-shrink: 0;
      }
      .icon > img {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
      }
      .i20 {
        width: 20px;
        height: 20px;
      }
      .i24 {
        width: 24px;
        height: 24px;
      }
      /* Figma exports monochrome glyphs as flat ink, so dark mode inverts them.
         .keep opts out, and it is only correct for a glyph whose colour is the
         point — brand orange, or white sitting on a fill that does NOT flip
         with the theme. Marking a plain ink glyph .keep leaves it dark on a
         dark surface; marking a white glyph .keep when its button is painted
         with a flipping token leaves it white on white. */
      html[data-theme="dark"] .icon:not(.keep) > img,
      html[data-theme="dark"] .ink img {
        filter: invert(1) brightness(0.97);
      }

      /* =============================================================
         DESKTOP — node 14:656 "pc", 1440 × 824
         ============================================================= */
      /* Framed like an application window, for the same reason the phone gets
         a bezel: without an edge the shell bleeds into the lab background and
         the 1440px frame stops reading as a frame — you lose the sense of how
         much of a real screen the widget is actually taking. */
      .pc {
        /* The containing block for the fullscreen sheet and its scrim, so
           both are measured against the app window rather than the lab's. */
        position: relative;
        width: 100%;
        height: 100%;
        display: flex;
        align-items: flex-start;
        background: var(--bg-100);
        border: 0.5px solid var(--border-300);
        border-radius: 12px;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.09);
        overflow: hidden;
      }

      /* --- collapsed sidebar, 52px --- */
      .pc-sidebar {
        width: 52px;
        height: 100%;
        display: flex;
        flex-direction: column;
        gap: 8px;
        padding: 0 8px 12px;
        background: var(--bg-100);
        border-right: 0.5px solid var(--border-secondary);
        overflow: hidden;
      }
      .pc-sidebar-items {
        flex: 1;
        width: 36px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        align-items: center;
      }
      .pc-sidebar-toggle {
        width: 36px;
        height: 68px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 8px;
        flex-shrink: 0;
      }
      .pc-sidebar-buttons {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
      }
      .pc-sidebar-btn {
        width: 36px;
        height: 36px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 8px;
        flex-shrink: 0;
      }
      .pc-account {
        width: 100%;
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 4px;
        border-radius: 8px;
      }
      .avatar-fig {
        width: 28px;
        height: 28px;
        border-radius: var(--radius-full);
        background: var(--secondary-fig);
        position: relative;
        flex-shrink: 0;
      }
      .avatar-fig > img {
        position: absolute;
        inset: 23.41%;
        width: 53.18%;
        height: 53.18%;
      }

      /* --- chat container --- */
      .pc-chat {
        flex: 1;
        height: 100%;
        min-width: 0;
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        padding: 80px 64px 12px;
        overflow: hidden;
      }
      .pc-messages {
        flex: 1;
        width: 100%;
        max-width: 720px;
        min-height: 0;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 24px;
        overflow: auto;
      }

      /* --- titlebar --- */
      .pc-titlebar {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 16px;
        background: var(--bg-100);
      }
      .pc-title {
        height: 36px;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        padding: 4px 4px 4px 8px;
        border-radius: var(--radius-md);
        font-size: var(--size-text-md);
        line-height: var(--lh-text-md);
        color: var(--text-primary);
        white-space: nowrap;
      }
      .pc-share {
        height: 36px;
        min-width: 75px;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        padding: 12px 8px;
        border: 0.5px solid var(--border-200);
        border-radius: 8px;
        overflow: hidden;
        font-size: var(--size-text-sm);
        line-height: var(--lh-text-sm);
        color: var(--text-primary);
      }

      /* --- user message --- */
      .pc-user-row {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        overflow: hidden;
      }
      .pc-user-bubble {
        max-width: 640px;
        padding: 12px 16px 12px 12px;
        background: var(--bg-300);
        border-radius: var(--radius-xl);
        font-size: var(--size-text-md);
        line-height: var(--lh-text-md);
        color: var(--text-primary);
        overflow: hidden;
      }
      .pc-user-bubble b {
        font-weight: 600;
      }

      .pc-icon-btn {
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 8px;
        overflow: hidden;
      }
      /* --- Claude response --- */
      .pc-response {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
      .pc-prose {
        width: 100%;
        padding: 0 16px;
        border-radius: var(--radius-xl);
        font-family: var(--font-serif);
        font-size: 16px;
        line-height: 1.6;
        color: var(--text-primary);
        /* "salt" from the body would map to long-s in serif fallbacks */
        font-feature-settings: normal;
        filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.02));
      }
      .pc-actions {
        width: 100%;
        display: flex;
        align-items: center;
        gap: 2px;
        padding: 6px 12px 20px;
      }
      .pc-action {
        width: 24px;
        height: 24px;
        border-radius: 8px;
        position: relative;
        overflow: hidden;
        flex-shrink: 0;
      }
      .pc-action > .icon {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 14px;
        height: 14px;
        transform: translate(-50%, -50%);
      }
      .pc-spark-row {
        width: 100%;
        display: flex;
        align-items: center;
        padding-left: 16px;
      }

      /* --- composer --- */
      .pc-composer {
        position: absolute;
        bottom: 12px;
        left: 50%;
        transform: translateX(-50%);
        width: 752px;
        display: flex;
        flex-direction: column;
        align-items: center;
        background: var(--bg-000);
        border: 0.5px solid var(--border-200);
        border-radius: var(--radius-2xl);
        box-shadow: var(--shadow-panel);
        overflow: hidden;
      }
      .pc-composer-input {
        width: 100%;
        display: flex;
        align-items: flex-start;
        padding: 12px 16px;
      }
      .pc-composer-field {
        flex: 1;
        min-width: 0;
        position: relative;
        padding: 4px;
      }
      .pc-composer-placeholder {
        font-size: var(--size-text-md);
        line-height: var(--lh-text-md);
        color: var(--text-muted);
        opacity: 0.75;
        white-space: nowrap;
      }
      .pc-caret {
        position: absolute;
        left: 4px;
        top: calc(50% + 0.5px);
        transform: translateY(-50%);
        width: 1px;
        height: 20px;
        border-radius: 1px;
        background: var(--bg-200);
      }
      .pc-composer-bar {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 12px;
      }
      .pc-model {
        height: 32px;
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 0 4px 0 8px;
      }
      .pc-model span {
        font-family: var(--font-serif);
        font-size: 14px;
        line-height: 1.6;
        color: var(--text-primary);
        font-feature-settings: normal;
        white-space: nowrap;
      }
      .pc-send {
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        background: var(--brand-000);
        border: 0.5px solid var(--border-secondary);
        border-radius: 8px;
        filter: drop-shadow(var(--shadow-low));
      }
      .pc-send .icon {
        width: 16px;
        height: 16px;
      }
      .pc-send .icon > img {
        inset: 10.92% 17.18%;
        width: 65.64%;
        height: 78.14%;
      }
      .pc-composer-right {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        gap: 8px;
      }

      /* =============================================================
         MOBILE — node 15:1503, 402 × 874
         The bezel is presentation only; the Figma frame is the inner
         402 × 874 surface.
         ============================================================= */
      .device {
        padding: 10px;
        background: #0d0d0c;
        border-radius: 54px;
      }
      .mobile {
        position: relative;
        width: 402px;
        height: 874px;
        background: var(--bg-100);
        border-radius: 44px;
        overflow: hidden;
        display: flex;
        flex-direction: column;
      }

      .m-statusbar {
        position: relative;
        flex-shrink: 0;
        width: 100%;
        height: 50px;
        padding-top: 21px;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
      .m-statusbar-row {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: space-between;
      }
      .m-time {
        flex: 1;
        min-width: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0 6px 0 16px;
        font-family: -apple-system, "SF Pro Text", system-ui, sans-serif;
        font-size: 17px;
        font-weight: 590;
        line-height: 22px;
        color: var(--text-primary);
      }
      .m-island {
        width: 124px;
        height: 10px;
        flex-shrink: 0;
      }
      .m-levels {
        flex: 1;
        min-width: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 7px;
        padding: 0 16px 0 6px;
      }

      .m-navbar {
        position: relative;
        flex-shrink: 0;
        width: 100%;
        height: 54px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 16px;
      }
      .m-nav-btn {
        position: relative;
        width: 44px;
        height: 44px;
        border-radius: var(--radius-full);
        background: var(--bg-transparent);
        box-shadow: var(--shadow-panel);
        flex-shrink: 0;
      }
      .m-nav-btn > .icon {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
      }
      .m-nav-title {
        width: 280px;
        height: 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding-left: 16px;
        flex-shrink: 0;
      }
      .m-nav-title span {
        font-size: 17px;
        font-weight: 600;
        line-height: 1.4;
        color: var(--text-primary);
        white-space: nowrap;
      }
      .m-nav-caret {
        height: 100%;
        display: flex;
        align-items: center;
        padding-top: 4px;
      }

      .m-thread {
        flex: 1;
        min-height: 0;
        overflow-x: hidden;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        padding: 10px 16px 16px;
        display: flex;
        flex-direction: column;
        gap: 12px;
      }

      .m-user-row {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        gap: 5px;
      }
      .m-user-bubble {
        width: 226px;
        max-width: 312px;
        padding: 14px 16px;
        background: var(--bg-300);
        border-radius: var(--radius-xl-touch);
        font-size: 15px;
        line-height: 1.4;
        color: var(--default-text-100);
      }

      /* --- output controls + signature --- */
      .m-tail {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
      }
      .m-controls {
        width: 100%;
        height: 44px;
        display: flex;
        align-items: center;
        gap: 8px;
      }
      .m-signature {
        width: 100%;
        height: 44px;
        display: flex;
        align-items: center;
        gap: 16px;
      }
      .m-signature-text {
        flex: 1;
        min-width: 0;
        padding: 0 2px;
        font-size: 11px;
        line-height: 1.5;
        color: var(--text-muted);
        text-align: right;
      }

      /* --- composer, pinned to the bottom of the phone --- */
      .m-composer {
        position: relative;
        flex-shrink: 0;
        width: calc(100% - 32px);
        height: 100px;
        margin: 0 16px 16px;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        background: var(--bg-transparent);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
        border-radius: var(--radius-xl-touch);
        box-shadow: var(--shadow-panel);
        overflow: hidden;
      }
      .m-composer-field {
        width: 100%;
        height: 48px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding: 12px 16px;
        font-size: 15px;
        line-height: 1.4;
        color: var(--text-tertiary);
      }
      .m-composer-bar {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 8px;
      }
      .m-composer-group {
        display: flex;
        align-items: center;
        gap: 4px;
      }
      .m-round-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 6px;
        border-radius: 79px;
        overflow: hidden;
      }
      .m-voice {
        width: 36px;
        height: 36px;
        display: flex;
        align-items: center;
        justify-content: center;
        background: var(--text-primary);
        border-radius: 18px;
        overflow: hidden;
        flex-shrink: 0;
      }
