/*
 * Pi Pocket's theme: soft tiles over an Omarchy palette. The palette is the Omarchy theme's colors.toml (theme.js sets
 * the --o-* variables, from a bundled theme or the desktop's own); everything else mixes from it the way omarchy-shell
 * does: the foreground over the background at a few percent for fills and hairlines. Windows still tile like
 * Hyprland's, with rounded corners, 1px hairlines, and a soft accent ring on the one in focus. Geist sets the words;
 * JetBrains Mono only code, paths, branches, numbers, counts, and keys. Motion keeps Hyprland's curves.
 */
/*
 * Contents, in the order the cascade reads them. Search for "─── " and a name to jump to a section. A rule later in
 * the file wins over an earlier one of the same specificity, and some later sections restyle earlier ones on purpose:
 * move a rule only after checking what it crosses.
 *
 *   Fonts, tokens, and the reset   the palette's variables, light themes, scrollbars, base elements
 *   Motion                         Hyprland's curves, reduced motion, the theme reveal
 *   Loaders                        the boot screen, the spinner
 *   Layout                         windows on a desktop, the sidebar's edge
 *   Top bar
 *   Transcript                     messages, Pi's replies, code blocks, answer actions, arrivals, chevrons
 *   Tool cards                     what Pi did: activity groups and their timelines, approvals, the live line
 *   Composer                       the queue, slash commands, file mentions, the message box, the bar under it
 *   Extensions                     extension cards, and the switch every sheet uses
 *   Sessions                       the sidebar: tabs, groups, rows, selection, its foot
 *   The rail, The home screen
 *   Sheets                         sheets on phones, popups on wide screens, the drawer
 *   Pop-up menus                   the model and branch pickers
 *   Sheet parts and controls       sheet heads and bodies, menu rows, fields, buttons, segmented choices, checks,
 *                                  providers, invites
 *   Artifact viewer, Images
 *   Notices, sign-in, plain pages  also the server's own pages (sign-in, invites)
 *   People                         who is here, typing, the side chat
 *   Collaboration                  activity, quotes, mentions, pins, notes, reactions, take turns
 *   Parts of sheets                share, schedules, goals, running now, changes, spend
 *   Launcher, Appearance
 *   Sign in                        the app's sign-in screen
 *   Small glue                     the sheet host, viewers leaving, search keys, unread dots
 *   People panel, Peek tiles
 *   Diff viewer, Review            one file's diff, and every change in the folder file by file
 *   Files tile, Browser            the docked panels
 *   Files, commands, and find      file paths and mentions, `!` commands and notes, changes, the file viewer, find,
 *                                  messages sent before
 *   Syntax and rich markdown       code colors, and pages, images, and diffs drawn in replies
 *   Fluid motion                   Appearance's Fluid: springs, staggered arrivals, morphing layout; last, to win
 */

/* ─── Fonts, tokens, and the reset ───────────────────────────── */

@font-face {
    font-family: "Pocket Mono";
    src: url("/fonts/JetBrainsMono.woff2") format("woff2");
    font-weight: 100 800;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Sans";
    src: url("/fonts/Geist.woff2") format("woff2");
    font-weight: 100 900;
    font-display: swap;
}

/* Each font's own italic, which a browser downloads only when italic text shows (comments in code, emphasis). Fira
   Code has none: the browser slants its upright letters. */
@font-face {
    font-family: "Pocket Mono";
    src: url("/fonts/JetBrainsMono-Italic.woff2") format("woff2");
    font-weight: 100 800;
    font-style: italic;
    font-display: swap;
}

/* More fonts for themes to name in --sans and --mono (docs/extensions/themes.md lists them). A browser downloads one only
   when a theme uses it. */

/* The Nerd Fonts icons alone (their Mono build: one cell wide), in the private use areas they fill. */
@font-face {
    font-family: "Pocket Nerd Symbols";
    src: url("/fonts/NerdFontsSymbolsMono.woff2") format("woff2");
    font-display: swap;
    unicode-range: U+E000-F8FF, U+F0000-F1AF0;
}

@font-face {
    font-family: "Pocket Fira Code";
    src: url("/fonts/FiraCode-VF.woff2") format("woff2");
    font-weight: 300 700;
    font-display: swap;
}

@font-face {
    font-family: "Pocket IBM Plex Mono";
    src: url("/fonts/IBMPlexMono-Variable.woff2") format("woff2");
    font-weight: 100 700;
    font-display: swap;
}

@font-face {
    font-family: "Pocket IBM Plex Mono";
    src: url("/fonts/IBMPlexMono-Variable-Italic.woff2") format("woff2");
    font-weight: 100 700;
    font-style: italic;
    font-display: swap;
}

/* Iosevka has no variable font: the weights the app uses, upright and italic. 800 shows as 700, 100 as 400. Each file
   keeps every character but drops the optional letter variants (ss and cv features) the app never turns on, which
   were three quarters of its size. */
@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-Regular.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-SemiBold.woff2") format("woff2");
    font-weight: 600;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-Bold.woff2") format("woff2");
    font-weight: 700;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-Italic.woff2") format("woff2");
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-SemiBoldItalic.woff2") format("woff2");
    font-weight: 600;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Iosevka";
    src: url("/fonts/Iosevka-BoldItalic.woff2") format("woff2");
    font-weight: 700;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Inter";
    src: url("/fonts/InterVariable.woff2") format("woff2");
    font-weight: 100 900;
    font-display: swap;
}

@font-face {
    font-family: "Pocket Inter";
    src: url("/fonts/InterVariable-Italic.woff2") format("woff2");
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
}

:root {
    /* The palette. These defaults are Tokyo Night; theme.js replaces them. */
    --o-bg: #1a1b26;
    --o-bg-dark: #13141c;
    --o-bg-darker: #0e0e14;
    --o-bg-light: #24283b;
    --o-fg: #a9b1d6;
    --o-fg-dim: #565f89;
    --o-fg-light: #b4bee6;
    --o-fg-bright: #c0caf5;
    --o-accent: #7aa2f7;
    --o-selection: #292e42;
    --o-red: #f7768e;
    --o-yellow: #e0af68;
    --o-orange: #eb927b;
    --o-green: #9ece6a;
    --o-cyan: #449dab;
    --o-blue: #7aa2f7;
    --o-magenta: #ad8ee6;

    /* Surfaces, after omarchy-shell's control states: the foreground laid over the background. */
    --desk: var(--o-bg-darker);
    --bg: var(--o-bg);
    --panel: var(--bg);
    --card: color-mix(in srgb, var(--body) 4%, var(--bg));
    --card-2: color-mix(in srgb, var(--body) 8%, var(--bg));
    /* A selected segment, raised from its track. */
    --raised: color-mix(in srgb, var(--body) 12%, var(--bg));
    --hover: color-mix(in srgb, var(--body) 7%, transparent);
    --pressed: color-mix(in srgb, var(--body) 18%, transparent);
    --line: color-mix(in srgb, var(--body) 13%, var(--bg));
    --line-strong: color-mix(in srgb, var(--body) 26%, var(--bg));
    --edge: color-mix(in srgb, var(--body) 25%, transparent);
    /* Hairlines: the usual 1px line, and a stronger one (fields, a switch's track while off). */
    --hair: color-mix(in srgb, var(--body) 10%, transparent);
    --hair-2: color-mix(in srgb, var(--body) 17%, transparent);
    --text: var(--o-fg-bright);
    --body: var(--o-fg);
    /* Quieter text at 4.5:1 or more on the ground (WCAG AA) with every palette that comes with the app. */
    --muted: color-mix(in oklab, var(--body) 76%, var(--bg));
    --faint: color-mix(in oklab, var(--body) 42%, var(--bg));
    --accent: var(--o-accent);
    --accent-ink: var(--bg);
    /* The accent as a fill under text (buttons, badges): darker in light themes, so text on it stays readable. */
    --accent-fill: var(--accent);
    --accent-soft: color-mix(in srgb, var(--accent) 14%, transparent);
    --accent-line: color-mix(in srgb, var(--accent) 50%, transparent);
    /* The keyboard's focus ring: keep it visible (a theme may change its color, never take it away). */
    --focus-ring: var(--accent);
    /* The second color of loaders and thoughts. */
    --spark: var(--o-magenta);
    /* A second accent, for what a theme draws in two colors (Hyprland's active border is a gradient): the app uses none. */
    --accent-2: var(--spark);
    --brand: var(--o-orange);
    --ok: var(--o-green);
    --ok-soft: color-mix(in srgb, var(--o-green) 14%, transparent);
    --warn: var(--o-yellow);
    --warn-soft: color-mix(in srgb, var(--o-yellow) 10%, transparent);
    --warn-line: color-mix(in srgb, var(--o-yellow) 42%, transparent);
    --err: var(--o-red);
    --err-soft: color-mix(in srgb, var(--o-red) 14%, transparent);
    --err-line: color-mix(in srgb, var(--o-red) 50%, transparent);
    --code-bg: var(--o-bg-dark);
    /* Syntax colors, from the theme's own palette so every Omarchy theme colors code its way. */
    --hl-kw: var(--o-magenta);
    --hl-str: var(--o-green);
    --hl-num: var(--o-orange);
    --hl-fn: var(--o-blue);
    --hl-type: var(--o-yellow);
    --hl-op: var(--o-cyan);
    --hl-tag: var(--o-red);
    --scrim: color-mix(in srgb, var(--desk) 55%, transparent);
    /* Shadows: a soft lift (the message box), and what floats over the page (popovers, sheets, the launcher, PiP). */
    --sh: rgba(0, 0, 0, 0.5);
    --shadow: 0 18px 40px -18px var(--sh), 0 2px 6px -2px var(--sh);
    --pop: 0 24px 60px -16px var(--sh), 0 0 0 1px var(--hair-2);
    /*
     * Corners, from small to large: state squares; inline code, keys, and small tags; a segment in its track; small
     * buttons and list rows; icon buttons, fields, and segmented tracks; cards and primary buttons; windows, approval
     * cards, and peek tiles; the message box, sheets, and the launcher; PiP. Pills and avatars are round (999px).
     */
    --r-mark: 2px;
    --r-tag: 4px;
    --r-seg: 5px;
    --r-row: 6px;
    --r-control: 7px;
    --r-card: 8px;
    --r-window: 10px;
    --r-sheet: 12px;
    --r-float: 12px;
    --r-pill: 999px;
    /* Fields and plain controls that name no corner of their own. */
    --radius: var(--r-control);
    /* Hyprland's layout, softened: gaps_out 8, gaps_in 4, border_size 1. */
    --gap-out: 8px;
    --gap-in: 4px;
    --border: 1px;
    /* The conversation's column, and the message box under it, at their widest; room before the conversation's turns. */
    --transcript-width: clamp(720px, 72%, 1200px);
    --composer-width: calc(var(--transcript-width) + 48px);
    --transcript-gutter: 0px;
    /* The timeline in an activity group: where its rule and the centers of its marks are, the marks' size, and the gap
     * from a mark to its words (and to what a step shows under them). */
    --timeline-x: 22.5px;
    --step-mark-size: 19px;
    --step-gap: 10px;
    /* Tiled windows' border, the one in focus, and the ring around that one. */
    --window-border: var(--hair);
    --window-border-active: var(--accent-line);
    --window-ring: 0 0 0 3px var(--accent-soft);
    /* What shows in the gaps between tiled windows: the desktop's wallpaper when Appearance asks for it (inline), else this. */
    --wallpaper: none;
    /*
     * Density, from Appearance (`data-density`): how much room the spacing takes. Padding and gaps from top to bottom
     * scale by --space-y, and from side to side by --space-x; --leading is the conversation's line height. Rows that
     * are tap targets keep a floor on touch screens. Font sizes, corners, and colors stay as they are.
     */
    --space-y: 1;
    --space-x: 1;
    --leading: 1.65;

    /* Motion: Omarchy's Hyprland curves, and its speeds in milliseconds. */
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* easeOutQuint */
    --ease-in-out: cubic-bezier(0.65, 0.05, 0.36, 1); /* easeInOutCubic */
    --ease-almost: cubic-bezier(0.5, 0.5, 0.75, 1); /* almostLinear */
    --t-in: 410ms; /* windowsIn */
    --t-out: 150ms; /* windowsOut */
    --t-fade: 175ms; /* fadeIn */
    --t-border: 540ms; /* border */
    --t-hover: 140ms;
    /* Fluid motion's own (Appearance → Motion → Fluid): a spring that settles with a 2% overshoot (damping 0.78), a
     * glide that slows to rest without one, an exit that speeds away, and the step between staggered arrivals. */
    --ease-spring: linear(
        0,
        0.005 1.3%,
        0.037 3.7%,
        0.109 6.8%,
        0.222 10.5%,
        0.362 14.6%,
        0.514 19.2%,
        0.66 24.3%,
        0.785 29.6%,
        0.882 35.4%,
        0.95 41.4%,
        0.992 47.8%,
        1.013 54.4%,
        1.02 61.4%,
        1.019 68.6%,
        1.014 76.1%,
        1.009 83.8%,
        1.005 91.8%,
        1
    );
    --ease-glide: cubic-bezier(0.16, 1, 0.3, 1); /* easeOutExpo */
    --ease-exit: cubic-bezier(0.4, 0, 1, 1);
    --t-spring: 560ms;
    --t-glide: 420ms;
    --t-exit: 150ms;
    --stagger: 24ms;

    /* Ligatures: none, as in a terminal. A theme may turn on a font's own (`contextual`, `normal`). */
    --ligatures: none;
    --mono:
        "Pocket Mono", "Pocket Nerd Symbols", "JetBrains Mono", "JetBrainsMono Nerd Font",
        ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    --sans: "Pocket Sans", "Geist", ui-sans-serif, system-ui, sans-serif;
    color-scheme: dark;
}

:root[data-density="compact"] {
    --space-y: 0.7;
    --space-x: 0.85;
    --leading: 1.5;
}

:root[data-density="tight"] {
    --space-y: 0.45;
    --space-x: 0.7;
    --leading: 1.4;
}

/* Light themes: quieter text and the status colors darken toward the foreground, so they stay readable on light grounds. */
:root[data-mode="light"] {
    color-scheme: light;
    --sh: rgba(40, 40, 70, 0.14);
    --accent-ink: #fff;
    --scrim: color-mix(in srgb, var(--desk) 55%, transparent);
    --line: color-mix(in srgb, var(--body) 15%, var(--bg));
    --muted: color-mix(in oklab, var(--body) 87%, var(--bg));
    --faint: color-mix(in oklab, var(--body) 58%, var(--bg));
    --warn: color-mix(in oklab, var(--o-yellow) 62%, var(--o-fg));
    --ok: color-mix(in oklab, var(--o-green) 78%, var(--o-fg));
    --err: color-mix(in oklab, var(--o-red) 85%, var(--o-fg));
    --accent-fill: color-mix(in oklab, var(--accent) 76%, var(--body));
    /* Code's colors further still: halfway, yellow (the lightest) more, so each reads at 3:1 or better. */
    --hl-kw: color-mix(in oklab, var(--o-magenta) 50%, var(--o-fg));
    --hl-str: color-mix(in oklab, var(--o-green) 50%, var(--o-fg));
    --hl-num: color-mix(in oklab, var(--o-orange) 50%, var(--o-fg));
    --hl-fn: color-mix(in oklab, var(--o-blue) 50%, var(--o-fg));
    --hl-type: color-mix(in oklab, var(--o-yellow) 40%, var(--o-fg));
    --hl-op: color-mix(in oklab, var(--o-cyan) 50%, var(--o-fg));
    --hl-tag: color-mix(in oklab, var(--o-red) 50%, var(--o-fg));
}

* {
    box-sizing: border-box;
    /* No ligatures, as in a terminal: code shows the characters it has (=== stays three). Important, because each
     * `font` shorthand would reset it; a theme changes it through --ligatures (`contextual` for a font's `calt`). */
    font-variant-ligatures: var(--ligatures) !important;
}

html,
body {
    margin: 0;
    height: 100%;
    background: var(--desk);
    color: var(--body);
    font: 14px / 1.55 var(--sans);
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
}

#app {
    height: 100dvh;
}

button,
input,
textarea,
select {
    font: inherit;
    color: inherit;
}

button {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

/* iOS zooms into any text field smaller than 16px when it takes focus. Important, so a theme's size for a field (in a
 * later layer, which beats this one) does not bring the zoom back on touch screens. */
@media (pointer: coarse) {
    input,
    textarea,
    select {
        font-size: 16px !important;
    }
}

input,
textarea,
select {
    background: var(--card);
    border: 1px solid var(--hair-2);
    border-radius: var(--radius);
    padding: 0.6rem 0.75rem;
    width: 100%;
    outline: none;
    color: var(--text);
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    input:hover,
    textarea:hover,
    select:hover {
        border-color: var(--edge);
    }
}

input:focus,
textarea:focus,
select:focus {
    border-color: var(--accent-line);
}

::placeholder {
    color: var(--muted);
    opacity: 1;
}

::selection {
    background: color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--text);
}

:focus-visible {
    outline: 1px solid var(--focus-ring);
    outline-offset: 1px;
}

/* A field's ring lies on its own border, not a second line beside it. */
input:not([type="checkbox"], [type="radio"]):focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline-offset: -1px;
}

a {
    color: var(--accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

/* Thin round scrollbars, on hairline thumbs. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--hair-2) transparent;
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-thumb {
    background: var(--hair-2);
    border: 2px solid transparent;
    border-radius: var(--r-pill);
    background-clip: padding-box;
}

@media (hover: hover) {
    ::-webkit-scrollbar-thumb:hover {
        background-color: var(--muted);
    }
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
    background: transparent;
}

kbd {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    font: 600 11px/1 var(--mono);
    color: var(--text);
    background: var(--card);
    border: 1px solid var(--hair-2);
    border-bottom-width: 2px;
    border-radius: calc(var(--r-tag) + 1px);
    vertical-align: middle;
}

.mono {
    font-family: var(--mono);
}

.muted {
    color: var(--muted);
}

.small {
    font-size: 0.8rem;
}

.grow {
    flex: 1;
}

.meter {
    display: inline-flex;
    height: 4px;
    border-radius: calc(var(--r-mark) - 1px);
    overflow: hidden;
    background: var(--hair-2);
}

.meter > span {
    background: var(--accent);
}

.meter.warn > span {
    background: var(--warn);
}

.meter.err > span {
    background: var(--err);
}

.warn {
    color: var(--warn);
}

.ok {
    color: var(--ok);
}

.err {
    color: var(--err);
}

.pi {
    font-family: Georgia, "Times New Roman", serif;
    color: var(--brand);
}

/* ─── Motion ───────────────────────────────────────────────── */

/* Hyprland's popin 87%: what opens grows from 87% and fades in. */
@keyframes popin {
    from {
        opacity: 0;
        transform: scale(0.87);
    }
}

@keyframes popout {
    to {
        opacity: 0;
        transform: scale(0.87);
    }
}

@keyframes fade {
    from {
        opacity: 0;
    }
}

@keyframes fade-out {
    to {
        opacity: 0;
    }
}

@keyframes rise-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
}

/* What floats over the page (popovers, sheets, the launcher) rises a little and grows from 98% as it fades in. */
@keyframes pop {
    from {
        opacity: 0;
        transform: translateY(6px) scale(0.98);
    }
}

@keyframes pop-out {
    to {
        opacity: 0;
        transform: translateY(6px) scale(0.98);
    }
}

/* Reduced motion (the system's, or Appearance's): no movement, apart from what says something is working. */
:root[data-motion="reduced"] *,
:root[data-motion="reduced"] *::before,
:root[data-motion="reduced"] *::after {
    animation-duration: 1ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0s !important;
}

:root[data-motion="reduced"] .spinner::before {
    transform: translate(calc(100% + 2px), 0);
}

:root[data-motion="reduced"] .boot-bar span {
    transform: scaleX(0.7);
}

/* Theme changes: the new look grows as a circle from where it was chosen (theme.js sets the place). */
:root.theme-vt::view-transition-old(root),
:root.theme-vt::view-transition-new(root) {
    animation: none;
    mix-blend-mode: normal;
}

:root.theme-vt::view-transition-new(root) {
    animation: theme-reveal 0.75s var(--ease-out);
}

@keyframes theme-reveal {
    from {
        clip-path: circle(0 at var(--vt-x, 50%) var(--vt-y, 50%));
    }
    to {
        clip-path: circle(var(--vt-r, 150vmax) at var(--vt-x, 50%) var(--vt-y, 50%));
    }
}

/* ─── Loaders, after Omarchy's ───────────────────────────────── */

/* The boot screen: π over a flat square bar (Omarchy's boot screen) that eases toward 70% while it waits. */
.boot {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.1rem;
    height: 100dvh;
    padding: 1.5rem;
    font-family: var(--mono);
    color: var(--muted);
    text-align: center;
    background: var(--bg);
    animation: fade 0.3s var(--ease-almost);
}

.boot.inline {
    height: 100%;
    min-height: 16rem;
    background: none;
}

.boot-mark {
    font:
        4.5rem/1 Georgia,
        "Times New Roman",
        serif;
    color: var(--brand);
    animation: boot-breathe 2.4s var(--ease-in-out) infinite;
}

@keyframes boot-breathe {
    50% {
        opacity: 0.55;
    }
}

.boot.inline .boot-mark {
    font-size: 3rem;
}

.boot-bar {
    width: min(300px, 64vw);
    height: 8px;
    background: var(--line);
    overflow: hidden;
}

/* Scaled, not sized: a width would lay the page out on each frame, while the session it waits for loads. */
.boot-bar span {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--body);
    transform: scaleX(0);
    transform-origin: left;
    animation: boot-fill 15s cubic-bezier(0.12, 0.6, 0.3, 1) forwards;
}

@keyframes boot-fill {
    to {
        transform: scaleX(0.7);
    }
}

.boot-caption {
    font-size: 0.75rem;
    letter-spacing: 0.14em;
    text-transform: lowercase;
}

.boot-detail {
    max-width: 32ch;
    font-size: 0.75rem;
    line-height: 1.5;
    opacity: 0.8;
}

/* The inline spinner: one lit quadrant stepping around a square (▖▘▝▗), from the accent toward the spark. */
.spinner {
    position: relative;
    display: inline-block;
    flex: none;
    width: 0.85em;
    height: 0.85em;
    min-width: 11px;
    min-height: 11px;
    vertical-align: -0.1em;
    background:
        linear-gradient(var(--line), var(--line)) 0 0 / calc(50% - 1px) calc(50% - 1px) no-repeat,
        linear-gradient(var(--line), var(--line)) 100% 0 / calc(50% - 1px) calc(50% - 1px) no-repeat,
        linear-gradient(var(--line), var(--line)) 0 100% / calc(50% - 1px) calc(50% - 1px) no-repeat,
        linear-gradient(var(--line), var(--line)) 100% 100% / calc(50% - 1px) calc(50% - 1px)
            no-repeat;
}

.spinner::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: calc(50% - 1px);
    height: calc(50% - 1px);
    background: var(--accent);
    animation: quadrant 0.8s steps(1, end) infinite;
}

@keyframes quadrant {
    0% {
        transform: translate(0, calc(100% + 2px));
        background: var(--accent);
    }
    25% {
        transform: translate(0, 0);
        background: color-mix(in oklab, var(--accent) 67%, var(--spark));
    }
    50% {
        transform: translate(calc(100% + 2px), 0);
        background: color-mix(in oklab, var(--accent) 33%, var(--spark));
    }
    75% {
        transform: translate(calc(100% + 2px), calc(100% + 2px));
        background: var(--spark);
    }
}

.loader {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.6rem 0.1rem;
    font-size: 0.85rem;
    color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"], [data-motion="fluid"]) .pulse,
    :root:not([data-motion="full"], [data-motion="fluid"]) .live-dot,
    :root:not([data-motion="full"], [data-motion="fluid"]) .agents-dot.working,
    :root:not([data-motion="full"], [data-motion="fluid"]) .session-working,
    :root:not([data-motion="full"], [data-motion="fluid"]) .session-placeholder span {
        animation: none !important;
    }
}

.icon {
    flex: none;
}

/* ─── Layout: windows on a desktop ─────────────────────────── */

/*
 * The notch and the rounded corners at a phone's sides when it lies on its side (0 on every other screen). Only the
 * parts at a side edge keep clear of them (the rail, the top bar, the message box, what the conversation holds), so
 * their backgrounds still run to the edge. A sidebar owns the left edge from 960px up, and tiled windows sit inside
 * the layout's own padding, which takes the insets: neither leaves the left inset to the pane.
 */
:root {
    --inset-l: env(safe-area-inset-left);
    --inset-r: env(safe-area-inset-right);
}

@media (min-width: 960px) {
    :root {
        --inset-l: 0px;
    }
}

.layout {
    display: flex;
    height: 100dvh;
    background: var(--bg);
}

/* The sidebar and the conversation are windows. On wide screens with tiling on, they tile like Hyprland's, softened:
 * gaps over the desktop (or its wallpaper), rounded corners and a hairline, and a soft accent ring on the one in focus. */
.window {
    position: relative;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
}

/* The sidebar: the rail and the session list beside it, cut off rather than squeezed while it folds and unfolds. Wider
 * than usual, it takes 40% of the screen at most (`sessions.js` drags to the same), so the conversation keeps room. */
.sidebar {
    display: none;
    width: min(var(--sidebar-w, 312px), max(312px, 40vw));
    padding-left: env(safe-area-inset-left);
    flex: none;
    flex-direction: row;
    border-right: 1px solid var(--hair);
    background: var(--panel);
    transition: width var(--t-in) var(--ease-out);
}

.sidebar-clip {
    flex: 1;
    min-width: 0;
    display: flex;
    overflow: hidden;
}

:root.resizing .sidebar {
    transition: none;
}

:root.resizing,
:root.resizing * {
    cursor: col-resize !important;
    user-select: none;
}

.pane {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    height: 100dvh;
}

/* The home screen scrolls inside the window: the window itself must not clip its active border. */
.layout.home .pane {
    min-height: 0;
}

.home-list {
    width: 100%;
    flex: 1;
    min-height: 0;
    display: flex;
}

/* The rail at the screen's edge, as the sidebar's is; the list beside it no wider than reads well, centered. */
.home-list > .sessions {
    max-width: 584px;
    margin: 0 auto;
}

/* The rail keeps its buttons clear of the notch, and its line stays at their edge; the list keeps clear of the other side. */
.home-list > .rail {
    width: calc(56px + var(--inset-l));
    padding-left: var(--inset-l);
}

.home-list > .sessions {
    padding-right: calc(12px + var(--inset-r));
}

/* A short screen (a phone on its side): the rail drops its marks (Pi, and the sessions it is on) so its buttons fit,
 * and the home list puts its search and tabs side by side, so more sessions show (where they fit). */
@media (max-height: 500px) {
    .rail {
        gap: 2px;
    }
    .rail > :is(span.rail-brand, span.rail-brand + .rail-gap, span.rail-button) {
        display: none;
    }
}

/* A phone on its side (touch, and too short for any tablet): the list takes the whole width, not a column in the
 * middle. A short desktop window keeps its column. */
@media (max-height: 500px) and (min-width: 600px) and (pointer: coarse) {
    .home-list > .sessions {
        max-width: none;
    }
}

/* Side by side only where both fit: a short window that is also narrow keeps them stacked. */
@media (max-height: 500px) and (min-width: 600px) {
    .home-list > .sessions {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-rows: auto auto minmax(0, 1fr);
        column-gap: 8px;
    }
    .home-list > .sessions > * {
        grid-column: 1 / -1;
    }
    .home-list > .sessions > .search {
        grid-column: 1;
    }
    .home-list > .sessions > .session-tabs {
        grid-column: 2;
        margin-top: 12px;
    }
}

.splash {
    display: none;
}

@media (min-width: 960px) {
    .sidebar {
        display: flex;
    }
    .layout.home .home-list {
        display: none;
    }
    .splash {
        display: flex;
    }
    .topbar > .icon-button:first-child {
        display: none;
    }
    /* Folded: the rail alone, and the sidebar's border. */
    :root[data-rail="on"] .sidebar {
        width: calc(57px + env(safe-area-inset-left));
    }
    :root[data-tiling="on"][data-rail="on"] .sidebar {
        width: calc(56px + 2 * var(--border));
    }
    :root[data-tiling="on"] .sidebar {
        padding-left: 0;
    }

    :root[data-tiling="on"] .layout {
        --inset-r: 0px;
        padding: var(--gap-out) calc(var(--gap-out) + env(safe-area-inset-right)) var(--gap-out)
            calc(var(--gap-out) + env(safe-area-inset-left));
        gap: calc(var(--gap-in) * 2);
        background: var(--desk) var(--wallpaper, none) center / cover no-repeat;
    }
    /* Rounded, so what they hold is cut to their corners; the edges to drag sit inside them. */
    :root[data-tiling="on"] .window {
        border: var(--border) solid var(--window-border);
        border-radius: var(--r-window);
        overflow: hidden;
        height: auto;
        animation: popin var(--t-in) var(--ease-out) backwards;
        transition:
            border-color var(--t-border) var(--ease-out),
            box-shadow var(--t-border) var(--ease-out);
    }
    :root[data-tiling="on"] .pane {
        animation-delay: 60ms;
    }
    :root[data-tiling="on"][data-focus="sidebar"] .sidebar,
    :root[data-tiling="on"][data-focus="browser-panel"] .browser,
    :root[data-tiling="on"][data-focus="files-panel"] .files-tile,
    :root[data-tiling="on"][data-focus="extension-panel"] .ext-panel,
    :root[data-tiling="on"][data-focus="people-panel"] .people,
    :root[data-tiling="on"]:not([data-focus="sidebar"]):not([data-focus="browser-panel"]):not(
            [data-focus="files-panel"]
        ):not([data-focus="extension-panel"]):not([data-focus="people-panel"]):not(
            [data-focus="peeks"]
        )
        .pane {
        border-color: var(--window-border-active);
        box-shadow: var(--window-ring);
    }
}

/* Drag the sidebar's edge to resize it; double-click puts it back. Inside the window, which cuts off what is past it. */
.resize-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 8px;
    cursor: col-resize;
    z-index: 7;
    touch-action: none;
}

/* A sidebar a theme put on the right: its handle is on its left edge (`useSide`). */
.resize-handle.at-left {
    left: 0;
    right: auto;
}

.resize-handle::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 3px;
    width: 2px;
    height: 36px;
    margin-top: -18px;
    border-radius: 1px;
    background: var(--accent);
    opacity: 0;
    transform: scaleY(0.4);
    transition:
        opacity var(--t-hover) var(--ease-out),
        transform var(--t-in) var(--ease-out);
}

:root.resizing .resize-handle::before {
    opacity: 1;
    transform: none;
}

@media (hover: hover) {
    .resize-handle:hover::before {
        opacity: 1;
        transform: none;
    }
}

:root[data-rail="on"] .resize-handle {
    display: none;
}

/* ─── Top bar ──────────────────────────────────────────────── */

/*
 * The session's title over its folder and branch, what changed, the toggles, who is here, and the menu. The bar is as
 * wide as its pane and answers to that width, not the screen's: the room left decides which buttons show.
 */
.topbar {
    container: topbar / inline-size;
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: calc(46px + 12px * var(--space-y) + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) var(--inset-r) 0 var(--inset-l);
    border-bottom: 1px solid var(--hair);
    background: var(--bg);
}

/* Its room is the container's: the margins, not padding, keep the buttons off the edges. */
.topbar > :last-child {
    margin-right: 10px;
}

/*
 * The top bar keeps only the buttons with something to say (a page open, artifacts made, people here): the menu's
 * tiles open the rest. The peek and Files toggles always show where there is room (`top-toggle`, below).
 */
.topbar .quiet {
    display: none;
}

/*
 * On a phone a few more go to the places by the message box, which show the same (artifacts made, a page open): the
 * top bar's buttons are a thumb wide each and must leave room for the title and the menu.
 */
@media (max-width: 699px) {
    .topbar .quiet-phone {
        display: none;
    }
}

/* Its buttons: quiet, and lit in the accent while what they open is open. */
.topbar .icon-button {
    width: 36px;
    height: 36px;
    color: var(--muted);
}

@media (hover: hover) {
    .topbar .icon-button:hover {
        color: var(--text);
    }
}

.topbar .icon-button.on {
    background: var(--accent-soft);
    color: var(--accent);
}

/* Who is here: an avatar with its online mark, and how many more, in a pill that lights while the panel is open. */
.topbar .people-button {
    height: 36px;
    min-width: 36px;
    padding: 0 4px;
    border-radius: var(--r-pill);
    color: var(--muted);
}

.topbar .people-button.on {
    background: var(--accent-soft);
    color: var(--accent);
}

.topbar .online-mark {
    width: 8px;
    height: 8px;
}

.topbar .avatar,
.rail .avatar {
    font-size: 11px;
}

/* Below the sidebar's width the top bar leads back to the session list, each button a thumb wide. */
@media (max-width: 959px) {
    .topbar {
        gap: 2px;
    }
    .topbar > :first-child {
        margin-left: 4px;
    }
    .topbar > :last-child {
        margin-right: 6px;
    }
    .topbar > .title {
        margin-left: -8px;
    }
    .topbar > .icon-button {
        width: 44px;
        min-width: 44px;
        height: 44px;
    }
    /* As wide as who is here: an avatar, and how many more. */
    .topbar > .people-button {
        min-width: 44px;
        height: 44px;
    }
    /* Over the title's button, whose box reaches a little under it. */
    .topbar > .topbar-back {
        z-index: 1;
        color: var(--text);
    }
    /* Out past the chevron's tip, so it covers neither the arrow nor the title. */
    .topbar > .topbar-back .badge {
        top: -2px;
        right: 0;
    }
}

/* The room in the pane: the changes lose their count of files under 560px, the toggles go under 480px, then the
 * avatars under 420px. The widths are the pane's less its 2px of border (tiled windows). */
@container topbar (max-width: 557px) {
    .changes-button .changes-files {
        display: none;
    }
}

@container topbar (max-width: 477px) {
    .topbar .top-toggle {
        display: none;
    }
}

@media (min-width: 700px) {
    @container topbar (max-width: 417px) {
        .topbar .people-button {
            display: none;
        }
    }
}

/* The title and its line under it open the menu, all but the branch, which opens the branch picker. */
.title {
    position: relative;
    flex: 1;
    min-width: 120px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: calc(4px * var(--space-y)) 8px;
    margin-left: 12px;
    border-radius: var(--r-row);
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .title:has(> .title-open:hover) {
        background: var(--hover);
    }
}

/* Over the whole title, under the branch. */
.title-open {
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

.title-open:focus-visible {
    outline-offset: -1px;
}

.title-main {
    font-weight: 600;
    font-size: 15px;
    line-height: 1.3;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The folder's color and last part, then the branch. Keep its row while loading so the title stays put. */
.title-sub {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    min-height: 20px;
    font-size: 12px;
    line-height: 20px;
    color: var(--muted);
    white-space: nowrap;
}

.title-sub > span {
    flex: none;
}

.title-sub > .folder-mark {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--folder, var(--accent));
}

/* The folder's name stays whole (up to a share of the line); the branch gives way first. */
.title-sub > .title-folder {
    flex: none;
    max-width: 55%;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A subagent's line names its parent session instead, which may take the whole line. */
.title-sub > .title-folder.title-parent {
    flex: 0 1 auto;
    max-width: none;
    min-width: 0;
}

/* The branch: a small tag with the fork mark, cut short from its end when the room is short. */
.title-sub > .title-branch {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 1 auto;
    min-width: 0;
    height: 20px;
    padding: 0 7px;
    border-radius: calc(var(--r-tag) + 1px);
    background: var(--card);
    font: 11px / 1 var(--mono);
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.title-branch-name {
    min-width: 2ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Over the title's button, which takes the taps around it. */
.title-sub > button.title-branch {
    position: relative;
    z-index: 1;
}

@media (hover: hover) {
    .title-sub > button.title-branch:hover {
        color: var(--accent);
        background: var(--card-2);
    }
}

.title-sub > .title-worktree {
    font-size: 11.5px;
    color: var(--faint);
}

/* A phone shows the branch as plain mono text, as the design's phone board does. */
@media (max-width: 699px) {
    .title-sub > .title-branch {
        padding: 0;
        background: none;
        color: var(--faint);
    }
    .title-branch .icon {
        display: none;
    }
    @media (hover: hover) {
        .title-sub > button.title-branch:hover {
            background: none;
        }
    }
}

/*
 * A thumb's height on a touch screen, with its look kept: a layer past the branch takes the tap. The line under the
 * title is a little taller there, so that room stays in the top bar; the layer reaches into the bottom of the title's
 * line above (its descenders), and the rest of the title opens the menu.
 */
@media (pointer: coarse) {
    .title {
        padding-block: 0;
    }
    .title-sub {
        min-height: 24px;
    }
    .title-sub > button.title-branch::after {
        content: "";
        position: absolute;
        inset: -10px -8px -9px;
    }
}

/* What changed in the session's folder: lines added and removed, and how many files. */
.changes-button {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 30px;
    padding: 0 12px;
    border: 1px solid var(--hair);
    border-radius: var(--r-pill);
    background: var(--card);
    font-size: 12px;
    color: var(--muted);
    transition: border-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .changes-button:hover {
        border-color: var(--hair-2);
    }
}

.changes-button .added,
.changes-button .removed {
    font-family: var(--mono);
}

.changes-button .added {
    color: var(--ok);
}

.changes-button .removed {
    margin-left: -3px;
    color: var(--err);
}

@media (max-width: 959px) {
    .changes-button {
        margin-right: 4px;
    }
}

/* A phone: the counts alone, in a slimmer pill. */
@media (max-width: 699px) {
    .changes-button {
        height: 28px;
        padding: 0 10px;
        font-size: 11.5px;
    }
}

.icon-button {
    width: 40px;
    height: 40px;
    display: inline-grid;
    place-items: center;
    border-radius: var(--r-control);
    color: var(--muted);
    position: relative;
    flex: none;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

/* Not on touch screens, where a tapped button would keep the fill. */
@media (hover: hover) {
    .icon-button:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.icon-button:active {
    background: var(--pressed);
    transform: scale(0.94);
}

.icon-button.small {
    width: 24px;
    height: 24px;
}

.badge-host .badge,
.icon-button .count {
    position: absolute;
    top: 3px;
    right: 2px;
    min-width: 17px;
    height: 17px;
    border-radius: var(--radius);
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-size: 0.68rem;
    font-weight: 700;
    display: grid;
    place-items: center;
    padding: 0 4px;
    animation: popin var(--t-in) var(--ease-out);
}

.badge.warn {
    background: var(--warn);
    color: var(--accent-ink);
    border-radius: var(--radius);
    min-width: 18px;
    display: inline-grid;
    place-items: center;
    font-weight: 700;
    font-size: 0.7rem;
}

/* ─── Transcript ───────────────────────────────────────────── */

.scroller {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Room for the scrollbar on both sides, kept whether or not it shows: the column stays put, centered over the
     * message box, when a session long enough to scroll opens. */
    scrollbar-gutter: stable both-edges;
    position: relative;
    /* The room it gives, for what may run wider than the column (a reply's code blocks and tables, below): the
     * browser's own measure as it lays out, inside the scroll bar's gutters, so no script restyles the conversation
     * after it is drawn. A fixed or sticky element in it keeps its place: inline-size containment makes neither a
     * containing block nor a stacking context. */
    container-type: inline-size;
    padding-inline: var(--inset-l) var(--inset-r);
}

/* A column of turns: a person's message, what Pi did, Pi's reply, an approval, the live line. Its text size is
 * Appearance's; the cards inside keep fixed sizes. */
.transcript {
    max-width: var(--transcript-width);
    margin: 0 auto;
    padding: calc(28px * var(--space-y)) calc(28px * var(--space-x)) calc(24px * var(--space-y));
    padding-inline-start: calc(28px * var(--space-x) + var(--transcript-gutter));
    display: flex;
    flex-direction: column;
    gap: calc(16px * var(--space-y));
    font-size: var(--text-size, 15px);
    line-height: var(--leading);
}

/* A session opened rises into place; on a phone, where the route slides it in, the slide alone (`transcript.js`). */
.transcript.rising {
    animation: rise-in 0.36s var(--ease-out);
}

/* Turns stand apart: 10px more before each message or report (less at a tighter density). */
.transcript > :is(.user-row, .report, .report-group):not(:first-child) {
    margin-top: calc(10px * var(--space-y));
}

@media (max-width: 699px) {
    .transcript {
        padding: calc(18px * var(--space-y)) calc(16px * var(--space-x)) calc(14px * var(--space-y));
        padding-inline-start: calc(16px * var(--space-x) + var(--transcript-gutter));
    }
}

/* What arrives while the session is open slides up into place: a message sent, or Pi starting to answer. */
.enter {
    animation: rise-in 0.42s var(--ease-out) backwards;
}

.empty {
    display: grid;
    place-items: center;
    gap: 0.6rem;
    padding: 3rem 1rem;
    text-align: center;
    color: var(--muted);
}

.empty .pi {
    font-size: 3.2rem;
    opacity: 0.8;
}

.breadcrumb {
    align-self: flex-start;
    text-align: left;
    color: var(--accent);
    font-size: 13px;
    display: inline-flex;
    gap: 0.25rem;
    align-items: center;
}

.linked-sessions {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

.linked-sessions .breadcrumb {
    min-height: 40px;
    max-width: 100%;
    overflow-wrap: anywhere;
}

/* The explicit parent route stays beside the message box on every layout, even when the dock scrolls. */
.parent-session {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 44px;
    padding: 8px 12px;
    margin-bottom: 6px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--card);
    color: var(--accent);
    font-size: 12.5px;
    text-align: left;
}

@media (hover: hover) {
    .parent-session:hover {
        background: var(--hover);
    }
}

.parent-session > :not(.parent-session-title) {
    flex-shrink: 0;
}

.parent-session-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--muted);
}

/* A person's message: a card, with who and when over what they wrote. Scoped to its row: the launcher's input has a
 * `.prompt` of its own. */
.user-row > .prompt {
    display: flex;
    flex-direction: column;
    gap: calc(4px * var(--space-y));
    padding: calc(12px * var(--space-y)) calc(16px * var(--space-x)) calc(14px * var(--space-y));
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    background: var(--card);
    color: var(--text);
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (max-width: 699px) {
    .user-row > .prompt {
        padding: calc(12px * var(--space-y)) calc(14px * var(--space-x)) calc(13px * var(--space-y));
        border-radius: calc(var(--r-window) + 2px);
    }
}

.user-row > .prompt.tappable {
    cursor: pointer;
}

@media (hover: hover) {
    .user-row > .prompt.tappable:hover {
        background: var(--card-2);
    }
}

.prompt-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 8px;
    min-width: 0;
    font-size: 12.5px;
    line-height: 22px;
}

/* Yours takes the accent, someone else's their color (`--who`), anyone else a quiet one. */
.prompt-avatar {
    flex: none;
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--who) 20%, transparent);
    color: var(--who);
    font-size: 9.5px;
    font-weight: 600;
    line-height: 1;
}

.prompt-author {
    font-weight: 600;
    color: var(--text);
}

.prompt-time {
    color: var(--faint);
}

.prompt-body {
    min-width: 0;
    padding-left: 30px;
}

.user-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-wrap: pretty;
}

/* What a PR watch or a webhook fenced for Pi (a check's log, a post): a block of its own, scrolling past a few lines. */
.fenced-data {
    margin: 0.4rem 0;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--code-bg);
    overflow: hidden;
}

.fenced-label {
    padding: 4px 12px;
    border-bottom: 1px solid var(--hair);
    color: var(--muted);
    font-size: 12px;
}

.fenced-data pre {
    margin: 0;
    padding: 8px 12px;
    max-height: 14rem;
    overflow: auto;
    font: 12px / 1.55 var(--mono);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.attachments,
.files {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-top: 0.35rem;
}

/* Pi's words: plain prose, without a container. */
.reply {
    display: flex;
    flex-direction: column;
    gap: calc(10px * var(--space-y));
    min-width: 0;
    color: var(--body);
}

.reply > .md {
    display: flex;
    flex-direction: column;
    gap: calc(12px * var(--space-y));
}

.reply > .md > *,
.reply > .md > :where(.md-part) > * {
    margin: 0;
}

.reply > .md :is(h1, h2, h3, h4) {
    margin-top: calc(6px * var(--space-y));
}

.reply > .md li + li {
    margin-top: calc(4px * var(--space-y));
}

.reply > .md p {
    text-wrap: pretty;
}

.md {
    overflow-wrap: anywhere;
}

.md > :first-child {
    margin-top: 0;
}

.md > :last-child {
    margin-bottom: 0;
}

.md p,
.md ul,
.md ol {
    margin: 0.45rem 0;
}

/* Real lists, with a 20px column for the marker (`1.` or `•`), quiet. */
.md ul,
.md ol {
    padding-left: 20px;
}

.md li::marker {
    color: var(--muted);
    font-size: 13px;
}

.md h1,
.md h2,
.md h3,
.md h4 {
    margin: 0.9rem 0 0.4rem;
    color: var(--text);
    font-weight: 600;
    line-height: 1.4;
}

.md h1 {
    font-size: 1.2em;
}

.md h2 {
    font-size: 1.1em;
}

.md h3,
.md h4 {
    font-size: 1em;
}

.md code {
    padding: 2px 6px;
    border-radius: var(--r-tag);
    background: var(--card-2);
    color: var(--text);
    font: 12.5px var(--mono);
}

.md strong {
    color: var(--text);
    font-weight: 600;
}

/*
 * A reply's code blocks and tables may run wider than its words, up to the pane's room (the scroller's width, `cqi`)
 * less the column's padding. A code block as wide as its longest line, at least the column's width, centered on the
 * column; a table as wide as its cells, from the column's start toward the pane's edge. On a phone, and in a pane no
 * wider than the column, the room is the column, so nothing changes.
 */
.transcript {
    --wide-room: max(100%, calc(100cqi - 56px * var(--space-x) - var(--transcript-gutter)));
}

[data-part~="reply"] :is(.md, .md-part) > .code {
    position: relative;
    left: 50%;
    width: max-content;
    min-width: 100%;
    max-width: var(--wide-room);
    translate: -50%;
}

/* Words in a code block (a draft to copy, say) wrap in the column, as a reply's words do: a paragraph on one line would
 * otherwise run the pane's width and still scroll sideways. A block with no language is text too, as its label says,
 * unless the app draws it (a page or a picture: `data-kind`). */
.code:not([data-kind])
    > pre:is(
        :not([data-lang]),
        [data-lang="text" i],
        [data-lang="txt" i],
        [data-lang="plaintext" i],
        [data-lang="markdown" i],
        [data-lang="md" i]
    ) {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

[data-part~="reply"]
    :is(.md, .md-part)
    > .code:not([data-kind]):has(
        > pre:is(
                :not([data-lang]),
                [data-lang="text" i],
                [data-lang="txt" i],
                [data-lang="plaintext" i],
                [data-lang="markdown" i],
                [data-lang="md" i]
            )
    ) {
    left: 0;
    width: auto;
    max-width: 100%;
    translate: none;
}

[data-part~="reply"] :is(.md, .md-part) > table:not(.dv-table) {
    width: max-content;
    max-width: calc(100% + (var(--wide-room) - 100%) / 2);
}

/* A reply's own tables, in a card; a diff it shows draws its table itself. */
.md table:not(.dv-table) {
    display: block;
    max-width: fit-content;
    overflow-x: auto;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.93em;
}

.md table:not(.dv-table) :is(td, th) {
    padding: 6px 12px;
    text-align: left;
    /* Words break only when longer than the cell can be, and a cell keeps room for a few words: a crowded table
     * scrolls sideways instead of crushing its columns. */
    overflow-wrap: break-word;
    min-width: 12ch;
}

.md table:not(.dv-table) th {
    background: var(--card);
    color: var(--text);
    font-weight: 600;
}

.md table:not(.dv-table) :is(td, th):not(:last-child) {
    border-right: 1px solid var(--hair);
}

.md table:not(.dv-table) tr:not(:last-child) > :is(td, th) {
    border-bottom: 1px solid var(--hair);
}

.md hr {
    height: 0;
    margin: 1.1em 0;
    border: 0;
    border-top: 1px solid var(--hair);
}

.md blockquote {
    margin: 0.5rem 0;
    padding-left: 0.8rem;
    border-left: 2px solid var(--hair-2);
    color: var(--muted);
}

/* A code block: a bar with its file or language and Copy, then the code. */
.code {
    position: relative;
    margin: 0.5rem 0;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--code-bg);
    overflow: hidden;
}

.code-head {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 6px 0 14px;
    border-bottom: 1px solid var(--hair);
    font-size: 12px;
    color: var(--muted);
}

.code-lang {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: lowercase;
}

.code-head .copy {
    flex: none;
    height: 24px;
    margin-left: auto;
    padding: 0 9px;
    border-radius: var(--r-seg);
    font-size: 12px;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .code-head .copy:hover {
        color: var(--text);
        background: var(--hover);
    }
}

.md pre {
    margin: 0;
    padding: 12px 14px;
    overflow-x: auto;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--code-bg);
    font: 12.5px / 1.6 var(--mono);
}

.code pre {
    border: 0;
    border-radius: 0;
    background: none;
}

.md pre code {
    background: none;
    padding: 0;
    font-size: inherit;
    color: var(--body);
}

/* In the conversation, code follows Appearance's text size, as the prose does: 12.5px at the usual 15px. */
.transcript .md code,
.transcript .md pre {
    font-size: calc(var(--text-size, 15px) * 5 / 6);
}

.md.streaming > :last-child:not(.md-part)::after {
    content: "█";
    margin-left: 1px;
    color: var(--accent);
    animation: blink 1s steps(2) infinite;
}

@keyframes blink {
    50% {
        opacity: 0;
    }
}

/* Chevrons turn instead of swapping: closed points right, open points down. */
.chev {
    transition: transform 0.3s var(--ease-out);
}

.open > button > .chev,
.chev.open {
    transform: rotate(90deg);
}

/* A panel opening below its header: revealed from the top down. */
@keyframes unroll {
    from {
        clip-path: inset(0 0 100% 0);
        opacity: 0.3;
    }
    to {
        clip-path: inset(0 0 0 0);
    }
}

/* Under Pi's answers: reactions, then React, Discuss, Pin, Copy, and More. */
.answer-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-height: 26px;
    font-size: 12.5px;
    line-height: 1.6;
}

.reaction {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 26px;
    padding: 0 10px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-pill);
    color: var(--text);
    white-space: nowrap;
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.reaction > span {
    font: 11.5px var(--mono);
}

@media (hover: hover) {
    .reaction:hover {
        border-color: var(--edge);
    }
}

.reaction.mine {
    border-color: var(--accent-line);
    background: var(--accent-soft);
}

.answer-actions > button.answer-tool,
.reaction.add {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex: none;
    height: 26px;
    padding: 0 8px;
    border: 0;
    border-radius: var(--r-seg);
    color: var(--muted);
    white-space: nowrap;
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out),
        opacity var(--t-fade) var(--ease-out);
}

@media (hover: hover) {
    .answer-actions > button.answer-tool:hover,
    .reaction.add:hover {
        color: var(--text);
        background: var(--hover);
    }
}

/* With a mouse they show while the reply is hovered; touch screens always show them. */
@media (hover: hover) and (pointer: fine) {
    .reply .answer-actions > .answer-tool {
        opacity: 0;
        transition: opacity var(--t-fade) var(--ease-out);
    }
    .reply:hover .answer-actions > .answer-tool,
    .answer-actions:focus-within > .answer-tool,
    .answer-actions.picking > .answer-tool {
        opacity: 1;
    }
}

.reaction-host {
    position: relative;
    display: inline-flex;
}

/* The six emoji, in a popover over the button. */
.reaction-picker {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    z-index: 5;
    display: flex;
    gap: 2px;
    padding: 4px;
    border-radius: var(--r-card);
    background: var(--panel);
    box-shadow: var(--pop);
    animation: pop 0.2s var(--ease-out);
}

.reaction-picker button {
    width: 32px;
    height: 32px;
    border-radius: var(--r-row);
    font-size: 17px;
    line-height: 1;
}

@media (hover: hover) {
    .reaction-picker button:hover {
        background: var(--hover);
    }
}

/* ─── Tool cards ───────────────────────────────────────────── */

/* What Pi did between its words: a card with one line ("Read 2 files, ran 1 command · 18s") that opens into a
 * timeline. */
.activity {
    min-width: 0;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow: hidden;
}

.entry-anchor {
    display: block;
    height: 0;
}

/* One between rows takes no room: the gap before it is taken back. */
.entry-mark {
    margin-top: calc(-16px * var(--space-y));
}

.activity-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    /* 40px, 35px, and 30px; a thumb's 34px at least on a touch screen. */
    min-height: calc(22px + 18px * var(--space-y));
    padding: 0 calc(12px * var(--space-x));
    text-align: left;
    font-size: 13px;
    line-height: 1.5;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.activity.open > .activity-head {
    border-bottom: 1px solid var(--hair);
}

@media (hover: hover) {
    .activity-head:hover {
        color: var(--text);
        background: var(--hover);
    }
}

/* Inside a card that cuts off what is past it. */
:is(.activity-head, .step-head):focus-visible {
    outline-offset: -2px;
}

.activity-summary {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.activity-failed {
    flex: none;
    padding: 1px 7px;
    border-radius: var(--r-pill);
    background: var(--err-soft);
    color: var(--err);
    font: 500 11px var(--sans);
}

.activity-time {
    flex: none;
    font: 11.5px var(--mono);
    font-variant-numeric: tabular-nums;
    color: var(--faint);
}

.activity-time.live {
    color: var(--accent);
}

/* The timeline: a line per call, each with its mark on a thin rule. */
.timeline {
    position: relative;
    padding: calc(6px * var(--space-y)) 0;
}

/* A group that is one thought alone: its words, under the line that names it. */
.activity-thought {
    padding: calc(10px * var(--space-y)) calc(12px * var(--space-x)) calc(12px * var(--space-y));
}

/* What a person opened unrolls (`unrolling`, transcript.js); what opens by itself (a session's open groups, a group
 * that goes live) shows at once. A clip-path is painted on each frame, which a phone cannot spare as a session opens. */
:is(.timeline, .activity-thought, .step-body).unrolling {
    animation: unroll var(--t-in) var(--ease-out);
}

/* Above a long group's newest steps: it shows the rest, from the rule's left. */
.timeline-earlier {
    display: block;
    margin: 0 0 calc(4px * var(--space-y))
        calc(var(--timeline-x) + var(--step-mark-size) / 2 + var(--step-gap));
    padding: 4px 0;
}

.timeline::before {
    content: "";
    position: absolute;
    left: calc(var(--timeline-x) - 0.5px);
    top: 20px;
    bottom: 20px;
    width: 1px;
    background: var(--hair-2);
}

.step {
    position: relative;
    min-width: 0;
}

.step-line {
    display: flex;
    align-items: center;
    min-width: 0;
}

.step-head {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--step-gap);
    min-height: 34px;
    padding: 0 14px 0 calc(var(--timeline-x) - var(--step-mark-size) / 2);
    text-align: left;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .step-head:hover {
        background: var(--hover);
    }
}

/* Just finished: the line flashes its success color once. */
.step.settled > .step-line > .step-head {
    animation: settle 0.9s var(--ease-out);
}

@keyframes settle {
    from {
        background-color: color-mix(in srgb, var(--ok) 14%, transparent);
    }
}

/* How the call went, in a circle on the rule: its tint over the window's color, so the rule does not show through. */
.step-mark {
    --tint: var(--card-2);
    flex: none;
    display: grid;
    place-items: center;
    width: var(--step-mark-size);
    height: var(--step-mark-size);
    border-radius: 50%;
    background: linear-gradient(var(--tint), var(--tint)), var(--bg);
    box-shadow: 0 0 0 3px var(--bg);
    color: var(--muted);
    font: 600 10px / 1 var(--mono);
    transition:
        background-color var(--t-border) var(--ease-out),
        color var(--t-border) var(--ease-out);
}

.step-mark.done {
    --tint: var(--ok-soft);
    color: var(--ok);
}

.step-mark.error {
    --tint: var(--err-soft);
    color: var(--err);
}

.step-mark.asking {
    --tint: var(--warn-soft);
    color: var(--warn);
    box-shadow:
        inset 0 0 0 1px var(--warn-line),
        0 0 0 3px var(--bg);
}

.step-mark.spinning,
.step-mark.agent {
    --tint: var(--accent-soft);
    color: var(--accent);
}

.step-mark.thought {
    --tint: color-mix(in srgb, var(--spark) 16%, transparent);
    color: var(--spark);
}

/* Light themes' magenta can be faint as text on their ground: toward the foreground, as code's colors are. */
:root[data-mode="light"] .step-mark.thought {
    color: color-mix(in oklab, var(--spark) 60%, var(--body));
}

.step-label {
    flex: none;
    max-width: 45%;
    font: 600 12.5px var(--mono);
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.step-subject {
    flex: 1;
    min-width: 0;
    font: 12.5px var(--mono);
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.step-meta {
    flex: none;
    max-width: 40%;
    font: 12px var(--mono);
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
}

.step-meta.ok {
    color: var(--ok);
}

.step-meta.warn {
    color: var(--warn);
}

.step-meta.err {
    color: var(--err);
}

/* A subagent's line goes to it. */
.step-open {
    flex: none;
    height: 28px;
    margin-right: 8px;
    padding: 0 8px;
    border-radius: var(--r-seg);
    font-size: 12px;
    color: var(--accent);
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .step-open:hover {
        background: var(--hover);
    }
}

/* Who allowed or denied a call Lancet Guard asked about. */
.step-decision {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 14px 6px calc(var(--timeline-x) + var(--step-mark-size) / 2 + var(--step-gap));
    font-size: 12px;
    color: var(--muted);
}

.step-decision.allowed .icon {
    color: var(--ok);
}

.step-decision.denied .icon {
    color: var(--err);
}

/* Under a line, in line with its words: what the call made, and once tapped, its input and output. */
.step-extras,
.step-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
    margin: 2px 14px 10px calc(var(--timeline-x) + var(--step-mark-size) / 2 + var(--step-gap));
}

.step-extras + .step-body {
    margin-top: 0;
}

.step-extras > .thumbs {
    margin-top: 0;
}

.step-extras > .artifact-preview {
    max-width: min(100%, 420px);
}

.step-extras > .artifact-preview img {
    max-height: 240px;
}

.thought-body {
    max-height: 50vh;
    overflow: auto;
    padding: 10px 12px;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--code-bg);
    font-size: 13px;
    line-height: 1.55;
    color: var(--muted);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.tool-note {
    white-space: pre-wrap;
    font-size: 13px;
    color: var(--muted);
}

.step-body .dv-block {
    border-radius: var(--r-control);
    overflow: hidden;
    font-size: 0.76rem;
    line-height: 1.6;
}

pre.output,
pre.cmd,
pre.diff {
    margin: 0;
    padding: 10px 12px;
    max-height: 45vh;
    overflow: auto;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--code-bg);
    color: var(--body);
    font: 12px / 1.55 var(--mono);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

pre.cmd {
    color: var(--ok);
}

pre.output.error {
    color: var(--err);
}

pre.diff .add {
    color: var(--ok);
}

pre.diff .del {
    color: var(--err);
}

.cmd-sign {
    color: var(--faint);
}

/* An artifact a call made, or the browser it used: a way there. */
.artifact-link {
    align-self: flex-start;
    max-width: 100%;
    min-height: 30px;
    padding: 0 8px;
    margin-left: -8px;
    border-radius: var(--r-seg);
    text-align: left;
    font-size: 12.5px;
    color: var(--accent);
    overflow-wrap: anywhere;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .artifact-link:hover {
        background: var(--hover);
    }
}

/* A subagent's report: a card. */
.report {
    padding: 12px 14px;
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    background: var(--card);
}

.report.failed {
    border-color: var(--err-line);
}

/* Reports that arrived together, as one message to Pi: a card each. */
.report-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.report-head {
    display: flex;
    gap: 0.4rem;
    align-items: center;
    margin-bottom: 4px;
    font-size: 13px;
    color: var(--muted);
}

.report-name {
    color: var(--text);
    font-weight: 600;
    font-family: var(--mono);
}

.report-why {
    color: var(--err);
    font-size: 13px;
    overflow-wrap: anywhere;
}

/* Lancet Guard asks before a call: at the end of the turn, until someone answers. */
.approval {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--warn-line);
    border-radius: calc(var(--r-window) + 2px);
    background: var(--warn-soft);
    animation: pop 0.35s var(--ease-out);
}

.approval-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.approval-shield {
    flex: none;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: var(--r-row);
    background: color-mix(in srgb, var(--o-yellow) 16%, transparent);
    color: var(--warn);
}

.approval-title {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.approval-ask {
    font-size: 14.5px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text);
}

.approval-reason {
    font-size: 13px;
    line-height: 1.5;
    color: var(--muted);
}

.approval pre.cmd {
    padding: 10px 12px;
    border: 0;
    font-size: 12.5px;
    line-height: 1.5;
}

/* An extension's question for the person Pi works for (`host.ask`): a field for each value, a thumb's height. */
.ask-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 13px;
    color: var(--muted);
}

.ask-field input {
    min-height: 40px;
    padding: 8px 10px;
    border: 1px solid var(--line);
    border-radius: var(--r-control);
    background: var(--bg);
    color: var(--text);
    font: inherit;
    font-size: 15px;
}

.approval-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.approval-actions .button {
    height: 36px;
    padding: 0 16px;
    border-radius: var(--r-control);
    font-size: 13.5px;
}

.approval-actions .button.primary {
    padding: 0 18px;
}

/* The shared button's least height is 38px; touch screens keep their thumb height. */
@media not (pointer: coarse) {
    .approval-actions .button {
        min-height: 0;
    }
}

.approval-actions .button.deny {
    border-color: transparent;
    background: var(--card-2);
    color: var(--text);
}

@media (hover: hover) {
    .approval-actions .button.deny:hover {
        color: var(--err);
    }
}

/* On a phone: the answers share the width, thumb-tall. */
@media (max-width: 699px) {
    .approval {
        padding: 14px;
    }

    .approval-shield {
        width: 30px;
        height: 30px;
    }

    .approval-ask {
        font-size: 14px;
    }

    .approval-actions {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }

    .approval-actions .button {
        height: 42px;
        border-radius: calc(var(--r-control) + 1px);
        font-size: 14px;
    }
}

/* The live turn's last line: what Pi does now, for how long, and how to stop it. */
.live-line {
    display: flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    padding: 2px 2px 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--muted);
    animation: fade var(--t-fade) var(--ease-almost);
}

/* A dot with a soft ring, pulsing; the warning color while a call waits for an approval. */
.live-dot {
    flex: none;
    width: 8px;
    height: 8px;
    margin-inline: 4px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 4px var(--accent-soft);
    animation: pulse 1.4s infinite;
}

.live-line.waiting .live-dot {
    background: var(--warn);
    box-shadow: 0 0 0 4px var(--warn-soft);
}

.live-state {
    flex: none;
    color: var(--accent);
}

.live-line.waiting .live-state {
    color: var(--warn);
}

.live-time {
    flex: none;
    font: 11.5px var(--mono);
    font-variant-numeric: tabular-nums;
    color: var(--faint);
}

.live-why {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.live-line .live-limit {
    flex: none;
    font-variant-numeric: tabular-nums;
}

.live-retry {
    flex: none;
    padding: 1px 8px;
    font: inherit;
    font-size: 12px;
    color: var(--accent);
    background: transparent;
    border: 1px solid var(--accent-soft);
    border-radius: var(--r-control);
    cursor: pointer;
}

.live-retry:hover {
    background: var(--accent-soft);
}

/* Narrow: the line wraps, so the wait's facts and Retry now stay inside the column. */
@media (max-width: 600px) {
    .live-line {
        flex-wrap: wrap;
        row-gap: 2px;
    }

    .live-line .live-limit {
        flex: 0 1 auto;
    }

    .live-why {
        flex: 1 1 100%;
    }
}

.live-esc {
    flex: none;
    margin-left: auto;
    font: 11px var(--mono);
    color: var(--faint);
}

/*
 * Show thinking adds the timeline's bare chevron before the dot. It turns up when open, toward the thought above the
 * line. Its hit area reaches past the glyph without drawing a box, and the gap after it stays the line's own.
 */
.live-fold {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 14px;
    height: 14px;
    margin-right: -4px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--faint);
    position: relative;
    transition: color var(--t-hover) var(--ease-out);
}

.live-fold::before {
    content: "";
    position: absolute;
    inset: -8px;
}

.live-fold.open {
    color: var(--muted);
}

.live-fold.open > .chev {
    transform: rotate(-90deg);
}

@media (hover: hover) {
    .live-fold:hover {
        color: var(--body);
    }
}

@media (pointer: coarse) {
    .live-fold::before {
        inset: -13px;
    }
}

/* A quiet reading area, not another timeline card. The existing Thought steps and their boxes are unchanged. */
.live-thought {
    min-width: 0;
    padding: 10px 14px 12px;
    border-radius: var(--r-card);
    background: var(--card);
    animation: fade var(--t-fade) var(--ease-almost);
}

.live-thought-label {
    margin-bottom: 4px;
    color: var(--faint);
    font-size: 11.5px;
}

.live-thought-text {
    max-height: min(32vh, 260px);
    overflow-y: auto;
    overscroll-behavior: contain;
    overflow-wrap: anywhere;
    white-space: pre-wrap;
    font-size: 13px;
    line-height: 1.65;
    color: var(--muted);
}

.live-thought-text.is-empty {
    color: var(--faint);
}

.live-thought-text.streaming::after {
    content: "";
    display: inline-block;
    width: 2px;
    height: 1em;
    margin-left: 3px;
    vertical-align: -2px;
    background: var(--accent);
    animation: blink 1s steps(2) infinite;
}

.error-box {
    padding: 10px 14px;
    border: 1px solid var(--err-line);
    border-radius: var(--r-card);
    background: var(--err-soft);
    color: var(--err);
    font-size: 13.5px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.divider {
    text-align: center;
    color: var(--muted);
    font-size: 13px;
    border-top: 1px solid var(--hair);
    padding-top: 0.5rem;
}

.divider-body {
    text-align: left;
    margin-top: 0.5rem;
    font-size: 13.5px;
}

.history {
    display: flex;
    flex-direction: column;
    gap: 16px;
    opacity: 0.75;
}

.history > :is(.user-row, .report, .report-group):not(:first-child) {
    margin-top: 10px;
}

.pulse {
    width: 7px;
    height: 7px;
    border-radius: var(--radius);
    background: var(--accent);
    display: inline-block;
    animation: pulse 1.4s infinite;
}

@keyframes pulse {
    50% {
        opacity: 0.35;
    }
}

/* The way back to the newest message. */
.jump {
    position: sticky;
    bottom: 0.8rem;
    left: 100%;
    margin-right: 0.8rem;
    width: 40px;
    height: 40px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-pill);
    background: var(--bg);
    box-shadow: var(--shadow);
    color: var(--body);
    display: grid;
    place-items: center;
    float: right;
    animation: popin var(--t-in) var(--ease-out);
    transition:
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

@media (hover: hover) {
    .jump:hover {
        border-color: var(--accent-line);
        color: var(--accent);
    }
}

.jump:active {
    transform: scale(0.92);
}

/* ─── Composer ─────────────────────────────────────────────── */

.composer-wrap {
    padding: 4px calc(24px * var(--space-x) + var(--inset-r))
        calc(env(safe-area-inset-bottom) + 12px * var(--space-y))
        calc(24px * var(--space-x) + var(--inset-l));
    max-width: var(--composer-width);
    width: 100%;
    margin: 0 auto;
}

@media (max-width: 699px) {
    .composer-wrap {
        padding-inline: calc(12px * var(--space-x) + var(--inset-l))
            calc(12px * var(--space-x) + var(--inset-r));
    }
}

/*
 * What is above the message box: who is typing, the queue, and the bars. `dock.js` shares its room: the bars show
 * whole, and the queue and the subagents' list take what is left of its share, and scroll.
 */
.inbox-count {
    display: none;
    height: 1.25rem;
    line-height: 1.25rem;
    margin: 0 0 0.25rem 0.1rem;
    color: var(--muted);
    font-size: 12px;
}

/* How many wait, when the queue does not show them all. */
.dock[data-count="on"] > .inbox-count {
    display: block;
}

/* Folded for the subagents' list: out of sight, its rows still laid out for `dock.js` to measure. */
.dock[data-queue="folded"] > .inbox {
    visibility: hidden;
}

/* Too little room even so (a phone on its side with every bar up): the dock stops, and scrolls. */
.dock[data-capped] {
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* There, a swipe on the queue that reaches its end goes on to scroll the dock, to the bars below it. */
.dock[data-capped] > .inbox {
    overscroll-behavior: auto;
}

/* Little room for the conversation: each bar keeps one line, its words cut short, its buttons whole. */
.dock[data-compact] > :is(.plan-bar, .goal-bar, .watch-bar, .trust-bar) {
    flex-wrap: nowrap;
}

.dock[data-compact] > :is(.plan-bar, .goal-bar, .watch-bar, .trust-bar) > .grow {
    flex: 1 1 0;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dock[data-compact] > :is(.plan-bar, .goal-bar, .watch-bar, .trust-bar) > :not(.grow) {
    flex: none;
    white-space: nowrap;
}

.dock[data-compact] .trust-actions {
    gap: 0.5rem;
}

/* Messages waiting for Pi: a few rows' height at most, so the conversation stays in view; more scroll inside. */
.inbox {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 6px;
    max-height: min(28vh, 12rem);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* A message waiting for Pi: Steer or Queue, what it says, and a way to take it back. */
.queued {
    /* Its own height in a queue that scrolls: shrunk, the dock would measure it smaller and let it grow again. */
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 34px;
    padding: 0 4px 0 12px;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--card);
    font-size: 13px;
}

.queued-mode {
    color: var(--accent);
    font-weight: 600;
    flex: none;
}

.queued-text {
    flex: 1;
    min-width: 0;
    align-self: stretch;
    padding: 0;
    color: var(--text);
    font: inherit;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Tapped: what the queue holds of the message (its start), wrapped (the queue scrolls past a few lines), with who sent it
   and its × at its top. */
.queued-text.open {
    padding: 8px 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.queued:has(> .queued-text.open) {
    align-items: flex-start;
}

.queued:has(> .queued-text.open) > .queued-mode {
    padding-top: 8px;
}

.queued:has(> .queued-text.open) > .queued-remove {
    margin-top: 4px;
}

.queued .queued-remove {
    width: 26px;
    height: 26px;
    color: var(--muted);
}

/* Tapped open, one's own message: a row of buttons under it to move it to Steer or Queue, or send it now. */
.queued:has(> .queued-actions) {
    flex-wrap: wrap;
}

.queued-actions {
    flex-basis: 100%;
    display: flex;
    gap: 6px;
    padding-bottom: 8px;
}

/* Interrupt, tapped once: the color of stopping the run. */
.queued-actions .button.danger {
    border-color: var(--err);
    color: var(--err);
}

/* A thumb's room around the small mark. */
@media (pointer: coarse) {
    .queued .queued-remove::after {
        content: "";
        position: absolute;
        inset: -8px -4px;
    }
}

/* Slash commands: suggestions while typing a name, then a hint for the one that will run. */
.commands {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-bottom: 6px;
    padding: 4px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    max-height: 40vh;
    overflow-y: auto;
    animation: rise-in 0.3s var(--ease-out);
}

.command {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    width: 100%;
    text-align: left;
    padding: 7px 10px;
    border-radius: var(--r-row);
    font-size: 13px;
    transition: background-color var(--t-hover) var(--ease-out);
}

.command.on {
    background: var(--hover);
}

@media (hover: hover) {
    .command:hover {
        background: var(--hover);
    }
}

.command-name {
    color: var(--accent);
    flex: none;
}

.command-args {
    color: var(--muted);
    flex: none;
}

.command-description {
    color: var(--muted);
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* File mentions: an icon, the name with what matched marked, then its folder. */
.file-option {
    align-items: center;
}

.file-icon {
    flex: none;
    color: var(--muted);
}

.file-option.on .file-icon {
    color: var(--accent);
}

.file-name {
    flex: none;
    max-width: 60%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-option mark {
    background: none;
    color: var(--accent);
    font-weight: 700;
}

.file-note {
    font-size: 12.5px;
    color: var(--muted);
    padding: 7px 10px;
}

.command-hint.wraps {
    white-space: normal;
}

.command-hint {
    font-size: 12.5px;
    padding: 0 10px 6px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The message box: a card that takes the accent's line while it has the focus. */
.composer {
    container: composer / inline-size;
    position: relative;
    background: var(--card);
    border: 1px solid var(--hair-2);
    border-radius: var(--r-sheet);
    box-shadow: var(--shadow);
    transition: border-color var(--t-border) var(--ease-out);
}

.composer:focus-within {
    border-color: var(--accent-line);
}

@media (max-width: 699px) {
    .composer {
        border-radius: var(--r-float);
    }
}

.composer .files {
    margin: 0;
    padding: 10px 14px 0;
}

/* One line to start with, growing with the text (`fitBox`). */
.composer textarea {
    display: block;
    border: 0;
    border-radius: 0;
    outline: none;
    background: none;
    color: var(--text);
    resize: none;
    padding: calc(14px * var(--space-y)) calc(16px * var(--space-x)) 2px;
    max-height: 40vh;
    font-size: 15px;
    line-height: 1.5;
    /* As tall as what is written, to the most above; browsers without this measure it in script (`fitBox`). */
    field-sizing: content;
}

/* Touch screens keep 16px, below which iOS zooms into the field. */
@media (pointer: coarse) {
    .composer textarea {
        padding: calc(13px * var(--space-y)) calc(15px * var(--space-x)) 2px;
        font-size: 16px;
    }
    /* The status line's own room below it is enough. */
    .composer-wrap {
        padding-bottom: calc(env(safe-area-inset-bottom) + 2px);
    }
}

.composer-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: calc(6px * var(--space-y)) calc(10px * var(--space-x)) calc(4px + 6px * var(--space-y));
}

/* On a phone its bottom keeps 5px or more at every density: the status line's guard reaches up into it for a thumb's
 * tap. */
@media (max-width: 699px) {
    .composer-row {
        gap: 4px;
        padding: calc(6px * var(--space-y)) calc(8px * var(--space-x))
            calc(3px + 5px * var(--space-y));
    }
}

.composer-row .attach-button {
    width: 32px;
    height: 32px;
    border-radius: var(--r-control);
    color: var(--muted);
}

/* The model and its thinking level: opens the model menu. */
.model-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    height: 30px;
    padding: 0 10px 0 11px;
    border-radius: var(--r-pill);
    background: var(--hover);
    font-size: 13px;
    color: var(--text);
    white-space: nowrap;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .model-chip:hover {
        background: var(--card-2);
    }
}

.model-chip .model-spark {
    color: var(--accent);
}

.model-chip .model-name {
    min-width: 4ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

.model-chip .model-level {
    color: var(--muted);
}

/* The chevron points down: the menu opens up from it, over the conversation. */
.model-chip .model-caret {
    color: var(--faint);
    transform: rotate(90deg);
}

.model-chip.warn {
    color: var(--warn);
}

/* A narrow message box (a narrow pane, or a phone) gives up the level first, then, while Pi works and Steer and Queue
 * take room, Plan and the sparkle: the model's name stays. */
@container composer (max-width: 340px) {
    .model-chip .model-level {
        display: none;
    }
}

@container composer (max-width: 540px) {
    .composer.busy .model-chip .model-level {
        display: none;
    }
}

@container composer (max-width: 400px) {
    .composer.busy :is(.plan-chip, .model-caret) {
        display: none;
    }
}

@container composer (max-width: 355px) {
    .composer.busy .model-chip .model-spark {
        display: none;
    }
}

/* Steer, Queue, and Interrupt leave no room for the model on a narrow box while Pi works: it shows again after. */
@container composer (max-width: 480px) {
    .composer.busy .composer-row .model-chip {
        display: none;
    }
}

/* Below a 360 px screen (an iPhone SE is 320 px), Steer, Queue, and Interrupt would push Stop out of the box: while Pi
 * works, Attach goes and the three get closer. Attach comes back when Pi stops. A 360 px screen's box is 334 px. */
@container composer (max-width: 333px) {
    .composer.busy .composer-row .attach-button {
        display: none;
    }

    .composer.busy .mode-switch button {
        padding-inline: 6px;
    }
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    border: 1px solid var(--line);
    background: var(--card-2);
    border-radius: var(--radius);
    padding: 0.2rem 0.55rem;
    font-size: 0.78rem;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

/* An attachment: a long name gives way, never its size or the button that removes it. */
.files .chip > * {
    flex: none;
}

.files .chip > .chip-name {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (hover: hover) {
    button.chip:hover {
        border-color: var(--edge);
        color: var(--text);
    }
}

.chip.toggle.on {
    color: var(--accent);
    border-color: var(--accent-line);
    background: var(--accent-soft);
}

/* Plan mode: an outlined pill, filled softly in the accent while it is on. */
.composer-row .plan-chip {
    flex: none;
    height: 30px;
    padding: 0 12px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-pill);
    font-size: 13px;
    color: var(--muted);
    white-space: nowrap;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .composer-row .plan-chip:hover {
        color: var(--text);
    }
}

.composer-row .plan-chip.on {
    border-color: var(--accent-line);
    background: var(--accent-soft);
    color: var(--accent);
}

/* While Pi works: whether a message steers the run or waits for its end. */
.mode-switch {
    flex: none;
    display: flex;
    padding: 2px;
    border-radius: var(--r-pill);
    background: var(--hover);
}

.mode-switch button {
    height: 28px;
    padding: 0 10px;
    border-radius: var(--r-pill);
    font-size: 12.5px;
    font-weight: 500;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .mode-switch button:hover {
        color: var(--text);
    }
}

.mode-switch button.on {
    color: var(--text);
    background: var(--raised);
}

.mode-switch button.interrupt.on {
    color: var(--err);
}

.stop-button,
.send-button {
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

.stop-button:active,
.send-button:active:not(:disabled) {
    transform: scale(0.92);
}

/* Stop: a square in the failure color, on its soft tint. */
.stop-button {
    background: var(--err-soft);
}

@media (hover: hover) {
    .stop-button:hover {
        background: color-mix(in srgb, var(--o-red) 22%, transparent);
    }
}

.stop-square {
    width: 11px;
    height: 11px;
    border-radius: var(--r-mark);
    background: var(--err);
}

/* Send: the accent with something to send, quiet without; then a tap on it goes to the text (composer.js). */
.send-button {
    background: var(--card-2);
    color: var(--faint);
    cursor: default;
}

.send-button:disabled {
    pointer-events: none;
}

.send-button.ready {
    background: var(--accent-fill);
    color: var(--accent-ink);
    cursor: pointer;
}

@media (hover: hover) {
    .send-button.ready:hover {
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
    }
}

.send-button.ready .icon {
    transition: transform var(--t-in) var(--ease-out);
}

@media (hover: hover) {
    .send-button.ready:hover .icon {
        transform: translateY(-2px);
    }
}

/* Dictation (voice.js): a quiet mic beside Send; while it listens, the accent and a ring that breathes. */
.composer-row .composer-mic {
    width: 32px;
    height: 32px;
    border-radius: var(--r-control);
    color: var(--muted);
}

.mic-button.listening {
    color: var(--accent);
    background: var(--accent-soft);
    box-shadow: inset 0 0 0 1px var(--accent-line);
}

.mic-button.listening::after {
    content: "";
    position: absolute;
    inset: 0;
    border: 1px solid var(--accent);
    border-radius: var(--r-control);
    pointer-events: none;
    animation: listening 1.6s var(--ease-out) infinite;
}

@keyframes listening {
    from {
        opacity: 0.9;
        transform: scale(1);
    }
    to {
        opacity: 0;
        transform: scale(1.35);
    }
}

/* Still, the inset ring alone says it listens. */
:root[data-motion="reduced"] .mic-button.listening::after {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"], [data-motion="fluid"]) .mic-button.listening::after {
        display: none;
    }
}

/* Square buttons elsewhere: the chat's send. */
.round {
    width: 36px;
    height: 36px;
    border-radius: var(--radius);
    display: grid;
    place-items: center;
    flex: none;
    animation: popin 0.3s var(--ease-out);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

.round:active:not(:disabled) {
    transform: scale(0.9);
}

.round.send {
    background: var(--accent-fill);
    color: var(--accent-ink);
}

@media (hover: hover) {
    .round.send:not(:disabled):hover {
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
    }
}

.round.send:not(:disabled) .icon {
    transition: transform var(--t-in) var(--ease-out);
}

@media (hover: hover) {
    .round.send:not(:disabled):hover .icon {
        transform: translateY(-2px);
    }
}

.round.send:disabled {
    background: var(--raised);
    color: var(--muted);
    cursor: default;
}

/* Under the message box: who is here, how fast the last answer came, the context, the cache, the spend, and Lancet
 * Guard. Its numbers are in mono. */
.status-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px 14px;
    padding-top: calc(3px + 5px * var(--space-y));
    font-size: 11.5px;
    line-height: 16px;
    color: var(--muted);
    white-space: nowrap;
}

.status-line .num {
    font: 11px var(--mono);
    font-variant-numeric: tabular-nums;
}

.status-line .context {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.status-line .meter {
    width: 36px;
}

/* Lancet Guard: a pill that opens Extensions, green while it guards and yellow while it does not. */
.status-line .guard {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: var(--r-pill);
    background: var(--ok-soft);
    color: var(--ok);
    font: inherit;
}

.status-line .guard.off {
    background: var(--warn-soft);
    color: var(--warn);
}

/* How fast the last answer came, once Appearance turns it on: its two halves spaced like the line's items. */
.status-line .speed {
    display: inline-flex;
    align-items: center;
    column-gap: inherit;
}

.status-line .speed .short {
    display: none;
}

/* A line too narrow for one row takes shorter forms, one after another, until it fits (`fitStatus`, composer.js). */
.status-line[data-short~="words"] {
    column-gap: 8px;
}

.status-line[data-short~="words"] .speed {
    column-gap: 1ch;
}

.status-line[data-short~="words"] .speed .long,
.status-line[data-short~="here"] .here.alone,
.status-line[data-short~="guard"] .guard .word,
.status-line[data-short~="cache"] .cache,
.status-line[data-short~="wait"] .speed .wait,
.status-line[data-short~="wait"] .speed.wait-only {
    display: none;
}

.status-line[data-short~="words"] .speed .short {
    display: inline;
}

/* Extensions' items: their text, in a tone, and their short form on a narrow line. */
.status-line .ext-status .short,
.status-line[data-short~="ext"] .ext-status .long {
    display: none;
}

.status-line[data-short~="ext"] .ext-status .short {
    display: inline;
}

.status-line .ext-status.warn {
    color: var(--warn);
}

.status-line .ext-status.error {
    color: var(--err);
}

.status-line .ext-status.muted {
    color: var(--faint);
}

/* One whose page or panel is open: lit in the accent, as the top bar's toggles are. */
.status-line .ext-status.on {
    color: var(--accent);
}

@media (hover: hover) {
    .status-line button.ext-status:hover {
        color: var(--text);
    }
}

/* Words that go from sight but not from a screen reader: "77%" is still the context's, "1.2s" the first token's. */
.status-line[data-short~="words"] .speed .rate + .wait .word,
.status-line[data-short~="context"] .context .word {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Narrow, the wait has no words of its own: "42 tok/s · 1.2s". */
.status-line[data-short~="words"] .speed .rate + .wait::before {
    content: "·";
    margin-right: 1ch;
}

/* ─── Extensions ───────────────────────────────────────────── */

.extension {
    display: flex;
    gap: 14px;
    padding: 12px 14px;
    background: var(--bg);
}

.notifications-sheet .extension,
.message-worktree {
    align-items: center;
}

.guard-confirm {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
    padding: 10px 12px;
    border-radius: var(--r-control);
    border: 1px solid var(--warn-line);
    background: var(--warn-soft);
    color: var(--text);
    font-size: 12.5px;
}

.guard-confirm .primary {
    background: var(--warn);
    border-color: transparent;
}

.extension-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    overflow-wrap: anywhere;
}

.extension-title {
    font-size: 14px;
    color: var(--text);
}

.extension.off .extension-title {
    color: var(--muted);
}

.extension-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.45rem;
}

/* The on and off switch (`Switch` in ui.js), in every sheet that has one. */
.switch {
    position: relative;
    width: 38px;
    height: 22px;
    flex: none;
    padding: 3px;
    border-radius: var(--r-pill);
    background: var(--hair-2);
    border: 0;
    transition:
        background-color var(--t-in) var(--ease-out),
        border-color var(--t-in) var(--ease-out);
}

.switch span {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: var(--r-pill);
    background: var(--text);
    box-shadow: 0 1px 2px var(--sh);
    transition:
        transform var(--t-in) var(--ease-out),
        background-color var(--t-in) var(--ease-out);
}

.switch.on {
    background: var(--accent-fill);
}

.switch.on span {
    transform: translateX(16px);
    background: var(--accent-ink);
}

@media (pointer: coarse) {
    .switch::before {
        content: "";
        position: absolute;
        inset: -10px -3px;
    }
}

.switch:disabled {
    opacity: 0.45;
    cursor: default;
}

/* ─── The rail: Pi, the tools, and you; folded, the sessions too ─── */

.rail {
    width: 56px;
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-height: 0;
    padding: calc(env(safe-area-inset-top) + 12px) 0 calc(env(safe-area-inset-bottom) + 12px);
    border-right: 1px solid var(--hair);
    /* A short screen (a phone on its side) scrolls the rail rather than cut off its last buttons. */
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: none;
}

.rail-brand,
.rail-button {
    position: relative;
    flex: none;
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    border-radius: var(--r-control);
}

/* Phones and touch screens: a thumb's size. */
@media (max-width: 959px), (pointer: coarse) {
    .rail-brand,
    .rail-button {
        width: 44px;
        height: 44px;
    }
}

.rail-brand {
    font:
        22px/1 Georgia,
        serif;
    color: var(--brand);
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    button.rail-brand:hover {
        background: var(--hover);
    }
}

.rail-button {
    color: var(--muted);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .rail-button:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.rail-gap {
    flex: none;
    height: 6px;
}

.rail-fill {
    flex: 1;
}

/* The sessions, while the list shows. */
.rail-button.on {
    color: var(--text);
    background: var(--card-2);
}

/* A tool whose window is open (peek tiles, PiP, the subagents board, an extension's page): the accent's soft fill. */
.rail-button.open {
    color: var(--accent);
    background: var(--accent-soft);
}

.rail-new,
.rail-running.lit,
.rail-agents.lit,
.rail-pip.lit {
    color: var(--accent);
}

.rail-new .icon {
    stroke-width: 2.4;
}

/* How many: sessions where Pi works, or subagents that work or wait. */
.rail-count {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 15px;
    height: 15px;
    padding: 0 4px;
    display: grid;
    place-items: center;
    border-radius: var(--r-pill);
    background: var(--accent-fill);
    color: var(--accent-ink);
    box-shadow: 0 0 0 2px var(--bg);
    font: 600 9.5px/1 var(--mono);
    animation: popin var(--t-in) var(--ease-out);
}

/* A dot at a button's corner: something new in PiP, or a subagent that failed or waits for an approval. */
.rail-trouble,
.rail-news {
    position: absolute;
    right: 4px;
    bottom: 4px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--bg);
}

.rail-trouble {
    background: var(--err);
}

.rail-news {
    right: 5px;
    bottom: 5px;
    background: var(--accent);
}

@media (max-width: 959px), (pointer: coarse) {
    .rail-count {
        top: 4px;
        right: 3px;
    }
    .rail-trouble {
        right: 8px;
        bottom: 8px;
    }
    .rail-news {
        right: 9px;
        bottom: 9px;
    }
}

/* You: a round avatar, a little apart from the tools. */
.rail-me {
    margin-top: 4px;
    border-radius: 50%;
}

/* Folded: the sessions as numbered tiles, like Waybar's workspaces, between New and the tools. */
.rail-items {
    position: relative;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 6px 0;
    border-top: 1px solid var(--hair);
    border-bottom: 1px solid var(--hair);
    scrollbar-width: none;
}

.rail:has(.rail-items) {
    overflow-y: hidden;
}

/* The open session's tile is lit by a soft fill that slides from tile to tile, under the numbers. */
.rail-items .slide-y {
    left: 50%;
    width: 36px;
    margin-left: -18px;
    border-radius: var(--r-control);
    background: var(--accent-soft);
    z-index: 0;
}

.ws {
    position: relative;
    z-index: 1;
    flex: none;
    width: 36px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: var(--r-row);
    font: 600 12.5px var(--mono);
    color: var(--muted);
    animation: rise-in 0.38s var(--ease-out) backwards;
    animation-delay: calc(min(var(--i, 0), 14) * 18ms);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .ws:hover {
        color: var(--text);
        background: var(--hover);
    }
}

.ws.active {
    color: var(--accent);
}

.ws.waiting {
    color: var(--warn);
}

/* A working session's tile: a still underline, accent to spark. */
.ws.busy::after {
    content: "";
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 3px;
    height: 2px;
    border-radius: 1px;
    background: linear-gradient(90deg, var(--accent), var(--spark));
}

.ws .unread-dot {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
}

/* ─── Sessions: the list beside the rail ───────────────────────── */

.sessions {
    flex: 1;
    /* Narrower, as the sidebar unfolds, it is cut off rather than squeezed. */
    min-width: 204px;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding: calc(env(safe-area-inset-top) + 14px) 12px calc(env(safe-area-inset-bottom) + 10px);
    container: sessions / inline-size;
}

.sessions-head {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding-left: 4px;
    flex: none;
}

.sessions-name {
    font-weight: 600;
    font-size: 15px;
    color: var(--text);
}

.sessions-count {
    margin-right: auto;
    font: 11px var(--mono);
    color: var(--faint);
}

.new-button {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 30px;
    padding: 0 11px 0 9px;
    border-radius: calc(var(--r-row) - 1px);
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 600;
    font-size: 13px;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .new-button:hover {
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
    }
}

.new-button .icon {
    stroke-width: 2.4;
}

/* A search field: the sheets' (providers, a message's, the pickers') and the session list's. */
.search {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    padding: 0 12px;
    color: var(--muted);
    margin-bottom: 0;
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .search:hover {
        border-color: var(--line-strong);
    }
}

.search:has(input:focus) {
    border-color: var(--accent-line);
    color: var(--muted);
}

.search input {
    flex: 1;
    border: 0;
    border-radius: 0;
    background: none;
    padding: 7px 0;
    min-width: 0;
    font-size: 13.5px;
}

.search input:focus-visible {
    outline: none;
}

@media (pointer: coarse) {
    .search input {
        font-size: 16px;
    }
}

.search kbd {
    cursor: pointer;
    flex: none;
    border: 1px solid var(--hair);
    border-radius: var(--r-tag);
    font-size: 10.5px;
    color: var(--faint);
}

.sessions .search {
    flex: none;
    margin: 12px 0 0;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    min-height: 34px;
    padding: 0 6px 0 10px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    color: var(--muted);
    transition:
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .sessions .search:hover {
        border-color: var(--hair-2);
    }
}

.sessions .search:has(input:focus) {
    border-color: var(--accent-line);
    background: var(--card);
    color: var(--muted);
}

.sessions .search.filled {
    border-color: var(--accent-line);
    color: var(--accent);
}

/* The field's frame shows the focus. */
.sessions .search input:focus-visible,
.board-search input:focus-visible {
    outline: none;
}

.sessions .search input {
    flex: 1;
    min-width: 0;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    font-size: 13px;
    color: var(--text);
}

/* "Ctrl K": a small tag at the field's end. */
.sessions .search-keys {
    padding: 4px 6px;
    border: 1px solid var(--hair);
    border-radius: var(--r-tag);
    font: 10.5px / 1 var(--mono);
    color: var(--faint);
    white-space: nowrap;
    opacity: 1;
}

.search-clear {
    position: relative;
    flex: none;
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    color: var(--muted);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .search-clear:hover {
        background: var(--hover);
        color: var(--text);
    }
}

/* Touch screens have no Ctrl K: the launcher's button takes its place. */
.search-launcher {
    position: relative;
    flex: none;
    width: 22px;
    height: 22px;
    display: none;
    place-items: center;
    color: var(--muted);
}

@media (pointer: coarse) {
    .search-launcher {
        display: grid;
    }
    .search-launcher::before {
        content: "";
        position: absolute;
        inset: -9px;
    }
}

/* Recent, Folders, Archived: a segmented track, its raised segment sliding to the one chosen. */
.session-tabs {
    position: relative;
    flex: none;
    margin-top: 10px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    padding: 3px;
    border-radius: var(--r-control);
    background: var(--card);
}

.session-tabs button {
    position: relative;
    z-index: 1;
    height: 26px;
    display: grid;
    place-items: center;
    padding: 0 6px;
    border-radius: var(--r-seg);
    font-size: 12.5px;
    color: var(--muted);
    transition: color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .session-tabs button:hover {
        color: var(--text);
    }
}

.session-tabs button.on {
    color: var(--text);
    font-weight: 500;
}

.slide-x {
    position: absolute;
    left: 0;
    top: 3px;
    bottom: 3px;
    border-radius: var(--r-seg);
    background: var(--raised);
    transition:
        transform var(--t-in) var(--ease-out),
        width var(--t-in) var(--ease-out);
}

.session-items {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    display: flex;
    flex-direction: column;
    margin: 4px -4px 0;
    padding: 0 4px 4px;
}

/* A bar that slides from item to item: the folded rail's open session. */
.slide-y {
    position: absolute;
    left: 0.3rem;
    top: 0;
    width: 2px;
    background: var(--accent);
    z-index: 2;
    pointer-events: none;
    transition:
        transform var(--t-in) var(--ease-out),
        height var(--t-in) var(--ease-out),
        opacity var(--t-fade) var(--ease-almost);
}

.slide-x.instant,
.slide-y.instant {
    transition: none;
}

.session-group {
    display: flex;
    flex-direction: column;
}

.group-head {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: calc(4px + 10px * var(--space-y)) 8px calc(6px * var(--space-y));
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
    text-align: left;
    transition: color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .group-head:hover {
        color: var(--text);
    }
}

.group-head:focus-visible {
    color: var(--text);
}

.group-name {
    flex: 0 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.group-name b {
    font-weight: inherit;
}

/* A folder's group: its path quiet, its last part bold, and the path cut short first when it is long. */
.group-name:has(.last) {
    display: flex;
}

.group-name .first,
.group-name .last {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.group-name .first {
    flex: 0 1 auto;
}

.group-name .last {
    flex: none;
    max-width: 100%;
    color: var(--text);
    font-weight: 600;
}

/* How many, in mono, beside the name; the fold's chevron at the end. */
.group-count {
    flex: 1;
    font: 11px var(--mono);
    color: var(--faint);
}

/* A dot on a folded group: a session inside needs you, or failed. */
.group-trouble {
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--warn);
}

.group-trouble.failed {
    background: var(--err);
}

.group-head .icon {
    color: var(--faint);
    transition: transform var(--t-in) var(--ease-out);
}

.session-group.closed .group-head .icon {
    transform: rotate(-90deg);
}

/* Groups fold smoothly: a one-row grid whose row goes from 1fr to 0fr. */
.group-body {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows var(--t-in) var(--ease-out);
}

.group-body > div {
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.session-group.closed .group-body {
    grid-template-rows: 0fr;
}

.session-row {
    position: relative;
    padding-inline-start: calc(var(--linked-depth, 0) * 14px);
}

/* A row new to this page rises in, the rows in turn. Back to the list builds it again: those rows show as they were,
 * and the list slides in whole (`data-route`), so it does not flicker (`sessions.js`). */
.session-row.arriving {
    animation: rise-in 0.38s var(--ease-out) backwards;
    animation-delay: calc(min(var(--i, 0), 14) * 18ms);
}

/*
 * Linked-session branches are decorative; each row keeps its own button and actions. Each line runs down from the middle
 * of its parent's mark, and turns with a soft corner to the row's own.
 */
.session-branches {
    position: absolute;
    inset: 0 auto 0 15px;
    display: flex;
    pointer-events: none;
    color: color-mix(in srgb, var(--muted) 60%, transparent);
}

.session-branches > span {
    position: relative;
    width: 14px;
}

.session-branches > .continues::before,
.session-branches > .elbow::before {
    content: "";
    position: absolute;
    left: 0;
    top: -1px;
    bottom: -1px;
    border-left: 1.5px solid currentColor;
}

.session-branches > .elbow::after {
    content: "";
    position: absolute;
    left: 0;
    top: -1px;
    bottom: 50%;
    width: 8px;
    border-bottom: 1.5px solid currentColor;
    border-left: 1.5px solid currentColor;
    border-bottom-left-radius: calc(var(--r-tag) + 1px);
}

/* The last child: only the corner, no line on down. */
.session-branches > .elbow:not(.continues)::before {
    display: none;
}

/*
 * A row with linked sessions under it: a button on its right shows how many and folds them away (`sessions.js`). The
 * row's own button keeps its right side clear of it, and the hover actions move in beside it.
 */
.session-fold {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 44px;
    padding: 0 6px;
    font: 11px var(--mono);
    color: var(--muted);
}

/* The control itself: how many, and a chevron, in a quiet pill; the whole 44px beside it takes the tap. */
.session-fold-pill {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 20px;
    padding: 0 6px;
    border: 1px solid var(--hair);
    border-radius: var(--r-pill);
    background: var(--card-2);
    transition:
        color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

/* Above the open session: its group stays open, so the fold waits. */
.session-fold:disabled {
    cursor: default;
    opacity: 0.5;
}

@media (hover: hover) {
    .session-fold:not(:disabled):hover .session-fold-pill {
        color: var(--text);
        border-color: var(--accent-line);
    }
}

.session-fold .icon {
    transition: transform var(--t-in) var(--ease-out);
}

.session-fold.folded .icon {
    transform: rotate(-90deg);
}

.session-row.with-fold .session {
    padding-right: 64px;
}

.session-row.with-fold .session-actions {
    right: 62px;
}

/* Chips take a line under the title: the fold stays beside the title's line. */
.session-row.with-chips .session-fold {
    bottom: 20px;
}

/* One line: the folder's color, the title, and what goes on there on the right. */
.session {
    display: grid;
    grid-template-columns: 8px minmax(0, 1fr) auto;
    align-items: center;
    gap: 0 11px;
    width: 100%;
    /* 36px, 32px, and 29px. */
    height: calc(24px + 12px * var(--space-y));
    padding: 0 10px;
    border-radius: var(--r-row);
    text-align: left;
    border: 1px solid transparent;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .session:hover {
        background: var(--hover);
    }
}

/* Keep focus outlines inside list controls: scrolling and folding groups clip their edges. */
.group-head:focus-visible,
.session:focus-visible {
    outline-offset: -1px;
}

/* The open session: the accent's soft fill, and its title in bold. */
.session-row.active .session {
    background: var(--accent-soft);
}

.session-row.active .session-title {
    font-weight: 600;
}

/* Selected rows (Ctrl/⌘+click or drag, Shift+click): the soft fill, a border, and a check for the folder's mark. */
.session-row.selected .session {
    background: var(--accent-soft);
    border-color: var(--accent-line);
}

/* A finger held on a row, before its actions open: after the open and selected rows' fills, so it shows on them too. */
.session-row.pressing .session {
    background: var(--hover);
}

.session-mark {
    display: grid;
    place-items: center;
    width: 8px;
    height: 8px;
}

/*
 * A session's square: its folder's color (--folder), 8px with softly rounded corners, in the shape of its state. Solid:
 * finished, not read yet. Hollow and dim: read, or never run. Quadrants with one lit: working. Two bars: waiting for
 * you. A hollow square with a dot: waiting for a provider's limit to clear. A cross: failed, cut out of a solid square while not read, drawn once read.
 */
.state-mark {
    --line-w: 1.5px;
    --cut: 2px;
    --q: 3.5px;
    position: relative;
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: calc(var(--r-mark) - 0.5px);
    color: var(--folder, var(--muted));
}

.state-mark.fresh {
    background: currentColor;
}

.state-mark.seen {
    box-shadow: inset 0 0 0 var(--line-w) currentColor;
    opacity: 0.55;
}

/* Pi Pocket's spinner, in the folder's color: one lit quadrant stepping around the four. */
.state-mark.working {
    overflow: hidden;
    --dim: color-mix(in oklab, currentColor 28%, transparent);
    background:
        linear-gradient(var(--dim), var(--dim)) 0 0 / var(--q) var(--q) no-repeat,
        linear-gradient(var(--dim), var(--dim)) 100% 0 / var(--q) var(--q) no-repeat,
        linear-gradient(var(--dim), var(--dim)) 0 100% / var(--q) var(--q) no-repeat,
        linear-gradient(var(--dim), var(--dim)) 100% 100% / var(--q) var(--q) no-repeat;
}

/* Still (reduced motion), the top left quadrant stays lit. */
.state-mark.working::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: var(--q);
    height: var(--q);
    background: currentColor;
    animation: state-quadrant 1.6s steps(1, end) infinite;
}

@keyframes state-quadrant {
    0% {
        transform: translate(0, calc(var(--q) + 1px));
    }
    25% {
        transform: translate(0, 0);
    }
    50% {
        transform: translate(calc(var(--q) + 1px), 0);
    }
    75% {
        transform: translate(calc(var(--q) + 1px), calc(var(--q) + 1px));
    }
}

.state-mark.waiting {
    background: linear-gradient(90deg, currentColor 0 3px, transparent 0 5px, currentColor 0);
}

/* Pi waits for the provider's limit to clear: a hollow square, not dimmed, with a dot at its center. */
.state-mark.limited {
    box-shadow: inset 0 0 0 var(--line-w) currentColor;
    background: radial-gradient(circle at center, currentColor 0 1.25px, transparent 1.5px);
}

.state-mark.failed {
    background: currentColor;
    -webkit-mask:
        linear-gradient(
            45deg,
            #000 calc(50% - var(--cut) / 2),
            transparent 0 calc(50% + var(--cut) / 2),
            #000 0
        ),
        linear-gradient(
            135deg,
            #000 calc(50% - var(--cut) / 2),
            transparent 0 calc(50% + var(--cut) / 2),
            #000 0
        );
    -webkit-mask-composite: source-in;
    mask:
        linear-gradient(
            45deg,
            #000 calc(50% - var(--cut) / 2),
            transparent 0 calc(50% + var(--cut) / 2),
            #000 0
        ),
        linear-gradient(
            135deg,
            #000 calc(50% - var(--cut) / 2),
            transparent 0 calc(50% + var(--cut) / 2),
            #000 0
        );
    mask-composite: intersect;
}

.state-mark.failed.seen {
    box-shadow: none;
    background:
        linear-gradient(
            45deg,
            transparent calc(50% - var(--line-w) / 2),
            currentColor 0 calc(50% + var(--line-w) / 2),
            transparent 0
        ),
        linear-gradient(
            135deg,
            transparent calc(50% - var(--line-w) / 2),
            currentColor 0 calc(50% + var(--line-w) / 2),
            transparent 0
        );
    -webkit-mask: none;
    mask: none;
}

.folder-mark {
    flex: none;
    width: 7px;
    height: 7px;
    background: var(--folder, var(--muted));
}

.state-check {
    flex: none;
    display: grid;
    place-items: center;
    width: 11px;
    height: 11px;
    border-radius: var(--r-mark);
    background: var(--accent-fill);
    color: var(--accent-ink);
    animation: popin 0.16s var(--ease-out);
}

.state-check .icon {
    stroke-width: 3.5;
}

.session-title {
    font-size: 13.5px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--t-hover) var(--ease-out);
}

/* A search that matched the folder or model, not the title: it shows after the title, which keeps its room first. */
.session-title.with-hit {
    display: flex;
    gap: 8px;
}

.session-name {
    flex: none;
    max-width: 65%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.session-hit {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 12px;
    color: var(--muted);
}

/* New chat messages there, in a session not open. */
.session.unread .session-title {
    font-weight: 600;
}

/* Marked unread, or finished since this browser last looked: the title reads bold, like the dot beside the time says. */
.session-row.marked-unread .session-title,
.session-row.unseen .session-title {
    font-weight: 600;
}

.session-title mark,
.launcher mark {
    background: none;
    color: var(--accent);
    font-weight: 800;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

.session-side {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 7px;
    font: 11px var(--mono);
    color: var(--faint);
    transition: opacity var(--t-hover) var(--ease-out);
}

/* Subagents at work there (or failed ones, in red): ⑂ and how many, in a small pill. */
.session-fork {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 18px;
    padding: 0 6px;
    border-radius: var(--r-pill);
    background: var(--accent-soft);
    font-weight: 600;
    color: var(--accent);
}

.session-fork.failed {
    background: var(--err-soft);
    color: var(--err);
}

.session-fork .icon {
    stroke-width: 2.4;
}

/* A call waits for you there. */
.session-needs {
    display: grid;
    place-items: center;
    height: 18px;
    padding: 0 7px;
    border-radius: var(--r-pill);
    background: var(--warn-soft);
    color: var(--warn);
    font: 500 11px var(--sans);
}

/* Pi works there. */
.session-working {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    animation: pulse 1.4s ease-in-out infinite;
}

.session-side .avatar {
    font-size: 8px;
}

.session-side .unread-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
}

/* A call waiting says more than how long ago: the title keeps the room. */
.session-needs ~ .session-time {
    display: none;
}

.session-time {
    min-width: 22px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Hold Alt: each of the first nine rows shows the number that jumps to it, in the time's place. */
.session-num {
    display: none;
}

:root[data-alt="on"] .session-num {
    display: inline-grid;
    animation: popin 0.2s var(--ease-out);
}

:root[data-alt="on"] .session-time:has(~ .session-num) {
    display: none;
}

/* Archive, pin, and mark unread: on the row's right, shown on hover or while the row has focus. */
.session-actions {
    position: absolute;
    top: 50%;
    right: 6px;
    margin-top: -13px;
    display: flex;
    gap: 4px;
}

.session-act {
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    color: var(--muted);
    background: var(--card-2);
    border: 1px solid var(--hair);
    border-radius: var(--r-seg);
    opacity: 0;
    transform: translateX(4px);
    transition:
        opacity var(--t-hover) var(--ease-out),
        transform var(--t-in) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .session-act:hover {
        color: var(--accent);
        border-color: var(--accent-line);
    }
}

.session-act + .session-act {
    transition-delay: 25ms;
}

.session-pin.on {
    color: var(--brand);
}

.session-unread.on {
    color: var(--accent);
}

/* Touch screens archive, pin, and mark-unread from a long press on the row instead: an unseen button would take taps meant for it. */
@media (hover: none) {
    .session-actions {
        display: none;
    }
}

/* The buttons take the right side's place, widened so a long title ends before them (one to three 26px buttons). */
@media (hover: hover) {
    .session-row:hover .session-act,
    .session-act:focus-visible {
        opacity: 1;
        transform: none;
    }
    .session-row:not(.no-acts):hover .session-side {
        opacity: 0;
        min-width: 56px;
    }
    .session-row.one-act:hover .session-side {
        min-width: 26px;
    }
    /* Three live buttons: archive, pin, and mark-unread. */
    .session-row.three-acts:hover .session-side {
        min-width: 86px;
    }
    /* And an extension's action (`pocket.sessionAction` with an icon). */
    .session-row.four-acts:hover .session-side {
        min-width: 116px;
    }
    /* Keyboard focus in the row shows them too, not the focus a click leaves on the open session's row. Kept apart
       from the rules above: a browser without :has() drops only these. */
    .session-row:has(:focus-visible) .session-act {
        opacity: 1;
        transform: none;
    }
    .session-row:not(.no-acts):has(:focus-visible) .session-side {
        opacity: 0;
        min-width: 56px;
    }
    .session-row.one-act:has(:focus-visible) .session-side {
        min-width: 26px;
    }
    .session-row.three-acts:has(:focus-visible) .session-side {
        min-width: 86px;
    }
    .session-row.four-acts:has(:focus-visible) .session-side {
        min-width: 116px;
    }
    /* While Ctrl/⌘ drags a selection, rows do not show their buttons. */
    :root.selecting .session-row .session-act {
        opacity: 0;
    }
    :root.selecting .session-row .session-side {
        opacity: 1;
        min-width: 0;
    }
}

/*
 * Extensions' chips under a row's title (`pocket.sessionChips`), such as tags. The row's button grows to hold them, so
 * its fill and its click take the whole row; only the chips that do something take clicks of their own.
 */
.session-row.with-chips .session {
    height: calc(24px + 12px * var(--space-y) + 20px);
    padding-bottom: 20px;
}

.session-row.with-chips .session-actions {
    top: calc(12px + 6px * var(--space-y));
}

.session-chips {
    position: absolute;
    left: calc(var(--linked-depth, 0) * 14px + 30px);
    right: 10px;
    bottom: calc(4px + 2px * var(--space-y));
    display: flex;
    gap: 4px;
    overflow: hidden;
    pointer-events: none;
}

.session-chip {
    flex: none;
    max-width: 100%;
    height: 17px;
    padding: 0 6px;
    overflow: hidden;
    border: 1px solid var(--hair);
    border-radius: var(--r-tag);
    background: var(--card-2);
    color: var(--muted);
    font-size: 11px;
    line-height: 15px;
    white-space: nowrap;
    text-overflow: ellipsis;
}

button.session-chip {
    pointer-events: auto;
    cursor: pointer;
    transition:
        color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    button.session-chip:hover {
        color: var(--accent);
        border-color: var(--accent-line);
    }
}

/* A taller target for a finger, past the chip's own edges. */
@media (pointer: coarse) {
    button.session-chip {
        position: relative;
    }
    button.session-chip::before {
        content: "";
        position: absolute;
        inset: -6px -2px;
    }
}

/* While taps select rows (after Select), a tap on a chip selects its row too. */
.sessions.tap-selecting button.session-chip {
    pointer-events: none;
}

/* A linked row's branch turns into its title's line, not the middle of the taller row. */
.session-row.with-chips .session-branches > .elbow::after {
    bottom: auto;
    height: calc(13px + 6px * var(--space-y));
}

/* Extensions' filters beside the search (`pocket.sessionFilter`): lit while one narrows the list. */
.search-filter {
    position: relative;
    flex: none;
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    border-radius: var(--r-seg);
    color: var(--muted);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .search-filter:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.search-filter.on {
    color: var(--accent);
}

.search-filter.badge-host .badge {
    top: -6px;
    right: -7px;
    min-width: 14px;
    height: 14px;
    padding: 0 3px;
    font-size: 0.6rem;
}

@media (pointer: coarse) {
    .search-filter::before {
        content: "";
        position: absolute;
        inset: -9px -4px;
    }
}

/* On its way into or out of the archive: dimmed until the server's list moves it. */
.session-row.moving {
    opacity: 0.4;
    pointer-events: none;
    transition: opacity var(--t-hover) var(--ease-out);
}

:root.selecting,
:root.selecting * {
    user-select: none;
}

/* A finger held on a row: nothing selects, the sheet that press opens rising under the finger included. */
:root.holding,
:root.holding * {
    -webkit-user-select: none;
    user-select: none;
}

/* What to do with the selected sessions: docked under the list. */
.select-bar {
    container-type: inline-size;
    flex: none;
    margin-top: 6px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
    min-width: 0;
    padding: 4px 4px 4px 9px;
    border: 1px solid var(--accent-line);
    border-radius: var(--r-control);
    background: var(--accent-soft);
    animation: rise-in var(--t-in) var(--ease-out);
}

.select-count {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    font-size: 0.76rem;
    color: var(--muted);
    white-space: nowrap;
}

.select-count b {
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

/* A narrow bar (a narrow list, or larger text) shows just the count, so the buttons fit. */
@container (max-width: 14rem) {
    .select-word {
        display: none;
    }
}

.select-bar .button {
    padding: 0.2rem 0.5rem;
    font-size: 0.76rem;
}

.select-clear {
    flex: none;
    width: 24px;
    height: 24px;
    border-radius: var(--r-seg);
    display: grid;
    place-items: center;
    color: var(--body);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .select-clear:hover {
        background: var(--hover);
        color: var(--text);
    }
}

/* A thumb's size on a touch screen, where a long press starts a selection. */
@media (pointer: coarse) {
    .select-bar .button {
        min-height: 36px;
        padding-inline: 0.8rem;
    }
    .select-clear {
        width: 36px;
        height: 36px;
    }
}

.sessions-empty {
    padding: 1.2rem 0.6rem;
    color: var(--muted);
    font-size: 0.85rem;
    animation: fade var(--t-fade) var(--ease-almost);
}

/* A session row's shape while the list loads: a title bar, pulsing one row after another. */
.session-placeholder {
    display: flex;
    align-items: center;
    height: 36px;
    padding: 0 10px 0 29px;
}

.session-placeholder span {
    height: 0.6rem;
    width: var(--width);
    border-radius: var(--r-mark);
    background: var(--line);
    animation: placeholder 1.4s ease-in-out var(--delay) infinite;
}

@keyframes placeholder {
    50% {
        opacity: 0.35;
    }
}

/* ─── The home screen on wide screens: a fastfetch for Pi Pocket ─── */

/* One centered column, 640px at most. */
.splash {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    align-items: center;
    justify-content: safe center;
    flex-direction: column;
    gap: 28px;
    padding: 40px;
}

.splash > * {
    width: min(640px, 100%);
    flex: none;
}

.fetch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 36px;
}

.fetch-logo {
    margin: 0;
    font: 13px / 1.15 var(--mono);
    color: var(--brand);
    user-select: none;
    animation: popin 0.6s var(--ease-out) backwards;
}

.fetch-info {
    flex: 1;
    min-width: 260px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.fetch-info > * {
    animation: rise-in 0.42s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 45ms + 120ms);
}

.fetch-title {
    margin-bottom: 8px;
    font: 600 15px var(--mono);
    color: var(--text);
}

.fetch-title b {
    color: var(--accent);
}

.fetch-row {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr);
    gap: 12px;
    margin: 0;
    font-size: 13.5px;
    line-height: 1.75;
}

.fetch-row dt {
    color: var(--muted);
}

.fetch-row dd {
    margin: 0;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.fetch-colors {
    display: flex;
    gap: 6px;
    margin-top: 10px;
}

.fetch-colors span {
    width: 16px;
    height: 16px;
    border-radius: var(--r-tag);
    transition: transform var(--t-in) var(--ease-out);
}

@media (hover: hover) {
    .fetch-colors span:hover {
        transform: translateY(-3px);
    }
}

/* New session, the launcher, and Appearance: 38px buttons, set in full here. */
.splash-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    animation: rise-in 0.5s var(--ease-out) 0.45s backwards;
}

.splash-actions .button {
    height: 38px;
    padding: 0 14px;
    gap: 8px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-control);
    background: var(--card);
    color: var(--text);
    font-size: 13.5px;
    font-weight: 500;
}

@media (hover: hover) {
    .splash-actions .button:hover {
        border-color: var(--hair-2);
        background: var(--card-2);
    }
}

.splash-actions .button.primary {
    border-color: transparent;
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 600;
}

@media (hover: hover) {
    .splash-actions .button.primary:hover {
        border-color: transparent;
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
    }
}

/* The key's name, in mono beside the label. */
.splash-actions .button kbd {
    min-width: 0;
    height: auto;
    padding: 0;
    border: 0;
    background: none;
    font: 400 11px var(--mono);
    color: var(--faint);
    opacity: 1;
}

.splash-actions .button.primary kbd {
    color: inherit;
    opacity: 0.7;
}

/* Jump back in: a row per recent session, numbered as Alt+1…9 number them. */
.splash-recent {
    display: flex;
    flex-direction: column;
    gap: 4px;
    animation: rise-in 0.5s var(--ease-out) 0.55s backwards;
}

.splash-heading {
    padding: 0 4px 6px;
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
}

.splash-row {
    display: flex;
    align-items: center;
    gap: 12px;
    height: 40px;
    padding: 0 12px;
    border-radius: var(--r-control);
    text-align: left;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .splash-row:hover {
        background: var(--hover);
    }
}

.splash-key {
    flex: none;
    width: 20px;
    height: 20px;
    display: grid;
    place-items: center;
    border: 1px solid var(--hair-2);
    border-radius: calc(var(--r-tag) + 1px);
    font: 11px / 1 var(--mono);
    color: var(--muted);
}

.splash-title {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.splash-meta {
    flex: none;
    font: 11.5px var(--mono);
    color: var(--faint);
}

/* ─── Sheets ───────────────────────────────────────────────── */

/* omarchy-shell's scrim: the desktop's darkest color over everything, at about half. */
.overlay {
    position: fixed;
    inset: 0;
    background: var(--scrim);
    z-index: 20;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    animation: fade var(--t-fade) var(--ease-almost);
}

/* Phones: a sheet from the bottom edge, rounded on top. Wide screens: a rounded popup near the top that floats. */
.sheet {
    background: var(--panel);
    width: 100%;
    max-width: 560px;
    max-height: 86dvh;
    border-radius: calc(var(--r-sheet) + 8px) calc(var(--r-sheet) + 8px) 0 0;
    box-shadow:
        0 -1px 0 var(--hair-2),
        0 -20px 40px -20px var(--sh);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    animation: sheet-up var(--t-in) var(--ease-out);
    padding-bottom: env(safe-area-inset-bottom);
    outline: none;
}

@keyframes sheet-up {
    from {
        transform: translateY(100%);
    }
}

@keyframes sheet-down {
    to {
        transform: translateY(100%);
    }
}

/* Closing: Hyprland's windowsOut, short and linear. */
.leaving {
    pointer-events: none;
}

.leaving .overlay {
    animation: fade-out var(--t-out) linear forwards;
}

.leaving .sheet {
    animation: sheet-down 0.2s var(--ease-in-out) forwards;
}

@media (min-width: 700px) {
    .overlay {
        align-items: flex-start;
        /* A sheet keeps 16px from the sides, and clear of a notch. */
        padding: 7vh max(16px, var(--inset-r)) 16px max(16px, var(--inset-l));
    }
    /* The drawer keeps its place, and its rail clears the notch itself (below). */
    .overlay.drawer-overlay {
        padding-left: 16px;
    }
    .sheet {
        max-width: 500px;
        border-radius: var(--r-sheet);
        box-shadow: var(--pop);
        animation: pop 0.28s var(--ease-out);
    }
    .sheet.wide {
        max-width: 760px;
    }
    .leaving .sheet {
        animation: pop-out var(--t-out) linear forwards;
    }
}

/* The drawer: the session list sliding in from the left on narrow screens. Over `.overlay`'s place for sheets. */
.overlay.drawer-overlay {
    align-items: stretch;
    justify-content: flex-start;
}

.drawer {
    display: flex;
    width: min(86vw, 340px);
    height: 100dvh;
    background: var(--panel);
    border-radius: 0 var(--r-sheet) var(--r-sheet) 0;
    box-shadow:
        1px 0 0 var(--hair-2),
        20px 0 40px -20px var(--sh);
    overflow: hidden;
    animation: drawer-in var(--t-in) var(--ease-out);
}

/* The drawer's rail keeps its buttons clear of the notch, as the home list's does; its line stays at their edge. */
.drawer > .rail {
    width: calc(56px + var(--inset-l));
    padding-left: var(--inset-l);
}

/* Wide enough for `.overlay`'s 16px margin, the drawer starts that far in: the notch is that much nearer. */
@media (min-width: 700px) {
    .drawer > .rail {
        width: calc(56px + max(0px, var(--inset-l) - 16px));
        padding-left: max(0px, calc(var(--inset-l) - 16px));
    }
}

@keyframes drawer-in {
    from {
        transform: translateX(-100%);
    }
}

.leaving .drawer {
    animation: drawer-out 0.2s var(--ease-in-out) forwards;
}

@keyframes drawer-out {
    to {
        transform: translateX(-100%);
    }
}

/* ─── Pop-up menus: the model and branch pickers ───────────── */

/* A menu up from the control that opens it (the model chip, the branch), over the conversation without dimming it. */
.pop-overlay {
    background: none;
    animation: none;
}

.pop-menu {
    position: fixed;
    display: flex;
    flex-direction: column;
    background: var(--panel);
    border-radius: var(--r-window);
    box-shadow: var(--pop);
    overflow: hidden;
    outline: none;
    animation: pop 0.25s var(--ease-out);
}

/* No chip to open from: in the middle of the screen. */
.pop-menu.free {
    position: relative;
    width: min(420px, calc(100vw - 16px));
    max-height: 80dvh;
    margin: auto;
}

.leaving .pop-menu {
    animation: pop-out var(--t-out) linear forwards;
}

/* A menu down from a control near the top (the branch in the top bar): it comes and goes from above. */
.pop-menu.down {
    animation-name: pop-menu-down;
}

.leaving .pop-menu.down {
    animation: pop-menu-up var(--t-out) linear forwards;
}

@keyframes pop-menu-down {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }
}

@keyframes pop-menu-up {
    to {
        opacity: 0;
        transform: translateY(-8px);
    }
}

.pop-menu-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.55rem 0.8rem;
    border-bottom: 1px solid var(--line);
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text);
}

.pop-menu-link {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--muted);
    transition: color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .pop-menu-link:hover {
        color: var(--accent);
    }
}

.pop-menu-search {
    margin: 0.5rem 0.6rem 0.25rem;
}

/* The field's frame shows the focus. */
.pop-menu-search input:focus-visible {
    outline: none;
}

.pop-menu-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.pop-menu-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.5rem 0.8rem;
    text-align: left;
    border-bottom: 1px solid var(--line);
    color: var(--text);
}

.pop-menu-row:last-child {
    border-bottom: 0;
}

.pop-menu-row.on {
    background: var(--card-2);
    box-shadow: inset 0 0 0 1px var(--edge);
}

.pop-menu-row-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.pop-menu-row-name {
    font-size: 0.86rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pop-menu-row-sub {
    font-size: 0.7rem;
    color: var(--muted);
}

.pop-menu-row .icon {
    color: var(--accent);
}

.pop-menu-note {
    margin: 0;
    padding: 0.6rem 0.8rem;
}

.pop-menu-foot {
    padding: 0.4rem 0.8rem 0.7rem;
    border-top: 1px solid var(--line);
}

.pop-menu-foot p {
    margin: 0.2rem 0 0;
}

/* Under the thinking levels: the owner's Make default, or in the default's picker, how the default works. */
.pop-menu-default {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.3rem 0.8rem;
    padding-block: 0.55rem;
    font-size: 0.75rem;
}

.pop-menu-foot + .pop-menu-default {
    border-top: 0;
    padding-top: 0;
}

.pop-menu-default-mark {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--ok);
}

.pop-menu-head-sub {
    margin-left: 0.4rem;
    font-weight: 400;
    color: var(--muted);
}

/* A heading between a menu's groups of rows. */
.pop-menu-label {
    padding: 10px 10px 4px;
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

/* The branch picker: what is checked out beside its title, and how far each branch is from its remote one. */
.branch-picker {
    background: var(--bg);
}

.branch-picker.down {
    animation-name: pop;
}

.branch-picker .pop-menu-head {
    padding: 12px 14px;
    border-color: var(--hair);
    font-size: 13px;
    font-weight: 600;
}

.branch-picker .pop-menu-list {
    padding: 6px;
}

.branch-picker .pop-menu-foot {
    border-color: var(--hair);
    font-size: 12px;
}

.branch-picker .pop-menu-row {
    border: 0;
    border-radius: var(--r-row);
    padding: 8px 10px;
}

.branch-picker .pop-menu-row.on {
    background: var(--card);
    box-shadow: none;
    color: var(--text);
}

.branch-picker .pop-menu-row-name {
    font-size: 13px;
}

.branch-picker .pop-menu-row-sub {
    font-size: 11.5px;
    color: var(--faint);
}

.branch-head {
    display: inline-flex;
    padding: 2px 8px;
    border-radius: calc(var(--r-tag) + 1px);
    background: var(--card);
    font-size: 12px;
    align-items: center;
    gap: 0.3rem;
    min-width: 0;
    overflow: hidden;
    font-weight: 400;
    color: var(--muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.branch-track {
    flex: none;
    font: 0.7rem var(--mono);
    color: var(--muted);
}

.branch-track.warn {
    color: var(--warn);
}

/* A branch checked out in another worktree: listed, but switched to only there. */
.pop-menu-row.elsewhere {
    color: var(--muted);
}

/*
 * The model picker, above the model chip: a header with the way to Providers, a row per model (its provider under its
 * name, a check on the current one), and Thinking's levels in one track.
 */
.model-menu .pop-menu-head {
    padding: 12px 14px 8px;
    border-bottom: 0;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--muted);
}

.model-menu .pop-menu-link {
    gap: 5px;
    font-size: 12.5px;
    color: var(--accent);
}

.model-menu .pop-menu-list {
    padding: 0 6px 6px;
}

.model-menu .pop-menu-row {
    gap: 10px;
    padding: 8px 10px;
    border-bottom: 0;
    border-radius: var(--r-row);
}

.model-menu .pop-menu-row.current {
    background: var(--card);
}

.model-menu .pop-menu-row.on {
    background: var(--hover);
    box-shadow: none;
}

.model-menu .pop-menu-row-text {
    line-height: 1.35;
}

.model-menu .pop-menu-row-name {
    font-size: 13.5px;
}

.model-menu .pop-menu-row.current .pop-menu-row-name {
    font-weight: 500;
}

.model-menu .pop-menu-row-sub {
    font: 11px var(--mono);
    color: var(--faint);
}

.model-menu .pop-menu-foot {
    padding: 10px 14px 14px;
    border-top: 1px solid var(--hair);
}

.model-menu .pop-menu-foot .label {
    margin-bottom: 8px;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--muted);
}

.model-scope {
    display: inline-flex;
    align-items: center;
    margin-left: 5px;
    font-size: 11px;
    font-weight: 400;
    white-space: nowrap;
}

.model-scope button {
    padding: 6px 3px;
    color: var(--muted);
    font: inherit;
}

.model-scope button.on {
    color: var(--accent);
}

/*
 * On a touch screen scoped and all keep their size; each one's hit area reaches out to about 45px high, away from the
 * other and within the header. Providers stays on top where the two meet on a narrow phone.
 */
@media (pointer: coarse) {
    .model-scope button,
    .model-menu .pop-menu-head > .pop-menu-link {
        position: relative;
    }
    .model-scope button::before {
        content: "";
        position: absolute;
        inset: -8px -1px -8px -14px;
    }
    .model-scope button:last-of-type::before {
        inset: -8px -18px -8px -1px;
    }
}

/* Thinking: the levels in one track, the chosen one raised. Past the general segmented rules, which come later. */
.segmented.model-levels {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 0;
    padding: 3px;
    border: 0;
    border-radius: var(--r-control);
    background: var(--card);
}

.segmented.model-levels button {
    height: 26px;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    border: 0;
    border-radius: var(--r-seg);
    background: none;
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 500;
}

.segmented.model-levels button.on {
    background: var(--raised);
    color: var(--text);
}

@media (hover: hover) {
    .segmented.model-levels button:not(.on):hover {
        color: var(--text);
    }
}

/* ─── Sheet parts and controls ───────────────────────────────── */

.sheet-head {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: calc(42px + 14px * var(--space-y));
    flex: none;
    padding: 0 10px 0 calc(20px * var(--space-x));
    border-bottom: 1px solid var(--hair);
    position: relative;
}

.sheet-head > .icon-button {
    width: 34px;
    height: 34px;
}

.sheet-head > .sheet-back {
    width: 32px;
    height: 32px;
    margin-left: -10px;
}

@media (max-width: 699px) {
    .sheet-head {
        padding-top: 14px;
        min-height: calc(56px + 14px * var(--space-y));
    }
    .sheet-head > .icon-button {
        width: 40px;
        height: 40px;
    }
}

.grip {
    display: none;
    position: absolute;
    top: 8px;
    left: 50%;
    width: 36px;
    height: 5px;
    margin-left: -18px;
    border-radius: var(--r-mark);
    background: var(--hair-2);
}

@media (max-width: 699px) {
    .grip {
        display: block;
    }
    /* A menu a swipe closes: its grip at the edge it goes from, with room. */
    .pop-menu > .grip + .pop-menu-head {
        padding-top: 20px;
    }
    .pop-menu.down {
        padding-bottom: 16px;
    }
    .pop-menu.down > .grip {
        top: auto;
        bottom: 6px;
    }
}

.sheet-head h2 {
    flex: 1;
    min-width: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sheet-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    padding: calc(16px * var(--space-y)) calc(20px * var(--space-x)) calc(20px * var(--space-y));
    display: flex;
    flex-direction: column;
    gap: calc(14px * var(--space-y));
}

.sheet-body > * {
    flex-shrink: 0;
}

.sheet-body p {
    margin: 0;
}

.sheet-body .small {
    font-size: 12px;
}

.sheet-list {
    overflow: hidden;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--bg);
}

.sheet-list > :not(:first-child) {
    border-top: 1px solid var(--hair);
}

.sheet-list > .list-item {
    border-radius: 0;
    margin: 0;
}

/* Rows that are controls themselves: the ring inside the list, which cuts off what is past its edges. */
.sheet-list > :is(button, .list-item):focus-visible {
    outline-offset: -2px;
}

.sheet-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* Shared menu rows: inset groups in sheets, quiet standalone rows elsewhere. */
.list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    width: 100%;
    /* 44px, 40px, and 37px. */
    min-height: calc(32px + 12px * var(--space-y));
    text-align: left;
    padding: calc(12px * var(--space-y)) calc(14px * var(--space-x));
    border-radius: var(--r-row);
    background: var(--bg);
    border: 0;
    font-size: 13.5px;
    color: var(--text);
    text-decoration: none;
    margin-bottom: 2px;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        padding var(--t-in) var(--ease-out);
}

@media (hover: hover) {
    .list-item:hover {
        background: var(--card);
    }
}

.list-item:active {
    background: var(--pressed);
}

.list-item > span:first-child {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.list-item.active {
    background: var(--accent-soft);
    color: var(--accent);
}

.group-title,
.label {
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
    margin: calc(4px * var(--space-y)) 2px calc(6px * var(--space-y));
}

.field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.field > .label {
    margin: 0;
    color: var(--muted);
    font-size: 12.5px;
}

.field input,
.field textarea {
    font-size: 14.5px;
    border-radius: calc(var(--r-control) + 1px);
}

@media (pointer: coarse) {
    .field input,
    .field textarea {
        font-size: 16px;
    }
}

/* Native checkbox semantics and label targets, drawn in the shared sheet palette. */
.check input[type="checkbox"],
.subagent-model input[type="checkbox"] {
    appearance: none;
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 14px;
    height: 14px;
    margin: 0;
    padding: 0;
    border: 1.5px solid var(--hair-2);
    border-radius: calc(var(--r-tag) - 1px);
    background: var(--card);
    color: var(--accent-ink);
    cursor: pointer;
}

.check input[type="checkbox"]::before,
.subagent-model input[type="checkbox"]::before {
    content: "";
    width: 4px;
    height: 7px;
    margin-top: -2px;
    border: solid currentColor;
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
    opacity: 0;
}

.check input[type="checkbox"]:checked,
.subagent-model input[type="checkbox"]:checked {
    border-color: var(--accent-fill);
    background: var(--accent-fill);
}

.check input[type="checkbox"]:checked::before,
.subagent-model input[type="checkbox"]:checked::before {
    opacity: 1;
}

.check input[type="checkbox"]:disabled,
.subagent-model input[type="checkbox"]:disabled {
    opacity: 0.5;
    cursor: default;
}

.row {
    display: flex;
    gap: 0.45rem;
    align-items: center;
}

.row input {
    flex: 1;
}

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-height: 38px;
    border: 1px solid transparent;
    background: var(--card-2);
    border-radius: var(--r-control);
    padding: 7px 16px;
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    color: var(--text);
    white-space: nowrap;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

@media (hover: hover) {
    .button:hover {
        background: var(--raised);
    }
}

.button:active:not(:disabled) {
    transform: scale(0.97);
}

.button.primary {
    background: var(--accent-fill);
    border-color: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 600;
}

@media (hover: hover) {
    .button.primary:hover {
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
    }
}

.button kbd {
    background: transparent;
    color: inherit;
    opacity: 0.7;
    border-color: currentColor;
}

.button.ghost {
    background: none;
    border-color: var(--hair-2);
    color: var(--muted);
}

@media (hover: hover) {
    .button.ghost:hover {
        background: var(--hover);
        color: var(--err);
    }
}

.button.sheet-footer {
    min-height: 40px;
    border-radius: calc(var(--r-control) + 1px);
}

/* Away from Save, in the color of what cannot be undone here. */
.button.sheet-footer.signout {
    margin-top: 14px;
    color: var(--err);
}

.button.small {
    min-height: 30px;
    padding: 4px 11px;
    border-radius: calc(var(--r-row) - 1px);
    font-size: 12.5px;
}

.button.wide {
    width: 100%;
}

.button:disabled {
    opacity: 0.5;
}

.link {
    color: var(--accent);
    font-size: 0.85rem;
}

.segmented {
    display: flex;
    flex-wrap: wrap;
    align-self: flex-start;
    gap: 0;
    padding: 3px;
    border-radius: var(--r-control);
    background: var(--card);
}

.segmented button {
    min-height: 28px;
    border: 0;
    border-radius: var(--r-seg);
    padding: 4px 11px;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--muted);
    background: none;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .segmented button:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.segmented button.on {
    background: var(--raised);
    color: var(--text);
}

/*
 * The folder picker, laid out as a desktop's file dialog: the path and New folder on top, places beside the folders,
 * and the folder Open takes with Cancel and Open at the bottom. A fixed height: only the places and the folders scroll.
 */
.sheet.folder-sheet {
    height: min(86dvh, 600px);
}

.folder-sheet .sheet-body {
    flex: 1;
    min-height: 0;
    gap: 0.5rem;
    padding-bottom: 0.75rem;
}

.fp-bar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
}

.fp-bar > .icon-button,
.fp-new {
    background: var(--card);
    border-radius: var(--r-row);
}

.fp-bar > .icon-button:disabled {
    opacity: 0.35;
    pointer-events: none;
}

.fp-new {
    flex: none;
    gap: 0.3rem;
}

.fp-crumbs {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    overflow-x: auto;
    scrollbar-width: none;
    white-space: nowrap;
    min-height: 34px;
    padding: 0 6px;
    border-radius: var(--r-row);
    background: var(--card);
    font: 13px var(--mono);
}

.fp-crumbs::-webkit-scrollbar {
    display: none;
}

/* A path too long for the field fades in from its start rather than being cut there (folder.js marks it cut). */
.fp-crumbs.cut::before {
    content: "";
    position: sticky;
    left: 0;
    z-index: 1;
    flex: none;
    align-self: stretch;
    width: 28px;
    margin: 0 -22px 0 -6px;
    background: linear-gradient(to right, var(--card) 6px, transparent);
    pointer-events: none;
}

.fp-crumb {
    flex: none;
    padding: 0.3rem 0.35rem;
    border-radius: var(--radius);
    color: var(--muted);
}

@media (hover: hover) {
    .fp-crumb:hover {
        background: var(--hover);
        color: var(--accent);
    }
}

.fp-crumb.here {
    color: var(--text);
    font-weight: 600;
}

.fp-sep {
    flex: none;
    color: var(--line-strong);
}

/* A path or a new folder's name being typed. */
.fp-line {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.fp-line input {
    flex: 1;
    min-width: 0;
    height: 34px;
    padding: 0.3rem 0.5rem;
    font-size: 0.85rem;
}

.fp-line .icon-button {
    width: 32px;
    height: 32px;
    color: var(--muted);
}

.fp-path-input {
    flex: 1;
    min-width: 0;
}

.fp-naming {
    padding: 0.35rem 0.4rem 0.35rem 0.6rem;
    border-bottom: 1px solid var(--line);
    background: var(--accent-soft);
}

/* A small phone's folder list is narrow: the name takes the whole line, OK and Cancel go under it. */
@media (max-width: 480px) {
    .fp-naming {
        flex-wrap: wrap;
        justify-content: flex-end;
    }
    .fp-naming input {
        flex-basis: 100%;
    }
}

/* A typed path that is not there, with Create it. */
.folder-missing {
    flex: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.3rem 0.6rem;
    padding: 0.3rem 0.3rem 0.3rem 0.6rem;
    border: 1px solid var(--warn-line);
    background: var(--warn-soft);
    font-size: 0.82rem;
    color: var(--body);
    overflow-wrap: anywhere;
}

.fp-missing-actions {
    display: flex;
    align-items: center;
    gap: 0.2rem;
}

.fp-missing-actions .icon-button {
    width: 32px;
    height: 32px;
}

/* Places beside the folders, as in a file dialog's sidebar. */
.fp-main {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 12px;
    overflow: hidden;
}

.fp-places {
    flex: none;
    width: clamp(7rem, 28%, 11rem);
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 0.3rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg);
}

.fp-place {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    width: 100%;
    min-height: 2rem;
    padding: 0.25rem 0.45rem;
    border-radius: var(--radius);
    text-align: left;
    font-size: 0.82rem;
    color: var(--body);
}

.fp-place span {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.fp-place .icon {
    flex: none;
    color: var(--muted);
}

@media (hover: hover) {
    .fp-place:hover {
        background: var(--hover);
    }
}

.fp-place.on {
    background: var(--accent-soft);
    color: var(--accent);
}

.fp-place.on .icon {
    color: var(--accent);
}

/* A favorite's shortcut, Ctrl/⌘+1…9, at the end of its place. */
.fp-key {
    flex: none;
    margin-left: auto;
    font: 11px var(--mono);
    color: var(--faint);
}

.fp-places-title {
    margin: 10px 10px 4px;
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

.fp-pi {
    margin: auto 0.45rem 0.2rem;
    padding-top: 0.6rem;
    text-align: left;
    font-size: 0.78rem;
}

.fp-list {
    flex: 1;
    min-width: 0;
    padding: 4px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg);
}

.fp-list:focus-visible {
    outline: none;
}

.fp-row {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    min-height: 34px;
    padding: 6px 10px;
    border-radius: calc(var(--r-row) - 1px);
    text-align: left;
    font: 13px var(--mono);
    color: var(--body);
    user-select: none;
}

@media (hover: hover) {
    .fp-row:hover {
        background: var(--hover);
    }
}

/* The selected folder: what Open takes. */
.fp-row.on {
    background: var(--accent-soft);
    color: var(--accent);
}

.fp-row .icon {
    flex: none;
    color: var(--accent);
}

.fp-row .fp-chev {
    margin-left: auto;
    color: var(--muted);
}

.fp-name {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.fp-note {
    margin: 0;
    padding: 0.8rem;
    font-size: 0.82rem;
    color: var(--muted);
}

/* The bottom: the folder Open takes, the options, then Cancel and Open, as a file dialog's. */
.fp-foot {
    flex: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.9rem;
}

.fp-target {
    flex: 1 0 100%;
    min-width: 0;
    display: flex;
    gap: 0.4rem;
    font-size: 0.82rem;
    white-space: nowrap;
}

.fp-target .mono {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text);
}

/* Star the folder Open takes, to keep it among the places as a favorite. */
.fp-target .fp-star {
    flex: none;
    width: 28px;
    height: 28px;
    margin: -6px 0;
    color: var(--muted);
}

.fp-star.on {
    color: var(--accent);
}

.fp-star.on .icon {
    fill: currentColor;
}

@media (pointer: coarse) {
    .fp-target .fp-star {
        width: 40px;
        height: 40px;
        margin: -12px 0;
    }
}

.fp-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.9rem;
}

.fp-options .check {
    margin-bottom: 0;
}

.fp-buttons {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
}

.fp-buttons .button {
    min-width: 6.5rem;
    justify-content: center;
}

/* Phones: the buttons share the width, under the options. */
@media (max-width: 699px) {
    .fp-new {
        padding-inline: 0.6rem;
    }
    .fp-buttons {
        flex: 1 0 100%;
    }
    .fp-buttons .button {
        flex: 1;
    }
    .fp-places {
        width: 8.5rem;
    }
    .fp-row,
    .fp-place {
        min-height: 40px;
    }
}

.check {
    display: flex;
    gap: 0.4rem;
    align-items: center;
    font-size: 0.82rem;
    color: var(--muted);
    margin-bottom: 0.35rem;
}

.provider {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 14px 16px;
    background: var(--bg);
}

.provider-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.provider-name {
    font-weight: 500;
}

.provider .provider-needs {
    display: inline-block;
    padding: 1px 7px;
    border-radius: var(--r-pill);
    background: var(--warn-soft);
    font-size: 11.5px;
    font-weight: 500;
}

@media (max-width: 699px) {
    .provider {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
    }
}

/* Providers by state: what needs a sign-in first, then what works, then the rest. */
.providers-main {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

.providers-main > *,
.providers-side > * {
    flex-shrink: 0;
}

.provider-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.provider-group-head {
    margin: 0 2px;
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

.provider-group-head .muted {
    margin-left: 4px;
}

.providers-side {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/*
 * Wide screens, the owner's view: the providers to sign in to on the left, and what is shared on the right (the refresh,
 * and the models for subagents). A fixed height, and each side scrolls on its own. Narrower: one column, as on a phone.
 */
@media (min-width: 700px) {
    .sheet.providers-sheet.with-side {
        max-width: 760px;
    }
}

@media (min-width: 1000px) {
    .sheet.providers-sheet.with-side {
        max-width: 1160px;
        height: min(86dvh, 880px);
    }
    .providers-sheet.with-side .sheet-body {
        overflow-y: hidden;
    }
    .providers-sheet .providers-layout {
        flex: 1;
        min-height: 0;
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(340px, 400px);
        gap: 24px;
    }
    .providers-sheet .providers-main {
        grid-column: 1;
        grid-row: 1;
        min-height: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
        padding-right: 6px;
    }
    .providers-sheet .providers-side {
        grid-column: 2;
        grid-row: 1;
        min-height: 0;
        padding: 16px;
        gap: 4px;
        border: 1px solid var(--hair);
        border-radius: var(--r-card);
        background: var(--card);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    .providers-side .model-refresh {
        margin-top: 0;
    }
    .providers-side .subagent-models {
        flex: 1 1 0;
        min-height: 18rem;
        margin: 0;
        padding: 12px 0 0;
        border-bottom: 0;
        border-top: 1px solid var(--line);
    }
    .providers-side .subagent-models > .label {
        margin: 0;
        font-size: 13px;
        font-weight: 600;
        color: var(--text);
    }
    .providers-side .subagent-models-list {
        flex: 1;
        min-height: 8rem;
        max-height: none;
        background: var(--bg);
    }
    .providers-main .search {
        position: sticky;
        top: 0;
        z-index: 2;
        flex: none;
        min-height: 40px;
        /* Opaque, so rows scrolling under it do not show through. */
        background: linear-gradient(var(--card), var(--card)), var(--panel);
    }
}

.provider-actions {
    display: flex;
    gap: 0.35rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* What a provider said when it would not renew a sign-in. */
.provider-why {
    overflow-wrap: anywhere;
}

/* Shared refresh feedback stays visible after a request and wraps provider messages as plain text. */
.model-refresh {
    margin-block: 0.5rem;
    min-width: 0;
}

.model-refresh .button.model-refresh-button {
    min-height: 40px;
}

.model-refresh-status {
    max-height: 22dvh;
    overflow-y: auto;
    overflow-wrap: anywhere;
    overscroll-behavior: contain;
}

.model-refresh-status p {
    margin: 0.35rem 0 0;
}

/* The owner's choice of how long a run waits for a provider's limit to clear. */
.limit-wait {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.6rem 0 0.8rem;
    margin-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
}

.limit-wait p {
    margin: 0;
}

.limit-wait .segmented {
    flex-wrap: wrap;
}

/* The owner's choice of models for subagents, above the providers. */
.subagent-models {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.6rem 0 0.8rem;
    margin-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
}

.subagent-models p {
    margin: 0;
}

/* What is allowed, on one line: the list under it stays put while models are checked one after another. */
.subagent-models-chosen {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.subagent-models .search {
    margin-bottom: 0;
}

/* Every model, by provider. A long list scrolls in its own box, so the providers stay near. */
.subagent-models-list {
    max-height: min(22rem, 45dvh);
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
}

.subagent-models-list > p {
    padding: 0.6rem;
}

.subagent-models-head {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 6px 12px;
    background: var(--card);
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

.subagent-model {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 44px;
    padding: 8px 12px;
    border-top: 1px solid var(--hair);
    cursor: pointer;
}

.subagent-model > span {
    min-width: 0;
    overflow-wrap: anywhere;
}

.subagent-model .muted {
    display: block;
}

.invite {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: stretch;
}

.qr {
    background: #fff;
    border-radius: var(--radius);
    padding: 0.6rem;
    /* Smaller on short screens, so the invite sheet fits a laptop window without scrolling. */
    width: min(70vw, clamp(160px, 25dvh, 260px));
    align-self: center;
}

.qr svg {
    display: block;
    width: 100%;
    height: auto;
}

/* The invite code, for typing on the other device: easy to spot and to read out. */
.invite-details {
    display: flex;
    align-items: center;
    gap: 16px;
}

.invite-details .qr {
    flex: none;
    width: 150px;
    border-radius: var(--r-window);
}

.invite-code {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

@media (max-width: 480px) {
    .invite-details {
        flex-direction: column;
    }
    .invite-code {
        align-self: stretch;
    }
}

.invite-code-head {
    align-self: stretch;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
}

.invite-code-value {
    display: flex;
    gap: 0.6em;
    font: 600 24px var(--mono);
    letter-spacing: 0.08em;
    color: var(--text);
    user-select: all;
}

.code-big {
    font: 600 22px var(--mono);
    letter-spacing: 0.12em;
    text-align: center;
    padding: 6px;
    border-radius: var(--r-control);
    background: var(--bg);
}

.auth-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border-radius: var(--r-window);
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
}

.auth-inline {
    padding: 16px;
    border-radius: var(--r-window);
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
}

.auth-inline-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 12px;
    color: var(--text);
}

.auth-inline-head strong {
    font-size: 14px;
    font-weight: 600;
}

.auth-inline .auth-card {
    padding: 0;
    border: 0;
    background: none;
}

.auth-event {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

/* ─── Artifact viewer ──────────────────────────────────────── */

.viewer {
    position: fixed;
    inset: 0;
    z-index: 30;
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    background: var(--bg);
    display: flex;
    flex-direction: column;
}

.viewer-head {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 58px;
    padding: calc(env(safe-area-inset-top) + 8px) 10px 8px 20px;
    border-bottom: 1px solid var(--hair);
}

.artifact-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.artifact-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    text-align: left;
}

@media (hover: hover) {
    .artifact-card:hover {
        border-color: var(--accent-line);
    }
}

.artifact-cover {
    height: 120px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 8px;
    background: var(--card);
    color: var(--faint);
    font: 11px var(--mono);
}

.artifact-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: 100%;
    padding: 10px 12px;
    overflow-wrap: anywhere;
}

.artifact-name {
    color: var(--text);
    font-size: 13.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.message-actions > .group-title {
    margin: 0;
    padding: 8px 14px;
    background: var(--card);
}

/* A viewer has nothing to do with a message of files alone: no empty box. */
.message-actions:empty {
    display: none;
}

.message-model-search {
    padding: 8px 14px;
}

.message-preview {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
    /* Room as a clear border, not padding: the clamp clips at the padding's edge, so a fourth line would show in it. */
    border: solid transparent;
    border-width: 12px 14px;
    border-radius: var(--r-card);
    background: var(--card);
    color: var(--body);
    font-size: 13.5px;
}

@media (max-width: 480px) {
    .viewer-head {
        flex-wrap: wrap;
    }
    .viewer-title {
        flex-basis: calc(100% - 50px);
    }
    .artifact-grid {
        grid-template-columns: 1fr;
    }
}

.viewer-title {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.viewer-title strong {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.viewer select {
    width: auto;
    padding: 0.3rem 0.4rem;
}

.viewer iframe {
    flex: 1;
    border: 0;
    width: 100%;
    background: #fff;
}

/* ─── Images ───────────────────────────────────────────────── */

.thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.4rem;
}

.prompt-body > .thumbs:first-child {
    margin-top: 0;
}

.thumb {
    display: block;
    padding: 0;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow: hidden;
    background: var(--card);
    cursor: zoom-in;
    max-width: 100%;
}

.thumb img {
    display: block;
    width: auto;
    max-width: min(180px, 100%);
    height: 140px;
    object-fit: cover;
}

.thumb:only-child img {
    max-width: 100%;
    height: auto;
    max-height: 320px;
    object-fit: contain;
}

.md img {
    max-width: 100%;
    height: auto;
    max-height: 460px;
    border-radius: var(--r-card);
    border: 1px solid var(--hair);
    background: var(--card);
    cursor: zoom-in;
    vertical-align: middle;
}

.md a img {
    cursor: pointer;
}

.md img.broken {
    display: none;
}

.image-missing {
    display: inline-block;
    font-size: 0.8rem;
    color: var(--muted);
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius);
    padding: 0.25rem 0.55rem;
}

.artifact-preview {
    display: block;
    width: 100%;
    padding: 0.5rem;
    border: 1px solid var(--line);
    background: #fff;
    cursor: zoom-in;
}

.artifact-preview img {
    display: block;
    width: 100%;
    height: auto;
    max-height: 360px;
    object-fit: contain;
}

.chip.with-thumb {
    padding-left: 0.2rem;
}

.chip-thumb {
    width: 22px;
    height: 22px;
    border-radius: var(--radius);
    object-fit: cover;
    flex: none;
}

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 35;
    background: color-mix(in srgb, var(--desk) 95%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(env(safe-area-inset-top) + 3.2rem) calc(0.5rem + env(safe-area-inset-right))
        calc(env(safe-area-inset-bottom) + 0.5rem) calc(0.5rem + env(safe-area-inset-left));
    animation: fade var(--t-fade) var(--ease-almost);
    cursor: zoom-out;
}

.lightbox > img {
    animation: pop var(--t-in) var(--ease-out);
}

.lightbox img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--radius);
    background: #fff;
}

.lightbox-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: calc(env(safe-area-inset-top) + 0.4rem) calc(0.4rem + env(safe-area-inset-right))
        0.4rem calc(0.9rem + env(safe-area-inset-left));
    background: linear-gradient(color-mix(in srgb, var(--desk) 80%, transparent), transparent);
    cursor: default;
}

.lightbox-title {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 0.85rem;
    color: var(--muted);
}

/* ─── Notices, sign-in, plain pages ────────────────────────── */

/* Notices: small tiles that hang from the top edge, a state square in their level's color (the accent, a warning's
 * yellow, an error's red) and a countdown line until they go. A tap dismisses one, or does what it offers (a chevron
 * says so); on a phone, a swipe up puts it away. */
.notices {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    top: calc(env(safe-area-inset-top) + 0.6rem);
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: min(calc(100vw - 20px), 440px);
    pointer-events: none;
}

@media (min-width: 700px) {
    .notices {
        width: min(92vw, 400px);
    }
}

.notice {
    --level: var(--accent);
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: flex-start;
    gap: 11px;
    min-height: 44px;
    padding: 12px 12px 13px 14px;
    border-radius: var(--r-card);
    background:
        linear-gradient(100deg, color-mix(in srgb, var(--level) 9%, transparent), transparent 48%),
        var(--panel);
    box-shadow: var(--pop);
    color: var(--text);
    text-align: left;
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.4;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
    animation: toast-in 0.28s var(--ease-out);
}

.notice.warning {
    --level: var(--warn);
}

.notice.error {
    --level: var(--err);
}

/* The level, as the session list's state squares say a session's: a lit square with a soft halo. */
.notice-mark {
    flex: none;
    width: 8px;
    height: 8px;
    margin: 6px 1px 0;
    border-radius: calc(var(--r-mark) - 0.5px);
    background: var(--level);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--level) 18%, transparent);
}

.notice-text {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

.notice > .icon {
    flex: none;
    margin-top: 2px;
    color: var(--faint);
    transition: color var(--t-hover) var(--ease-out);
}

.notice.acts > .icon {
    color: var(--muted);
}

@media (hover: hover) {
    .notice:hover {
        background:
            linear-gradient(
                100deg,
                color-mix(in srgb, var(--level) 12%, transparent),
                transparent 55%
            ),
            var(--card);
    }

    .notice:hover > .icon {
        color: var(--text);
    }
}

.notice:active {
    scale: 0.985;
}

.notice:focus-visible {
    outline: 2px solid var(--accent-line);
    outline-offset: 2px;
}

/* How long until it goes: a hairline in its level's color, shrinking from the right. */
.notice::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: color-mix(in srgb, var(--level) 55%, transparent);
    transform-origin: left;
    animation: countdown var(--life, 4.5s) linear forwards;
}

.notice.held::after {
    animation-play-state: paused;
}

@keyframes countdown {
    to {
        transform: scaleX(0);
    }
}

/* Like the popovers' pop, but from above: the notice hangs from the top edge. `translate`, not `transform`, so one
 * swiped away goes on up from where the finger left it. */
@keyframes toast-in {
    from {
        opacity: 0;
        translate: 0 -8px;
        scale: 0.97;
    }
}

@keyframes toast-out {
    to {
        opacity: 0;
        translate: 0 -8px;
        scale: 0.97;
    }
}

.notice.leaving {
    pointer-events: none;
    animation: toast-out var(--t-out) linear forwards;
}

.signin,
.plain {
    max-width: 440px;
    margin: 0 auto;
    padding: 3rem 1.2rem;
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
}

.signin .pi.big {
    font-size: 4rem;
    text-align: center;
}

.signin h1,
.plain h1 {
    margin: 0;
    text-align: center;
    font-size: 1.4rem;
}

.plain form {
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
}

.plain label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    color: var(--muted);
}

.plain button {
    min-height: 42px;
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 600;
    border-radius: calc(var(--r-control) + 1px);
    padding: 10px 16px;
}

.plain h1,
.signin h1 {
    color: var(--text);
    font-weight: 600;
}

body.plain-page {
    height: auto;
}

/* ─── People: who is here, typing, and the side chat ───────── */

/* Who else is here, in the top bar: an avatar with an online mark, and how many more. */
.people-button {
    height: 40px;
    min-width: 40px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    position: relative;
    flex: none;
    color: var(--body);
    border-radius: var(--r-control);
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .people-button:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.people-here {
    position: relative;
    display: inline-grid;
}

.online-mark {
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--ok);
    box-shadow: 0 0 0 2px var(--bg);
}

.online-mark.away {
    background: var(--faint);
}

.people-more {
    font: 11px var(--mono);
    color: var(--muted);
}

.avatar {
    display: inline-grid;
    place-items: center;
    flex: none;
    background: color-mix(in srgb, var(--who, var(--accent)) 20%, transparent);
    color: var(--who, var(--accent));
    border: 0;
    border-radius: 50%;
    font-size: 0.62rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0;
}

.avatar.typing {
    animation: avatar-typing 1.2s ease-in-out infinite;
}

@keyframes avatar-typing {
    50% {
        background: var(--accent-soft);
    }
}

.typing-line {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 12px;
    color: var(--muted);
    padding: 0 0.2rem 0.3rem;
}

.typing-dots {
    display: inline-flex;
    gap: 3px;
}

.typing-dots span {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--accent);
    animation: typing-dot 1.2s infinite ease-in-out;
}

.typing-dots span:nth-child(2) {
    animation-delay: 0.15s;
}

.typing-dots span:nth-child(3) {
    animation-delay: 0.3s;
}

@keyframes typing-dot {
    0%,
    60%,
    100% {
        opacity: 0.3;
    }
    30% {
        opacity: 1;
    }
}

.chat-label {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px;
    color: var(--faint);
    font-size: 11.5px;
}

.chat-log {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 1;
    min-height: 80px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 4px 2px 8px;
}

.chat-log::before {
    content: "";
    margin-top: auto;
}

.chat-msg {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
}

.chat-msg.mine {
    align-items: flex-end;
}

.chat-msg:not(.grouped) {
    margin-top: 10px;
}

.chat-msg:first-child {
    margin-top: 0;
}

.chat-meta {
    font-size: 11.5px;
    display: flex;
    gap: 6px;
    padding: 0 4px;
    align-items: baseline;
    color: var(--faint);
}

.chat-meta .muted {
    color: var(--faint);
}

.chat-name {
    color: var(--who, var(--accent));
    font-weight: 600;
}

.chat-text {
    max-width: 85%;
    padding: 8px 12px;
    border-radius: calc(var(--r-window) + 2px) calc(var(--r-window) + 2px)
        calc(var(--r-window) + 2px) var(--r-tag);
    background: var(--card-2);
    color: var(--text);
    font-size: 13.5px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.chat-msg.mine .chat-text {
    border-radius: calc(var(--r-window) + 2px) calc(var(--r-window) + 2px) var(--r-tag)
        calc(var(--r-window) + 2px);
    background: var(--accent-soft);
}

.chat-compose {
    display: flex;
    gap: 6px;
    align-items: flex-end;
    background: var(--card);
    border: 1px solid var(--hair-2);
    border-radius: var(--r-sheet);
    padding: 4px 4px 4px 14px;
}

.chat-compose:focus-within {
    border-color: var(--accent-line);
}

.chat-compose textarea {
    flex: 1;
    min-width: 0;
    border: 0;
    outline: 0;
    background: none;
    color: var(--text);
    resize: none;
    padding: 5px 0;
    max-height: 30vh;
    overflow-x: hidden;
    font: 13.5px/1.45 var(--sans);
}

.chat-compose .round.send {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    flex: none;
}

.chat-compose .round.send:disabled {
    background: var(--card-2);
    color: var(--faint);
    opacity: 1;
}

@media (pointer: coarse) {
    .chat-compose textarea {
        font-size: 16px;
    }

    .chat-compose .round.send {
        width: 40px;
        height: 40px;
    }
}

/* Codemode: the tool calls a script made, under its code. */
.nested-calls {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin: 0.35rem 0;
    font-size: 0.8rem;
}

.nested-call {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.45rem;
}

.nested-status {
    width: 1rem;
    text-align: center;
    color: var(--ok);
}

.nested-call.error .nested-status,
.nested-error {
    color: var(--err);
}

.nested-call.running .nested-status,
.nested-call.cancelled .nested-status {
    color: var(--muted);
}

.nested-error {
    flex-basis: 100%;
    padding-left: 1.45rem;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ─── Collaboration: activity, quotes, mentions, pins, notes, reactions, take turns ─── */

.avatar.away {
    opacity: 0.45;
}

.tabs {
    flex-wrap: nowrap;
}

.tabs button {
    flex: 1;
    white-space: nowrap;
}

.chat-event {
    text-align: center;
    font-size: 11.5px;
    color: var(--faint);
    margin: 5px 0;
}

.chat-msg.open .chat-text,
.chat-msg.mentions-me .chat-text {
    box-shadow: inset 0 0 0 1px var(--accent-line);
}

.chat-text {
    cursor: default;
}

.chat-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding: 2px 4px 4px;
}

.chat-quote {
    max-width: 85%;
    text-align: left;
    border: 1px solid var(--hair);
    border-radius: var(--r-row);
    background: var(--card);
    color: var(--muted);
    font-size: 12px;
    padding: 5px 10px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

.quote-draft {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: var(--r-row);
    background: var(--card);
    color: var(--muted);
    font-size: 12px;
}

.quote-draft .quote-text {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mention {
    color: var(--accent);
    font-weight: 700;
}

.mention.me {
    background: var(--accent-soft);
    padding: 0 0.15rem;
}

.mention-list {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    background: var(--panel);
}

.mention-list .list-item {
    margin: 0;
    border: 0;
    border-bottom: 1px solid var(--line);
}

.pin-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-y: auto;
}

.pin {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: calc(var(--r-control) + 1px);
    padding: 9px 8px 9px 12px;
}

.pin-main {
    flex: 1;
    min-width: 0;
    text-align: left;
}

.pin-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    font-size: 11.5px;
}

.pin-text {
    color: var(--text);
    font-size: 13px;
    overflow-wrap: anywhere;
}

textarea.notes {
    min-height: 12rem;
    resize: vertical;
    line-height: 1.5;
}

/* Bars above the message box: who drives (take turns), plan mode, a goal, a PR watch, and project trust. The dot says
   which: the accent for plan mode, a goal, and a watch, the warning color for a question (who drives, whether to
   trust) and for a watch that had to stop. */
.driver-bar,
.plan-bar,
.goal-bar,
.watch-bar,
.trust-bar,
.view-only {
    --tone: var(--warn);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    padding: 6px 10px 6px 14px;
    margin-bottom: 5px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    font-size: 13px;
    line-height: 1.4;
}

.driver-bar::before,
.plan-bar::before,
.goal-bar::before,
.watch-bar::before,
.trust-bar::before,
.view-only::before {
    content: "";
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--tone);
}

.plan-bar,
.goal-bar,
.watch-bar:is(.watching, .merged, .closed) {
    --tone: var(--accent);
}

.watch-bar a {
    color: inherit;
}

/* The trust question keeps its words a readable width: on a phone its answers go under them, together, to the right. */
.trust-bar > .grow {
    flex: 1 1 15rem;
}

/* The plan bar's words keep a readable width too: its buttons go under them when they would squeeze them. */
.plan-bar > .grow {
    flex: 1 1 18rem;
}

.plan-bar > .link {
    margin-left: auto;
}

/* Trust choices keep the three existing decisions, with a selected radio and soft accent card. */
.trust-choice {
    justify-content: flex-start;
    gap: 12px;
    padding: 14px;
    margin-bottom: 8px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
}

.trust-choice.active {
    border-color: var(--accent-line);
}

.trust-radio {
    width: 18px;
    height: 18px;
    flex: none;
    border-radius: var(--r-pill);
    border: 1.5px solid var(--hair-2);
}

.active > .trust-radio {
    border: 5px solid var(--accent);
}

.trust-choice-text {
    flex: 1;
}

/* An answer in the trust sheet: what it does over the folder it is about, which wraps rather than squeezes it. */
.list-item > span.trust-choice-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    min-width: 0;
    text-align: left;
}

.trust-choice-text > .mono {
    overflow-wrap: anywhere;
}

.trust-current {
    flex: none;
    color: var(--accent);
    font-size: 0.78rem;
}

.trust-actions {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-left: auto;
}

.driver-bar.mine {
    --tone: var(--ok);
}

.driver-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text);
    font-weight: 600;
}

.driver-label > .icon {
    color: var(--tone, var(--muted));
}

.driver-ask {
    color: var(--warn);
}

.driver-pick {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.view-only {
    --tone: var(--muted);
}

.view-only > span {
    flex: 1;
}

.composer-row.stop-only {
    padding: 4px 6px;
}

.unread-dot {
    width: 8px;
    height: 8px;
    background: var(--accent);
}

.person-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
}

@media (max-width: 480px) {
    .person-row {
        flex-wrap: wrap;
    }
    .person-actions {
        flex-basis: 100%;
    }
}

.person-main {
    flex: 1;
    min-width: 0;
}

.person-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.3rem;
}

.flash {
    animation: flash 1.6s ease-out;
}

@keyframes flash {
    0%,
    30% {
        background: var(--accent-soft);
        outline: 1px solid var(--accent-line);
    }
}

/* ─── Parts of sheets: share, schedules, goals, running now, changes, spend ─── */

/* Share to Pi: what another app shared, before it goes into a message box. */
.share-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 9rem;
    overflow-y: auto;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--card);
    padding: 12px 14px;
    margin: 0;
    font-size: 13.5px;
}

/* A switch with its label, inside a card such as an extension's. */
.setting {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.4rem;
}

/* A choice under its words when the two do not fit side by side, as on a phone. */
.setting.wrap {
    flex-wrap: wrap;
}

.setting.wrap > .grow {
    flex: 1 1 14rem;
}

/* A scheduled message in its sheet: what Pi gets, when, and who set it. */
.schedule {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    font-size: 13.5px;
}

.schedule > .icon {
    flex: none;
    box-sizing: content-box;
    padding: 8px;
    border-radius: var(--r-row);
    background: var(--accent-soft);
    color: var(--accent);
}

/* A change to a lesson that waits for the owner, under the lesson it would change. */
.lesson-proposal {
    margin-top: 0.35rem;
    padding-left: 0.6rem;
    border-left: 2px solid var(--accent);
}

/* Under Pi's memory call: the lesson's state, and Approve and Discard while it waits. */
.lesson-call {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.6rem;
    margin-top: 0.3rem;
}

.lesson-call.waiting {
    padding: 0.35rem 0.5rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 2px solid var(--accent);
    font-size: 0.82rem;
}

/* The words that wait keep a readable width: where Approve and Discard would squeeze them, they go below. */
.lesson-call.waiting > .grow {
    flex: 1 1 16rem;
}

/* Memory: a lesson Pi keeps, who saved it and where, and what can be done with it. */
.lesson {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 11px 14px;
    font-size: 13.5px;
}

.sheet-list:has(> .lesson.pending) {
    border-color: var(--warn-line);
}

.lesson-text {
    overflow-wrap: anywhere;
}

.lesson-source a {
    color: inherit;
    text-decoration: underline;
    text-decoration-color: var(--line-strong);
    overflow-wrap: anywhere;
}

.lesson-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.3rem 0.6rem;
}

.lesson-source {
    flex: 1 1 10rem;
    min-width: 0;
}

.lesson-actions {
    justify-content: flex-end;
    flex-wrap: wrap;
    margin-left: auto;
}

.lesson-actions .button.danger {
    border-color: var(--err);
    color: var(--err);
}

.lesson-add {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border-radius: var(--r-window);
    border: 1px solid var(--hair);
    background: var(--card);
}

.lesson-add textarea {
    border: 0;
    background: none;
    resize: vertical;
    padding: 2px 4px;
}

.lesson-add > .row {
    flex-wrap: wrap;
}

.lesson-add .segmented {
    background: var(--bg);
    flex: 1 0 auto;
    flex-wrap: nowrap;
}

.lesson-add .segmented button {
    flex: 1;
    white-space: nowrap;
}

/* Done when: a goal met, or one Pi gave up on. */
.goal-bar.met {
    --tone: var(--ok);
}

.goal-bar.gave-up {
    --tone: var(--warn);
}

/* Running now: a session, then what is at work in it. */
.running {
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow: hidden;
}

.running-head,
.running-task {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.running-head {
    padding: 10px 12px 10px 14px;
    background: var(--card);
}

.running-head > .folder-mark {
    width: 8px;
    height: 8px;
    border-radius: calc(var(--r-mark) - 0.5px);
}

.running-head .link {
    min-width: 0;
    text-align: left;
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.running-head .warn {
    padding: 1px 8px;
    border-radius: var(--r-pill);
    background: var(--warn-soft);
}

.running-head .button {
    background: var(--err-soft);
    color: var(--err);
}

.running-task {
    font-size: 13px;
    padding: 9px 14px;
    border-top: 1px solid var(--hair);
}

.running-task > .grow {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Spend: a person or a session, what Pi spent for it, and its limit. */
.spend-total {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 10px;
    color: var(--muted);
    font-size: 13px;
}

.spend-total strong {
    color: var(--text);
    font: 600 30px var(--mono);
    letter-spacing: -0.02em;
}

.spend-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    min-height: 48px;
    padding: 10px 14px;
    font-size: 13.5px;
    color: var(--text);
}

.spend-row > .grow {
    min-width: 100px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.spend-row > .mono {
    width: 64px;
    text-align: right;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}

.spend-row > .muted {
    width: 100px;
    text-align: right;
}

.spend-change {
    width: 56px;
    flex: none;
    text-align: right;
}

.spend-usage {
    width: 80px;
    height: 5px;
    flex: none;
    overflow: hidden;
    border-radius: var(--r-mark);
    background: var(--hair-2);
    color: var(--accent);
}

.spend-usage.warn {
    color: var(--warn);
}

.spend-usage > span {
    display: block;
    width: var(--usage);
    height: 100%;
    background: currentColor;
}

@media (max-width: 480px) {
    .spend-row > .grow {
        flex-basis: calc(100% - 180px);
    }
    .spend-row > .muted {
        width: auto;
        margin-left: auto;
    }
    .spend-usage {
        width: 64px;
    }
}

.limit-edit {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.limit-edit input {
    width: 72px;
    min-height: 30px;
    padding: 4px 8px;
    border-radius: var(--r-seg);
    font-family: var(--mono);
}

/* ─── Launcher: sessions, actions, and themes, with visible search modes ─── */

.launcher-overlay {
    position: fixed;
    inset: 0;
    z-index: 45;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: calc(env(safe-area-inset-top) + 11vh) 10px 10px;
    background: var(--scrim);
    animation: fade var(--t-fade) var(--ease-almost);
}

.launcher {
    width: min(640px, 100%);
    max-height: 74dvh;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    border-radius: var(--r-sheet);
    box-shadow: var(--pop);
    overflow: hidden;
    animation: pop 0.28s var(--ease-out);
    outline: none;
}

.leaving.launcher-overlay {
    animation: fade-out var(--t-out) linear forwards;
    pointer-events: none;
}

.leaving .launcher {
    animation: pop-out var(--t-out) linear forwards;
}

.launcher kbd {
    padding: 4px 6px;
    border: 1px solid var(--hair);
    border-radius: var(--r-tag);
    background: none;
    font-size: 10.5px;
    color: var(--faint);
}

.launcher-input {
    display: flex;
    flex: none;
    align-items: center;
    gap: 10px;
    height: 58px;
    padding: 0 12px 0 18px;
    border-bottom: 1px solid var(--hair);
    color: var(--accent);
}

.launcher-input .prompt {
    font: 600 15px var(--mono);
}

.launcher-input input {
    min-width: 0;
    flex: 1;
    border: 0;
    background: none;
    padding: 0;
    font-size: 16px;
    color: var(--text);
}

.launcher-input input:focus-visible {
    outline: none;
}

.launcher-input input::placeholder {
    color: var(--muted);
}

.launcher-escape {
    color: var(--muted);
}

.launcher-close {
    display: grid;
    place-items: center;
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: var(--r-control);
    color: var(--muted);
}

@media (hover: hover) {
    .launcher-close:hover {
        background: var(--hover);
    }
}

.launcher-types {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    gap: 4px;
    padding: 10px 14px 4px;
}

.launcher-types button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 28px;
    padding: 0 11px;
    border: 1px solid transparent;
    border-radius: var(--r-pill);
    color: var(--muted);
    font-size: 12.5px;
    font-weight: 500;
}

.launcher-types button[aria-pressed="true"] {
    background: var(--card-2);
    border-color: var(--hair-2);
    color: var(--text);
}

@media (hover: hover) {
    .launcher-types button:hover {
        background: var(--card-2);
        border-color: var(--hair-2);
        color: var(--text);
    }
}

.launcher-types kbd {
    padding: 0;
    border: 0;
    background: none;
    font-size: 11px;
    color: var(--faint);
}

.launcher-summary {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 4px 18px 0;
    min-height: 36px;
    color: var(--faint);
    font-size: 12px;
}

.launcher-summary .launcher-group {
    flex: 1;
    padding: 0;
}

.launcher-summary button {
    min-height: 36px;
    padding: 0.4rem;
    color: var(--text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.launcher-list {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 4px 8px 8px;
    scroll-padding: 8px;
}

.launcher-list:empty {
    flex: none;
    padding: 0;
}

.launcher-group {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 10px 5px;
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

.launcher-count {
    font: 400 11px var(--mono);
}

.launcher-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 42px;
    padding: 6px 10px;
    border-radius: var(--r-control);
    text-align: left;
    color: var(--text);
}

.launcher-item.on {
    background: var(--card-2);
}

.launcher-item .glyph {
    width: 28px;
    height: 28px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: calc(var(--r-row) - 1px);
    background: var(--card);
    color: var(--muted);
}

.launcher-item .main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.35;
}

.launcher-title {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 14px;
    font-weight: 400;
}

.launcher-item .detail {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    font-size: 12px;
    color: var(--muted);
}

.launcher-path {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.launcher-path.session-path {
    font-family: var(--mono);
}

.launcher-state {
    flex: none;
    max-width: 50%;
    height: 20px;
    padding: 0 8px;
    line-height: 20px;
    border-radius: var(--r-pill);
    background: var(--card);
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.launcher-state.waiting {
    background: var(--warn-soft);
    color: var(--warn);
}

.launcher-state.working {
    background: var(--accent-soft);
    color: var(--accent);
}

.launcher-folder {
    width: 9px;
    height: 9px;
    border-radius: var(--r-mark);
    background: var(--folder);
}

.launcher-match-note {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-style: italic;
}

.launcher mark {
    color: var(--text);
    text-decoration-color: var(--accent);
}

.launcher-item .hint {
    flex: none;
    display: flex;
    gap: 4px;
    align-items: center;
    font-size: 11px;
    color: var(--faint);
}

.launcher-item .hint kbd {
    color: inherit;
}

.launcher-item .swatch {
    display: grid;
    grid-template-columns: 1fr 1fr;
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: calc(var(--r-row) - 1px);
    overflow: hidden;
    box-shadow: 0 0 0 1px var(--hair-2);
}

.launcher-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.65rem;
    min-height: 0;
    overflow-y: auto;
    padding: 1.6rem 1rem;
    color: var(--muted);
    text-align: center;
    font-size: 0.9rem;
}

.launcher-empty strong {
    color: var(--text);
    overflow-wrap: anywhere;
}

.launcher-empty .button {
    min-height: 44px;
    flex: none;
    margin-top: 0.45rem;
}

.launcher-status {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.launcher-foot {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    gap: 8px 16px;
    padding: 10px 18px;
    border-top: 1px solid var(--hair);
    font-size: 12px;
    color: var(--faint);
}

.launcher-foot span {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.launcher-foot kbd {
    padding: 0;
    border: 0;
    color: inherit;
}

.launcher-prefix-help {
    margin-left: auto;
}

.launcher-foot .launcher-touch-help {
    display: none;
}

@media (pointer: coarse) {
    .launcher-overlay {
        padding: calc(env(safe-area-inset-top) + 16px) 8px calc(env(safe-area-inset-bottom) + 16px);
    }
    .launcher {
        max-height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 32px);
    }
    .launcher-input {
        padding: 0.5rem 0.7rem;
        gap: 0.6rem;
    }
    .launcher-escape,
    .launcher-types kbd,
    .launcher-item .hint:has(kbd) {
        display: none;
    }
    .launcher-types {
        gap: 0.3rem;
        padding: 0.5rem;
    }
    .launcher-close {
        width: 44px;
        height: 44px;
    }
    .launcher-types button {
        height: auto;
        flex: 1;
        min-height: 44px;
        padding-inline: 0.5rem;
    }
    .launcher-summary,
    .launcher-summary button {
        min-height: 44px;
    }
    .launcher-item {
        min-height: 60px;
        gap: 0.6rem;
        padding-inline: 0.6rem;
    }
    .launcher-item .detail {
        gap: 0.4rem;
    }
    .launcher-foot .launcher-key-help,
    .launcher-foot .launcher-prefix-help {
        display: none;
    }
    .launcher-foot .launcher-touch-help {
        display: block;
    }
}

/* ─── Appearance ───────────────────────────────────────────── */

.theme-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}

/* A theme card draws a tiny Hyprland desktop in its own palette: the card sets the --o-* colors it uses. */
.theme-card {
    position: relative;
    display: flex;
    flex-direction: column;
    text-align: left;
    gap: 8px;
    padding: 8px 8px 10px;
    border-radius: var(--r-window);
    background: var(--o-bg);
    color: var(--o-fg);
    border: 1px solid color-mix(in srgb, var(--o-fg) 17%, transparent);
    transition:
        border-color var(--t-hover) var(--ease-out),
        box-shadow var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .theme-card:hover {
        border-color: var(--o-accent);
    }
}

.theme-card:active {
    transform: scale(0.97);
}

.theme-card.on {
    border-color: var(--o-accent);
    box-shadow:
        0 0 0 2px var(--o-bg),
        0 0 0 4px var(--o-accent);
}

.tc-desk {
    display: flex;
    gap: 5px;
    height: 62px;
    padding: 6px;
    border-radius: 9px;
    background: var(--o-bg-darker);
}

.tc-win {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px;
    border-radius: 5px;
    background: var(--o-bg);
    border: 1px solid color-mix(in srgb, var(--o-fg) 13%, transparent);
}

.tc-win:first-child {
    width: 34%;
}

.tc-win:last-child {
    flex: 1;
    border-color: var(--o-accent);
}

.tc-win i {
    height: 4px;
    border-radius: 2px;
    background: var(--o-fg);
    opacity: 0.4;
}

.tc-win i:nth-child(1) {
    width: 80%;
}

.tc-win i:nth-child(2) {
    width: 55%;
}

.tc-win i.lit {
    margin-top: auto;
    align-self: flex-end;
    height: 8px;
    border-radius: 3px;
    background: var(--o-accent);
    opacity: 1;
    width: 30%;
}

.tc-name {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 13px;
    font-weight: 500;
    color: var(--o-fg-bright, var(--o-fg));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tc-name small {
    font-weight: 400;
    font-size: 11px;
    color: inherit;
    opacity: 0.6;
}

.tc-dots {
    display: flex;
    gap: 4px;
}

.tc-dots i {
    width: 10px;
    height: 10px;
    border-radius: 3px;
}

.theme-desktop {
    grid-column: 1 / -1;
    flex-direction: row;
}

.theme-desktop .tc-desk {
    width: 42%;
    flex: none;
    height: auto;
    min-height: 70px;
}

.theme-desktop .tc-text {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
}

.theme-desktop .tc-note {
    padding: 0 0 0.45rem;
    font-size: 0.68rem;
    color: var(--o-fg);
    opacity: 0.75;
}

.setting-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: calc(12px * var(--space-y)) calc(14px * var(--space-x));
    background: var(--o-bg);
    font-size: 14px;
}

.setting-row .segmented {
    align-self: center;
    flex: none;
}

@media (max-width: 480px) {
    .setting-row:has(.segmented) {
        flex-wrap: wrap;
        gap: 8px;
    }
    .setting-row:has(.segmented) .setting-text {
        flex-basis: 100%;
    }
}

.setting-row .setting-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.setting-row .setting-text span:first-child {
    color: var(--text);
}

.setting-row .setting-text span + span {
    font-size: 12px;
    color: var(--muted);
}

/* Appearance → Layout: a slot's items, each with arrows to move it and a switch to show it. */
.slot-label {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.slot-moves {
    display: flex;
    flex: none;
}

.slot-moves .icon-button {
    width: 30px;
    height: 30px;
    color: var(--muted);
}

.slot-moves .icon-button:disabled {
    opacity: 0.35;
    cursor: default;
}

.slot-moves .slot-earlier {
    transform: scaleX(-1);
}

.shortcuts {
    display: grid;
    grid-template-columns: 9.5rem 1fr;
    gap: 8px 18px;
    margin: 0;
    font-size: 13.5px;
    align-items: baseline;
}

.shortcuts dt {
    display: flex;
    gap: 0.2rem;
    justify-content: flex-end;
}

.shortcuts dd {
    margin: 0;
    color: var(--body);
}

/* The theme: a card for each theme folder, in the app's own colors (a theme cannot be drawn small, as colors can). */
.look-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 10px;
}

.look-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-height: 64px;
    padding: 10px 12px;
    text-align: left;
    border-radius: var(--r-card);
    background: var(--card);
    border: 1px solid var(--hair-2);
    transition: border-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .look-card:not(:disabled):hover {
        border-color: var(--accent-line);
    }
}

.look-card.on {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent);
}

.look-card.broken {
    cursor: default;
    opacity: 0.8;
}

.look-name {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text);
}

.look-name small {
    font: 10.5px var(--mono);
    color: var(--faint);
}

.look-detail {
    font-size: 12px;
    color: var(--muted);
}

.look-problem {
    font-size: 12px;
    color: var(--err);
}

.look-tools,
.look-duplicate {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 10px 0 4px;
}

.look-duplicate input {
    flex: 1;
    min-width: 160px;
}

/* The owner's fonts for the theme in use: a menu each for words and code, ligatures, and a preview in them. */
.font-tools {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 8px 12px;
    margin: 10px 0 4px;
}

.font-menu {
    display: grid;
    gap: 4px;
    font-size: 12px;
    color: var(--muted);
}

.font-menu .switch {
    justify-self: start;
}

.font-menu strong {
    padding: 6px 0;
    font-weight: 500;
    color: var(--text);
    font-size: 14px;
}

.font-title,
.font-duplicate {
    grid-column: 1 / -1;
}

.font-title {
    margin: 4px 0 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
}

.font-title em {
    font-style: normal;
    color: var(--accent);
}

.font-duplicate {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.font-duplicate .look-duplicate {
    flex: 1;
    margin: 0;
}

.text-size {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.text-size-field {
    display: flex;
    align-items: center;
    gap: 4px;
    color: var(--muted);
    font-size: 12px;
}

.text-size-field input {
    width: 4.5rem;
    padding: 0.35rem 0.5rem;
    text-align: right;
    font-family: var(--mono);
}

@media (max-width: 480px) {
    .setting-row:has(.text-size) {
        flex-wrap: wrap;
        gap: 8px;
    }

    .setting-row:has(.text-size) .setting-text {
        flex-basis: 100%;
    }
}

.font-preview {
    grid-column: 1 / -1;
    padding: 10px 12px;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    font-size: 14px;
    line-height: 1.5;
}

.font-preview code {
    display: block;
    margin-top: 4px;
    font-family: var(--mono);
    white-space: pre;
    overflow-x: auto;
}

/* ─── Sign in: the app's screen (the server's pages are under Notices) ─── */

.signin {
    animation: rise-in 0.5s var(--ease-out);
}

.signin .row {
    padding: 6px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-window);
    background: var(--card);
    box-shadow: var(--shadow);
}

.signin .row:focus-within {
    border-color: var(--accent-line);
}

.signin .row input {
    min-width: 0;
    border: 0;
    background: none;
}

.signin .row input:focus-visible {
    outline: none;
}

/* ─── Small glue: the sheet host, viewers leaving, search keys, unread dots ─── */

.sheet-host {
    display: contents;
}

.leaving .viewer,
.leaving .lightbox {
    animation: fade-out var(--t-out) linear forwards;
}

.viewer {
    animation: pop 0.28s var(--ease-out);
}

.search-keys {
    display: inline-flex;
    gap: 2px;
    flex: none;
    cursor: pointer;
    opacity: 0.8;
    transition: opacity var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .search-keys:hover {
        opacity: 1;
    }
}

.search:has(input:focus) .search-keys {
    opacity: 0;
}

/* A narrow list keeps the search's words whole: its keys give way. */
@container sessions (max-width: 200px) {
    .search-keys {
        display: none;
    }
}

@media (pointer: coarse) {
    .search-keys,
    .splash-actions kbd,
    .launcher-item .hint kbd {
        display: none;
    }
}

/* Subagents at work, in the top bar: marked, not blinking. */
.topbar .pulse {
    animation: none;
}

.unread-dot {
    animation: popin var(--t-in) var(--ease-out);
}

.empty.hint .pi {
    animation: boot-breathe 3s var(--ease-in-out) infinite;
}

/* ─── People panel ─────────────────────────────────────────── */

/* Wide screens: the chat, pinned, and notes in a window beside the conversation, sliding in from the right. Narrower
 * ones show them as a sheet instead, so the panel exists only where it fits. */
.people {
    flex: 0 0 var(--people-w, 320px);
    height: 100dvh;
    border-left: 1px solid var(--hair);
    background: var(--bg);
}

/* Past the tiled windows' pop-in, which would otherwise win. */
:root .layout > .people.window {
    animation: people-in var(--t-in) var(--ease-out) backwards;
}

:root .layout > .people.window.leaving {
    animation: people-out var(--t-out) linear forwards;
}

@keyframes people-in {
    from {
        opacity: 0;
        transform: translateX(48px);
    }
}

@keyframes people-out {
    to {
        opacity: 0;
        transform: translateX(48px);
    }
}

.people-head {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 58px;
    flex: none;
    padding: 0 10px 0 16px;
    border-bottom: 1px solid var(--hair);
}

.people-head h2 {
    margin: 0;
    color: var(--text);
    font-size: 15px;
    font-weight: 600;
}

.people-count {
    flex: 1;
    font: 11px var(--mono);
    color: var(--faint);
}

.people-head .icon-button {
    width: 32px;
    height: 32px;
    border-radius: var(--r-row);
}

.people .sheet-body,
.people-sheet .sheet-body {
    flex: 1;
    min-height: 0;
    padding: 0;
    overflow: hidden;
}

.people-sheet {
    height: 86dvh;
}

.people-sheet .sheet-head h2 {
    flex: none;
}

.people-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    gap: 6px;
    padding: 8px 10px 10px;
    overflow-y: auto;
}

.people-content > :not(.chat-log, .pin-list, .notes) {
    flex-shrink: 0;
}

.people-roster {
    max-height: 176px;
    overflow-y: auto;
}

.people-person {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px;
    border-radius: var(--r-row);
}

.people-person-info {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    line-height: 1.3;
}

.people-person-name {
    color: var(--text);
    font-size: 13.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.people-person-state {
    font-size: 12px;
    color: var(--muted);
}

.people-person-state.typing {
    color: var(--accent);
}

.people-role {
    font-size: 11.5px;
    color: var(--faint);
}

.people-turns {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 2px 2px;
    padding: 10px 12px;
    border-radius: calc(var(--r-control) + 1px);
    background: var(--card);
}

.people-turns-title,
.people-turns-hint {
    display: block;
    line-height: 1.35;
}

.people-turns-title {
    font-size: 13px;
    color: var(--text);
}

.people-turns-hint {
    font-size: 11.5px;
    color: var(--muted);
}

.people-turns .button {
    min-height: 28px;
    border-radius: calc(var(--r-row) - 1px);
    padding: 0 11px;
    font-size: 12px;
    flex: none;
}

.people-pin {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0 2px;
    padding: 9px 12px;
    border: 1px solid var(--hair);
    border-radius: calc(var(--r-control) + 1px);
    text-align: left;
    font-size: 12.5px;
    color: var(--body);
}

.people-pin > .icon {
    color: var(--accent);
    flex: none;
    margin-top: 3px;
}

.people-pin > span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.people-pin b {
    font-weight: 600;
    color: var(--text);
}

.people-content .mention-list {
    border: 1px solid var(--hair-2);
    border-radius: var(--r-card);
    overflow: hidden;
    background: var(--bg);
    box-shadow: var(--shadow);
}

.people-content textarea.notes {
    flex: 1;
    min-height: 160px;
    resize: none;
    border-radius: var(--r-card);
    font-size: 13.5px;
}

.people-button.on {
    color: var(--accent);
    background: var(--accent-soft);
}

@media (pointer: coarse) {
    .people-head .icon-button,
    .people-turns .button {
        min-height: 40px;
        min-width: 40px;
    }

    .people-content textarea.notes {
        font-size: 16px;
    }
}

/* ─── Peek tiles ───────────────────────────────────────────── */

/* Other sessions beside the conversation, one tile each: a column on wide screens, scrolling, and a strip under the
 * top bar on narrow ones. With tiling, the column is bare and each tile a card of its own; the column takes the focus
 * ring. Turned on or off, the column slides like the People panel; the tiles in it then change without motion: only
 * the conversation moves. */
.peeks {
    flex: 0 0 var(--peeks-w, clamp(260px, 21vw, 340px));
    height: 100dvh;
    min-height: 0;
    border-left: 1px solid var(--hair);
    background: var(--panel);
}

:root .layout > .peeks.window {
    animation: people-in var(--t-in) var(--ease-out) backwards;
}

:root .layout > .peeks.window.leaving {
    animation: people-out var(--t-out) linear forwards;
}

/* Turned on with nothing to show yet: what will show here. */
.peeks-empty {
    margin: auto 0;
    padding: 24px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    text-align: center;
    color: var(--muted);
    font-size: 13px;
}

.peeks-empty p {
    margin: 0;
}

.peeks-empty .icon {
    color: var(--faint);
}

/* The top bar's switch, while off: another session waits for you. */
.peek-dot {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--warn);
    box-shadow: 0 0 0 2px var(--bg);
}

.peeks-list {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
    scroll-snap-type: y proximity;
    scrollbar-width: thin;
}

.peek {
    position: relative;
    flex: none;
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    background: var(--card);
    scroll-snap-align: start;
    transition: border-color var(--t-hover) var(--ease-out);
}

.peek.waiting {
    border-color: var(--warn-line);
}

/* Its header opens the session: its folder's square and title, and its path. */
.peek-head {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 12px 14px 8px;
    /* The tile's corners, inside its border: the hover fill and the focus ring follow them. */
    border-radius: calc(var(--r-window) - 1px) calc(var(--r-window) - 1px) 0 0;
    text-align: left;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .peek-head:hover {
        background: var(--hover);
    }
}

/* Inside the tile, which cuts off what is past its rounded edge. */
.peek-head:focus-visible {
    outline-offset: -2px;
}

.peek-name {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.peek-title,
.peek-cwd {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.peek-title {
    flex: 1;
    min-width: 0;
    color: var(--text);
    font-size: 13.5px;
    font-weight: 500;
}

.peek-cwd {
    padding-left: 16px;
    color: var(--faint);
    font-size: 11px;
}

/* The last few lines: a mark for who or what, then the words, two lines at most. */
.peek-lines {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 2px 14px 10px;
    cursor: pointer;
}

.peek-line {
    display: flex;
    gap: 7px;
    min-width: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--body);
}

.peek-mark {
    flex: none;
    width: 14px;
    font: 600 11px / 18px var(--mono);
    color: var(--faint);
}

.peek-line.user .peek-mark {
    color: var(--accent);
}

/* Pi's own words: its mark in Georgia, as everywhere. */
.peek-mark.pi {
    color: var(--brand);
    font:
        13px / 1.5 Georgia,
        serif;
}

.peek-text {
    min-width: 0;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.peek-line.user .peek-text {
    color: var(--muted);
}

.peek-line.user b {
    color: var(--o-cyan);
    font-weight: 600;
}

.peek-line.cmd .peek-text {
    font: 12px / 1.5 var(--mono);
}

.peek-line.err,
.peek-line .err {
    color: var(--err);
}

.peek-line.faint {
    color: var(--faint);
}

.peek-run {
    color: var(--accent);
}

.peek-skeleton i {
    display: block;
    height: 0.45rem;
    margin: 0.3rem 0;
    border-radius: var(--r-mark);
    background: var(--card-2);
}

.peek-skeleton i:nth-child(2) {
    width: 80%;
}

.peek-skeleton i:nth-child(3) {
    width: 60%;
}

/* The subagents at work in a peek tile: a row each, those waiting first, then how many more. */
.agent-tiles {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0 8px 8px;
    padding-top: 6px;
    border-top: 1px solid var(--hair);
}

.agent-tile {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 7px 9px 8px;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--card-2);
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
    /* A double tap picks and opens it; the browser's double-tap zoom would take the second tap. */
    touch-action: manipulation;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .agent-tile:hover {
        border-color: var(--line);
        background: var(--hover);
    }
}

.agent-tile:focus-visible {
    outline-offset: -2px;
}

/* The board's selected one: ringed as its square is. */
.agent-tile.on {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.agent-tile.waiting.on {
    outline-color: var(--warn);
}

.agent-tile.waiting {
    border-color: var(--warn-line);
    background: var(--warn-soft);
}

.agent-tile-head {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* The session list's square, in its folder's color, a step larger here. */
.agent-tile .state-mark {
    width: 9px;
    height: 9px;
    --q: 4px;
    --cut: 2px;
}

.agent-tile-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--accent);
    font: 600 12px / 1.4 var(--mono);
}

.agent-tile.waiting .agent-tile-name {
    color: var(--warn);
}

.agent-tile-state {
    flex: none;
    color: var(--faint);
    font-size: 10.5px;
    letter-spacing: 0.02em;
}

.agent-tile.waiting .agent-tile-state {
    color: var(--warn);
}

.agent-tile-now {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
    color: var(--muted);
    font: 11.5px / 1.45 var(--mono);
}

/* In a peek tile, one line each: the square and the name, then what it does, cut short. */
.agent-tiles .agent-tile {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-color: transparent;
    background: transparent;
}

.agent-tiles .agent-tile-head {
    flex: 0 1 auto;
    max-width: 45%;
}

.agent-tiles .agent-tile-name {
    flex: 0 1 auto;
}

/* The square's shape and the row's color say its state; the words are its label's. */
.agent-tiles .agent-tile-state {
    display: none;
}

.agent-tiles .agent-tile-now {
    display: block;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.agent-tiles .agent-tile.waiting {
    border-color: var(--warn-line);
    background: var(--warn-soft);
}

/* The rest, counted: the board shows them all. */
.agent-more {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 26px;
    padding: 3px 6px;
    border: 0;
    border-radius: var(--r-control);
    background: transparent;
    color: var(--muted);
    font: 500 11.5px / 1.4 var(--sans);
    text-align: left;
    cursor: pointer;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.agent-more svg:last-child {
    margin-left: auto;
    color: var(--faint);
}

.agent-more-wait {
    color: var(--warn);
}

@media (hover: hover) {
    .agent-more:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.agent-more:focus-visible {
    outline-offset: -2px;
}

/* The call a session waits on: the whole command when it is short enough to allow from here, and the guard's reason. */
.peek-ask {
    flex: none;
    margin: 0 10px 10px;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    border: 1px solid var(--warn-line);
    border-radius: var(--r-control);
    background: var(--warn-soft);
}

.peek-ask-tool {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--warn);
}

/* Which subagent asks, where the session's tile shows a subagent's call. */
.peek-ask-who {
    margin-left: auto;
    overflow: hidden;
    color: var(--muted);
    font: 500 11.5px / 1.4 var(--sans);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.peek-ask-what {
    font-size: 12px;
    line-height: 1.45;
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
}

/* A command short enough to allow from here shows whole, never clamped. */
.peek-ask-what.whole {
    display: block;
    -webkit-line-clamp: unset;
    line-clamp: none;
    overflow: visible;
}

.peek-ask-why {
    font-size: 12px;
    color: var(--muted);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* The state in words (needs you, working, done, new), and Deny and Allow where a call waits. */
.peek-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 10px 0 14px;
    border-top: 1px solid var(--hair);
}

.peek-status {
    flex: 1;
    min-width: 0;
    color: var(--faint);
    font-size: 12.5px;
    font-weight: 500;
    white-space: nowrap;
}

.peek-status::first-letter {
    text-transform: uppercase;
}

.peek.working .peek-status {
    color: var(--accent);
}

.peek.waiting .peek-status {
    color: var(--warn);
}

.peek.done .peek-status {
    color: var(--ok);
}

/* The command a tile asks about opens its session too, as the rest of the tile does: there it shows whole. */
.peek-ask-host {
    display: contents;
    cursor: pointer;
}

.peek-actions {
    display: inline-flex;
    gap: 8px;
}

.peek-actions .button.small {
    min-height: 30px;
    padding: 0 12px;
    border: 0;
    border-radius: calc(var(--r-row) - 1px);
    background: var(--card-2);
    color: var(--text);
    font-size: 12.5px;
    font-weight: 500;
}

@media (hover: hover) {
    .peek-actions .button.small:hover:not(:disabled) {
        color: var(--err);
    }
}

.peek-actions .button.small.primary {
    padding: 0 14px;
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 600;
}

@media (hover: hover) {
    .peek-actions .button.small.primary:hover:not(:disabled) {
        background: color-mix(in oklab, var(--accent-fill) 85%, var(--text));
        color: var(--accent-ink);
    }
}

.peek-seen {
    width: 30px;
    height: 30px;
    color: var(--ok);
}

/* Calls waiting for approval out of view: a way to them, at the column's edge. */
.peeks-jump {
    position: absolute;
    left: 50%;
    z-index: 2;
    transform: translateX(-50%);
    padding: 5px 12px;
    border-radius: var(--r-pill);
    background: var(--warn);
    box-shadow: var(--pop);
    color: var(--accent-ink);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

.peeks-jump.up {
    top: 8px;
}

.peeks-jump.down {
    bottom: 8px;
}

.peek-strip {
    flex: none;
    animation: peek-strip-in var(--t-in) var(--ease-out) backwards;
    display: flex;
    gap: 8px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 8px calc(12px + var(--inset-r)) 8px calc(12px + var(--inset-l));
    border-bottom: 1px solid var(--hair);
    scroll-snap-type: x proximity;
    scrollbar-width: none;
}

.peek-strip::-webkit-scrollbar {
    display: none;
}

@keyframes peek-strip-in {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }
}

.peek-strip .peek {
    width: 240px;
    border-radius: var(--r-card);
}

.peek-strip .peek-head {
    padding: 8px 12px 2px;
    border-radius: calc(var(--r-card) - 1px) calc(var(--r-card) - 1px) 0 0;
}

.peek-strip .peek-cwd {
    display: none;
}

.peek-strip .peek-lines {
    padding: 0 12px 8px;
}

.peek-strip .peek-ask {
    margin: 0 8px 8px;
    padding: 8px 10px;
}

.peek-strip .peek-foot {
    min-height: 0;
    padding: 0 8px 8px 12px;
    border-top: 0;
}

@media (min-width: 960px) {
    /* Bare: the tiles are the cards, and the column's ring shows the focus. */
    :root[data-tiling="on"] .peeks.window {
        height: auto;
        border: 0;
        border-radius: var(--r-window);
        overflow: visible;
        background: none;
    }
    :root[data-tiling="on"][data-focus="peeks"] .peeks.window {
        outline: 1px solid var(--window-border-active);
        outline-offset: 2px;
    }
    :root[data-tiling="on"] .peeks-list {
        padding: 0;
    }
    :root[data-tiling="on"] .peeks .peek {
        background: var(--bg);
    }
}

/* ─── Diff viewer ──────────────────────────────────────────── */

/* One file's diff, a rounded card: a header that sticks while its lines scroll by, then the lines in a table, one or
 * two sides. (`clip`, not `hidden`: the header must still stick to the scroller that holds the card.) */
.dv {
    --dv-n: 40px;
    --dv-add: color-mix(in srgb, var(--ok) 11%, transparent);
    --dv-del: color-mix(in srgb, var(--err) 11%, transparent);
    min-width: 0;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--code-bg);
    overflow: clip;
}

@media (max-width: 520px) {
    .dv {
        --dv-n: 34px;
    }
}

.dv-head {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 42px;
    padding: 0 10px;
    background: var(--card);
    border-bottom: 1px solid var(--hair);
    font-size: 12.5px;
}

.dv.folded .dv-head {
    border-bottom: 0;
}

.dv.viewed .dv-name {
    color: var(--muted);
}

.dv-fold {
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    flex: none;
    border-radius: calc(var(--r-tag) + 1px);
    color: var(--muted);
}

@media (hover: hover) {
    .dv-fold:hover {
        background: var(--hover);
        color: var(--text);
    }
}

/* What kind of change: M, A, D, R in a small tile. */
.change-kind {
    flex: none;
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    border-radius: var(--r-tag);
    background: var(--warn-soft);
    color: var(--warn);
    font: 600 10px/1 var(--mono);
}

.change-kind.added,
.change-kind.new {
    background: var(--ok-soft);
    color: var(--ok);
}

.change-kind.deleted {
    background: var(--err-soft);
    color: var(--err);
}

.change-kind.renamed {
    background: var(--accent-soft);
    color: var(--accent);
}

.dv-title {
    flex: 1;
    min-width: 0;
    display: flex;
    text-align: left;
    color: inherit;
}

/* A renamed file's old path, before its new one. */
.dv-was {
    margin-right: 0.5ch;
}

/* A long path gives up its folders before its name. */
.dv-path {
    display: flex;
    min-width: 0;
    font-family: var(--mono);
    white-space: nowrap;
}

.dv-dir {
    min-width: 1ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--faint);
    font-family: var(--mono);
}

.dv-name {
    flex: none;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text);
    font-weight: 600;
}

.dv-counts {
    display: inline-flex;
    gap: 6px;
    flex: none;
    font: 11.5px var(--mono);
}

.dv-chip {
    flex: none;
    height: 18px;
    padding: 0 6px;
    border-radius: var(--r-tag);
    font-size: 11px;
}

.dv-chip.warn {
    color: var(--warn);
    border-color: var(--warn-line);
}

.dv-tool.icon-button {
    width: 28px;
    height: 28px;
    border-radius: calc(var(--r-row) - 1px);
    font-size: 13px;
    color: var(--muted);
}

@media (hover: hover) {
    .dv-tool.icon-button:hover {
        color: var(--text);
    }
}

/* On touch, the icons a size up. */
@media (pointer: coarse) {
    .dv-tool .icon,
    .file-tools .icon-button .icon {
        width: 18px;
        height: 18px;
    }
}

.dv-tool.danger {
    width: auto;
    padding: 0 8px;
    color: var(--err);
}

/* Viewed: a checkbox in a small button. Checking it folds the file away. */
.dv-viewed {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    height: 26px;
    padding: 0 9px 0 7px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-seg);
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
    user-select: none;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .dv-viewed:hover {
        color: var(--text);
    }
}

.dv-viewed.on {
    border-color: var(--accent-line);
    background: var(--accent-soft);
    color: var(--accent);
}

.dv-viewed:has(:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.dv-viewed input {
    appearance: none;
    position: relative;
    flex: none;
    width: 13px;
    height: 13px;
    margin: 0;
    padding: 0;
    border: 1.5px solid currentColor;
    border-radius: calc(var(--r-tag) - 1px);
    background: none;
    cursor: pointer;
}

.dv-viewed input:checked {
    background: var(--accent);
    border-color: var(--accent);
}

.dv-viewed input:checked::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--accent-ink);
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E")
        center / 9px no-repeat;
}

@media (max-width: 520px) {
    .dv-viewed span {
        display: none;
    }
}

.dv-scroll {
    overflow-x: auto;
    padding: 4px 0 8px;
}

.dv-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    font: 12px/1.7 var(--mono);
    color: var(--body);
    tab-size: 4;
}

/* Without wrapping, a long line scrolls the diff sideways instead of breaking. */
.dv:not(.wrap) .dv-table {
    width: max-content;
    min-width: 100%;
}

/* Side by side, the two halves stay as wide as each other however long their lines. */
.dv:not(.wrap) .dv-table.split col:not(.dv-col-n) {
    width: 50%;
}

.dv:not(.wrap) .dv-table.split .dv-n {
    min-width: var(--dv-n);
}

.dv-col-n {
    width: var(--dv-n);
}

.dv-n {
    padding: 0 8px 0 0;
    text-align: right;
    vertical-align: top;
    color: var(--faint);
    user-select: none;
    white-space: nowrap;
}

/* Numbers are drawn, not written: copying lines leaves them out. */
.dv-n::before {
    content: attr(data-n);
}

.dv-n.go {
    cursor: pointer;
}

@media (hover: hover) {
    .dv-n.go:hover {
        color: var(--accent);
        text-decoration: underline;
    }
}

/* The code, with the sign of an added or removed line in an 18px column of its own. */
.dv-code {
    position: relative;
    padding: 0 12px 0 18px;
    vertical-align: top;
    white-space: pre;
}

.dv.wrap .dv-code {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.dv-code::before {
    content: attr(data-sign);
    position: absolute;
    left: 0;
    width: 18px;
    text-align: center;
    user-select: none;
}

.dv-code:empty::after {
    content: " ";
}

.dv-code.add,
.dv-n.add,
.dv-row.add > .dv-n.none {
    background: var(--dv-add);
}

.dv-code.del,
.dv-n.del,
.dv-row.del > .dv-n.none {
    background: var(--dv-del);
}

.dv-code.add::before {
    color: var(--ok);
}

.dv-code.del::before {
    color: var(--err);
}

.dv-code.add mark {
    background: color-mix(in srgb, var(--ok) 32%, transparent);
    color: inherit;
}

.dv-code.del mark {
    background: color-mix(in srgb, var(--err) 32%, transparent);
    color: inherit;
}

/* A comment's words that changed: the comment's faint color is too weak on the change's highlight. */
.dv-code .hl-com mark,
.dv-code mark .hl-com {
    color: var(--muted);
}

/* The side of a split row with no line: hatched, as an absence rather than an empty line. */
.dv-code.none,
.dv-n.none {
    background: repeating-linear-gradient(
        -45deg,
        transparent 0 5px,
        color-mix(in srgb, var(--body) 4%, transparent) 5px 6px
    );
}

.dv-table.split .dv-code + .dv-n {
    border-left: 1px solid var(--hair);
}

.dv-hunk td {
    padding: 6px 12px;
    color: var(--accent);
    font-size: 11.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dv-context {
    margin-left: 0.8em;
    color: var(--muted);
}

.dv-gap td {
    padding: 2px 8px;
    background: var(--hover);
    text-align: center;
}

.dv-gap button {
    padding: 2px 10px;
    border-radius: calc(var(--r-tag) + 1px);
    color: var(--accent);
    font: 11.5px var(--mono);
}

@media (hover: hover) {
    .dv-gap button:hover {
        background: var(--hover);
    }
}

.dv-reading {
    color: var(--muted);
    font: 11.5px var(--mono);
}

/* A note under a line ("No newline at end of file") starts where the code does: past the numbers, and the sign. */
.dv-note td {
    padding: 0 12px 0 calc(2 * var(--dv-n) + 18px);
    color: var(--muted);
    font-style: italic;
}

.dv-table.split .dv-note td {
    padding-left: calc(var(--dv-n) + 18px);
}

.dv-note span {
    font-size: 11.5px;
}

.dv-empty {
    margin: 0;
    padding: 10px 14px;
    color: var(--muted);
    font-size: 13px;
}

.dv-empty.err {
    color: var(--err);
}

.dv-empty .link {
    margin-left: 0.4rem;
}

.dv-wait {
    padding: 6px 14px;
}

/* A diff in a tool card or a reply: it scrolls inside a bound, like the card's other output. */
.dv-block {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 60vh;
    overflow: auto;
}

.dv-block .dv-head {
    position: static;
}

/* ─── Review ─────────────────────────────────────────────── */

.dr {
    display: flex;
    flex-direction: column;
    outline: none;
    min-width: 0;
}

/* "N files", the counts, how many are viewed, then the layout and Look again. */
.dr-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
    padding: 12px 14px;
    font-size: 13px;
    color: var(--muted);
}

/* The folder gives way when there is no room; the branch, a way to switch it, stays in sight. */
.dr-where {
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
}

.dr-path {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--faint);
}

.dr-branch {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 20px;
    padding: 0 7px;
    border-radius: calc(var(--r-tag) + 1px);
    background: var(--card);
    color: var(--muted);
}

@media (hover: hover) {
    button.dr-branch:hover {
        background: var(--card-2);
        color: var(--accent);
    }
}

.dr-stats {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.dr-stats strong {
    color: var(--text);
    font-weight: 500;
}

.dr-stats .dv-counts {
    font-size: 12px;
}

.dr-viewed {
    font-size: 12.5px;
}

/* The layout and Look again, together at the end of the row, or of the next one when there is no room. */
.dr-actions {
    flex: none;
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 10px;
}

.dr-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 0 12px 10px;
}

.dr-filter,
.ft-filter {
    flex: 1;
    min-width: 7rem;
    height: 30px;
    padding: 0 10px;
    border-color: var(--hair);
    border-radius: calc(var(--r-row) - 1px);
}

@media (pointer: fine) {
    .dr-filter,
    .ft-filter {
        font-size: 12.5px;
    }
}

.dr-tools .chip {
    height: 30px;
    padding: 0 10px;
    border-radius: calc(var(--r-row) - 1px);
    background: none;
    font-size: 12px;
}

.dr-main {
    display: grid;
    gap: 10px;
    min-width: 0;
    padding: 0 12px 14px;
}

.dr.wide .dr-main {
    grid-template-columns: minmax(170px, 240px) minmax(0, 1fr);
    align-items: start;
}

.dr-tree {
    padding: 6px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: var(--card);
    max-height: 40vh;
    overflow: auto;
}

.dr.wide .dr-tree {
    position: sticky;
    top: 0;
    max-height: calc(100dvh - 10rem);
}

/* A row of a tree of files, the changed ones and the folder's: a rounded 28px row in mono. */
.dr-row,
.ft-row {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    min-height: 28px;
    padding: 0 8px 0 calc(8px + var(--depth, 0) * 14px);
    border-radius: var(--r-seg);
    text-align: left;
    color: var(--body);
    font: 12.5px var(--mono);
    white-space: nowrap;
}

.ft-row.muted {
    color: var(--muted);
}

@media (hover: hover) {
    .dr-row:hover,
    .ft-row:hover {
        background: var(--hover);
    }
}

.dr-row.on,
.ft-row.on {
    background: var(--accent-soft);
    color: var(--accent);
}

.dr-row.dir,
.ft-row.dir {
    color: var(--text);
}

.dr-row .chev,
.ft-row .chev {
    flex: none;
    width: 12px;
    color: var(--faint);
}

.dr-row.seen .dr-name {
    color: var(--muted);
}

.dr-name,
.ft-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dr-pi {
    color: var(--spark);
    font-size: 11px;
}

.dr-tail {
    margin-left: auto;
    padding-left: 6px;
    color: var(--ok);
}

.dr-tail .dv-counts {
    font-size: 11px;
}

.dr-files {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.dr-file {
    scroll-margin-top: 0.3rem;
}

/* Going to a change (n, p) leaves room for the file's header, which sticks at the top. */
.dr .dv-row,
.dr .dv-hunk {
    scroll-margin-top: 2.6rem;
}

.dr-clean {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    padding: 2.5rem 1rem;
    color: var(--ok);
    font-size: 0.85rem;
}

.dr-clean p {
    margin: 0;
    color: var(--muted);
}

.dr-pionly {
    padding: 0 12px 14px;
}

.dr-pionly .list-item {
    font-size: 0.8rem;
}

/* ─── Files tile ───────────────────────────────────────────── */

/* Phones and narrow windows: over the conversation, as the Browser panel is. Wide screens: a window beside it. */
.files-tile {
    position: fixed;
    inset: 0;
    z-index: 15;
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: popin var(--t-in) var(--ease-out);
}

.files-resize {
    display: none;
}

/* Over the conversation, below 1100px: no frame of its own. */
@media (max-width: 1099px) {
    :root[data-tiling="on"] .files-tile.window {
        border: 0;
        border-radius: 0;
        box-shadow: none;
    }
}

@media (min-width: 1100px) {
    .layout.filing .files-tile {
        position: relative;
        inset: auto;
        z-index: auto;
        flex: 0 0 var(--files-w, 44%);
        max-width: calc(100% - 440px);
        height: 100dvh;
        border-left: 1px solid var(--hair);
        padding-inline: 0 var(--inset-r);
        animation-delay: 90ms;
    }
    :root[data-tiling="on"] .layout.filing .files-tile {
        height: auto;
    }
    .files-resize {
        display: block;
        left: 0;
        right: auto;
    }
}

/* ─── Extension panels ─────────────────────────────────────── */

/* An extension's panel takes the Files tile's place: over the conversation below 1100px, a window beside it above. */
.ext-panel {
    position: fixed;
    inset: 0;
    z-index: 15;
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: popin var(--t-in) var(--ease-out);
}

@media (max-width: 1099px) {
    :root[data-tiling="on"] .ext-panel.window {
        border: 0;
        border-radius: 0;
        box-shadow: none;
    }
}

@media (min-width: 1100px) {
    .layout.paneling .ext-panel {
        position: relative;
        inset: auto;
        z-index: auto;
        flex: 0 0 var(--ext-panel-w, 400px);
        max-width: calc(100% - 440px);
        height: 100dvh;
        border-left: 1px solid var(--hair);
        padding-inline: 0 var(--inset-r);
        animation-delay: 90ms;
    }
    .layout.paneling .ext-panel.wide {
        --ext-panel-w: 44%;
    }
    :root[data-tiling="on"] .layout.paneling .ext-panel {
        height: auto;
    }
}

.ext-panel-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: none;
    height: calc(58px + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) 10px 0 14px;
    border-bottom: 1px solid var(--hair);
}

.ext-panel-bar .icon-button {
    width: 34px;
    height: 34px;
    color: var(--muted);
}

.ext-panel-bar .ext-panel-back {
    width: 44px;
    height: 44px;
    margin-left: -8px;
    color: var(--text);
}

@media (hover: hover) {
    .ext-panel-bar .icon-button:hover {
        color: var(--text);
    }
}

.ext-panel-title {
    flex: 1;
    min-width: 0;
}

.ext-panel-title h2 {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 15px;
    font-weight: 600;
}

.ext-panel-sub {
    color: var(--faint);
    font-size: 11.5px;
}

.ext-panel-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 14px 14px calc(14px + env(safe-area-inset-bottom));
}

/* The bar: Files and Changes as a switch, the folder, and close. */
.files-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: none;
    height: calc(58px + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) 10px 0 14px;
    border-bottom: 1px solid var(--hair);
}

.files-bar .icon-button {
    width: 34px;
    height: 34px;
    color: var(--muted);
}

@media (hover: hover) {
    .files-bar .icon-button:hover {
        color: var(--text);
    }
}

.files-root {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--faint);
    font: 11.5px var(--mono);
}

/* The switch between Files and Changes, and the review's layout: a track with the chosen one raised. */
.files-tabs,
.dr-layout {
    display: flex;
    flex: none;
    padding: 3px;
    border-radius: var(--r-control);
    background: var(--card);
}

.files-tabs button,
.dr-layout button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 28px;
    padding: 0 12px;
    border-radius: var(--r-seg);
    font-size: 13px;
    font-weight: 500;
    color: var(--muted);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .files-tabs button:hover,
    .dr-layout button:hover {
        color: var(--text);
    }
}

.files-tabs button.on,
.dr-layout button.on {
    background: var(--raised);
    color: var(--text);
}

.dr-layout {
    padding: 2px;
    border-radius: var(--r-row);
}

.dr-layout button {
    height: 26px;
    padding: 0 10px;
    font-size: 12px;
}

.files-count {
    display: grid;
    place-items: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--r-pill);
    background: var(--accent-soft);
    color: var(--accent);
    font: 600 10px/1 var(--mono);
}

.files-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    overscroll-behavior: contain;
}

/* As wide as the tile, never as wide as what is inside: a long line or a wide page scrolls within it instead. */
.files-bar,
.files-body {
    width: 100%;
}

.files-body[hidden] {
    display: none;
}

/* Files: the tree, and the open file beside it when the tile is wide enough, or instead of it when not. */
.ft {
    display: flex;
    height: 100%;
    min-height: 0;
}

.ft-pane {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.ft.side .ft-pane {
    flex: 0 0 220px;
    border-right: 1px solid var(--hair);
}

.ft-tools {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 10px 8px 6px 10px;
}

.ft-tools .icon-button {
    width: 28px;
    height: 28px;
    border-radius: calc(var(--r-row) - 1px);
    color: var(--muted);
}

@media (hover: hover) {
    .ft-tools .icon-button:hover {
        color: var(--text);
    }
}

.ft-tree {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 2px 6px 10px;
}

.ft-spacer {
    width: 12px;
    flex: none;
}

.ft-row.dot .ft-name {
    color: var(--muted);
}

.ft-row.changed.deleted .ft-name {
    color: var(--err);
    text-decoration: line-through;
}

/* M, A, D: what changed in a file, at the row's end; a folder with changes inside has a dot. */
.ft-kind {
    margin-left: auto;
    padding-left: 6px;
    font: 600 10px var(--mono);
}

.ft-kind.modified,
.ft-kind.renamed {
    color: var(--warn);
}

.ft-kind.new,
.ft-kind.added {
    color: var(--ok);
}

.ft-kind.deleted {
    color: var(--err);
}

.ft-dot {
    width: 6px;
    height: 6px;
    margin-left: auto;
    border-radius: 50%;
    background: var(--warn);
    flex: none;
}

/* Matches for what was typed in Go to file: an icon, the name, then its folder. */
.ft-row.match {
    padding-left: 8px;
}

.ft-row.match .icon {
    flex: none;
    color: var(--muted);
}

.ft-row mark {
    background: none;
    color: var(--accent);
    font-weight: 800;
}

.ft-parent {
    min-width: 0;
    margin-left: auto;
    padding-left: 0.6rem;
    color: var(--faint);
    font-size: 11px;
    overflow: hidden;
    text-overflow: ellipsis;
    direction: rtl;
}

.ft-note {
    padding: 0.5rem 0.8rem;
}

.ft-view {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: auto;
}

.ft-view-head {
    position: sticky;
    top: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 8px;
    flex: none;
    min-height: 42px;
    padding: 0 10px 0 14px;
    background: var(--bg);
    border-bottom: 1px solid var(--hair);
}

.ft-view-head .icon-button {
    width: 28px;
    height: 28px;
    border-radius: calc(var(--r-row) - 1px);
    color: var(--muted);
}

.ft-view-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font: 600 12.5px var(--mono);
    color: var(--text);
}

/* In the tile, the file's code fills the view on the code's ground; the bar above it is the viewer's own buttons. */
.ft-view .file-viewer {
    flex: 1;
    gap: 0;
}

.ft-view .file-viewer > :not(.file-tools, .file-view) {
    margin: 10px 14px;
}

.ft-view .file-tools {
    padding: 6px 10px 6px 14px;
}

.ft-view .file-view {
    flex: 1;
    border: 0;
    border-radius: 0;
}

.ft-empty {
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    color: var(--faint);
}

/* The file viewer, in the tile and the sheet: a bar of what the file is and what can be done with it, then the file. */
.file-viewer {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 0;
}

.file-tools {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.file-tools .file-path {
    flex: 1;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-tools .icon-button {
    width: 32px;
    height: 32px;
}

/* ─── Browser ──────────────────────────────────────────────── */

/* Phones and narrow windows: the page full screen, over the conversation and under sheets. Wide screens: a window
 * beside the conversation, tiled like the others. */
.browser {
    position: fixed;
    inset: 0;
    z-index: 15;
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: popin var(--t-in) var(--ease-out);
}

.browser-resize {
    display: none;
}

/* Over the conversation, below 1100px: no frame of its own. */
@media (max-width: 1099px) {
    :root[data-tiling="on"] .browser.window {
        border: 0;
        border-radius: 0;
        box-shadow: none;
    }
}

@media (min-width: 1100px) {
    .layout.browsing .browser {
        position: relative;
        inset: auto;
        z-index: auto;
        flex: 0 0 var(--browser-w, clamp(420px, 36vw, 520px));
        max-width: calc(100% - 440px);
        height: 100dvh;
        border-left: 1px solid var(--line);
        padding-inline: 0 var(--inset-r);
        animation-delay: 90ms;
    }
    :root[data-tiling="on"] .layout.browsing .browser {
        height: auto;
    }
    .browser-resize {
        display: block;
        left: 0;
        right: auto;
    }
}

.browser-bar {
    display: flex;
    align-items: center;
    gap: 4px;
    min-height: 58px;
    flex: none;
    padding: env(safe-area-inset-top) 8px 0 10px;
    border-bottom: 1px solid var(--hair);
    background: var(--bg);
}

.browser-bar .icon-button {
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: calc(var(--r-row) - 1px);
    color: var(--muted);
}

.browser-bar .badge {
    border-radius: var(--r-pill);
    font: 600 9.5px var(--mono);
}

.browser-bar .badge.err {
    background: var(--warn-soft);
    color: var(--warn);
}

.browser-bar .icon-button:disabled {
    opacity: 0.35;
    cursor: default;
    background: none;
    transform: none;
}

.browser-bar .icon-button.on {
    color: var(--accent);
    background: var(--accent-soft);
}

.browser-address {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    height: 34px;
    margin: 0 4px;
    padding: 0 12px;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--card);
}

.browser-address:focus-within {
    border-color: var(--accent-line);
}

.browser-live {
    width: 7px;
    height: 7px;
    flex: none;
    border-radius: 50%;
    background: var(--ok);
}

.browser-address input {
    height: 32px;
    min-width: 0;
    border: 0;
    border-radius: 0;
    outline: 0;
    padding: 0;
    background: transparent;
    font: 12.5px var(--mono);
    text-overflow: ellipsis;
}

.browser-address input[readonly] {
    color: var(--muted);
}

@media (pointer: coarse) {
    .browser-address {
        height: 40px;
    }

    .browser-address input {
        font-size: 16px;
    }
}

@media (max-width: 480px) {
    .browser-forward {
        display: none !important;
    }
}

.badge-host .badge.err {
    background: var(--err);
    color: var(--accent-ink);
}

/* The topbar's mark while the session has a page open. */
.browser-dot {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 6px;
    height: 6px;
    border-radius: var(--radius);
    background: var(--accent);
    animation: popin var(--t-in) var(--ease-out);
}

/* Loading: a short bar sweeping under the address bar. */
.browser-progress {
    position: relative;
    height: 2px;
    flex: none;
    overflow: hidden;
}

.browser-progress.on::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 35%;
    background: var(--accent);
    animation: browser-load 1.1s var(--ease-in-out) infinite;
}

@keyframes browser-load {
    from {
        transform: translateX(-100%);
    }
    to {
        transform: translateX(300%);
    }
}

.browser-stage {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    background: var(--code-bg);
    overflow: hidden;
}

.browser-frame {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

/* The frame keeps its shape: it is as large as fits, so a tap's place on it is its place on the page. */
.browser-screen {
    display: block;
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    background: #fff;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    touch-action: none;
    outline: none;
}

.browser-screen.live:focus {
    outline: 1px solid var(--accent);
    outline-offset: -1px;
}

/* A page that crashed keeps its last frame, with the news over it. */
.browser-crashed {
    position: absolute;
    top: 0.6rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 0.6rem;
    max-width: calc(100% - 1.2rem);
    padding: 0.45rem 0.6rem 0.45rem 0.8rem;
    background: var(--panel);
    border: 1px solid var(--err-line);
    color: var(--err);
    animation: popin var(--t-in) var(--ease-out);
}

.browser-note {
    margin: auto;
    max-width: 30rem;
    padding: 2rem 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
    text-align: center;
    color: var(--muted);
}

.browser-note p {
    margin: 0;
}

.browser-start {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 14px;
    padding: 24px;
    overflow-y: auto;
    text-align: left;
    color: var(--muted);
    background: var(--code-bg);
    animation: fade var(--t-fade) var(--ease-almost);
}

.browser-start > * {
    width: 100%;
    max-width: 372px;
    margin-left: auto;
    margin-right: auto;
    flex-shrink: 0;
}

.browser-start h2 {
    color: var(--text);
    font-size: 15px;
    font-weight: 600;
    margin-top: 0;
    margin-bottom: -10px;
}

.browser-note .browser-start {
    position: static;
    background: none;
    padding: 0;
}

.browser-start p {
    margin-top: 0;
    margin-bottom: 0;
    font-size: 13px;
    text-wrap: pretty;
}

.browser-servers {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.browser-servers-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--faint);
}

.browser-server-list {
    display: flex;
    flex-direction: column;
    gap: 1px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow: hidden;
    background: var(--hair);
}

.browser-server {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 14px;
    background: var(--bg);
    color: var(--text);
    text-align: left;
}

@media (hover: hover) {
    .browser-server:hover {
        background: var(--card);
    }
}

.browser-server .mono {
    font-size: 13px;
    flex: none;
}

.browser-server-title {
    min-width: 0;
    margin-left: auto;
    font-size: 12px;
    color: var(--faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Typing on touch screens: a field of the app's own, whose keyboard sends text to the page. */
.browser-type {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.4rem 0.4rem calc(env(safe-area-inset-bottom) + 0.4rem);
    border-top: 1px solid var(--line);
    background: var(--panel);
}

/* Hidden, it stays focusable (not display: none), so the tap that shows it can open the phone's keyboard. */
.browser-type.hidden {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0;
    pointer-events: none;
    transform: translateY(100%);
}

.browser-type input {
    flex: 1;
    min-width: 0;
    padding: 0.4rem 0.6rem;
}

.browser-type .key {
    min-width: 34px;
    height: 34px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--card);
    color: var(--text);
}

.browser-type .key:active {
    background: var(--pressed);
}

.browser-console {
    flex: none;
    height: min(42%, 150px);
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--line);
    background: var(--panel);
    animation: fade var(--t-fade) var(--ease-almost);
}

.browser-console header {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 32px;
    padding: 0 8px 0 12px;
    font-size: 12px;
    border-bottom: 1px solid var(--hair);
}

.browser-console header strong {
    font-weight: 500;
}

.browser-console .spacer {
    flex: 1;
}

.browser-console-lines {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 6px 0;
    font-size: 11.5px;
    line-height: 1.7;
}

.console-line {
    display: flex;
    gap: 0.6rem;
    padding: 0 12px;
    white-space: pre-wrap;
    word-break: break-word;
}

.console-text {
    flex: 1;
    min-width: 0;
}

.console-source {
    flex: none;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--faint);
}

.console-line.error {
    color: var(--err);
    background: var(--err-soft);
}

.console-line.warn {
    color: var(--warn);
    background: var(--warn-soft);
}

.console-line.dialog {
    color: var(--accent);
}

.console-line.debug {
    color: var(--faint);
}

.console-nav {
    margin-top: 4px;
    padding: 2px 12px;
    border-bottom: 1px solid var(--hair);
    color: var(--faint);
    font-size: 11px;
}

.browser-foot {
    padding: 0.3rem 0.8rem calc(env(safe-area-inset-bottom) + 0.3rem);
    border-top: 1px solid var(--line);
    text-align: center;
}

/* ─── Files, commands, and find ──────────────────────────────── */

/* File paths in replies (inline code that names a file) open the viewer. */
.md code[data-path] {
    cursor: pointer;
    text-decoration: underline dotted color-mix(in srgb, var(--accent) 60%, transparent);
    text-underline-offset: 3px;
}

@media (hover: hover) {
    .md code[data-path]:hover {
        color: var(--accent);
    }
}

/* @mentions of files in messages, and the files sent along. */
.file-mention {
    color: var(--accent);
    font: inherit;
    padding: 0;
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}

.skill-chip {
    margin-bottom: 0.3rem;
}

.tool-open {
    align-self: flex-start;
}

/* `!` commands people ran, and notes about what people did. */
.shell-row {
    animation: rise-in 0.3s var(--ease-out);
}

.shell-card {
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    padding: 10px 14px;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.shell-card > .link {
    align-self: flex-start;
}

.shell-card.failed {
    border-color: var(--err-line);
}

.shell-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.6rem;
    font-size: 13px;
}

.shell-command {
    color: var(--ok);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

.shell-card:not(.open) .shell-command {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.note-line {
    text-align: center;
    font-size: 12.5px;
    color: var(--muted);
}

.link.danger {
    color: var(--err);
    font-weight: 700;
}

/* The file viewer: line numbers, the line asked for marked, long lines wrapped. */
.file-path {
    overflow-wrap: anywhere;
    margin-top: 0;
}

.file-view {
    font: 12px/1.7 var(--mono);
    background: var(--code-bg);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    padding: 10px 0;
    overflow-x: auto;
}

.file-line {
    display: flex;
    min-width: 0;
}

.file-line .ln {
    flex: none;
    width: 42px;
    padding-right: 14px;
    text-align: right;
    color: var(--faint);
    user-select: none;
}

.file-line .lt {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    min-width: 0;
    color: var(--body);
    padding-right: 12px;
}

.file-line.on {
    background: var(--accent-soft);
}

.file-line.on .ln {
    color: var(--accent);
}

.file-image {
    max-width: 100%;
    border: 1px solid var(--hair);
    border-radius: var(--radius);
}

.file-entry {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

/* Find in session. */
.find-input {
    width: 100%;
    min-height: 42px;
    border-radius: calc(var(--r-control) + 1px);
}

.find-search .find-input {
    min-height: 40px;
}

.find-count {
    color: var(--faint);
    font-size: 11.5px;
}

.find-results {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.find-result {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    text-align: left;
    padding: 9px 12px;
    border-radius: var(--r-control);
    border: 0;
    transition: background-color var(--t-hover) var(--ease-out);
}

.find-result.on {
    background: var(--hover);
}

@media (hover: hover) {
    .find-result:hover {
        background: var(--hover);
    }
}

.find-who {
    font-size: 12px;
    color: var(--faint);
}

.find-snippet {
    font-size: 13.5px;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.find-snippet mark {
    padding: 0 2px;
    border-radius: var(--r-mark);
    background: var(--accent-soft);
    color: var(--accent);
}

/* Ctrl+R: messages sent before. */
.history-text {
    color: var(--text);
}

/* ─── Syntax and rich markdown ─────────────────────────────── */

/* Syntax colors: the --hl- colors, darker in light themes. */
.hl-kw {
    color: var(--hl-kw);
}

.hl-str {
    color: var(--hl-str);
}

.hl-com {
    color: var(--faint);
    font-style: italic;
}

.hl-num,
.hl-lit {
    color: var(--hl-num);
}

.hl-fn {
    color: var(--hl-fn);
}

.hl-type,
.hl-attr {
    color: var(--hl-type);
}

.hl-op,
.hl-prop,
.hl-meta {
    color: var(--hl-op);
}

.hl-tag,
.hl-re,
.hl-var {
    color: var(--hl-tag);
}

/* A run of HTML between the blocks the app draws itself: its children lay out as the reply's own. */
.md-part {
    display: contents;
}

.md > .md-part:first-child > :first-child {
    margin-top: 0;
}

.md > .md-part:last-child > :last-child {
    margin-bottom: 0;
}

.md.streaming > .md-part:last-child > :last-child::after {
    content: "█";
    margin-left: 1px;
    color: var(--accent);
    animation: blink 1s steps(2) infinite;
}

/* A code block that shows more than code: its bar also has what it can show, and Run. */
.rich-tabs {
    display: inline-flex;
    margin-left: 0.4rem;
    padding: 2px;
    border-radius: var(--r-row);
    background: var(--hover);
}

.rich-tabs button,
.rich-run {
    height: 22px;
    padding: 0 8px;
    border-radius: var(--r-seg);
    font: inherit;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .rich-tabs button:hover,
    .rich-run:hover {
        color: var(--text);
    }
}

.rich-tabs button.on {
    color: var(--text);
    background: var(--raised);
}

.rich-run {
    background: var(--ok-soft);
    color: var(--ok);
}

@media (hover: hover) {
    .rich-run:hover {
        color: var(--ok);
    }
}

.rich-run.on {
    background: var(--err-soft);
    color: var(--err);
}

/* A page and an image, drawn as a browser would: on white, whatever the theme. */
.html-preview,
.run-frame {
    display: block;
    width: 100%;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: #fff;
}

/* Inside a code block's frame, its own border is the frame's. */
.code > :is(.html-preview, .run-frame, .rich-svg, .rich-note) {
    border: 0;
    border-radius: 0;
}

.rich-svg {
    display: block;
    max-width: 100%;
    max-height: 70vh;
    padding: 0.6rem;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    background: #fff;
    cursor: zoom-in;
}

.code.rich > .dv-block {
    max-height: none;
}

.rich-note {
    margin: 0;
    padding: 0.6rem;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
}

/* A long code block, folded to its first lines until asked for the rest. */
.code.long:not(.open) pre {
    max-height: 22em;
    overflow: hidden;
    mask-image: linear-gradient(#000 75%, transparent);
}

.code-more {
    display: block;
    width: 100%;
    padding: 6px;
    border-top: 1px solid var(--hair);
    background: var(--card);
    color: var(--accent);
    font: 12px var(--mono);
}

@media (hover: hover) {
    .code-more:hover {
        background: var(--hover);
    }
}

.file-tools .button.on {
    color: var(--err);
}

/* ─── Phones: places, pushed screens, and going back ───────── */

/* Keep the anchored menu out of the layout's flex row, including its gap. */
.nav-menu-host {
    display: contents;
}

/* The menu and the phone's places share a three-column grid of soft tiles. */
.places {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
    padding: 8px 12px 12px;
}

.nav-menu .sheet-body,
.places-sheet .sheet-body {
    padding: 0;
    gap: 0;
}

.nav-menu :is(.menu-session, .group) {
    margin: 0;
    padding: 6px 6px 8px;
    border-top: 1px solid var(--hair);
}

.nav-menu .menu-session:empty {
    display: none;
}

.nav-menu .group-title {
    margin: 0;
    padding: 8px 10px 4px;
    color: var(--faint);
    font-size: 12px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
}

.nav-menu .list-item,
.places-sheet .list-item {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-height: 36px;
    margin: 0;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--r-row);
    background: none;
    color: var(--text);
    font-size: 13.5px;
}

@media (hover: hover) {
    .nav-menu .list-item:hover,
    .places-sheet .list-item:hover {
        background: var(--hover);
    }
}

@media (hover: hover) {
    .nav-menu .list-item:hover > span:first-child,
    .places-sheet .list-item:hover > span:first-child {
        color: var(--text);
    }
}

.nav-menu .list-item > :first-child,
.places-sheet .list-item > :first-child {
    flex: none;
    white-space: nowrap;
}

.nav-menu .list-item > :last-child:not(:first-child),
.places-sheet .list-item > :last-child:not(:first-child) {
    flex: 1;
    min-width: 0;
    text-align: right;
    font-size: 12px;
    color: var(--faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.places-sheet .list-item {
    width: auto;
    margin: 0 6px 8px;
}

.nav-menu .menu-signout {
    color: var(--err);
}

@media (min-width: 700px) {
    /* Sheet still owns focus and Esc; its existing sheet trail owns Back, even from a child sheet. */
    .nav-menu-host .overlay {
        padding: 0;
        background: none;
    }
    .nav-menu {
        position: fixed;
        left: var(--menu-left, calc(100vw - 368px));
        top: var(--menu-top, 64px);
        width: 360px;
        max-height: var(--menu-height, calc(100dvh - 72px));
        border-radius: calc(var(--r-window) + 2px);
        box-shadow: var(--pop);
        animation: pop 0.25s var(--ease-out);
    }
    .nav-menu .sheet-head {
        height: auto;
        min-height: 0;
        padding: 10px 12px 2px 16px;
        border: 0;
    }
    .nav-menu .grip,
    .nav-menu .sheet-head h2::before {
        display: none;
    }
    .nav-menu .sheet-head h2 {
        margin: 0;
        font-size: 13px;
        font-weight: 600;
    }
    .nav-menu .sheet-head .icon-button {
        width: 28px;
        height: 28px;
    }
}

@media (pointer: coarse) {
    .nav-menu .list-item,
    .places-sheet .list-item {
        min-height: 44px;
    }
}

.place {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
    gap: 5px;
    height: 66px;
    padding: 8px 4px;
    border-radius: var(--r-card);
    background: var(--card);
    border: 1px solid var(--hair);
    color: var(--body);
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform 90ms var(--ease-out);
}

@media (hover: hover) {
    .place:hover {
        border-color: var(--hair-2);
        background: var(--card-2);
        color: var(--text);
    }
}

.place:active {
    background: var(--pressed);
    transform: scale(0.96);
}

.place.on {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent-line);
}

.place-icon {
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    position: static;
}

.place-icon .badge {
    top: 7px;
    right: 8px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--r-pill);
    background: var(--accent-fill);
    color: var(--accent-ink);
    font: 600 9.5px/1 var(--mono);
    box-shadow: none;
}

.place-icon .browser-dot {
    top: 10px;
    right: 10px;
}

.place-label {
    max-width: 100%;
    font-size: 12px;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Phones: a session opened slides in from the right, and going back brings the list (or the session before) in from
 * the left, so where back goes is where things came from. `data-route` is set on the window while it slides (back.js).
 */
@media (max-width: 959px) {
    /* Held inside the window: a scroller sliding in from the right (a route, a swipe's lean) would make the page wider
     * than the screen, and a phone's browser widen and pan its view to fit. */
    .pane {
        overflow-x: clip;
    }
    .pane[data-route="forward"] > .scroller {
        animation: route-forward 0.32s var(--ease-out);
    }
    .pane[data-route="back"] > .scroller,
    .pane[data-route="back"] > .home-list {
        animation: route-back 0.32s var(--ease-out);
    }
}

@keyframes route-forward {
    from {
        opacity: 0;
        transform: translateX(24%);
    }
}

@keyframes route-back {
    from {
        opacity: 0;
        transform: translateX(-24%);
    }
}

/* Back the browser already showed with its own slide: what it closes goes at once (back.js). */
:root[data-back-shown] .leaving {
    display: none !important;
}

/* Phones: the places, beside the message box where a thumb reaches (composer.js). Elsewhere the menu has them. */
.composer-row .places-button {
    display: none;
}

@media (max-width: 699px) {
    .composer-row .places-button {
        display: inline-grid;
        width: 32px;
        height: 36px;
        color: var(--muted);
    }
    .composer-row .places-button .browser-dot {
        top: 6px;
        right: 5px;
        width: 7px;
        height: 7px;
        box-shadow: 0 0 0 2px var(--card);
    }
    /* Room for it: the model's name gives way first. */
    .composer-row .model-chip {
        flex: 0 1 auto;
        padding-inline: 6px;
    }
    /* While Pi works, Steer and Queue take the plan chip's place (`/plan` still turns plan mode on or off). */
    .composer.busy .plan-chip,
    .composer.busy .model-caret {
        display: none;
    }
    .mode-switch button {
        padding-inline: 8px;
    }
    /* While Pi works the row is full, and Stop holds the end of it: Send shows once there is something to send, in the
       mic's place (the mic stays while it listens, to stop it). */
    .composer.busy:not(.filled):has(.composer-mic) .send-button,
    .composer.busy.filled .composer-mic:not(.listening) {
        display: none;
    }
}

/* A swipe's mark: back, or the place a swipe on the conversation opens, following the finger in from its side. */
.swipe-mark {
    position: fixed;
    top: 0;
    z-index: 60;
    height: 44px;
    min-width: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0 0.8rem;
    background: var(--panel);
    border: 1px solid var(--line-strong);
    color: var(--muted);
    font-size: 0.82rem;
    box-shadow: 0 6px 20px rgb(0 0 0 / 0.35);
    pointer-events: none;
    opacity: 0;
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.swipe-mark[data-side="left"] {
    left: 0;
}

.swipe-mark[data-side="right"] {
    right: 0;
}

.swipe-mark.armed {
    background: var(--accent-fill);
    color: var(--accent-ink);
}

.swipe-mark.going {
    transition:
        transform 0.2s var(--ease-out),
        opacity 0.2s var(--ease-out);
}

/* The Files tile's way back to the conversation, where the tile covers it. */
.files-bar .files-back {
    width: 44px;
    height: 44px;
    margin-left: -8px;
    color: var(--text);
}

/* Focus lands on the whole tile or panel where it covers the conversation: no ring around the screen. */
.layout > :is(.files-tile, .browser, .ext-panel):focus-visible {
    outline: none;
}

/*
 * Where they cover the conversation, the Files tile and the Browser panel are screens pushed over it: they slide in
 * from the right, as a phone's screens do. So does a file opened in the tile over its tree.
 */
@media (max-width: 1099px) {
    /* Past the tiled windows' pop-in, which would otherwise win. */
    :root .layout > .files-tile.window,
    :root .layout > .browser.window,
    :root .layout > .ext-panel.window {
        animation: push-in 0.36s var(--ease-out);
    }
    :root .layout > .files-tile.window.leaving,
    :root .layout > .browser.window.leaving,
    :root .layout > .ext-panel.window.leaving {
        animation: push-out 0.24s var(--ease-in-out) forwards;
    }
}

@keyframes push-in {
    from {
        transform: translateX(100%);
    }
}

@keyframes push-out {
    to {
        transform: translateX(100%);
    }
}

/*
 * A file open where the tile is too narrow for it beside the tree is a screen of its own, over the whole tile (the
 * tile is the nearest positioned box): its header, with the way back to the tree, is the only one. The tree stays
 * underneath as it was, scrolled where it was.
 */
.ft:not(.side) > .ft-view {
    position: absolute;
    inset: 0;
    z-index: 4;
    background: var(--bg);
    animation: push-in 0.32s var(--ease-out);
}

.ft:not(.side) > .ft-view.leaving {
    animation: push-out 0.24s var(--ease-in-out) forwards;
}

/* Under a file that covers the whole tile, the tile's bar is out of reach of taps, keys, and screen readers too. */
@media (max-width: 1099px) {
    .files-tile:has(> .files-body:not([hidden]) > .ft:not(.side) > .ft-view:not(.leaving))
        > .files-bar {
        visibility: hidden;
    }
}

.ft:not(.side) > .ft-view > .ft-view-head {
    padding-top: env(safe-area-inset-top);
}

/* Docked beside the conversation, the tile keeps its tabs and its close button above the file. */
@media (min-width: 1100px) {
    .layout.filing .ft {
        position: relative;
    }
    .layout.filing .ft:not(.side) > .ft-view > .ft-view-head {
        padding-top: 0;
    }
}

/* Touch: rows and controls a thumb tall. */
@media (pointer: coarse) {
    .files-tabs button {
        height: 40px;
        padding: 0 14px;
        font-size: 14px;
    }
    .ft-tools .icon-button,
    .ft-view-head .icon-button {
        width: 44px;
        height: 44px;
    }
    .ft-view-head {
        min-height: 48px;
        padding-left: 6px;
    }
    .ft-view-name {
        font-size: 14px;
    }
    .ft-filter {
        min-height: 42px;
    }
    .ft-row {
        min-height: 44px;
        gap: 8px;
        padding-left: calc(10px + var(--depth, 0) * 16px);
        font-size: 14px;
    }
    .ft-row .icon {
        width: 16px;
        height: 16px;
    }
    .ft-row .chev {
        width: 14px;
        height: 14px;
    }
    .ft-spacer {
        width: 14px;
    }
    .dr-row {
        min-height: 40px;
    }
    .browser-bar .icon-button {
        width: 40px;
        height: 40px;
    }
    .browser-address input {
        height: 40px;
    }
}

/*
 * Phones: the Browser panel's bar as an in-app browser's. Close and the address on the first row, the page's tools
 * spread a thumb apart on the second.
 */
@media (max-width: 700px) {
    .browser-bar {
        flex-wrap: wrap;
        justify-content: space-between;
        row-gap: 0.2rem;
        padding-bottom: 0.2rem;
    }
    .browser-bar > .browser-close {
        order: -2;
    }
    .browser-bar > .browser-address {
        order: -1;
        flex: 1 1 calc(100% - 52px);
        margin-right: 0;
    }
}

/*
 * Touch: every control a thumb can hit, at least about 40px each way. Buttons, tabs, and chips grow where there is
 * room. Inline controls (a code block's Copy, a reply's actions, the status line's branch) keep their look and get a
 * taller hit area instead: padding with a matching negative margin, so nothing around them moves.
 */
@media (pointer: coarse) {
    .button {
        min-height: 44px;
    }
    .button.small {
        min-height: 38px;
        padding-inline: 0.8rem;
    }
    .segmented button {
        min-height: 42px;
        min-width: 40px;
    }
    /* iOS zooms into a text field under 16px as it takes focus. (The board's field is styled after this: hence
     * the board in its selector.) */
    .sessions .search input,
    .board .board-search input,
    .fp-line input,
    .launcher-input input {
        font-size: 16px;
    }
    /* Rows a thumb can take, and that answer the press: 40px, 37px, and 34px. */
    .session {
        height: calc(30px + 10px * var(--space-y));
    }
    .session:active {
        background: var(--pressed);
    }
    /* The session list keeps its look; its tabs, folds, and clear button take a taller tap. */
    .session-tabs button::after,
    .search-clear::before {
        content: "";
        position: absolute;
        inset: -10px -8px -4px;
    }
    /* 40px square, as 0.11 made the search's buttons. */
    .search-clear::before {
        inset: -9px;
    }
    /* New and the board's filters keep their look and take a thumb-tall tap. */
    .new-button,
    .board-filter,
    .agents-held .link {
        position: relative;
    }
    .new-button::before,
    .board-filter::before,
    .agents-held .link::before {
        content: "";
        position: absolute;
    }
    .agents-held .link::before {
        inset: -12px -8px;
    }
    .new-button::before {
        inset: -6px -3px;
    }
    /* Rows of filters far enough apart that their taps do not overlap (after the board's own gap, hence .board). */
    .board .board-legend {
        row-gap: 16px;
    }
    .board-filter::before {
        inset: -8px -4px;
    }
    .group-head {
        position: relative;
    }
    .group-head::after {
        content: "";
        position: absolute;
        inset: -4px 0 -2px;
    }
    .search .icon-button.small {
        width: 40px;
        height: 40px;
    }
    /* Thumb-sized already: a hit area past it would take taps meant for the end of the search. */
    .search .icon-button.small::before {
        content: none;
    }
    .composer-row .attach-button {
        width: 32px;
        height: 36px;
    }
    .composer-row .composer-mic {
        width: 32px;
        height: 36px;
    }
    .composer-row .stop-button,
    .composer-row .send-button {
        width: 36px;
        height: 36px;
    }
    /* Kept small to fit one line on a phone; a layer past each takes a tap about 40px wide and tall. */
    .composer-row
        :is(
            .places-button,
            .attach-button,
            .model-chip,
            .plan-chip,
            .composer-mic,
            .stop-button,
            .send-button
        ) {
        position: relative;
    }
    .composer-row
        :is(
            .places-button,
            .attach-button,
            .model-chip,
            .plan-chip,
            .composer-mic,
            .stop-button,
            .send-button
        )::before {
        content: "";
        position: absolute;
        inset: -4px -2px;
    }
    /* The chips are shorter: their layers reach further up and down. */
    .composer-row :is(.model-chip, .plan-chip)::before {
        inset: -5px -2px;
    }
    /* Where the row has room, the icon buttons are as wide as a thumb's tap (their look is the icon alone). */
    @container composer (min-width: 360px) {
        .composer-row :is(.places-button, .attach-button, .composer-mic) {
            width: 36px;
        }
    }
    /* Steer and Queue too, taller only: side by side, their layers must not take each other's taps. */
    .mode-switch button {
        position: relative;
    }
    .mode-switch button::before {
        content: "";
        position: absolute;
        inset: -6px 0;
    }
    /* A call's line, a little taller for a thumb; a group's line keeps a thumb's height at every density. */
    .step-head {
        min-height: 36px;
    }
    .activity-head {
        min-height: max(34px, calc(22px + 18px * var(--space-y)));
    }
    .browser-servers .chip,
    .dr-tools .chip {
        min-height: 38px;
    }
    .dr-filter {
        min-height: 40px;
    }
    .dv-tool.icon-button,
    .file-tools .icon-button {
        width: 40px;
        height: 40px;
    }
    .dv-fold {
        width: 36px;
        height: 36px;
        margin-left: -0.3rem;
    }
    .dv-title {
        align-self: stretch;
        align-items: center;
    }
    .dv-viewed {
        min-height: 36px;
        /* Its label hides on a phone: the checkbox alone, centered in a thumb's width. */
        min-width: 42px;
        justify-content: center;
        padding-inline: 10px;
    }
    .check {
        min-height: 40px;
    }
    /* Boxed ones (Copy, tabs, Run, a reaction, the top bar's changes) keep their box; an invisible layer past it
     * takes the tap. */
    .code-head .copy,
    .rich-tabs button,
    .rich-run,
    .answer-actions .reaction,
    .changes-button {
        position: relative;
        /* Above what follows (a preview's frame), so the layer past the box takes the tap there too. */
        z-index: 1;
    }
    /* Taller only: its neighbours touch it, and must keep their own edges. */
    .changes-button::after {
        content: "";
        position: absolute;
        inset: -8px 0;
    }
    /* Over them, as they scroll by: the way to the bottom keeps its taps. */
    .jump {
        z-index: 2;
    }
    .code-head .copy::after,
    .rich-tabs button::after,
    .rich-run::after,
    .answer-actions .reaction::after {
        content: "";
        position: absolute;
        inset: -12px -2px;
    }
    /* The status line's guard sits low: room below it, so its hit area stays on the screen, and above the message
     * box's bottom edge, which its hit area reaches into. */
    .status-line {
        position: relative;
        z-index: 1;
        padding-bottom: 0.6rem;
    }
    .answer-actions > button.answer-tool {
        height: auto;
    }
    .answer-actions > button:not(.reaction),
    .link.small,
    .running-head .link {
        padding-block: 11px;
        margin-block: -11px;
    }
    /* A task's Stop or Cancel, at the end of its row: wider too. */
    .running-task .link.small {
        padding-inline: 7px;
        margin-inline: -7px;
    }
    .answer-actions > button:not(.reaction) {
        min-width: 40px;
        justify-content: center;
        padding-inline: 6px;
        margin-inline: -6px;
    }
    /* The guard and the review's branch keep their small pills; an invisible layer past each takes a thumb's tap. */
    .status-line .guard,
    .dr-branch {
        position: relative;
    }
    .status-line .guard::after,
    .dr-branch::after {
        content: "";
        position: absolute;
        inset: -9px -6px;
    }
    .answer-actions .reaction.add {
        min-width: 40px;
        justify-content: center;
    }
    .answer-actions {
        gap: 0.6rem 1rem;
    }
    /* A switch and a small icon button (a chip's ×, Stop quoting) keep their size; their hit area reaches past it. */
    .switch::before,
    .icon-button.small::before {
        content: "";
        position: absolute;
        inset: -10px -4px;
    }
    .icon-button.small::before {
        inset: -8px;
    }
    .command,
    .artifact-link {
        min-height: 42px;
    }
    /* A peek tile's header opens its session; Allow, Deny, and Open answer from the tile. */
    .peek-strip .peek-head {
        min-height: 40px;
    }
    .peek-actions .button.small {
        min-height: 38px;
    }
    .peek-seen {
        width: 38px;
        height: 38px;
    }
    .pop-menu-link {
        padding-block: 11px;
        margin-block: -11px;
    }
}

/*
 * Phones: a diff's header in two lines when it would squeeze the file's name. The first line is the fold, the kind,
 * the name, and Viewed; the counts and the file's tools take the second, which a break between the two keeps.
 */
@media (max-width: 480px) {
    .dv-head {
        flex-wrap: wrap;
        row-gap: 0;
        padding-block: 3px;
    }
    .dv-head::after {
        content: "";
        order: 1;
        flex: 0 0 100%;
    }
    .dv-head > :is(.dv-chip, .dv-counts, .dv-tool) {
        order: 2;
    }
    /* Under the name: the first of them starts where the kind's tile does. */
    .dv-head > :is(.dv-chip, .dv-counts) {
        margin-left: 2.9rem;
    }
    .dv-head > .dv-chip ~ :is(.dv-chip, .dv-counts) {
        margin-left: 0;
    }
    .dv-head > .dv-counts {
        margin-right: auto;
    }
    /* Compact, with the tap reaching to 40px past the button, but not up into Viewed above it. */
    .dv-head > .dv-tool.icon-button {
        width: 36px;
        height: 36px;
    }
    .dv-head > .dv-tool.icon-button::before {
        content: "";
        position: absolute;
        inset: 0 -4px -4px;
    }
    /* Going to a change (n, p) clears the header's two lines. */
    .dr .dv-row,
    .dr .dv-hunk {
        scroll-margin-top: 5.6rem;
    }
}

/*
 * Pi's sessions from the terminal. The list: a card per folder, a row per session (its title over how long and how
 * recent, a tag when it continues here). One of them: what it worked with, then its last messages as a conversation,
 * then Continue, kept in sight at the foot of the sheet.
 */
.pi-folder {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    animation: rise-in 0.34s var(--ease-out) backwards;
}

.pi-folder-head {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    min-width: 0;
    padding: 0 0.15rem;
    color: var(--muted);
    font-size: 0.78rem;
}

.pi-folder-head .icon {
    align-self: center;
}

.pi-folder-name {
    flex: none;
    max-width: 60%;
    color: var(--text);
    font-family: var(--mono);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pi-folder-parent {
    min-width: 0;
    font-family: var(--mono);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pi-folder-list {
    display: flex;
    flex-direction: column;
    background: var(--bg);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    overflow: hidden;
}

.pi-session {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    min-height: 3.2rem;
    padding: 0.55rem 0.6rem 0.55rem 0.75rem;
    background: none;
    border: 0;
    border-top: 1px solid var(--hair);
    color: var(--text);
    font: inherit;
    font-size: 13.5px;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--t-hover) var(--ease-out);
}

.pi-session:first-child {
    border-top: 0;
}

@media (hover: hover) {
    .pi-session:hover {
        background: var(--card-2);
    }
}

@media (hover: hover) {
    .pi-session:hover .pi-session-title {
        color: var(--accent);
    }
}

.pi-session > .icon {
    color: var(--muted);
}

.pi-session-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.pi-session-title,
.pi-session-meta {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pi-session-meta {
    color: var(--muted);
    font-size: 0.76rem;
}

.pi-tag {
    color: var(--accent);
    background: var(--accent-soft);
    border-radius: var(--r-pill);
    padding: 0.05rem 0.5rem;
    font-size: 0.72rem;
    white-space: nowrap;
}

.pi-tag.behind {
    color: var(--warn);
    background: var(--warn-soft);
}

.pi-facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.3rem 0.9rem;
    margin: 0;
    padding: 0.6rem 0.75rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: 0.82rem;
}

.pi-facts > div {
    display: contents;
}

.pi-facts dt {
    color: var(--muted);
}

.pi-facts dd {
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* The session's whole title, however long: the sheet's own title is short. */
.pi-title {
    margin: 0;
    font-size: 1rem;
    color: var(--text);
    overflow-wrap: anywhere;
}

.pi-results {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
}

.pi-note {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.3rem 0.6rem;
    font-size: 0.85rem;
}

.pi-convo {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}

.pi-convo > .label {
    margin-bottom: 0;
}

.pi-ask {
    display: flex;
    justify-content: flex-end;
}

.pi-ask > div,
.pi-reply {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 6;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 0.88rem;
}

.pi-ask > div {
    max-width: 85%;
    background: var(--card-2);
    border: 1px solid var(--line);
    border-radius: calc(var(--r-window) + 2px) calc(var(--r-window) + 2px) var(--r-tag)
        calc(var(--r-window) + 2px);
    padding: 10px 14px;
}

.pi-reply {
    color: var(--body);
}

/* Continue stays in sight as the conversation scrolls under it. */
.pi-continue {
    position: sticky;
    bottom: -20px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0 -20px -20px;
    padding: 14px 20px 20px;
    background: var(--bg);
    border-top: 1px solid var(--hair);
}

.pi-continue > p {
    margin: 0;
}

/*
 * The subagents bar, above the message box. Folded: a dot per subagent (pulsing while it works), the counts, and what the
 * newest one does. Unfolded: a row each, which opens it.
 */
.agents-bar {
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    margin-bottom: 6px;
    font-size: 13px;
    overflow: hidden;
}

.agents-top {
    display: flex;
    align-items: center;
    padding-right: 0.2rem;
}

.agents-summary {
    flex: 1;
    min-width: 0;
    min-height: 36px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 12px;
    background: none;
    border: 0;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.agents-dots {
    display: inline-flex;
    gap: 3px;
    flex: none;
}

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

.agents-dot.working {
    background: var(--accent);
    animation: pulse 1.4s infinite;
}

.agents-dot.failed {
    background: var(--err);
}

.agents-dot.stopped {
    background: var(--muted);
}

.agents-more {
    margin-left: 2px;
    color: var(--muted);
    font-size: 0.7rem;
    line-height: 7px;
}

.agents-count {
    flex: 0 1 auto;
    min-width: 0;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.agents-lead {
    flex: 1;
    min-width: 0;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.agents-chevron {
    display: inline-flex;
    flex: none;
    margin-left: auto;
    color: var(--muted);
    transform: rotate(-90deg);
    transition: transform var(--t-in) var(--ease-out);
}

.agents-bar.open .agents-chevron {
    transform: rotate(90deg);
}

/* Reports a spend limit holds back: why, and the way to raise it (subagents.js). */
.agents-held {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.6rem;
    padding: 0.35rem 0.75rem 0.45rem;
    border-top: 1px solid var(--hair);
    color: var(--warn);
    font-size: 12.5px;
    line-height: 1.4;
}

.agents-held .link {
    font-size: inherit;
}

.agents-bar:has(.agents-held) {
    border-color: var(--warn-line);
}

.agents-list {
    max-height: min(40vh, 22rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    border-top: 1px solid var(--hair);
}

.agent-row {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--hair);
}

.agent-row:last-child {
    border-bottom: 0;
}

.agent-open {
    flex: 1;
    min-width: 0;
    min-height: 2.75rem;
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.5rem 0.6rem;
    background: none;
    border: 0;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .agent-open:hover {
        background: var(--hover);
    }
}

.agent-mark {
    flex: none;
    width: 1rem;
    padding-top: 0.05rem;
    color: var(--ok);
    font-weight: 700;
    text-align: center;
}

.agent-row.failed .agent-mark {
    color: var(--err);
}

.agent-row.stopped .agent-mark {
    color: var(--muted);
}

.agent-error {
    color: var(--err);
    font-size: 0.78rem;
    overflow-wrap: anywhere;
}

.agent-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.agent-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.2rem 0.5rem;
}

.agent-name {
    font-family: var(--mono);
    font-weight: 600;
}

.agent-when {
    color: var(--muted);
    font-size: 0.76rem;
    font-variant-numeric: tabular-nums;
}

.agent-chip {
    color: var(--accent);
    background: var(--accent-soft);
    border-radius: var(--r-pill);
    padding: 0 0.45rem;
    font-size: 0.72rem;
    white-space: nowrap;
}

.agent-now,
.agent-asked {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.agent-now {
    font-family: var(--mono);
    font-size: 12px;
}

.agent-asked {
    color: var(--muted);
    font-size: 0.76rem;
}

.agent-stop {
    flex: none;
    margin-right: 0.2rem;
}

/* ─── Extensions' pages ──────────────────────────────────────── */

/*
 * A page an extension's browser module added, in the conversation's place as the subagents board is: the board's
 * header, and what the extension draws below it, scrolling.
 */
.ext-page {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: fade var(--t-fade) var(--ease-almost);
}

.ext-page-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 1rem calc(1rem + var(--inset-r)) calc(env(safe-area-inset-bottom) + 1rem)
        calc(1rem + var(--inset-l));
}

/*
 * Extensions' rail buttons, together: four buttons' height at most, past which they scroll rather than push the app's
 * own buttons away. Beside the session list it keeps that height, and a short window scrolls the whole rail, as it does
 * the app's own buttons; in the folded rail it gives way first (to one button), so the sessions' tiles keep their room.
 */
.rail-exts {
    flex: none;
    max-height: calc(4 * 44px + 3 * 4px);
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
}

.rail:has(.rail-items) .rail-exts {
    flex: 0 1 auto;
    min-height: 44px;
    max-height: max(44px, min(4 * 44px + 3 * 4px, 22vh));
}

/* Inside the button, where the group's edge does not cut it off. */
.rail-exts .rail-button:focus-visible {
    outline-offset: -1px;
}

/* An extension's badge may be text: it stays within its button, cut with an ellipsis. */
.rail-ext .rail-count {
    display: block;
    max-width: 32px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: center;
    line-height: 15px;
}

/* Safe mode, in the Extensions sheet: this tab loads no extension's browser part. */
.safe-mode {
    margin: 0 0 0.75rem;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--warn);
}

/* ─── Subagents board ─────────────────────────────────────────── */

/*
 * Every subagent in every session, in the conversation's place: a square each, a row per session, the bar of states
 * that filters by one, what needs you, and the one selected. Phones: one column, and a bar at the bottom.
 */
.board {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: fade var(--t-fade) var(--ease-almost);
}

.board-head {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 62px;
    padding: env(safe-area-inset-top) calc(12px + var(--inset-r)) 0 calc(22px + var(--inset-l));
    border-bottom: 1px solid var(--hair);
}

.board-title {
    flex: 1;
    min-width: 0;
}

.board-title h2 {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text);
}

.board-sub {
    font-size: 12px;
    color: var(--muted);
}

.board-search {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    width: 240px;
    height: 34px;
    padding: 0 10px;
    border-radius: var(--r-control);
    background: var(--card);
    border: 1px solid var(--hair);
    color: var(--muted);
    transition: border-color var(--t-hover) var(--ease-out);
}

.board-search.filled,
.board-search:focus-within {
    border-color: var(--accent-line);
}

.board-search input {
    flex: 1;
    min-width: 0;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    font-size: 13px;
    color: var(--text);
}

.board-search-row {
    flex: none;
    padding: 10px 12px 0;
}

.board-search-row .board-search {
    width: 100%;
}

/* A state's color drives the mark, cell, and detail pill. */
.board-mark,
.board-cell,
.board-detail-state {
    --state: var(--muted);
}

:is(.board-mark, .board-cell, .board-detail-state).waiting {
    --state: var(--warn);
}
:is(.board-mark, .board-cell, .board-detail-state).failed {
    --state: var(--err);
}
:is(.board-mark, .board-cell, .board-detail-state).working {
    --state: var(--accent);
}
:is(.board-mark, .board-cell, .board-detail-state).done {
    --state: var(--ok);
}

.board-mark {
    flex: none;
    width: 10px;
    height: 10px;
    display: grid;
    place-items: center;
    border-radius: var(--r-mark);
    background: var(--state);
    color: var(--accent-ink);
    font: 600 8px/1 var(--mono);
}

/* How many are in each state, as one bar, and a legend that filters by one. */
.board-summary-bar {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px 22px 0;
}

.board-states {
    display: flex;
    gap: 3px;
    height: 8px;
    border-radius: calc(var(--r-tag) - 1px);
    overflow: hidden;
}

.board-state {
    flex-basis: 0;
    transition: opacity var(--t-fade) var(--ease-almost);
}

.board-state.waiting {
    background: var(--warn);
}

.board-state.failed {
    background: var(--err);
}

.board-state.working {
    background: var(--accent);
}

.board-state.stopped {
    background: var(--line-strong);
}

.board-state.done {
    background: var(--ok);
}

.board-state.dim {
    opacity: 0.25;
}

.board-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.board-filter {
    position: relative;
    display: flex;
    align-items: center;
    gap: 7px;
    height: 30px;
    padding: 0 11px;
    border: 1px solid var(--hair);
    border-radius: var(--r-pill);
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text);
    transition: background-color var(--t-hover) var(--ease-out);
}

.board-filter.on {
    background: var(--card-2);
    border-color: var(--hair-2);
}

@media (hover: hover) {
    .board-filter:hover {
        background: var(--card-2);
        border-color: var(--hair-2);
    }
}

.board-filter .board-mark {
    width: 8px;
    height: 8px;
    border-radius: calc(var(--r-mark) - 0.5px);
}

.board-filter-count {
    font: 400 11px var(--mono);
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}

.board-body {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 16px;
    padding: 16px calc(22px + var(--inset-r)) 22px calc(22px + var(--inset-l));
}

.board-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.board-map {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 4px;
    scroll-padding: 4px;
}

.board-empty {
    padding: 1.2rem 0;
    color: var(--muted);
    font-size: 0.85rem;
}

/* A session: its title and how its subagents are, a square for each, and a sub-tile for each at work. */
.board-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    margin-bottom: 8px;
    padding: 12px 14px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    transition: opacity var(--t-fade) var(--ease-almost);
}

.board-row-head {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* The subagents at work in it: what each does now, at a glance, without opening one. */
.board-live {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--hair);
}

.board-live-more {
    grid-column: 1 / -1;
    justify-self: start;
    min-height: 28px;
    padding: 4px 10px;
    border: 1px solid var(--hair);
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font: 500 12px / 1.4 var(--sans);
    cursor: pointer;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .board-live-more:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.board-session {
    flex: 1;
    min-width: 100px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
}

.board-session-title {
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 9px;
}

.board-session-name {
    min-width: 0;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .board-session:hover .board-session-name {
        color: var(--accent);
    }
}

.board-summary {
    max-width: 100%;
    padding-left: 17px;
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-summary.waiting {
    color: var(--warn);
}

.board-summary.failed {
    color: var(--err);
}

.board-summary.working {
    color: var(--accent);
}

.board-cells {
    flex: 0 1 auto;
    max-width: 60%;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    justify-content: flex-end;
    gap: 6px;
}

/* A session's finished subagents left off the board, counted: "+12". */
.board-older {
    align-self: center;
    margin-left: 3px;
    color: var(--muted);
    font: 11px var(--mono);
}

.board-cell {
    flex: none;
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border: 1px solid color-mix(in srgb, var(--state) 40%, transparent);
    border-radius: calc(var(--r-row) - 1px);
    background: color-mix(in srgb, var(--state) 14%, transparent);
    outline-offset: 2px;
    transition: opacity var(--t-fade) var(--ease-almost);
}

@media (hover: hover) {
    .board-cell:hover {
        border-color: var(--state);
    }
}

.board-cell.on {
    outline: 2px solid var(--state);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--state) 14%, transparent);
}

.board-cell.dim {
    opacity: 0.25;
}

.board-cell-core {
    width: 8px;
    height: 8px;
    border-radius: calc(var(--r-mark) - 0.5px);
    background: var(--state);
    color: var(--accent-ink);
    font: 600 8px/1 var(--mono);
}

.board-cell.working .board-cell-core {
    animation: pulse 1.4s ease-in-out infinite;
}

/* What the square under the mouse does, or the selected one's. */
.board-status {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 30px;
    padding: 0 4px;
    font-size: 11.5px;
    white-space: nowrap;
    overflow: hidden;
}

.board-status .board-mark {
    width: 8px;
    height: 8px;
}

.board-status-name {
    font: 600 11.5px var(--mono);
    color: var(--text);
}

.board-status-when {
    color: var(--muted);
}

.board-status-line {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--muted);
}

.board-status-line.working,
.board-status-line.stopped,
.board-status-line.done {
    color: var(--body);
}

.board-status-line.waiting {
    color: var(--warn);
}

.board-status-line.failed {
    color: var(--err);
}

.board-keys {
    flex: none;
    margin-left: auto;
    color: var(--faint);
}

/* The side: what needs you, then the one selected. */
.board-side {
    flex: none;
    width: 300px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow-y: auto;
}

.board-needs {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.board-needs .label {
    margin: 0 0 2px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: normal;
    text-transform: none;
}

.board-needs-count {
    font-family: var(--mono);
    color: var(--warn);
}

.board-need {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr);
    align-items: center;
    gap: 0 8px;
    padding: 8px;
    border-radius: var(--r-row);
    text-align: left;
    border: 1px solid transparent;
    transition: background-color var(--t-hover) var(--ease-out);
}

@media (hover: hover) {
    .board-need:hover {
        background: var(--hover);
    }
}

.board-need.on {
    background: var(--accent-soft);
    border-color: var(--accent-line);
}

.board-need-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.board-need-head {
    font-size: 13px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-need-head b {
    font-weight: 600;
}

.board-need.waiting .board-need-what {
    color: var(--warn);
}

.board-need.failed .board-need-what {
    color: var(--err);
}

.board-need-session {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-detail {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px;
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    background: var(--card);
}

.board-detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 9px;
    min-width: 0;
}

.board-detail-name {
    min-width: 0;
    font: 600 14px var(--mono);
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-detail-state {
    flex: none;
    margin-left: auto;
    padding: 2px 9px;
    border-radius: var(--r-pill);
    background: color-mix(in srgb, var(--state) 14%, transparent);
    color: var(--state);
    font-size: 12px;
    font-weight: 500;
}

.board-facts {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr);
    gap: 8px 12px;
    font-size: 13px;
}

.board-facts > span:not([class]) {
    color: var(--muted);
}

.board-link {
    min-width: 0;
    text-align: left;
    color: var(--accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (hover: hover) {
    .board-link:hover {
        text-decoration: underline;
        text-underline-offset: 2px;
    }
}

.board-when {
    font-family: var(--mono);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.board-asked {
    color: var(--body);
    text-wrap: pretty;
    overflow-wrap: anywhere;
}

.board-now {
    color: var(--text);
    overflow-wrap: anywhere;
}

.board-now.waiting {
    color: var(--warn);
}

.board-error {
    font: 12px/1.5 var(--mono);
    color: var(--err);
    overflow-wrap: anywhere;
}

.board-detail .agent-chip {
    align-self: flex-start;
}

.board-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.board-actions .button {
    min-height: 36px;
    padding: 0 14px;
    font-size: 13px;
}

@media (hover: hover) {
    .board-stop:hover {
        border-color: var(--err);
        color: var(--err);
    }
}

.board-actions .button.primary {
    flex: 1;
}

/* Phones: one column, what needs you first, thumb-sized squares, and the one selected in a bar at the bottom. */
.board-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 12px calc(12px + var(--inset-r)) 16px calc(12px + var(--inset-l));
}

/* Room under the last row for the bar over it. */
.board-list.with-bar {
    padding-bottom: 200px;
}

.board.phone .board-needs {
    gap: 2px;
    padding: 12px 0;
    border-bottom: 1px solid var(--hair);
}

.board.phone .board-needs .label {
    margin-bottom: 4px;
}

.board.phone .board-need {
    gap: 0 10px;
    min-height: 44px;
    padding: 4px 8px;
}

.board.phone .board-need-head {
    font-size: 0.84rem;
}

.board.phone .board-need-session {
    font-size: 0.7rem;
}

.board.phone .board-row {
    gap: 8px;
    padding: 12px;
}

.board.phone .board-row-head {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
}

.board.phone .board-live {
    grid-template-columns: 1fr;
}

.board.phone .board-session {
    min-height: 24px;
    justify-content: center;
}

.board.phone .board-session-title {
    gap: 8px;
}

.board.phone .board-session-name {
    font-size: 0.84rem;
}

.board.phone .board-summary {
    flex: none;
    margin-left: auto;
    padding-left: 0;
    font-size: 0.68rem;
}

.board.phone .board-cells {
    max-width: none;
    justify-content: flex-start;
    gap: 6px;
}

.board.phone .board-cell {
    width: 40px;
    height: 40px;
}

.board-bar {
    position: absolute;
    left: calc(8px + var(--inset-l));
    right: calc(8px + var(--inset-r));
    bottom: 8px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 12px calc(env(safe-area-inset-bottom) + 14px);
    border: 1px solid var(--hair-2);
    border-radius: var(--r-sheet);
    background: var(--bg);
    box-shadow: var(--pop);
    animation: pop var(--t-in) var(--ease-out);
}

.board-bar-head {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.board-bar .board-detail-name {
    font-size: 14px;
}

.board-bar .board-detail-state {
    margin-left: 0;
    font-size: 11px;
}

.board-bar-when {
    margin-left: auto;
    font-size: 0.72rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.board-bar-close {
    flex: none;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: var(--r-row);
    margin: -6px -6px -6px 0;
    color: var(--body);
}

.board-bar-session {
    font-size: 0.74rem;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-bar-line {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 13px;
    color: var(--body);
    overflow-wrap: anywhere;
}

.board-bar-line.waiting {
    color: var(--warn);
}

.board-bar-line.failed {
    color: var(--err);
}

.board-bar-actions {
    display: flex;
    gap: 6px;
}

.board-bar-actions .button {
    height: 44px;
    font-size: 0.86rem;
}

.board-bar-actions .button.primary {
    flex: 1;
}

.board-bar-actions .button:not(.primary) {
    flex: none;
    width: 96px;
}

/* ─── PiP ──────────────────────────────────────────────────── */

/*
 * PiP's window: anchored to the bottom right corner, wherever the app is and however tall the message box grows, over
 * the conversation and its panels and under sheets, the launcher, and notices. It never reaches up over a session's top
 * bar (`--topbar-h`, which app.js publishes): on a short screen it is shorter instead. It grows from 92% at its
 * corner. On phones it is a sheet from the bottom edge, over a light scrim.
 */
.pip-panel {
    --pip-top: max(
        calc(var(--gap-out) + env(safe-area-inset-top)),
        calc(var(--topbar-h, 0px) + 6px)
    );
    position: fixed;
    right: calc(16px + env(safe-area-inset-right));
    bottom: calc(16px + env(safe-area-inset-bottom));
    width: min(420px, calc(100vw - 32px));
    height: min(620px, calc(100dvh - max(90px, var(--pip-top) + 16px)));
    max-height: calc(100dvh - var(--pip-top) - 16px - env(safe-area-inset-bottom));
    z-index: 18;
    display: flex;
    flex-direction: column;
    background: var(--o-bg-dark);
    border: 1px solid var(--hair);
    border-radius: var(--r-float);
    box-shadow: var(--pop);
    font: 14.5px/1.6 var(--sans);
    transform-origin: bottom right;
    animation: pip-in 0.32s var(--ease-out);
}

@keyframes pip-in {
    from {
        opacity: 0;
        transform: scale(0.92);
    }
}

.pip-panel.leaving {
    animation: pop-out var(--t-out) linear forwards;
}

.pip-resize {
    display: none;
}

@media (min-width: 768px) {
    .pip-panel {
        width: var(--pip-width, 420px);
        height: var(--pip-height, min(620px, calc(100dvh - 90px)));
        max-width: min(
            800px,
            calc(100vw - 32px - env(safe-area-inset-left) - env(safe-area-inset-right))
        );
        max-height: calc(100dvh - var(--pip-top) - 16px - env(safe-area-inset-bottom));
    }

    .pip-resize {
        display: block;
        position: absolute;
        touch-action: none;
        user-select: none;
        z-index: 1;
    }

    .pip-resize-left {
        left: -12px;
        top: 12px;
        bottom: 0;
        width: 16px;
        cursor: ew-resize;
    }

    .pip-resize-top {
        top: -12px;
        left: 12px;
        right: 0;
        height: 16px;
        cursor: ns-resize;
    }

    .pip-resize-corner {
        left: -12px;
        top: -12px;
        width: 24px;
        height: 24px;
        cursor: nwse-resize;
    }
}

@media (min-width: 768px) and (any-pointer: coarse) {
    .pip-resize-left {
        left: -34px;
        top: 22px;
        width: 44px;
    }

    .pip-resize-top {
        top: -34px;
        left: 22px;
        height: 44px;
    }

    .pip-resize-corner {
        left: -22px;
        top: -22px;
        width: 44px;
        height: 44px;
    }
}

.pip-head {
    display: grid;
    grid-template-columns: 30px minmax(0, 1fr) auto repeat(4, 40px);
    align-items: center;
    gap: 2px;
    padding: 10px 8px 10px 16px;
    position: relative;
    flex: none;
    border-bottom: 1px solid var(--hair);
}

.pip-head .grip {
    display: none;
}

.pip-heading {
    min-width: 0;
    margin-left: 8px;
    line-height: 1.3;
}

.pip-title-line {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
}

.pip-head h2 {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
}

.pip-head .pip-model {
    display: flex;
    gap: 4px;
    width: 100%;
    min-width: 0;
    height: 22px;
    padding: 0;
    position: relative;
    border: 0;
    border-radius: var(--r-tag);
    background: transparent;
    font: 12px var(--sans);
    color: var(--muted);
    text-align: left;
    white-space: nowrap;
}

/* A quiet model label with the original thumb-sized target; its extra area covers only the title. */
.pip-head .pip-model::before {
    content: "";
    position: absolute;
    inset: -18px 0 0;
}

.pip-model .model-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pip-model .model-level {
    display: none;
}

.pip-head > .icon-button {
    width: 40px;
    height: 40px;
    min-width: 0;
    border-radius: var(--r-row);
    color: var(--muted);
}

.pip-head > .icon-button:nth-last-child(4) {
    grid-column: 4;
}

.pip-head > .icon-button:nth-last-child(3) {
    grid-column: 5;
}

.pip-head > .icon-button:nth-last-child(2) {
    grid-column: 6;
}

.pip-head > .icon-button:last-child {
    grid-column: 7;
}

.pip-status {
    min-width: 0;
    color: var(--muted);
    font-size: 11px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* How full PiP's context is, as a session's status line shows it. */
.pip-context {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-right: 4px;
    font: 11px var(--mono);
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pip-context .meter {
    width: 28px;
}

.pip-mark {
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
}

.pip-mark.working .icon,
.pip-bubble.busy .icon,
.rail-pip.lit .icon {
    animation: pulse 1.4s ease-in-out infinite;
}

.pip-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    overflow-x: hidden;
    padding: 12px 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.pip-body::before {
    content: "";
    margin-top: auto;
}

.pip-body > * {
    flex-shrink: 0;
}

.pip-you {
    align-self: flex-end;
    max-width: 84%;
    padding: 10px 14px;
    background: var(--accent-soft);
    border-radius: var(--r-sheet) var(--r-sheet) calc(var(--r-tag) + 1px) var(--r-sheet);
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    animation: rise-in var(--t-fade) var(--ease-out);
}

/* A message of yours that waits while PiP works: dimmed, with what happens to it and a way to take it back. */
.pip-you.pending {
    opacity: 0.7;
    border: 1px dashed var(--accent-line);
}

.pip-pending-line {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 4px;
    font-size: 12px;
    color: var(--muted);
    white-space: normal;
}

.pip-pending-withdraw {
    min-height: 40px;
    padding: 0 4px;
    color: var(--accent);
    font: inherit;
}

.pip-reply {
    color: var(--body);
    overflow-wrap: anywhere;
}

.pip-reply .md > :first-child {
    margin-top: 0;
}

.pip-reply .md > :last-child {
    margin-bottom: 0;
}

.pip-steps,
.pip-event {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--muted);
    font-size: 12.5px;
}

.pip-steps.working {
    color: var(--accent);
}

.pip-tick {
    width: 16px;
    height: 16px;
    flex: none;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--ok-soft);
    color: var(--ok);
}

.pip-error {
    color: var(--err);
    font-size: 0.85rem;
}

/* A report from a session PiP follows: three lines until opened. */
.pip-report {
    padding: 12px 14px;
    background: var(--card);
    border: 1px solid var(--hair);
    border-radius: var(--r-window);
    color: var(--body);
}

.pip-report-head {
    display: flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    min-height: 20px;
    margin-bottom: 6px;
    color: var(--accent);
    font-size: 12px;
    font-weight: 500;
}

.pip-report-head span {
    flex: 1;
    text-align: left;
}

.pip-report-fold {
    color: var(--muted);
    transition: transform 300ms var(--ease-out);
}

.pip-report.open .pip-report-fold {
    transform: rotate(180deg);
}

.pip-report-text {
    font-size: 13.5px;
    line-height: 1.55;
}

.pip-report-text > :first-child {
    margin-top: 0;
}

.pip-report-text > :last-child {
    margin-bottom: 0;
}

/* What a webhook posted: as it came, shown once the card is open. */
.pip-report-data {
    margin: 6px 0 0;
    padding: 6px 8px;
    max-height: 16rem;
    overflow: auto;
    background: var(--code-bg);
    border: 1px solid var(--hair);
    border-radius: var(--r-row);
    font: 12px var(--mono);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.pip-report:not(.open) .pip-report-data {
    display: none;
}

.pip-report:not(.open) .pip-report-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.pip-welcome {
    margin-top: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 40px;
}

.pip-hello {
    margin: 0;
    font-size: 17px;
    font-weight: 600;
    color: var(--text);
}

.pip-intro {
    margin: 0;
    color: var(--muted);
    font-size: 13.5px;
    text-wrap: pretty;
}

.pip-welcome .button {
    min-height: 40px;
    white-space: normal;
}

.pip-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

.pip-chip {
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-card);
    color: var(--text);
    font-size: 13px;
    text-align: left;
}

.pip-chip:disabled {
    opacity: 0.5;
    cursor: default;
}

@media (hover: hover) {
    .pip-chip:not(:disabled):hover {
        border-color: var(--accent-line);
        color: var(--text);
    }
}

.pip-loading {
    margin: auto;
}

/* A call of PiP's waits for approval, which the panel cannot give: a line that leads to where it can. */
.pip-approval {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 12px 6px;
    padding: 8px 12px;
    border: 1px solid var(--warn-line);
    border-radius: calc(var(--r-control) + 1px);
    background: var(--warn-soft);
    color: var(--warn);
    font-size: 12.5px;
}

.pip-approval .button {
    min-height: 40px;
}

/* Quick access to the owner's private all-project memory approval queue. */
.pip-memory {
    flex: none;
    margin: 0 12px 6px;
}

.pip-memory .button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    min-height: 44px;
    padding: 8px 12px;
    border: 0;
    border-radius: calc(var(--r-control) + 1px);
    background: var(--card);
    color: var(--body);
    font-size: 12.5px;
    text-align: left;
}

@media (hover: hover) {
    .pip-memory .button:hover {
        background: var(--card-2);
    }
}

.pip-memory-count {
    flex: none;
    color: var(--muted);
    font: 11.5px var(--mono);
    font-variant-numeric: tabular-nums;
}

.pip-memory-count.waiting {
    color: var(--accent);
}

.pip-composer-wrap {
    flex: none;
    min-width: 0;
    padding: 4px 12px 12px;
}

.pip-attachments {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 144px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-bottom: 6px;
}

.pip-attachment {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 4px 6px;
    border: 1px solid var(--hair);
    border-radius: calc(var(--r-control) + 1px);
    background: var(--card);
    font-size: 12px;
}

.pip-attachment .thumb {
    flex: none;
}

.pip-attachment .thumb img {
    width: 48px;
    height: 48px;
    object-fit: cover;
}

.pip-attachment-remove {
    min-width: 44px;
    min-height: 44px;
}

.pip-attachment-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pip-attachment > .muted,
.pip-attachment > .spinner,
.pip-attachment-remove {
    flex: none;
}

.pip-you .thumbs,
.pip-you .attachments {
    margin-top: 0.3rem;
    max-width: 100%;
    white-space: normal;
}

.pip-you .attachments .chip {
    max-width: 100%;
    overflow-wrap: anywhere;
}

.pip-composer {
    display: flex;
    align-items: flex-end;
    min-height: 48px;
    gap: 4px;
    padding: 1px 5px;
    border: 1px solid var(--hair-2);
    border-radius: calc(var(--r-float) + 4px);
    background: var(--card);
}

.pip-composer:focus-within {
    border-color: var(--accent-line);
}

.pip-composer textarea {
    flex: 1;
    min-width: 0;
    max-height: 160px;
    padding: 0.55rem 0;
    resize: none;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--text);
    font: 15px/1.45 var(--sans);
}

.pip-composer > .icon-button {
    width: 44px;
    min-width: 44px;
    height: 44px;
    min-height: 44px;
    border: 4px solid transparent;
    border-radius: 50%;
    background-clip: padding-box;
}

.pip-composer .pip-send {
    background-color: var(--card-2);
    color: var(--faint);
}

/* iOS zooms into a text field smaller than 16px as it takes focus: PiP's box keeps the app's touch size. */
@media (pointer: coarse) {
    .pip-composer textarea {
        font-size: 16px;
    }

    .pip-report-head {
        min-height: 40px;
    }
}

.pip-composer .pip-send:not(:disabled) {
    color: var(--accent-ink);
    background-color: var(--accent-fill);
}

.pip-composer .pip-send[aria-label="Stop PiP"] {
    color: var(--err);
    background-color: var(--err-soft);
}

.pip-scrim {
    display: none;
}

/* The mark in the corner, while PiP works or has something new: above the message box, out of its way. */
.pip-bubble {
    position: fixed;
    right: calc(var(--gap-out) + 6px + env(safe-area-inset-right));
    bottom: calc(104px + env(safe-area-inset-bottom));
    z-index: 16;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    background: var(--o-bg-dark);
    color: var(--accent);
    border: 1px solid var(--hair-2);
    border-radius: 50%;
    box-shadow: var(--shadow);
    animation: pip-in 0.32s var(--ease-out);
}

.pip-bubble.leaving {
    animation: popout var(--t-out) linear forwards;
}

.pip-dot {
    position: absolute;
    top: 5px;
    right: 5px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
}

@media (max-width: 699px) {
    .pip-panel {
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 86dvh;
        max-height: calc(100dvh - env(safe-area-inset-top));
        border: 0;
        border-radius: calc(var(--r-sheet) + 8px) calc(var(--r-sheet) + 8px) 0 0;
        background: var(--bg);
        box-shadow:
            0 -1px 0 var(--hair-2),
            0 -20px 40px -20px var(--sh);
        padding-bottom: env(safe-area-inset-bottom);
        animation: sheet-up var(--t-in) var(--ease-out);
    }

    .pip-panel.leaving {
        animation: sheet-down 0.2s var(--ease-in-out) forwards;
    }

    .pip-head {
        padding: 23px 10px 10px 14px;
        grid-template-columns: 32px minmax(0, 1fr) repeat(4, 40px);
    }

    .pip-head h2 {
        font-size: 16px;
    }

    .pip-context {
        grid-column: 2;
        grid-row: 2;
        margin: 0 0 0 8px;
        justify-self: start;
    }

    .pip-head > .icon-button {
        grid-row: 1 / 3;
    }

    .pip-head > .icon-button:nth-last-child(4) {
        grid-column: 3;
    }

    .pip-head > .icon-button:nth-last-child(3) {
        grid-column: 4;
    }

    .pip-head > .icon-button:nth-last-child(2) {
        grid-column: 5;
    }

    .pip-head > .icon-button:last-child {
        grid-column: 6;
    }

    .pip-head .grip {
        display: block;
    }

    /* Above the message box and the jump to the newest message, both at the bottom right. */
    .pip-bubble {
        bottom: calc(176px + env(safe-area-inset-bottom));
    }

    .pip-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 17;
        background: var(--scrim);
        animation: fade var(--t-fade) var(--ease-almost);
    }

    .pip-scrim.leaving {
        animation: fade-out var(--t-out) linear forwards;
    }
}

/* A webhook in its sheet: name and where it sends, what Pi is told, its address when just made, and how it was used. */
.hook {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px;
    margin-top: 10px;
    border-radius: var(--r-card);
    background: var(--bg);
    border: 1px solid var(--hair);
}

.hook-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    border-radius: var(--r-window);
    border: 1px solid var(--hair);
    background: var(--card);
}

.hook-form input,
.hook-form textarea,
.hook-form .segmented {
    background: var(--bg);
}

.hook.fresh {
    border-color: var(--accent);
}

.hook-head,
.hook-actions {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.hook-actions {
    align-items: center;
}

.hook-text {
    font-size: 0.85rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.hook-address {
    overflow-wrap: anywhere;
    user-select: all;
    color: var(--accent);
}

/* ─── Extension gallery ────────────────────────────────────── */

/*
 * One calm place for extensions: quiet rows like the menu's, each with a steady mark, one action at a time, and the
 * technical words folded away until asked for.
 */
.sheet.extension-hub {
    max-width: 1180px;
}

.ext-hub-bar {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Discover, Installed, Updates: a segmented track, as the session list's tabs. */
.ext-tabs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    flex: none;
    padding: 3px;
    border-radius: var(--r-card);
    background: var(--card);
}

.ext-tabs button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 32px;
    padding: 0 10px;
    border-radius: var(--r-seg);
    color: var(--muted);
    font-size: 13px;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.ext-tabs button.on {
    background: var(--raised);
    color: var(--text);
    font-weight: 500;
}

@media (hover: hover) {
    .ext-tabs button:not(.on):hover {
        color: var(--text);
    }
}

.ext-count {
    min-width: 18px;
    padding: 0 5px;
    border-radius: var(--r-seg);
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-size: 11px;
    font-weight: 600;
    line-height: 18px;
}

.extension-hub-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.ext-search {
    position: relative;
    flex: 1;
    min-width: 0;
}

.ext-search > .icon {
    position: absolute;
    top: 50%;
    left: 12px;
    translate: 0 -50%;
    color: var(--faint);
    pointer-events: none;
}

.ext-search input {
    min-height: 40px;
    padding-left: 36px;
    border-color: transparent;
    border-radius: var(--r-card);
}

/* Squarer buttons than elsewhere, to match the rows. */
:is(.extension-hub, .extension-detail-sheet) .button {
    border-radius: var(--r-row);
}

.ext-icon-button {
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: var(--r-card);
    color: var(--muted);
}

/* Kinds and tags: one row that scrolls sideways on a phone, so the list starts high. */
.gallery-tags.ext-filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    margin-inline: -2px;
    padding: 2px;
    mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
}

.ext-filters::-webkit-scrollbar {
    display: none;
}

.ext-filters .gallery-tag {
    flex: none;
}

.ext-filters-gap {
    flex: none;
    width: 1px;
    margin: 6px 2px;
    background: var(--hair-2);
}

.extension-hub-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
    gap: 20px;
}

.extension-hub-list,
.extension-hub-detail {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

/* Reassurance, not alarm: what keeps the owner safe, in one line. */
.ext-assure {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0;
    padding: 10px 12px;
    border-radius: var(--r-card);
    background: var(--card);
    color: var(--muted);
    font-size: 12.5px;
    line-height: 1.5;
}

.ext-assure > .icon {
    flex: none;
    margin-top: 1px;
    color: var(--ok);
}

.ext-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* A row: its mark and words open it; its one action or switch sits at the end. */
.ext-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 10px;
    padding: 4px 10px 4px 4px;
    border-radius: var(--r-card);
    transition: background-color var(--t-hover) var(--ease-out);
}

.ext-row.selected {
    background: var(--accent-soft);
}

.ext-row-open {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    min-width: 0;
    padding: 8px;
    border-radius: var(--r-row);
    color: var(--text);
    text-align: left;
}

@media (hover: hover) {
    .ext-row:not(.selected):hover {
        background: var(--card);
    }
}

.ext-tile {
    display: grid;
    flex: none;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: var(--r-control);
    background: color-mix(in srgb, var(--tint) 14%, transparent);
    color: var(--tint);
    font-size: 15px;
    font-weight: 600;
    transition:
        opacity var(--t-hover) var(--ease-out),
        filter var(--t-hover) var(--ease-out);
}

.ext-tile.large {
    width: 52px;
    height: 52px;
    border-radius: var(--r-window);
    font-size: 21px;
}

.ext-row.off .ext-tile {
    filter: saturate(0);
    opacity: 0.55;
}

.ext-row-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding-top: 1px;
}

.ext-row-title {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--text);
    font-size: 14px;
    font-weight: 500;
    overflow-wrap: anywhere;
}

.ext-row.off .ext-row-title {
    color: var(--muted);
}

.ext-row-desc {
    display: -webkit-box;
    overflow: hidden;
    color: var(--muted);
    font-size: 12.5px;
    line-height: 1.45;
    overflow-wrap: anywhere;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.ext-row-meta {
    color: var(--faint);
    font-size: 11.5px;
}

.ext-row-meta.warn {
    color: var(--warn);
}

.ext-row-meta.accent {
    color: var(--accent);
}

.ext-row-chevron {
    color: var(--faint);
    transition: rotate var(--t-hover) var(--ease-out);
}

.ext-row.open .ext-row-chevron {
    rotate: 180deg;
}

.ext-row-end {
    display: flex;
    align-items: center;
    justify-content: flex-end;
}

/* What sits under a row, lined up with its words. */
.ext-row-under {
    grid-column: 1 / -1;
    margin: 0 0 8px 56px;
}

.ext-row-under:empty {
    display: none;
}

.ext-row-under > .setting {
    margin-top: 0;
}

.ext-row-more {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px 14px;
    border-radius: var(--r-card);
    background: var(--card);
}

.ext-row-more > .setting {
    margin-top: 0;
}

.ext-state {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--muted);
    font-size: 12px;
    white-space: nowrap;
}

.ext-state.on {
    color: var(--ok);
}

.ext-state.bad {
    color: var(--err);
}

.ext-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--ok);
    box-shadow: 0 0 0 3px var(--ok-soft);
}

.button.ext-get {
    border-radius: var(--r-row);
    background: var(--accent-soft);
    color: var(--accent);
    padding-inline: 14px;
}

@media (hover: hover) {
    .button.ext-get:hover {
        background: color-mix(in srgb, var(--accent) 24%, transparent);
    }
}

.ext-confirm {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-card);
    background: var(--card);
    color: var(--text);
    font-size: 12.5px;
}

.ext-row-under.guard-confirm {
    margin-top: 0;
}

.extension-management {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

.extension-management .group {
    display: flex;
    flex-direction: column;
}

.ext-intro {
    margin: 0;
    color: var(--muted);
    font-size: 12.5px;
    line-height: 1.5;
}

.ext-footer {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding-top: 14px;
    border-top: 1px solid var(--hair);
    color: var(--faint);
    font-size: 12px;
    line-height: 1.55;
}

.ext-footer .link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    text-decoration: none;
}

/* One entry. */
.gallery-entry-content {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

.ext-back {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: 4px;
    min-height: 36px;
    margin-left: -4px;
    color: var(--muted);
    font-size: 13px;
}

.ext-detail-head {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.ext-detail-name {
    min-width: 0;
}

.ext-detail-name .pi-title {
    margin: 0;
    font-size: 20px;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

.ext-detail-by {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    margin-top: 4px;
    color: var(--muted);
    font-size: 12.5px;
}

.gallery-entry-content .gallery-description {
    margin: 0;
    font-size: 14px;
    line-height: 1.65;
}

.ext-detail-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin-top: -6px;
    color: var(--faint);
    font-size: 12px;
}

.ext-callout {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding: 10px 12px 10px 14px;
    border-radius: var(--r-card);
    background: var(--accent-soft);
    color: var(--text);
    font-size: 13px;
}

/* The steps to trust something new: numbered marks on a thin line, the one to take now in the accent. */
.ext-steps {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 16px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
    list-style: none;
}

.ext-step {
    position: relative;
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr);
    gap: 12px;
    padding-bottom: 18px;
}

.ext-step:last-child {
    padding-bottom: 0;
}

.ext-step:not(:last-child)::before {
    content: "";
    position: absolute;
    top: 30px;
    bottom: 4px;
    left: 12.5px;
    width: 1px;
    background: var(--hair-2);
}

.ext-step-mark {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-row);
    color: var(--muted);
    font-size: 12px;
    font-weight: 600;
}

.ext-step.now .ext-step-mark {
    border-color: transparent;
    background: var(--accent-fill);
    color: var(--accent-ink);
}

.ext-step.done .ext-step-mark {
    border-color: transparent;
    background: var(--ok-soft);
    color: var(--ok);
}

.ext-step-body {
    min-width: 0;
}

.ext-step-title {
    color: var(--text);
    font-size: 14px;
    font-weight: 500;
    line-height: 26px;
}

.ext-step:not(.now, .done) .ext-step-title {
    color: var(--muted);
}

.ext-step-text {
    color: var(--muted);
    font-size: 12.5px;
    line-height: 1.55;
}

/* A module's settings (`web.settings`) in its open row: its fields as the app's settings rows. */
.ext-settings {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 0;
    border-top: 1px solid var(--line);
}

.ext-setting-input,
.ext-settings select {
    min-height: 36px;
    max-width: 220px;
    padding: 6px 8px;
    border: 1px solid var(--line);
    border-radius: var(--r-control);
    background: var(--bg);
    color: var(--text);
    font: inherit;
}

.ext-step-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}

.ext-row-more > .ext-step-actions {
    margin-top: 0;
}

.ext-on {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px 16px;
    border: 1px solid var(--hair);
    border-radius: var(--r-card);
}

.ext-on-text {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--muted);
    font-size: 13.5px;
}

.ext-on-text strong {
    color: var(--ok);
    font-weight: 600;
}

.ext-adds dl {
    display: grid;
    gap: 8px;
    margin: 0;
}

.ext-adds dl > div {
    display: grid;
    grid-template-columns: 7.5rem minmax(0, 1fr);
    gap: 12px;
    font-size: 13px;
}

.ext-adds dt {
    color: var(--muted);
}

.ext-adds dd {
    margin: 0;
    color: var(--text);
    overflow-wrap: anywhere;
}

.ext-adds dd.ext-sentence::first-letter {
    text-transform: uppercase;
}

.ext-adds dd.mono {
    font-size: 12px;
    line-height: 1.6;
}

.ext-remove {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}

.extension-hub-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    min-height: 200px;
    padding: 32px;
    color: var(--muted);
    font-size: 13.5px;
    text-align: center;
    line-height: 1.6;
}

.ext-empty-mark {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--r-window);
    background: var(--ok-soft);
    color: var(--ok);
}

.ext-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.gallery-technical {
    border-top: 1px solid var(--hair);
    padding-top: 12px;
}

.gallery-technical > summary {
    padding: 6px 0;
    color: var(--muted);
    font-size: 13px;
    cursor: pointer;
}

.gallery-technical[open] > summary {
    margin-bottom: 16px;
}

.gallery-technical > .group + .group {
    margin-top: 16px;
}

@media (max-width: 520px) {
    .ext-adds dl > div {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px;
    }
    .ext-row-under {
        margin-left: 12px;
    }
}

@media (min-width: 1000px) {
    .sheet.extension-hub {
        height: min(860px, 88dvh);
        max-height: 88dvh;
    }
    .extension-hub > .sheet-body {
        overflow: hidden;
        padding: 18px 24px 24px;
        gap: 14px;
    }
    .ext-hub-bar {
        flex-direction: row;
        align-items: center;
        gap: 16px;
    }
    .ext-tabs {
        width: 360px;
    }
    .extension-hub-toolbar {
        flex: 1;
    }
    .extension-hub-layout {
        flex: 1;
        flex-shrink: 1;
        grid-template-columns: minmax(340px, 0.9fr) minmax(0, 1.1fr);
        gap: 0;
        overflow: hidden;
    }
    .extension-hub-list,
    .extension-hub-detail {
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-gutter: stable;
        padding: 2px 16px 8px 0;
    }
    .extension-hub-detail {
        border-left: 1px solid var(--hair);
        padding-left: 28px;
    }
    .ext-back {
        display: none;
    }
    .extension-hub-layout:is(.installed, .updates):not(.has-selection) {
        grid-template-columns: minmax(0, 1fr);
    }
    .extension-hub-layout:is(.installed, .updates):not(.has-selection) > .extension-hub-detail {
        display: none;
    }
    /* One readable column, not a wall of cards, when nothing is open beside it. */
    .extension-hub-layout:is(.installed, .updates):not(.has-selection) > .extension-hub-list {
        padding-inline: max(0px, calc((100% - 760px) / 2));
    }
    .extension-hub-empty {
        flex: 1;
    }
    .sheet.gallery:not(.extension-hub) {
        max-width: 1000px;
    }
}

@media (max-width: 999px) {
    .extension-hub:has(.extension-hub-layout.has-selection) :is(.ext-hub-bar, .ext-filters) {
        display: none;
    }
    .extension-hub-layout:not(.has-selection) .ext-row.selected {
        background: none;
    }
    .extension-hub-layout.has-selection > .extension-hub-list,
    .extension-hub-layout:not(.has-selection) > .extension-hub-detail {
        display: none;
    }
}

.extension-gallery {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
}

.pi-tag.gallery-on {
    color: var(--ok);
    background: var(--ok-soft);
}

.pi-tag.gallery-bad {
    color: var(--err);
    background: var(--err-soft);
}

.pi-tag.gallery-plain {
    color: var(--muted);
    background: var(--card-2);
}

/* Filter chips: one at a time filters the list. */
.gallery-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.gallery-tag {
    min-height: 30px;
    padding: 4px 12px;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-row);
    background: none;
    color: var(--muted);
    font-size: 12.5px;
    white-space: nowrap;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

@media (pointer: coarse) {
    .gallery-tag {
        min-height: 34px;
        padding: 5px 13px;
    }
}

@media (hover: hover) {
    .gallery-tag:hover {
        background: var(--hover);
        color: var(--text);
    }
}

.gallery-tag.on {
    color: var(--accent);
    border-color: var(--accent-line);
    background: var(--accent-soft);
}

.gallery-problems,
.gallery-notes,
.gallery-warn ul {
    margin: 0;
    padding-left: 1.2rem;
    overflow-wrap: anywhere;
}

.gallery-panel > .setting {
    margin: 0;
    padding: 10px 14px;
}

.gallery-address {
    overflow-wrap: anywhere;
    color: var(--text);
}

.gallery-index-form {
    padding: 12px 14px;
}

.gallery-wrap {
    flex-wrap: wrap;
}

.gallery-description {
    overflow-wrap: anywhere;
    color: var(--body);
}

.gallery-warn {
    padding: 10px 12px;
    border: 1px solid var(--warn-line);
    border-radius: var(--r-card);
    background: var(--warn-soft);
    color: var(--text);
    overflow-wrap: anywhere;
}

.gallery-revoked .sheet-actions {
    margin-top: 8px;
    justify-content: flex-start;
}

.gallery-declares dd.mono {
    font-size: 0.78rem;
}

.gallery-file {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.6rem;
    padding: 8px 14px;
    font-size: 12.5px;
    overflow-wrap: anywhere;
}

.gallery-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

@media (pointer: coarse) {
    .gallery-actions .button {
        min-height: 40px;
    }
}

/* Code: each file under its own head, scrolling sideways inside its box on a narrow screen. */
.gallery-source {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.gallery-source-head,
.gallery-entry-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.6rem;
}

.gallery-entry-head .group-title {
    flex: 1;
}

/* Share's form: where the files are, which only their author knows. One column on a phone. */
.gallery-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 0.75rem 0.9rem;
}

.gallery-field input[aria-invalid="true"] {
    border-color: var(--warn);
}

.gallery-source-name {
    font-size: 13px;
    color: var(--text);
    overflow-wrap: anywhere;
}

pre.gallery-code {
    margin: 0;
    padding: 10px 12px;
    max-height: 60vh;
    overflow: auto;
    border: 1px solid var(--hair);
    border-radius: var(--r-control);
    background: var(--code-bg);
    color: var(--body);
    font: 12px / 1.55 var(--mono);
    white-space: pre;
    tab-size: 4;
}

/* An update: what each file does, and what was added to or taken from its declarations. */
.gallery-change {
    color: var(--muted);
}

.gallery-change.added,
.gallery-added {
    color: var(--ok);
}

.gallery-change.removed,
.gallery-removed {
    color: var(--err);
}

.gallery-change.changed {
    color: var(--warn);
}

/* ─── Fluid motion ─────────────────────────────────────────── */

/*
 * Appearance → Motion → Fluid: the same app, moving more. What floats over the page arrives on a spring and leaves
 * quickly; what it holds follows a step behind; layout changes morph (theme.js, `morph`); a pressed control springs
 * back. Only transform and opacity move, apart from a few small things (a notice's blur, the message box's glow), so a
 * long session costs nothing more. Nothing waits before it can be used: arrivals take pointers from their first frame,
 * and what leaves finishes inside the time the app keeps it (usePresence, ui.js). Last in the file, so it wins over
 * the usual motion at the same specificity. Auto never picks it: it is chosen.
 */
:root[data-motion="fluid"] {
    --ease-out: var(--ease-glide);
}

@supports not (animation-timing-function: linear(0, 1)) {
    :root {
        --ease-spring: var(--ease-glide);
    }
}

@keyframes fluid-fade {
    from {
        opacity: 0;
    }
}

@keyframes fluid-fade-out {
    to {
        opacity: 0;
    }
}

/* What floats near the middle: up a little, and from 95%. The spring carries the size; the fade is quicker. */
@keyframes fluid-float-in {
    from {
        transform: translateY(10px) scale(0.95);
    }
}

@keyframes fluid-float-out {
    to {
        opacity: 0;
        transform: translateY(4px) scale(0.97);
    }
}

/* What a sheet, a menu, or a group holds: each part a step after the one before. */
@keyframes fluid-rise {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
}

@keyframes fluid-drop {
    from {
        opacity: 0;
        transform: translateY(-5px);
    }
}

/* The scrim: a soft frost over the app as it dims. Its blur stays still; only its opacity moves, quickly, since what
 * it holds fades with it. */
:root[data-motion="fluid"] .overlay:not(.pop-overlay),
:root[data-motion="fluid"] .launcher-overlay {
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    animation: fluid-fade var(--t-fade) var(--ease-glide);
}

:root[data-motion="fluid"] .leaving .overlay:not(.pop-overlay),
:root[data-motion="fluid"] .leaving.launcher-overlay {
    animation: fluid-fade-out var(--t-exit) var(--ease-exit) forwards;
}

/* Phones: a sheet glides up from the bottom edge. A spring would lift it off the edge, so it slows to rest. */
:root[data-motion="fluid"] .sheet {
    animation: sheet-up var(--t-glide) var(--ease-glide);
}

:root[data-motion="fluid"] .leaving .sheet {
    animation: sheet-down 190ms var(--ease-exit) forwards;
}

/* What a sheet holds rises behind it, the first eight parts a step apart. */
:root[data-motion="fluid"] .sheet-body > :nth-child(-n + 8),
:root[data-motion="fluid"] .nav-menu .places > :nth-child(-n + 9) {
    animation: fluid-rise var(--t-glide) var(--ease-glide) backwards;
    animation-delay: calc(50ms + var(--fluid-i, 0) * var(--stagger));
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(2) {
    --fluid-i: 1;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(3) {
    --fluid-i: 2;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(4) {
    --fluid-i: 3;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(5) {
    --fluid-i: 4;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(6) {
    --fluid-i: 5;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(7) {
    --fluid-i: 6;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(8) {
    --fluid-i: 7;
}

:root[data-motion="fluid"] :is(.sheet-body, .places) > :nth-child(9) {
    --fluid-i: 8;
}

/* Wide screens: a sheet floats in on the spring, and the menu grows from its corner by the button. */
@media (min-width: 700px) {
    :root[data-motion="fluid"] .sheet {
        animation:
            fluid-fade var(--t-fade) var(--ease-glide),
            fluid-float-in var(--t-spring) var(--ease-spring);
    }
    :root[data-motion="fluid"] .leaving .sheet {
        animation: fluid-float-out var(--t-exit) var(--ease-exit) forwards;
    }
    :root[data-motion="fluid"] .nav-menu {
        transform-origin: 85% 0;
    }
}

/* The launcher: from just above, as if it dropped into place; its results follow. */
:root[data-motion="fluid"] .launcher {
    transform-origin: 50% 0;
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        fluid-float-in var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] .launcher-list {
    animation: fluid-rise var(--t-glide) var(--ease-glide) 40ms backwards;
}

:root[data-motion="fluid"] .leaving .launcher {
    animation: fluid-float-out 140ms var(--ease-exit) forwards;
}

/* Menus up from a control (the model, the branch): from the control's side. */
:root[data-motion="fluid"] .pop-menu {
    transform-origin: 30% 100%;
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        fluid-float-in var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] .pop-menu.down {
    transform-origin: 30% 0;
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        pop-menu-down var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] .leaving .pop-menu,
:root[data-motion="fluid"] .leaving .pop-menu.down {
    animation: fluid-float-out var(--t-exit) var(--ease-exit) forwards;
}

/* The drawer glides in; the list in it follows a little behind, as if pulled. */
:root[data-motion="fluid"] .drawer {
    animation: drawer-in var(--t-glide) var(--ease-glide);
}

:root[data-motion="fluid"] .drawer .session-items {
    animation: fluid-drawer-items var(--t-spring) var(--ease-glide) backwards;
}

@keyframes fluid-drawer-items {
    from {
        opacity: 0;
        transform: translateX(-28px);
    }
}

:root[data-motion="fluid"] .leaving .drawer {
    animation: drawer-out 190ms var(--ease-exit) forwards;
}

/* Notices: down from the top edge, out of a soft blur, and back up into it. */
:root[data-motion="fluid"] .notice {
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        fluid-toast-in var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] .notice.leaving {
    animation: fluid-toast-out var(--t-exit) var(--ease-exit) forwards;
}

@keyframes fluid-toast-in {
    from {
        translate: 0 -14px;
        scale: 0.94;
        filter: blur(4px);
    }
    60% {
        filter: blur(0);
    }
}

@keyframes fluid-toast-out {
    to {
        opacity: 0;
        translate: 0 -10px;
        scale: 0.96;
        filter: blur(3px);
    }
}

/* A session opened: its conversation settles up into place. */
:root[data-motion="fluid"] .transcript.rising {
    animation: fluid-rise var(--t-glide) var(--ease-glide);
}

/* A message sent lifts off from the message box below it, on the spring. */
:root[data-motion="fluid"] .user-row.enter {
    transform-origin: 100% 100%;
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        fluid-sent var(--t-spring) var(--ease-spring) backwards;
}

@keyframes fluid-sent {
    from {
        transform: translateY(28px) scale(0.96);
    }
}

/* Pi's answer, what it did, and reports: quieter, a short rise. */
:root[data-motion="fluid"] :is(.reply, .activity, .report).enter {
    animation: fluid-rise var(--t-glide) var(--ease-glide) backwards;
}

/* While Pi answers, each new paragraph, list, or code block fades in; what is already there never moves. */
:root[data-motion="fluid"] .md.streaming > .md-part {
    animation: fluid-fade 320ms var(--ease-glide);
}

/* The caret breathes instead of blinking. */
:root[data-motion="fluid"] .md.streaming > :last-child:not(.md-part)::after,
:root[data-motion="fluid"] .md.streaming > .md-part:last-child > :last-child::after {
    animation: fluid-caret 1.1s var(--ease-in-out) infinite alternate;
}

@keyframes fluid-caret {
    from {
        opacity: 1;
    }
    to {
        opacity: 0.2;
    }
}

/* A group of steps opening: it unrolls on the glide, and its first steps drop in one after another. */
:root[data-motion="fluid"] :is(.timeline, .activity-thought, .step-body).unrolling {
    animation: unroll var(--t-glide) var(--ease-glide);
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(-n + 10) {
    animation: fluid-drop var(--t-glide) var(--ease-glide) backwards;
    animation-delay: calc(30ms + var(--fluid-i, 0) * var(--stagger));
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(2) {
    --fluid-i: 1;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(3) {
    --fluid-i: 2;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(4) {
    --fluid-i: 3;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(5) {
    --fluid-i: 4;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(6) {
    --fluid-i: 5;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(7) {
    --fluid-i: 6;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(8) {
    --fluid-i: 7;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(9) {
    --fluid-i: 8;
}

:root[data-motion="fluid"] .timeline.unrolling > :nth-child(10) {
    --fluid-i: 9;
}

/* Chevrons and the sliding tabs' thumb turn and slide on the spring. */
:root[data-motion="fluid"] :is(.chev, .agents-chevron) {
    transition: transform var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] .slide-x {
    transition:
        transform var(--t-spring) var(--ease-spring),
        width var(--t-glide) var(--ease-glide);
}

/* Pressed, a control sinks at once; let go, it springs back. */
:root[data-motion="fluid"] :is(.button, .icon-button) {
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] :is(.stop-button, .send-button) {
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out),
        transform var(--t-spring) var(--ease-spring);
}

:root[data-motion="fluid"] :is(.button, .icon-button):active {
    transition-duration: var(--t-hover), var(--t-hover), var(--t-hover), 70ms;
}

:root[data-motion="fluid"] :is(.stop-button, .send-button):active {
    transition-duration: var(--t-hover), var(--t-hover), 70ms;
}

/* Send lights up: its arrow pops in on the spring. */
:root[data-motion="fluid"] .send-button.ready .icon {
    animation: fluid-arrow var(--t-spring) var(--ease-spring);
}

@keyframes fluid-arrow {
    from {
        transform: translateY(5px) scale(0.6);
        opacity: 0.4;
    }
}

/* The message box: a soft ring of the accent grows around it while it has the focus. */
:root[data-motion="fluid"] .composer {
    transition:
        border-color var(--t-border) var(--ease-glide),
        box-shadow var(--t-border) var(--ease-glide);
}

:root[data-motion="fluid"] .composer:focus-within {
    box-shadow:
        var(--shadow),
        0 0 0 4px color-mix(in srgb, var(--accent) 9%, transparent);
}

/* Panels beside the conversation, and screens pushed over it on phones: in on the spring or the glide. */
:root[data-motion="fluid"] .layout > .people.window {
    animation:
        fluid-fade var(--t-fade) var(--ease-glide),
        people-in var(--t-spring) var(--ease-spring) backwards;
}

:root[data-motion="fluid"] .layout > .people.window.leaving {
    animation: people-out var(--t-exit) var(--ease-exit) forwards;
}

@media (max-width: 959px) {
    :root[data-motion="fluid"] .pane[data-route="forward"] > .scroller {
        animation: route-forward var(--t-glide) var(--ease-glide);
    }
    :root[data-motion="fluid"] .pane[data-route="back"] > .scroller,
    :root[data-motion="fluid"] .pane[data-route="back"] > .home-list {
        animation: route-back var(--t-glide) var(--ease-glide);
    }
}

@media (max-width: 1099px) {
    :root[data-motion="fluid"] .layout > :is(.files-tile, .browser, .ext-panel).window {
        animation: push-in var(--t-glide) var(--ease-glide);
    }
    :root[data-motion="fluid"] .layout > :is(.files-tile, .browser, .ext-panel).window.leaving {
        animation: push-out 220ms var(--ease-exit) forwards;
    }
}

/*
 * Layout changes morph (theme.js, `morph`): folding the sidebar, Width, and tiling. The windows slide and resize as
 * one; what they hold keeps its size, held to its window's top left (the sidebar) or top middle (the conversation), so
 * no text stretches, and fades through: the old out quickly, then the new in. Notices keep their place above.
 */
:root.layout-vt .layout > .sidebar {
    transition: none;
    view-transition-name: fluid-sidebar;
}

:root.layout-vt .layout > .pane {
    view-transition-name: fluid-pane;
}

:root.layout-vt .notices {
    view-transition-name: fluid-notices;
}

:root.layout-vt::view-transition-group(*) {
    animation-duration: var(--t-glide);
    animation-timing-function: var(--ease-glide);
}

/* Each window keeps its ground while what it holds fades through. */
:root.layout-vt::view-transition-group(fluid-sidebar) {
    overflow: clip;
    background: var(--panel);
}

:root.layout-vt::view-transition-group(fluid-pane) {
    overflow: clip;
    background: var(--bg);
}

:root.layout-vt[data-tiling="on"]::view-transition-group(fluid-sidebar),
:root.layout-vt[data-tiling="on"]::view-transition-group(fluid-pane) {
    border-radius: var(--r-window);
}

:root.layout-vt::view-transition-old(fluid-sidebar),
:root.layout-vt::view-transition-new(fluid-sidebar) {
    height: 100%;
    object-fit: none;
    object-position: 0 0;
}

:root.layout-vt::view-transition-old(fluid-pane),
:root.layout-vt::view-transition-new(fluid-pane) {
    height: 100%;
    object-fit: none;
    object-position: 50% 0;
}

:root.layout-vt::view-transition-old(*),
:root.layout-vt::view-transition-new(*) {
    animation-duration: var(--t-fade);
    animation-timing-function: var(--ease-glide);
}

:root.layout-vt::view-transition-old(fluid-sidebar),
:root.layout-vt::view-transition-old(fluid-pane) {
    animation: fluid-fade-out 110ms var(--ease-exit) both;
}

:root.layout-vt::view-transition-new(fluid-sidebar),
:root.layout-vt::view-transition-new(fluid-pane) {
    animation: fluid-fade var(--t-glide) var(--ease-glide) 80ms both;
}

/* A page Pi showed in its reply: the card is a code block (`.code.rich`) between the words around it. */
.inline-row {
    min-width: 0;
}

.inline-row > .code {
    margin: 0;
}

/* The artifact's name as it was written, with its version; its buttons never break over two lines. */
.inline-artifact .code-lang {
    text-transform: none;
}

.inline-artifact .rich-run,
.inline-artifact .rich-tabs button,
.inline-artifact .code-head .copy {
    white-space: nowrap;
}

/* On a phone the bar has two lines: the name, then the buttons. */
@media (max-width: 699px) {
    .inline-artifact .code-head {
        flex-wrap: wrap;
        height: auto;
        row-gap: 2px;
        padding-block: 4px;
    }

    .inline-artifact .code-lang {
        flex: 1 0 100%;
    }

    .inline-artifact .rich-tabs {
        margin-left: 0;
    }
}
