/*
 * Pi Pocket's theme, after Omarchy. 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, square tiles, 2px window borders, no shadows or blur, JetBrains Mono
 * everywhere, and Hyprland's animation curves and timings for motion.
 */
/*
 * 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
 */

/* ─── 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;
}

: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;
    --o-active-a: #7aa2f7;
    --o-active-b: #7aa2f7;
    --o-active: linear-gradient(#7aa2f7, #7aa2f7);
    --o-inactive: rgba(89, 89, 89, 0.67);

    /* Surfaces, after omarchy-shell's control states: the foreground laid over the background. */
    --desk: var(--o-bg-darker);
    --bg: var(--o-bg);
    --panel: var(--o-bg);
    --card: color-mix(in srgb, var(--o-fg) 4%, var(--o-bg));
    --card-2: color-mix(in srgb, var(--o-fg) 8%, var(--o-bg));
    --raised: color-mix(in srgb, var(--o-fg) 11%, var(--o-bg));
    --hover: color-mix(in srgb, var(--o-fg) 8%, transparent);
    --pressed: color-mix(in srgb, var(--o-fg) 18%, transparent);
    --line: color-mix(in srgb, var(--o-fg) 13%, var(--o-bg));
    --line-strong: color-mix(in srgb, var(--o-fg) 26%, var(--o-bg));
    --edge: color-mix(in srgb, var(--o-fg) 25%, transparent);
    --text: var(--o-fg-bright);
    --body: var(--o-fg);
    --muted: color-mix(in oklab, var(--o-fg) 62%, var(--o-bg));
    --faint: color-mix(in oklab, var(--o-fg) 38%, var(--o-bg));
    --accent: var(--o-accent);
    --accent-ink: var(--o-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(--o-accent) 13%, transparent);
    --accent-line: color-mix(in srgb, var(--o-accent) 55%, transparent);
    /* The second color of loaders: the active border's last stop, or magenta when the border is one color. */
    --spark: var(--o-magenta);
    --brand: var(--o-orange);
    --ok: var(--o-green);
    --warn: var(--o-yellow);
    --warn-soft: color-mix(in srgb, var(--o-yellow) 9%, transparent);
    --warn-line: color-mix(in srgb, var(--o-yellow) 60%, transparent);
    --err: var(--o-red);
    --err-soft: color-mix(in srgb, var(--o-red) 9%, transparent);
    --err-line: color-mix(in srgb, var(--o-red) 55%, 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);
    --active: var(--o-active);
    --scrim: color-mix(in srgb, var(--o-bg-darker) 62%, transparent);
    --radius: 0;
    /* Hyprland's look as Omarchy sets it: gaps_out 10, gaps_in 5, border_size 2. */
    --gap-out: 10px;
    --gap-in: 5px;
    --border: 2px;

    /* 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;

    --mono:
        "Pocket Mono", "JetBrains Mono", "JetBrainsMono Nerd Font", ui-monospace, "SF Mono", Menlo,
        Consolas, monospace;
    color-scheme: dark;
}

/* 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;
    --o-inactive: rgba(89, 89, 89, 0.4);
    --scrim: color-mix(in srgb, var(--o-bg-darker) 55%, transparent);
    --line: color-mix(in srgb, var(--o-fg) 15%, var(--o-bg));
    --muted: color-mix(in oklab, var(--o-fg) 78%, var(--o-bg));
    --faint: color-mix(in oklab, var(--o-fg) 58%, var(--o-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(--o-accent) 76%, var(--o-fg));
    /* 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;
}

html,
body {
    margin: 0;
    height: 100%;
    background: var(--desk);
    color: var(--body);
    font: var(--text-size, 14px) / 1.6 var(--mono);
    font-variant-ligatures: none;
    -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. */
@media (pointer: coarse) {
    input,
    textarea,
    select {
        font-size: 16px;
    }
}

input,
textarea,
select {
    background: var(--card);
    border: 1px solid var(--line);
    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);
}

input:hover,
textarea:hover,
select:hover {
    border-color: var(--line-strong);
}

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

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

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

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

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

/* Thin square scrollbars, like a terminal's. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
}

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

::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border: 2px solid transparent;
    background-clip: padding-box;
}

::-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: 1.45em;
    height: 1.45em;
    padding: 0 0.3em;
    font: 600 0.68rem/1 var(--mono);
    color: var(--muted);
    background: var(--card);
    border: 1px solid var(--line-strong);
    border-bottom-width: 2px;
    vertical-align: middle;
}

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

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

.small {
    font-size: 0.8rem;
}

.pad {
    padding: 1rem;
}

.grow {
    flex: 1;
}

.meter {
    display: inline-flex;
    height: 4px;
    background: var(--line);
}

.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);
    }
}

/* 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 {
    width: 70%;
}

/* 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;
}

.boot-bar span {
    display: block;
    width: 0;
    height: 100%;
    background: var(--body);
    animation: boot-fill 15s cubic-bezier(0.12, 0.6, 0.3, 1) forwards;
}

@keyframes boot-fill {
    to {
        width: 70%;
    }
}

.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);
}

/*
 * Three lit cells, still: a session where Pi works, in the session list. While Pi works, only the conversation
 * itself moves (thinking, the streaming cursor, a tool's spinner); everywhere else a working session is marked, not
 * animated, so several runs at once do not fill the screen with motion.
 */
.mini-sweep {
    display: inline-flex;
    gap: 2px;
}

.mini-sweep i {
    width: 4px;
    height: 4px;
    background: var(--lit);
}

.mini-sweep i:nth-child(1) {
    --lit: var(--accent);
}
.mini-sweep i:nth-child(2) {
    --lit: color-mix(in oklab, var(--accent) 50%, var(--spark));
}
.mini-sweep i:nth-child(3) {
    --lit: var(--spark);
}

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

.icon {
    flex: none;
}

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

.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: gaps over
 * the desktop (or its wallpaper), a 2px inactive border, and the active border on the one in focus. */
.window {
    position: relative;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
}

.window::after {
    content: "";
    position: absolute;
    inset: calc(-1 * var(--border));
    border: var(--border) solid transparent;
    border-image: var(--active) 1;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-border) var(--ease-out);
    z-index: 6;
    display: none;
}

/* The sidebar: the rail and the session list beside it, cut off rather than squeezed while it folds and unfolds. */
.sidebar {
    display: none;
    width: var(--sidebar-w, 324px);
    flex: none;
    flex-direction: row;
    border-right: 1px solid var(--line);
    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 {
    max-width: 640px;
    width: 100%;
    margin: 0 auto;
    flex: 1;
    min-height: 0;
    display: flex;
}

.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: 57px;
    }
    :root[data-tiling="on"][data-rail="on"] .sidebar {
        width: calc(56px + 2 * var(--border));
    }

    :root[data-tiling="on"] .layout {
        padding: var(--gap-out);
        gap: calc(var(--gap-in) * 2);
        background: var(--desk) var(--wallpaper, none) center / cover no-repeat;
    }
    :root[data-tiling="on"] .window {
        border: var(--border) solid var(--o-inactive);
        height: auto;
        animation: popin var(--t-in) var(--ease-out) backwards;
    }
    :root[data-tiling="on"] .pane {
        animation-delay: 60ms;
    }
    :root[data-tiling="on"] .window::after {
        display: block;
    }
    :root[data-tiling="on"][data-focus="sidebar"] .sidebar::after,
    :root[data-tiling="on"][data-focus="browser"] .browser::after,
    :root[data-tiling="on"][data-focus="files-tile"] .files-tile::after,
    :root[data-tiling="on"][data-focus="people"] .people::after,
    :root[data-tiling="on"]:not([data-focus="sidebar"]):not([data-focus="browser"]):not(
            [data-focus="files-tile"]
        ):not([data-focus="people"]):not([data-focus="peeks"])
        .pane::after {
        opacity: 1;
    }
}

/* Drag the sidebar's edge to resize it; double-click puts it back. */
.resize-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    right: -7px;
    width: 12px;
    cursor: col-resize;
    z-index: 7;
    touch-action: none;
}

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

.resize-handle:hover::before,
:root.resizing .resize-handle::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, who is here, and the menu. */
.topbar {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 52px;
    padding: calc(env(safe-area-inset-top) + 4px) 8px 4px 16px;
    border-bottom: 1px solid var(--line);
    background: var(--bg);
}

/*
 * The top bar keeps only the buttons with something to say (a page open, artifacts made, people here, peek tiles on,
 * Files open): the menu's tiles open the rest.
 */
.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;
    }
}

/* 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: 0;
        padding-left: 4px;
    }
    /* Its way back says what the button would. */
    .topbar .quiet-narrow {
        display: none;
    }
    .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-back {
        z-index: 1;
        color: var(--text);
    }
    .topbar-back .badge {
        top: 2px;
        right: 0;
    }
}

/* 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: 0;
    display: flex;
    flex-direction: column;
    padding: 2px 6px;
    margin-left: -6px;
    transition: background-color var(--t-hover) var(--ease-out);
}

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

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

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

.title-main {
    font-weight: 700;
    font-size: 0.95rem;
    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: 7px;
    min-width: 0;
    min-height: 1lh;
    font-size: 0.72rem;
    color: var(--muted);
    white-space: nowrap;
}

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

.title-sub > .title-folder {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.title-sub > .title-branch {
    flex: 0 1 auto;
    min-width: 2ch;
    padding: 0 4px;
    margin: 0 -4px;
    font: inherit;
    color: inherit;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

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

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

/*
 * A thumb's height on a touch screen, with its look kept: the room around it takes the tap. The top bar is a little
 * taller there, and the line under the title too, so that room stays in the top bar; it reaches the bottom of the
 * title's line above the branch (its descenders), and the rest of the title opens the menu.
 */
@media (pointer: coarse) {
    .topbar {
        min-height: 56px;
    }
    .title {
        padding-block: 0;
    }
    .title-sub {
        min-height: 24px;
    }
    .title-sub > button.title-branch {
        padding-block: 10px;
        margin-block: -10px;
    }
}

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

.title-sub .faint {
    color: var(--faint);
}

/* 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 10px;
    border: 1px solid var(--line);
    font-size: 0.76rem;
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.changes-button:hover {
    border-color: var(--line-strong);
    background: var(--hover);
}

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

.changes-button .removed {
    color: var(--err);
}

.changes-button .changes-files {
    color: var(--muted);
}

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

/* A narrow phone: the counts of lines alone. */
@media (max-width: 380px) {
    .changes-button .changes-files {
        display: none;
    }
}

.icon-button {
    width: 40px;
    height: 40px;
    display: inline-grid;
    place-items: center;
    border-radius: var(--radius);
    color: var(--body);
    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);
}

.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;
    position: relative;
}

/* A column of turns: a person's message, what Pi did, Pi's reply, an approval, the live line. */
.transcript {
    max-width: 744px;
    margin: 0 auto;
    padding: 28px 20px 32px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    animation: rise-in 0.36s var(--ease-out);
}

/* Turns stand apart: 22px before each message or report (the gap's 14px and 8px more), 14px between the parts of one. */
.transcript > :is(.user-row, .report, .report-group):not(:first-child) {
    margin-top: 8px;
}

@media (max-width: 699px) {
    .transcript {
        padding: 20px 16px;
    }
}

/* 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: 0.85rem;
    display: inline-flex;
    gap: 0.25rem;
    align-items: center;
}

/* 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(--line);
    background: var(--card);
    color: var(--accent);
    font-size: 0.8rem;
    text-align: left;
}

.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 filled row with a prompt mark, 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: grid;
    grid-template-columns: 14px minmax(0, 1fr);
    gap: 4px 10px;
    padding: 10px 14px 12px;
    background: var(--card);
    color: var(--text);
    transition: background-color var(--t-hover) var(--ease-out);
}

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

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

.prompt-mark {
    grid-row: span 2;
    font-weight: 700;
    line-height: 1.55;
}

.user-row > .prompt:not(:has(> .prompt-head)) > .prompt-mark {
    grid-row: auto;
}

.prompt-head,
.prompt-body {
    grid-column: 2;
    min-width: 0;
}

.prompt-head {
    display: flex;
    flex-wrap: wrap;
    gap: 0 8px;
    font-size: 0.74rem;
    color: var(--muted);
}

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

.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(--line);
    background: var(--bg);
}

.fenced-label {
    padding: 0.2rem 0.5rem;
    border-bottom: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.75rem;
}

.fenced-data pre {
    margin: 0;
    padding: 0.4rem 0.5rem;
    max-height: 14rem;
    overflow: auto;
    font-size: 0.78rem;
    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, a little apart. */
.reply {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    color: var(--body);
    line-height: 1.65;
}

.reply > .md {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

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

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

.reply > .md li + li {
    margin-top: 4px;
}

.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;
}

.md ul,
.md ol {
    padding-left: 1.4rem;
}

.md h1,
.md h2,
.md h3 {
    font-size: 1rem;
    color: var(--text);
    margin: 0.9rem 0 0.4rem;
}

.md code {
    font-family: var(--mono);
    font-size: 0.92em;
    background: var(--card-2);
    color: var(--text);
    border-radius: var(--radius);
    padding: 1px 5px;
}

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

/* A reply's own tables; a diff it shows draws its table itself. */
.md table:not(.dv-table) {
    border-collapse: collapse;
    display: block;
    overflow-x: auto;
}

.md table:not(.dv-table) :is(td, th) {
    border: 1px solid var(--line);
    padding: 0.25rem 0.5rem;
    /* 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 blockquote {
    margin: 0.5rem 0;
    padding-left: 0.8rem;
    border-left: 2px solid var(--line-strong);
    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(--line);
    background: var(--code-bg);
}

.code-head {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 30px;
    padding: 0 6px 0 12px;
    border-bottom: 1px solid var(--line);
    font-size: 0.74rem;
    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: 22px;
    margin-left: auto;
    padding: 0 8px;
    font-size: 0.72rem;
    color: var(--body);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.code-head .copy:hover {
    color: var(--accent);
    background: var(--hover);
}

.md pre {
    margin: 0;
    padding: 10px 12px;
    overflow-x: auto;
    background: var(--code-bg);
    border-radius: var(--radius);
    font-size: 0.8rem;
    line-height: 1.55;
}

.code pre {
    background: none;
}

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

.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 var(--t-in) 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: 28px;
    line-height: 1.6;
}

.reaction {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 24px;
    padding: 0 8px;
    border: 1px solid var(--line);
    font-size: 0.74rem;
    color: var(--body);
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.reaction:hover {
    border-color: var(--line-strong);
}

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

.answer-actions > button.answer-tool,
.reaction.add {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 8px;
    border: 0;
    font-size: 0.74rem;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out),
        opacity var(--t-fade) var(--ease-out);
}

.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;
}

.reaction-picker {
    position: absolute;
    bottom: calc(100% + 4px);
    left: 0;
    z-index: 5;
    display: flex;
    gap: 0.1rem;
    background: var(--panel);
    border: 1px solid var(--line-strong);
    padding: 0.2rem;
}

.reaction-picker button {
    font-size: 1.1rem;
    padding: 0.15rem 0.3rem;
}

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

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

/* What Pi did between its words: one line ("Read 2 files, ran 1 command · 18s") that opens into a timeline. */
.activity {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

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

/* One between rows takes no room: the gap before it is taken back. */
.entry-mark {
    margin-top: -14px;
}

.activity-head {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 30px;
    padding: 2px 8px 2px 2px;
    text-align: left;
    font-size: 0.8rem;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

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

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

.activity-time {
    flex: none;
    font-size: 0.74rem;
    font-variant-numeric: tabular-nums;
}

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

/* The timeline: a line per call, each with its node on a thin rule. */
.timeline {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin: 4px 0 0 8px;
    border-left: 1px solid var(--line);
    animation: unroll var(--t-in) var(--ease-out);
}

.step {
    position: relative;
    min-width: 0;
    padding-left: 14px;
}

.step-node {
    position: absolute;
    left: -3px;
    top: 13px;
    width: 5px;
    height: 5px;
    background: color-mix(in srgb, var(--ok) 40%, var(--bg));
    transition: background-color var(--t-border) var(--ease-out);
}

.step[data-status="running"] > .step-node {
    background: var(--accent);
}

.step[data-status="approval"] > .step-node {
    background: var(--warn);
}

.step[data-status="error"] > .step-node {
    background: var(--err);
}

.step:is([data-status="denied"], [data-status="stopped"]) > .step-node {
    background: var(--line-strong);
}

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

.step-head {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 30px;
    padding: 3px 8px;
    text-align: left;
    transition: background-color var(--t-hover) var(--ease-out);
}

.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);
    }
}

.step-glyph {
    flex: none;
    width: 14px;
    text-align: center;
    font-size: 0.78rem;
    color: var(--muted);
}

.step-glyph.thought {
    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-glyph.thought {
    color: color-mix(in oklab, var(--spark) 60%, var(--o-fg));
}

.step-glyph.agent {
    color: var(--accent);
}

.step-label {
    flex: none;
    max-width: 45%;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

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

.step-meta {
    flex: none;
    max-width: 40%;
    font-size: 0.74rem;
    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: 30px;
    padding: 0 8px;
    font-size: 0.74rem;
    color: var(--accent);
    transition: background-color var(--t-hover) var(--ease-out);
}

.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 8px 6px 30px;
    font-size: 0.72rem;
    color: var(--muted);
}

/* Under a line, past its glyph: what the call made, and once tapped, its input and output. */
.step-extras,
.step-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    margin: 2px 8px 8px 30px;
}

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

.step-body {
    animation: unroll var(--t-in) var(--ease-out);
}

.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: 8px 10px;
    border: 1px solid var(--line);
    background: var(--code-bg);
    font-size: 0.76rem;
    line-height: 1.5;
    color: var(--muted);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

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

.step-body .dv-block {
    font-size: 0.76rem;
    line-height: 1.6;
}

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

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

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

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

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

/* 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;
    text-align: left;
    font-size: 0.76rem;
    color: var(--accent);
    overflow-wrap: anywhere;
    transition: background-color var(--t-hover) var(--ease-out);
}

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

.report {
    border: 1px solid var(--line);
    border-left: 2px solid var(--accent);
    background: var(--card);
    border-radius: var(--radius);
    padding: 0.5rem 0.75rem;
}

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

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

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

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

.report-why {
    color: var(--err);
    font-size: 0.85rem;
    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: 10px;
    padding: 12px 14px;
    border: 1px solid var(--warn-line);
    border-left: 2px solid var(--warn);
    background: var(--warn-soft);
    animation: popin var(--t-in) var(--ease-out);
}

.approval-head {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--warn);
}

.approval-reason {
    font-size: 0.8rem;
    color: var(--body);
}

.approval pre.cmd {
    font-size: 0.8rem;
}

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

.approval-actions .button {
    height: 32px;
    padding: 0 14px;
    font-size: 0.84rem;
}

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

/* 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: 10px;
    min-width: 0;
    padding: 2px 2px 0;
    font-size: 0.78rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    animation: fade var(--t-fade) var(--ease-almost);
}

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

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

.live-wait {
    flex: none;
    width: 8px;
    height: 8px;
    background: var(--warn);
}

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

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

.error-box {
    border: 1px solid var(--err-line);
    border-left: 2px solid var(--err);
    background: var(--err-soft);
    color: var(--err);
    border-radius: var(--radius);
    padding: 0.5rem 0.7rem;
    font-size: 0.87rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

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

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

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

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

.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.3;
    }
}

.jump {
    position: sticky;
    bottom: 0.8rem;
    left: 100%;
    margin-right: 0.8rem;
    width: 40px;
    height: 40px;
    border-radius: var(--radius);
    background: var(--bg);
    border: 2px solid var(--line-strong);
    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);
}

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

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

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

.composer-wrap {
    padding: 6px 20px calc(env(safe-area-inset-bottom) + 10px);
    max-width: 784px;
    width: 100%;
    margin: 0 auto;
}

@media (max-width: 699px) {
    .composer-wrap {
        padding-inline: 12px;
    }
}

/*
 * 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: 0.74rem;
}

/* 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 {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 32px;
    padding: 0 4px 0 10px;
    background: var(--card);
    border-left: 2px solid var(--accent);
    font-size: 0.82rem;
}

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

.queued-text {
    flex: 1;
    min-width: 0;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

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

/* Slash commands: suggestions while typing a name, then a hint for the one that will run. */
.commands {
    display: flex;
    flex-direction: column;
    margin-bottom: 0.35rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    max-height: 40vh;
    overflow-y: auto;
}

.commands {
    animation: rise-in 0.3s var(--ease-out);
}

.command {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    width: 100%;
    text-align: left;
    padding: 0.45rem 0.6rem;
    font-size: 0.85rem;
    border-left: 2px solid transparent;
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

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

.command.on {
    background: var(--hover);
    border-left-color: var(--accent);
}

.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: 800;
}

.file-note {
    font-size: 0.78rem;
    color: var(--muted);
    padding: 0.4rem 0.6rem;
}

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

.command-hint {
    font-size: 0.78rem;
    padding: 0 0.4rem 0.3rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The message box: a quiet card whose border takes the accent while it has the focus. */
.composer {
    position: relative;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    transition: border-color var(--t-border) var(--ease-out);
}

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

.composer .files {
    margin: 0;
    padding: 8px 12px 0;
}

/* One line to start with, growing with the text (`fitBox`). */
.composer textarea {
    display: block;
    border: 0;
    outline: none;
    background: none;
    color: var(--text);
    resize: none;
    padding: 10px 12px 2px;
    max-height: 40vh;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Touch screens keep 16px, below which iOS zooms into the field. */
@media (pointer: coarse) {
    .composer textarea {
        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: 4px;
    padding: 4px 6px 6px;
}

.composer-row .attach-button {
    width: 32px;
    height: 32px;
    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: 28px;
    padding: 0 9px;
    font-size: 0.76rem;
    color: var(--body);
    white-space: nowrap;
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.model-chip:hover {
    background: var(--hover);
    color: var(--text);
}

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

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

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

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

/* Below about 360px the model's short name alone; on a phone, while Steer and Queue take room, too. */
@media (max-width: 359px) {
    .model-chip .model-level {
        display: none;
    }
}

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

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

.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);
}

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);
}

.composer-row .plan-chip {
    flex: none;
    height: 26px;
    padding: 0 9px;
    font-size: 0.74rem;
    background: none;
    color: var(--muted);
}

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

/* While Pi works: whether a message steers the run or waits for its end. */
.mode-switch {
    flex: none;
    display: flex;
    height: 26px;
    border: 1px solid var(--line);
}

.mode-switch button {
    padding: 0 9px;
    font-size: 0.74rem;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

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

.mode-switch button.on {
    color: var(--accent);
    background: var(--accent-soft);
}

.stop-button,
.send-button {
    flex: none;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    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);
}

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

.stop-button {
    background: var(--card-2);
    border: 1px solid var(--line-strong);
}

.stop-button:hover {
    border-color: var(--err);
}

.stop-square {
    width: 12px;
    height: 12px;
    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;
}

.send-button.ready:hover {
    background: color-mix(in oklab, var(--accent-fill) 85%, var(--o-fg-bright));
}

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

.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;
    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(--radius);
    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"]) .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);
}

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

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

.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. */
.status-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px 12px;
    padding-top: 6px;
    font: 0.72rem var(--mono);
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

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

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

.status-line .guard {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--ok);
    font: inherit;
}

.status-line .guard.off {
    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;
}

/* 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: 0.8rem;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--line);
}

.extension:last-child {
    border-bottom: 0;
}

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

.extension-title {
    font-weight: 600;
}

.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: 42px;
    height: 24px;
    flex: none;
    border-radius: var(--radius);
    background: var(--card-2);
    border: 1px solid var(--line-strong);
    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(--radius);
    background: var(--muted);
    transition:
        transform var(--t-in) var(--ease-out),
        background-color var(--t-in) var(--ease-out);
}

.switch.on {
    background: var(--accent-soft);
    border-color: var(--accent);
}

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

.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: 4px;
    min-height: 0;
    padding: calc(env(safe-area-inset-top) + 10px) 0 calc(env(safe-area-inset-bottom) + 10px);
    background: var(--o-bg-dark);
    border-right: 1px solid var(--line);
    /* 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: 44px;
    height: 44px;
    display: grid;
    place-items: center;
}

.rail-brand {
    font:
        1.6rem/1 Georgia,
        serif;
    color: var(--brand);
    transition: transform var(--t-in) var(--ease-out);
}

.rail-brand:hover {
    transform: rotate(-8deg) scale(1.08);
}

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

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

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

.rail-fill {
    flex: 1;
}

/* The sessions, always on while the list shows: a lit tile with the accent's bar at the rail's edge. */
.rail-button.on {
    color: var(--text);
    background: var(--hover);
}

.rail-button.on::before {
    content: "";
    position: absolute;
    left: -5.5px;
    top: 9px;
    bottom: 9px;
    width: 2px;
    background: var(--accent);
}

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

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

.rail-agents.open {
    color: var(--text);
}

/* How many: sessions where Pi works, or subagents that work or wait. */
.rail-count {
    position: absolute;
    top: 6px;
    right: 6px;
    min-width: 13px;
    height: 13px;
    padding: 0 2px;
    display: grid;
    place-items: center;
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-size: 0.56rem;
    font-weight: 700;
    line-height: 1;
    animation: popin var(--t-in) var(--ease-out);
}

/* A subagent failed, or waits for an approval. */
.rail-trouble {
    position: absolute;
    right: 8px;
    bottom: 8px;
    width: 6px;
    height: 6px;
    background: var(--err);
}

/* 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: 0.4rem 0;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    scrollbar-width: none;
}

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

.rail-items .slide-y {
    left: 0;
    width: 2px;
}

.ws {
    position: relative;
    flex: none;
    width: 40px;
    height: 34px;
    display: grid;
    place-items: center;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--muted);
    border: 1px solid transparent;
    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),
        border-color var(--t-hover) var(--ease-out);
}

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

.ws.active {
    color: var(--accent);
    background: var(--hover);
    border-color: var(--edge);
}

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

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

.ws .unread-dot {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 5px;
    height: 5px;
}

/* ─── 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) + 12px) 10px calc(env(safe-area-inset-bottom) + 8px);
}

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

.sessions-name {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text);
}

.sessions-count {
    margin-right: auto;
    font-size: 0.72rem;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
}

.new-button {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 28px;
    padding: 0 9px 0 7px;
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 700;
    font-size: 0.76rem;
    transition: background-color var(--t-hover) var(--ease-out);
}

.new-button:hover {
    background: color-mix(in oklab, var(--accent-fill) 85%, var(--o-fg-bright));
}

.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: 0.4rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0 0.45rem 0 0.6rem;
    color: var(--muted);
    margin-bottom: 0.5rem;
    transition:
        border-color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

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

.search:focus-within {
    border-color: var(--accent);
    background: var(--bg);
    color: var(--accent);
}

.search input {
    border: 0;
    background: none;
    padding: 0.55rem 0;
    min-width: 0;
}

.search kbd {
    cursor: pointer;
    flex: none;
}

.sessions .search {
    flex: none;
    margin: 10px 0 0;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding: 0 6px 0 9px;
    background: var(--card);
    border: 1px solid transparent;
    color: var(--muted);
    transition:
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

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

.sessions .search.filled {
    border-color: var(--accent);
    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: 0.82rem;
    color: var(--text);
}

.sessions .search-keys {
    font-size: 0.64rem;
    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);
}

.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: tabs with a bar that slides to the one chosen. */
.session-tabs {
    position: relative;
    flex: none;
    margin-top: 10px;
    display: flex;
    gap: 16px;
    padding: 0 4px;
    border-bottom: 1px solid var(--line);
}

.session-tabs button {
    position: relative;
    padding: 0 0 6px;
    font-size: 0.72rem;
    color: var(--muted);
    transition: color var(--t-hover) var(--ease-out);
}

.session-tabs button:hover,
.session-tabs button.on {
    color: var(--text);
}

.slide-x {
    position: absolute;
    left: 0;
    bottom: -1px;
    height: 2px;
    background: var(--active);
    transition:
        transform var(--t-in) var(--ease-out),
        width var(--t-in) var(--ease-out);
}

.session-tabs .slide-x {
    background: var(--accent);
}

.session-items {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    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: 12px 8px 4px;
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--faint);
    text-align: left;
    transition: color var(--t-hover) var(--ease-out);
}

.group-head:hover {
    color: var(--muted);
}

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

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

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

/* 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(--body);
}

.group-count {
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

.group-head .icon {
    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: 1px;
}

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

.session-row {
    position: relative;
    animation: rise-in 0.38s var(--ease-out) backwards;
    animation-delay: calc(min(var(--i, 0), 14) * 18ms);
}

/* 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 10px;
    width: 100%;
    height: 34px;
    padding: 0 10px;
    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);
}

.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 an accent title. */
.session-row.active .session {
    background: var(--accent-soft);
}

.session-row.active .session-title {
    color: var(--accent);
}

/* 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;
}

.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;
    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: 0.84rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--t-hover) var(--ease-out);
}

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

/* Marked unread (this browser): the title reads bold, like the dot beside the time says. */
.session-row.marked-unread .session-title {
    font-weight: 700;
}

.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-size: 0.66rem;
    color: var(--faint);
    transition: opacity var(--t-hover) var(--ease-out);
}

/* Subagents at work there (or failed ones, in red): ⑂ and how many. */
.session-fork {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-weight: 600;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

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

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

.session-side .avatar {
    font-size: 0.52rem;
}

.session-side .mini-sweep i {
    width: 3px;
    height: 3px;
}

.session-side .unread-dot {
    width: 6px;
    height: 6px;
}

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

/* A session's state where a peek tile shows it: a square, three cells while Pi works, "!" while a call waits. */
.session-state {
    display: grid;
    place-items: center;
    width: 12px;
    height: 12px;
    align-self: start;
    margin-top: 0.3rem;
}

.state-idle {
    width: 6px;
    height: 6px;
    border: 1px solid var(--faint);
    transition:
        background-color var(--t-border) var(--ease-out),
        border-color var(--t-border) var(--ease-out);
}

.state-warn {
    display: grid;
    place-items: center;
    width: 12px;
    height: 12px;
    background: var(--warn);
    color: var(--accent-ink);
    font-size: 0.6rem;
    font-weight: 800;
    line-height: 1;
    animation: attention 1.6s var(--ease-in-out) infinite;
}

@keyframes attention {
    50% {
        box-shadow: 0 0 0 3px var(--warn-soft);
        opacity: 0.75;
    }
}

/* 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(--bg);
    border: 1px solid var(--line);
    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);
}

.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;
    }
    /* 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;
    }
    /* 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;
    }
}

/* 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;
}

/* What to do with the selected sessions: docked under the list. */
.select-bar {
    container-type: inline-size;
    flex: none;
    margin-top: 6px;
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    padding: 4px 4px 4px 9px;
    border: 1px solid var(--accent-line);
    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;
    display: grid;
    place-items: center;
    color: var(--body);
    transition:
        background-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.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: 34px;
    padding: 0 10px 0 28px;
}

.session-placeholder span {
    height: 0.6rem;
    width: var(--width);
    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 ─── */

.splash {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    align-items: center;
    justify-content: safe center;
    flex-direction: column;
    gap: 2.2rem;
    padding: 2rem;
}

.fetch {
    display: flex;
    align-items: flex-start;
    gap: 2.6rem;
}

.fetch-logo {
    margin: 0;
    font: 700 1.05rem/1.1 var(--mono);
    background: linear-gradient(170deg, var(--accent), var(--spark));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    user-select: none;
    animation: popin 0.6s var(--ease-out) backwards;
}

.fetch-info {
    display: flex;
    flex-direction: column;
    font-size: 0.86rem;
    min-width: 18rem;
}

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

.fetch-title {
    font-weight: 700;
    color: var(--text);
}

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

.fetch-rule {
    color: var(--faint);
    letter-spacing: -0.05em;
    overflow: hidden;
    white-space: nowrap;
}

.fetch-row {
    display: flex;
    gap: 0.5rem;
    margin: 0;
    white-space: nowrap;
}

.fetch-row dt {
    color: var(--accent);
    font-weight: 700;
    min-width: 6.5rem;
}

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

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

.fetch-colors {
    display: flex;
    margin-top: 0.8rem;
}

.fetch-colors span {
    width: 1.6rem;
    height: 0.9rem;
    transition: transform var(--t-in) var(--ease-out);
}

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

.splash-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
    animation: rise-in 0.5s var(--ease-out) 0.45s backwards;
}

.splash-actions .button {
    gap: 0.6rem;
}

.splash-recent {
    display: flex;
    flex-direction: column;
    width: min(34rem, 100%);
    animation: rise-in 0.5s var(--ease-out) 0.55s backwards;
}

.splash-recent .list-item {
    background: transparent;
}

.splash-recent .list-item kbd {
    margin-right: 0.6rem;
}

/* ─── 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. Wide screens: a popup window with the active border, popping in at 87%. */
.sheet {
    background: var(--panel);
    width: 100%;
    max-width: 560px;
    max-height: 86dvh;
    border-radius: var(--radius);
    border: 1px solid var(--line);
    border-top: 2px solid transparent;
    border-image: var(--active) 1;
    border-bottom: 0;
    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: center;
    }
    .sheet {
        border: 2px solid transparent;
        border-image: var(--active) 1;
        animation: popin 0.32s var(--ease-out);
    }
    .sheet.wide {
        max-width: 720px;
    }
    .leaving .sheet {
        animation: popout var(--t-out) linear forwards;
    }
}

/* The drawer: the session list sliding in from the left on narrow screens. */
.drawer-overlay {
    align-items: stretch !important;
    justify-content: flex-start !important;
}

.drawer {
    display: flex;
    width: min(86vw, 340px);
    height: 100dvh;
    background: var(--panel);
    border-right: 2px solid transparent;
    border-image: var(--active) 1;
    animation: drawer-in var(--t-in) var(--ease-out);
}

@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: 1px solid var(--line-strong);
    box-shadow: 0 12px 32px rgb(0 0 0 / 0.35);
    outline: none;
    animation: pop-menu-in var(--t-in) 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-menu-out var(--t-out) linear forwards;
}

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

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

/* 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);
}

.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;
}

/* What new sessions start with, under the thinking levels: the default, and making this one it. */
.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-text {
    min-width: 0;
    color: var(--body);
    overflow-wrap: anywhere;
}

.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: 0.55rem 0.8rem 0.25rem;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
    border-bottom: 1px solid var(--line);
}

/* The branch picker: what is checked out beside its title, and how far each branch is from its remote one. */
.branch-head {
    display: inline-flex;
    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);
}

/* Thinking: one bar of levels, the chosen one outlined. Past the general segmented rules, which come later. */
.segmented.model-levels {
    flex-wrap: nowrap;
    gap: 0;
    padding: 2px;
    border: 1px solid var(--line);
    background: var(--bg);
}

.segmented.model-levels button {
    flex: 1;
    min-width: 0;
    padding: 0.3rem 0.15rem;
    overflow: hidden;
    text-overflow: ellipsis;
    border-color: transparent;
    background: none;
    color: var(--muted);
}

.segmented.model-levels button.on {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--accent);
}

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

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

.sheet-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.6rem 0.5rem 0.4rem 1rem;
    position: relative;
}

.grip {
    position: absolute;
    top: 6px;
    left: 50%;
    width: 36px;
    height: 3px;
    margin-left: -18px;
    border-radius: var(--radius);
    background: var(--line-strong);
}

.sheet-head h2 {
    flex: 1;
    font-size: 0.95rem;
    color: var(--text);
    margin: 0.3rem 0 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sheet-head h2::before {
    content: "▪ ";
    color: var(--accent);
}

.sheet-body {
    overflow-y: auto;
    padding: 0.2rem 1rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
}

/* Menu rows, as omarchy-shell's menu draws them: a quiet card, and on hover a light fill, a border, accent text. */
.list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.7rem;
    border-radius: var(--radius);
    background: var(--card);
    border: 1px solid var(--line);
    color: var(--text);
    text-decoration: none;
    margin-bottom: 0.25rem;
    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);
}

.list-item:hover {
    border-color: var(--edge);
    background: var(--card-2);
}

.list-item:hover > span:first-child {
    color: var(--accent);
}

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

.sheet-body > .list-item,
.sheet-body > .group > .list-item {
    animation: rise-in 0.34s var(--ease-out) backwards;
}

.sheet-body > :nth-child(2) {
    animation-delay: 15ms;
}
.sheet-body > :nth-child(3) {
    animation-delay: 30ms;
}
.sheet-body > :nth-child(4) {
    animation-delay: 45ms;
}
.sheet-body > :nth-child(5) {
    animation-delay: 60ms;
}
.sheet-body > :nth-child(6) {
    animation-delay: 75ms;
}
.sheet-body > :nth-child(7) {
    animation-delay: 90ms;
}
.sheet-body > :nth-child(n + 8) {
    animation-delay: 105ms;
}

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

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

.group-title,
.label {
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
    margin: 0.3rem 0 0.35rem;
}

.field {
    display: flex;
    flex-direction: column;
}

.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;
    border: 1px solid var(--line-strong);
    background: var(--card-2);
    border-radius: var(--radius);
    padding: 0.55rem 0.9rem;
    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);
}

.button:hover {
    border-color: var(--accent);
    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: 700;
}

.button.primary:hover {
    background: color-mix(in oklab, var(--accent-fill) 85%, var(--o-fg-bright));
}

.button kbd {
    background: transparent;
    color: inherit;
    opacity: 0.7;
    border-color: currentColor;
}

.button.ghost {
    background: none;
}

.button.small {
    padding: 0.3rem 0.65rem;
    font-size: 0.82rem;
}

.button.wide {
    width: 100%;
}

.button:disabled {
    opacity: 0.5;
}

.link {
    color: var(--accent);
    font-size: 0.85rem;
}

.segmented {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
}

.segmented button {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.3rem 0.6rem;
    font-size: 0.82rem;
    background: var(--card);
    transition:
        background-color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out),
        color var(--t-hover) var(--ease-out);
}

.segmented button:hover {
    border-color: var(--edge);
}

.segmented button.on {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--accent);
}

.dir-list {
    display: flex;
    flex-direction: column;
    max-height: 42vh;
    overflow-y: auto;
}

/* Above the folders: Show hidden, and New folder. */
.dir-tools {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

.dir-tools .check {
    margin-bottom: 0;
}

/* A new folder's name, in the list where it will show. */
.new-folder {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.4rem 0.35rem 0.7rem;
    margin-bottom: 0.25rem;
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
    color: var(--accent);
}

.new-folder input {
    flex: 1;
    min-width: 0;
    height: 34px;
    padding: 0.3rem 0.5rem;
    font-size: 0.85rem;
}

.new-folder .icon-button {
    width: 32px;
    height: 32px;
    color: var(--muted);
}

/* A typed path that is not there yet, with Create it. */
.folder-missing {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem 0.6rem;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--warn-line);
    background: var(--warn-soft);
    font-size: 0.82rem;
    color: var(--body);
    overflow-wrap: anywhere;
}

.check {
    display: flex;
    gap: 0.4rem;
    align-items: center;
    font-size: 0.82rem;
    color: var(--muted);
    margin-bottom: 0.35rem;
}

.check input {
    width: auto;
}

.provider {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 0.2rem;
    border-bottom: 1px solid var(--line);
}

.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;
}

/* 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(--line);
    border-radius: var(--radius);
}

.subagent-models-list > p {
    padding: 0.6rem;
}

.subagent-models-head {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 0.35rem 0.6rem;
    background: var(--card-2);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}

.subagent-model {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 44px;
    padding: 0.35rem 0.6rem;
    border-top: 1px solid var(--line);
    cursor: pointer;
}

.subagent-model input {
    width: auto;
    flex: none;
}

.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-code {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    padding: 0.6rem 0.8rem 0.7rem;
    border: 1px solid var(--accent-line);
    background: var(--accent-soft);
    border-radius: var(--radius);
    text-align: center;
}

.invite-code-head {
    align-self: stretch;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--accent);
}

.invite-code-value {
    display: flex;
    gap: 0.6em;
    font: 700 1.7rem var(--mono);
    letter-spacing: 0.12em;
    color: var(--text);
    user-select: all;
}

.code-big {
    font: 600 1.8rem var(--mono);
    letter-spacing: 0.15em;
    text-align: center;
    padding: 0.5rem;
}

.auth-event {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

/* ─── Artifact viewer ──────────────────────────────────────── */

.viewer {
    position: fixed;
    inset: 0;
    z-index: 30;
    background: var(--bg);
    display: flex;
    flex-direction: column;
}

.viewer-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: calc(env(safe-area-inset-top) + 0.35rem) 0.4rem 0.35rem 0.8rem;
    border-bottom: 1px solid var(--line);
}

.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(--line);
    border-radius: var(--radius);
    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(--radius);
    border: 1px solid var(--line);
    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(--o-bg-darker) 95%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(env(safe-area-inset-top) + 3.2rem) 0.5rem
        calc(env(safe-area-inset-bottom) + 0.5rem);
    animation: fade var(--t-fade) var(--ease-almost);
    cursor: zoom-out;
}

.lightbox > img {
    animation: popin 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) 0.4rem 0.4rem 0.9rem;
    background: linear-gradient(
        color-mix(in srgb, var(--o-bg-darker) 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 ────────────────────────── */

/* Omarchy's notifications: the active border, and a countdown line until the notice goes. Top right on wide screens. */
.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: 0.5rem;
    width: min(92vw, 460px);
    pointer-events: none;
}

@media (min-width: 700px) {
    .notices {
        left: auto;
        right: calc(var(--gap-out) * 2);
        top: calc(var(--gap-out) * 2);
        transform: none;
        width: 380px;
    }
}

.notice {
    position: relative;
    overflow: hidden;
    background: var(--bg);
    border: 2px solid transparent;
    border-image: var(--active) 1;
    border-radius: var(--radius);
    padding: 0.6rem 0.85rem 0.7rem;
    text-align: left;
    font-size: 0.82rem;
    color: var(--text);
    pointer-events: auto;
    animation: notice-in var(--t-in) var(--ease-out);
}

.notice::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--accent);
    transform-origin: left;
    animation: countdown var(--life, 4.5s) linear forwards;
}

@keyframes countdown {
    to {
        transform: scaleX(0);
    }
}

@keyframes notice-in {
    from {
        opacity: 0;
        transform: translateX(28px);
    }
}

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

@keyframes notice-out {
    to {
        opacity: 0;
        transform: translateX(16px);
    }
}

.notice.error {
    border-image: none;
    border-color: var(--err);
}

.notice.error::after {
    background: var(--err);
}

.notice.warning {
    border-image: none;
    border-color: var(--warn);
}

.notice.warning::after {
    background: var(--warn);
}

.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 {
    background: var(--accent-fill);
    color: var(--accent-ink);
    font-weight: 700;
    border-radius: var(--radius);
    padding: 0.65rem;
}

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);
    transition: background-color var(--t-hover) var(--ease-out);
}

.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: 6px;
    height: 6px;
    background: var(--ok);
    border: 1px solid var(--bg);
}

.online-mark.away {
    background: var(--faint);
}

.people-more {
    font-size: 0.72rem;
    color: var(--muted);
}

.avatar {
    display: inline-grid;
    place-items: center;
    flex: none;
    background: var(--card-2);
    color: var(--who, var(--accent));
    border: 1px solid var(--who, var(--accent));
    font-size: 0.62rem;
    font-weight: 700;
    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: 0.75rem;
    color: var(--muted);
    padding: 0 0.2rem 0.3rem;
}

.typing-dots {
    display: inline-flex;
    gap: 3px;
}

.typing-dots span {
    width: 4px;
    height: 4px;
    background: var(--muted);
    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-here {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.chat-here .chip {
    gap: 0.4rem;
    padding-left: 0.25rem;
}

.chat-log {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-height: 8rem;
    max-height: 52dvh;
    overflow-y: auto;
    border: 1px solid var(--line);
    background: var(--bg);
    padding: 0.5rem 0.6rem;
}

.chat-msg {
    border-left: 2px solid var(--who, var(--accent));
    padding: 0 0 0 0.55rem;
}

.chat-msg:not(.grouped) {
    margin-top: 0.45rem;
}

.chat-msg:first-child {
    margin-top: 0;
}

.chat-meta {
    font-size: 0.7rem;
    display: flex;
    gap: 0.45rem;
    align-items: baseline;
}

.chat-name {
    color: var(--who, var(--accent));
    font-weight: 700;
}

.chat-text {
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.chat-compose {
    display: flex;
    gap: 0.4rem;
    align-items: flex-end;
    background: var(--card);
    border: 2px solid var(--line);
    padding: 0.3rem;
}

.chat-compose:focus-within {
    border-color: transparent;
    background:
        linear-gradient(var(--card), var(--card)) padding-box,
        var(--active) border-box;
}

.chat-compose textarea {
    flex: 1;
    border: 0;
    background: none;
    color: var(--text);
    resize: none;
    padding: 0.4rem 0.45rem;
    max-height: 30vh;
    line-height: 1.45;
}

/* 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;
}

.chip.away {
    opacity: 0.7;
}

.tabs {
    flex-wrap: nowrap;
}

.tabs button {
    flex: 1;
}

.chat-event {
    text-align: center;
    font-size: 0.7rem;
    color: var(--muted);
    margin: 0.35rem 0;
}

.chat-msg.open,
.chat-msg.mentions-me {
    background: var(--card);
}

.chat-text {
    cursor: default;
}

.chat-actions {
    display: flex;
    gap: 0.9rem;
    padding: 0.15rem 0 0.25rem;
}

.chat-quote,
.quote-draft {
    display: block;
    width: 100%;
    text-align: left;
    border-left: 2px solid var(--brand);
    background: var(--card);
    color: var(--body);
    font-size: 0.78rem;
    padding: 0.25rem 0.5rem;
    margin: 0.15rem 0 0.2rem;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

.quote-draft {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    -webkit-line-clamp: unset;
}

.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: 0.35rem;
}

.pin {
    display: flex;
    align-items: flex-start;
    gap: 0.3rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 2px solid var(--brand);
    padding: 0.4rem 0.3rem 0.4rem 0.6rem;
}

.pin-main {
    flex: 1;
    min-width: 0;
    text-align: left;
}

.pin-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    font-size: 0.7rem;
}

.pin-text {
    color: var(--text);
    font-size: 0.85rem;
    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 left edge
   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 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.7rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 2px solid var(--warn);
    padding: 0.4rem 0.6rem;
    margin-bottom: 0.35rem;
    font-size: 0.82rem;
}

.plan-bar,
.goal-bar,
.watch-bar:is(.watching, .merged, .closed) {
    border-left-color: 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;
}

/* 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 {
    border-left-color: var(--ok);
}

.driver-label {
    color: var(--text);
    font-weight: 600;
}

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

.driver-pick {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.view-only {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 2px solid var(--muted);
    padding: 0.55rem 0.7rem;
    font-size: 0.82rem;
}

.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: 0.55rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--line);
}

.person-main {
    flex: 1;
    min-width: 0;
}

.person-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.3rem;
}

.online-dot {
    width: 7px;
    height: 7px;
    flex: none;
    background: var(--line-strong);
}

.online-dot.on {
    background: var(--ok);
}

.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(--line);
    border-radius: var(--radius);
    padding: 0.5rem 0.65rem;
    margin: 0 0 0.5rem;
    font-size: 0.86rem;
}

/* 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;
}

.setting select {
    width: auto;
    flex: none;
    min-height: 40px;
}

/* 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: 0.6rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--line);
}

.schedule:last-child {
    border-bottom: 0;
}

/* 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: 0.3rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--line);
}

.lesson:last-child {
    border-bottom: 0;
}

.lesson.pending {
    border-left: 2px solid var(--warn);
    padding-left: 0.6rem;
}

.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: 0.45rem;
}

.lesson-add .segmented {
    flex-wrap: nowrap;
    min-width: 0;
}

.lesson-add .segmented button {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Done when: a goal met, or one Pi gave up on. */
.goal-bar.met {
    border-left-color: var(--ok);
}

.goal-bar.gave-up {
    border-left-color: var(--warn);
}

/* Running now: a session, then what is at work in it. */
.running {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--line);
}

.running:last-child {
    border-bottom: 0;
}

.running-head,
.running-task {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.running-head .link {
    text-align: left;
    font-size: 0.95rem;
}

.running-task {
    font-size: 0.84rem;
    padding: 0.25rem 0 0 0.6rem;
}

/* Changes: one row per changed file, with its diff under it once tapped. */
.changed {
    border-bottom: 1px solid var(--line);
}

.changed:last-child {
    border-bottom: 0;
}

.changed-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    text-align: left;
    padding: 0.5rem 0;
    font-size: 0.84rem;
}

.changed-head .mono {
    overflow-wrap: anywhere;
}

.change-kind {
    width: 1.3rem;
    text-align: center;
    font-family: var(--mono);
    font-size: 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.change-kind.added,
.change-kind.new {
    color: var(--ok);
}

.change-kind.deleted {
    color: var(--err);
}

/* Spend: a person or a session, what Pi spent for it, and its limit. */
.spend-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.6rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--line);
    font-size: 0.86rem;
}

.limit-edit {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.limit-edit input {
    width: 6rem;
}

/* ─── Launcher: Omarchy's Walker, for sessions, actions, and themes ─── */

.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) + min(14vh, 120px)) 10px 10px;
    background: var(--scrim);
    animation: fade var(--t-fade) var(--ease-almost);
}

.launcher {
    width: min(640px, 100%);
    max-height: min(560px, 74dvh);
    display: flex;
    flex-direction: column;
    background: color-mix(in srgb, var(--o-bg) 95%, transparent);
    border: 2px solid var(--o-fg);
    animation: popin 0.3s var(--ease-out);
    outline: none;
}

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

.leaving .launcher {
    animation: popout var(--t-out) linear forwards;
}

.launcher-input {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.2rem 0.9rem;
    border-bottom: 1px solid var(--line);
    color: var(--accent);
}

.launcher-input .prompt {
    font-weight: 800;
}

.launcher-input input {
    border: 0;
    background: none;
    padding: 0.75rem 0;
    font-size: 1.02rem;
    color: var(--text);
}

.launcher-mode {
    flex: none;
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px solid var(--line-strong);
    padding: 0.05rem 0.4rem;
}

.launcher-list {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.35rem;
    scroll-padding: 0.35rem;
}

/* The selection moves between rows instead of jumping: one highlight that slides. */
.launcher-list .slide-y {
    left: 0.35rem;
    right: 0.35rem;
    width: auto;
    background: var(--hover);
    border: 1px solid var(--edge);
    z-index: 0;
    transition:
        transform 0.22s var(--ease-out),
        height 0.22s var(--ease-out);
}

.launcher-group {
    position: relative;
    z-index: 1;
    padding: 0.6rem 0.6rem 0.25rem;
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--faint);
}

.launcher-item {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    width: 100%;
    min-height: 2.4rem;
    padding: 0.4rem 0.65rem;
    text-align: left;
    color: var(--body);
    transition: color 0.12s var(--ease-out);
}

.launcher-item.on {
    color: var(--accent);
}

.launcher-item .glyph {
    width: 1.3rem;
    flex: none;
    display: grid;
    place-items: center;
    color: var(--muted);
    font-size: 0.85rem;
}

.launcher-item.on .glyph {
    color: var(--accent);
}

.launcher-item .main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.launcher-item .main > span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.launcher-item .detail {
    font-size: 0.7rem;
    color: var(--muted);
}

.launcher-item .hint {
    flex: none;
    display: flex;
    gap: 0.25rem;
    align-items: center;
    font-size: 0.72rem;
    color: var(--muted);
}

.launcher-item .swatch {
    display: flex;
    flex: none;
    border: 1px solid var(--line);
}

.launcher-item .swatch i {
    width: 9px;
    height: 14px;
}

.launcher-empty {
    padding: 1.4rem 1rem;
    color: var(--muted);
    text-align: center;
    font-size: 0.85rem;
}

.launcher-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    padding: 0.45rem 0.9rem;
    border-top: 1px solid var(--line);
    font-size: 0.68rem;
    color: var(--muted);
}

.launcher-foot span {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

@media (pointer: coarse) {
    .launcher-foot {
        display: none;
    }
}

/* ─── Appearance ───────────────────────────────────────────── */

.theme-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(138px, 1fr));
    gap: 8px;
}

/* 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;
    background: var(--o-bg);
    color: var(--o-fg);
    border: 2px solid var(--line);
    transition:
        transform var(--t-in) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
    animation: rise-in 0.4s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 22ms);
}

.theme-card:hover {
    transform: translateY(-3px);
    border-color: var(--line-strong);
}

.theme-card:active {
    transform: scale(0.97);
}

.theme-card.on {
    border-color: transparent;
    border-image: var(--active) 1;
}

.theme-card.on::after {
    content: "✓";
    position: absolute;
    top: 4px;
    right: 4px;
    width: 16px;
    height: 16px;
    display: grid;
    place-items: center;
    font-size: 0.65rem;
    font-weight: 800;
    background: var(--o-accent);
    color: var(--o-bg);
    animation: popin 0.3s var(--ease-out);
}

.tc-desk {
    display: flex;
    gap: 3px;
    height: 58px;
    padding: 5px;
    background: var(--o-bg-darker);
}

.tc-win {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 4px;
    background: var(--o-bg);
    border: 1px solid var(--o-inactive);
}

.tc-win:first-child {
    width: 34%;
}

.tc-win:last-child {
    flex: 1;
    border-color: var(--o-accent);
    border-image: var(--o-active) 1;
}

.tc-win i {
    height: 3px;
    background: var(--o-fg);
    opacity: 0.35;
}

.tc-win i:nth-child(1) {
    width: 80%;
}

.tc-win i:nth-child(2) {
    width: 55%;
}

.tc-win i.lit {
    background: var(--o-accent);
    opacity: 1;
    width: 40%;
}

.tc-name {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.35rem 0.45rem 0.1rem;
    font-size: 0.74rem;
    font-weight: 700;
    color: var(--o-fg-bright, var(--o-fg));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tc-name small {
    font-weight: 400;
    font-size: 0.62rem;
    color: var(--o-accent);
}

.tc-dots {
    display: flex;
    gap: 3px;
    padding: 0.2rem 0.45rem 0.45rem;
}

.tc-dots i {
    width: 9px;
    height: 9px;
}

.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.45rem 0.45rem;
    font-size: 0.68rem;
    color: var(--o-fg);
    opacity: 0.75;
}

.setting-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--line);
}

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

.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: 0.74rem;
    color: var(--muted);
}

.shortcuts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.35rem 0.9rem;
    font-size: 0.8rem;
    align-items: center;
}

.shortcuts dt {
    display: flex;
    gap: 0.2rem;
    justify-content: flex-end;
}

.shortcuts dd {
    margin: 0;
    color: var(--body);
}

/* ─── Sign in: the app's screen (the server's pages are under Notices) ─── */

.signin {
    animation: rise-in 0.5s var(--ease-out);
}

.signin .row {
    border: 2px solid transparent;
    border-image: var(--active) 1;
    padding: 0.4rem;
    background: var(--bg);
}

.signin .row input {
    border: 0;
    background: 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: popin 0.32s 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);
}

.search-keys:hover {
    opacity: 1;
}

.search:focus-within .search-keys {
    opacity: 0;
}

@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, clamp(320px, 25vw, 420px));
    height: 100dvh;
    border-left: 1px solid var(--line);
    background: var(--panel);
}

/* 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 .sheet-body {
    flex: 1;
    min-height: 0;
    padding-bottom: 0.8rem;
}

/* The chat fills the window, its box at the bottom, as a chat app's does. */
.people .chat-log {
    flex: 1;
    max-height: none;
}

.people textarea.notes {
    flex: 1;
    resize: none;
}

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

/* ─── 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 is a window of its own; the tile under the
 * mouse takes the active border. 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(--line);
    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: 1.5rem 1rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    text-align: center;
    color: var(--muted);
    font-size: 0.86rem;
}

.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: 7px;
    right: 7px;
    width: 7px;
    height: 7px;
    background: var(--warn);
}

.peeks-list {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.6rem;
    scroll-snap-type: y proximity;
    scrollbar-width: thin;
}

.peek {
    position: relative;
    flex: none;
    height: var(--peek-h, 13rem);
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--card);
    border: 1px solid var(--line);
    scroll-snap-align: start;
    transition: border-color var(--t-hover) var(--ease-out);
}

.peek:hover,
.peek:focus-within {
    border-color: var(--accent-line);
}

.peek.waiting {
    height: auto;
    min-height: var(--peek-h, 13rem);
    border-color: var(--warn-line);
}

/* A waiting tile grows to show its whole call; its own lines keep to a few. */
.peek.waiting .peek-lines {
    flex: none;
    max-height: 5.6rem;
}

.peek-head {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    min-width: 0;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--line);
    text-align: left;
}

.peek-head .session-state {
    align-self: center;
    margin-top: 0;
}

.peek.done .state-idle {
    background: var(--ok);
    border-color: var(--ok);
}

.peek-name {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.peek-title,
.peek-cwd {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.peek-title {
    color: var(--text);
    font-size: 0.86rem;
}

.peek-cwd {
    color: var(--faint);
    font-size: 0.7rem;
}

.peek-lines {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 2px;
    padding: 0.35rem 0.6rem;
    font-size: 0.74rem;
    cursor: pointer;
    mask-image: linear-gradient(to bottom, transparent, #000 1.5rem);
}

.peek-line {
    flex: none;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--muted);
}

.peek-line.text {
    color: var(--text);
    white-space: normal;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}

.peek-line.user b {
    color: var(--accent);
    font-weight: 600;
}

.peek-line .pi {
    color: var(--brand);
    font-weight: 700;
}

.peek-mark {
    color: var(--faint);
}

/* 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;
    padding: 0.3rem 0.6rem;
    border-top: 1px solid var(--warn-line);
    background: var(--warn-soft);
    font-size: 0.72rem;
}

.peek-ask-what {
    color: var(--warn);
    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 {
    color: var(--muted);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

.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;
    background: var(--card-2);
}

.peek-skeleton i:nth-child(2) {
    width: 80%;
}

.peek-skeleton i:nth-child(3) {
    width: 60%;
}

.peek-foot {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 2.4rem;
    padding: 0.3rem 0.45rem 0.3rem 0.6rem;
    border-top: 1px solid var(--line);
}

.peek-status {
    margin-right: auto;
    color: var(--faint);
    font-size: 0.74rem;
    white-space: nowrap;
}

.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: 0.3rem;
}

.peek-actions .button.small,
.peek-seen {
    min-height: 1.9rem;
}

.peek-seen {
    width: 1.9rem;
    height: 1.9rem;
}

/* 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: 0.3rem 0.75rem;
    background: var(--warn);
    color: var(--accent-ink);
    font-size: 0.75rem;
    font-weight: 700;
    white-space: nowrap;
}

.peeks-jump.up {
    top: 0.5rem;
}

.peeks-jump.down {
    bottom: 0.5rem;
}

.peek-strip {
    flex: none;
    animation: peek-strip-in var(--t-in) var(--ease-out) backwards;
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--line);
    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,
.peek-strip .peek.waiting {
    width: 15rem;
    height: auto;
    min-height: 0;
}

.peek-strip .peek-head {
    padding: 0.35rem 0.55rem 0.15rem;
    border-bottom: 0;
}

.peek-strip .peek-cwd {
    display: none;
}

.peek-strip .peek-lines {
    padding: 0 0.55rem;
    mask-image: none;
}

.peek-strip .peek-line.text {
    display: block;
    white-space: nowrap;
}

.peek-strip .peek-ask {
    margin: 0.2rem 0.55rem 0;
    border: 1px solid var(--warn-line);
}

.peek-strip .peek-foot {
    min-height: 0;
    padding: 0.1rem 0.4rem 0.35rem 0.55rem;
    border-top: 0;
}

@media (min-width: 960px) {
    :root[data-tiling="on"] .peeks.window {
        height: auto;
        border: 0;
        background: none;
    }
    :root[data-tiling="on"] .peeks.window::after {
        display: none;
    }
    :root[data-tiling="on"] .peeks-list {
        gap: calc(var(--gap-in) * 2);
        padding: 0;
    }
    :root[data-tiling="on"] .peeks .peek {
        border: var(--border) solid var(--o-inactive);
        background: var(--bg);
    }
    :root[data-tiling="on"] .peeks .peek.waiting {
        border-color: var(--warn);
    }
    :root[data-tiling="on"] .peeks .peek:hover,
    :root[data-tiling="on"] .peeks .peek:focus-within {
        border-image: var(--active) 1;
    }
}

/* ─── Diff viewer ──────────────────────────────────────────── */

/* One file's diff: a header that sticks while its lines scroll by, then the lines in a table, one or two sides. */
.dv {
    border: 1px solid var(--line);
    background: var(--code-bg);
    min-width: 0;
}

.dv-head {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    min-height: 2.2rem;
    padding: 0.25rem 0.45rem;
    background: var(--card-2);
    border-bottom: 1px solid var(--line);
    font-size: 0.8rem;
}

.dv.folded .dv-head {
    border-bottom: 0;
}

.dv.viewed .dv-head {
    background: var(--card);
}

.dv.viewed .dv-name {
    color: var(--muted);
}

.dv-fold {
    display: inline-grid;
    place-items: center;
    width: 22px;
    height: 22px;
    flex: none;
    color: var(--muted);
}

.dv-fold:hover {
    color: var(--text);
}

.dv-head .change-kind {
    flex: none;
    width: 1.2rem;
    font-size: 0.68rem;
}

.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 {
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 1ch;
    white-space: nowrap;
    font-family: var(--mono);
}

.dv-name {
    color: var(--text);
    flex: none;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dv-counts {
    display: inline-flex;
    gap: 0.35rem;
    flex: none;
    font: 0.74rem var(--mono);
}

.dv-bar {
    display: inline-flex;
    gap: 1px;
    flex: none;
}

.dv-bar i {
    width: 7px;
    height: 7px;
    background: var(--line-strong);
}

.dv-bar i.add {
    background: var(--ok);
}

.dv-bar i.del {
    background: var(--err);
}

.dv-chip {
    flex: none;
    padding: 0 0.35rem;
    font-size: 0.68rem;
}

.dv-chip.warn {
    color: var(--warn);
    border-color: var(--warn-line);
}

.dv-tool.icon-button {
    width: 28px;
    height: 28px;
    font-size: 0.8rem;
    color: var(--muted);
}

.dv-tool.icon-button:hover {
    color: var(--text);
}

.dv-tool.danger {
    width: auto;
    padding: 0 0.4rem;
    color: var(--err);
}

.dv-viewed {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex: none;
    padding: 0.1rem 0.45rem;
    border: 1px solid var(--line);
    font-size: 0.72rem;
    color: var(--muted);
    cursor: pointer;
    user-select: none;
}

.dv-viewed:hover {
    border-color: var(--edge);
    color: var(--text);
}

.dv-viewed.on {
    color: var(--ok);
    border-color: color-mix(in srgb, var(--ok) 50%, transparent);
}

.dv-viewed input {
    width: auto;
    margin: 0;
    accent-color: var(--ok);
}

@media (max-width: 520px) {
    .dv-bar,
    .dv-viewed span {
        display: none;
    }
}

.dv-scroll {
    overflow-x: auto;
}

.dv-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    font: 0.76rem/1.55 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);
}

/* A number column's width, which notes under the lines count past too. */
.dv {
    --dv-n: 3.6em;
}

@media (max-width: 520px) {
    .dv {
        --dv-n: 2.9em;
    }
}

.dv-col-n {
    width: var(--dv-n);
}

.dv-n {
    padding: 0 0.55em 0 0.3em;
    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;
}

.dv-n.go:hover {
    color: var(--accent);
    text-decoration: underline;
}

.dv-code {
    position: relative;
    padding: 0 0.8em 0 1.5em;
    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.45em;
    user-select: none;
}

.dv-code:empty::after {
    content: " ";
}

.dv-code.add,
.dv-n.add {
    background: color-mix(in srgb, var(--ok) 11%, transparent);
}

.dv-code.del,
.dv-n.del {
    background: color-mix(in srgb, var(--err) 11%, transparent);
}

.dv-n.add,
.dv-code.add::before {
    color: var(--ok);
}

.dv-n.del,
.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;
}

/* 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(--o-fg) 4%, transparent) 5px 6px
    );
}

.dv-table.split .dv-code + .dv-n {
    border-left: 1px solid var(--line);
}

.dv-hunk td {
    padding: 0.2rem 0.7rem;
    background: color-mix(in srgb, var(--accent) 7%, transparent);
    color: var(--muted);
    font-size: 0.72rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dv-context {
    margin-left: 0.8em;
    color: var(--body);
}

.dv-gap td {
    padding: 0.1rem 0.4rem;
    background: color-mix(in srgb, var(--accent) 5%, transparent);
    text-align: center;
    border-block: 1px solid var(--line);
}

.dv-gap button {
    padding: 0.15rem 0.6rem;
    color: var(--accent);
    font: 0.72rem var(--mono);
}

.dv-gap button:hover {
    background: var(--hover);
}

.dv-reading {
    color: var(--muted);
    font: 0.72rem 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 0.8rem 0 calc(2 * var(--dv-n) + 1.5em);
    color: var(--muted);
    font-style: italic;
}

.dv-table.split .dv-note td {
    padding-left: calc(var(--dv-n) + 1.5em);
}

.dv-note span {
    font-size: 0.7rem;
}

.dv-empty {
    margin: 0;
    padding: 0.7rem 0.8rem;
    color: var(--muted);
    font-size: 0.82rem;
}

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

.dv-empty .link {
    margin-left: 0.4rem;
}

.dv-wait {
    padding: 0.4rem 0.8rem;
    border: 1px solid var(--line);
    border-top: 0;
}

.dv-settings {
    display: inline-flex;
    gap: 0.3rem;
}

/* 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: 0.5rem;
    max-height: 60vh;
    overflow: auto;
}

.dv-block .dv-head {
    position: static;
}

/* ─── Review ─────────────────────────────────────────────── */

.dr {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    outline: none;
    min-width: 0;
}

.dr-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.8rem;
    font-size: 0.8rem;
}

/* The folder gives way when there is no room; the branch, a way to switch it, stays in sight. */
.dr-where {
    flex: 1 1 12rem;
    min-width: 0;
    display: flex;
    align-items: baseline;
    color: var(--muted);
    font-size: 0.74rem;
    white-space: pre;
}

.dr-path {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dr-where > :not(.dr-path) {
    flex: none;
}

.dr-stats {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
    font-size: 0.78rem;
}

.dr-stats strong {
    color: var(--text);
}

.dr-progress {
    width: 64px;
    height: 4px;
    background: var(--line);
    overflow: hidden;
}

.dr-progress i {
    display: block;
    height: 100%;
    background: var(--ok);
    transition: width var(--t-in) var(--ease-out);
}

.dr-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
}

.dr-filter,
.ft-filter {
    flex: 1;
    min-width: 7rem;
    height: 32px;
    padding: 0.3rem 0.55rem;
    font-size: 0.8rem;
}

.dr-main {
    display: grid;
    gap: 0.6rem;
    min-width: 0;
}

.dr.wide .dr-main {
    grid-template-columns: minmax(170px, 240px) minmax(0, 1fr);
    align-items: start;
}

.dr-tree {
    padding: 0.3rem 0;
    border: 1px solid var(--line);
    background: var(--card);
    font-size: 0.78rem;
    max-height: 40vh;
    overflow: auto;
}

.dr.wide .dr-tree {
    position: sticky;
    top: 0;
    max-height: calc(100dvh - 10rem);
}

.dr-row,
.ft-row {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    width: 100%;
    min-height: 1.7rem;
    padding: 0.15rem 0.5rem 0.15rem calc(0.5rem + var(--depth, 0) * 0.85rem);
    text-align: left;
    color: var(--body);
    white-space: nowrap;
}

/* The files tree steps in a little further than the changes tree: it nests deeper, with a chevron on each folder. */
.ft-row {
    padding-left: calc(0.4rem + var(--depth, 0) * 0.9rem);
}

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

.dr-row:hover,
.ft-row:hover {
    background: var(--hover);
}

.dr-row.on,
.ft-row.on {
    background: var(--accent-soft);
    color: var(--text);
    box-shadow: inset 2px 0 var(--accent);
}

.dr-row.dir {
    color: var(--muted);
}

.dr-row .change-kind {
    flex: none;
    width: 1.1rem;
    font-size: 0.64rem;
}

.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: 0.7rem;
}

.dr-tail {
    margin-left: auto;
    padding-left: 0.4rem;
    color: var(--ok);
    font-size: 0.7rem;
}

.dr-tail .dv-counts {
    font-size: 0.68rem;
}

.dr-files {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    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 .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;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: popin var(--t-in) var(--ease-out);
}

.files-resize {
    display: none;
}

@media (max-width: 1099px) {
    :root[data-tiling="on"] .files-tile.window {
        border: 0;
    }
    .files-tile.window::after {
        display: none !important;
    }
}

@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(--line);
        animation-delay: 90ms;
    }
    :root[data-tiling="on"] .layout.filing .files-tile {
        height: auto;
    }
    .files-resize {
        display: block;
        left: -7px;
        right: auto;
    }
}

.files-bar {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: calc(env(safe-area-inset-top) + 0.3rem) 0.35rem 0;
    border-bottom: 1px solid var(--line);
}

.files-bar .icon-button {
    width: 34px;
    height: 34px;
}

.files-tabs {
    display: flex;
    align-self: stretch;
}

.files-tabs button {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 0.75rem;
    font-size: 0.82rem;
    color: var(--muted);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition:
        color var(--t-hover) var(--ease-out),
        border-color var(--t-hover) var(--ease-out);
}

.files-tabs button:hover {
    color: var(--text);
}

.files-tabs button.on {
    color: var(--text);
    border-bottom-color: var(--accent);
}

.files-count {
    min-width: 1.3rem;
    padding: 0 0.3rem;
    background: var(--accent-soft);
    color: var(--accent);
    font-size: 0.68rem;
    text-align: center;
}

.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-body > .dr {
    padding: 0.6rem 0.7rem 1.2rem;
}

/* 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 clamp(210px, 34%, 300px);
    border-right: 1px solid var(--line);
}

.ft-tools {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    padding: 0.45rem 0.4rem 0.3rem 0.5rem;
}

.ft-tools .icon-button {
    width: 32px;
    height: 32px;
    color: var(--muted);
}

.ft-tools .icon-button:hover {
    color: var(--text);
}

.ft-fold-all {
    transform: rotate(180deg);
}

.ft-root {
    padding: 0.1rem 0.7rem 0.35rem;
    color: var(--muted);
    font-size: 0.72rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ft-tree {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding-bottom: 1rem;
    font-size: 0.8rem;
}

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

.ft-row.dir > .icon:not(.chev) {
    color: var(--accent);
}

.ft-spacer {
    width: 12px;
    flex: none;
}

.ft-row.dot .ft-name {
    color: var(--muted);
}

.ft-row.changed.modified .ft-name,
.ft-row.changed.renamed .ft-name {
    color: var(--warn);
}

.ft-row.changed.new .ft-name,
.ft-row.changed.added .ft-name {
    color: var(--ok);
}

.ft-row.changed.deleted .ft-name {
    color: var(--err);
    text-decoration: line-through;
}

.ft-kind {
    margin-left: auto;
    padding-left: 0.4rem;
    font: 0.66rem 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: 5px;
    height: 5px;
    margin-left: auto;
    background: var(--warn);
    flex: none;
}

.ft-row.match {
    padding-left: 0.7rem;
}

.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(--muted);
    font-size: 0.7rem;
    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: 0.3rem;
    min-height: 42px;
    padding: 0 0.35rem 0 0.7rem;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
}

.ft-view-head .icon-button {
    width: 32px;
    height: 32px;
}

.ft-view-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.84rem;
    color: var(--text);
}

.ft-view .file-viewer {
    padding: 0.5rem 0.6rem 1.2rem;
}

.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;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    animation: popin var(--t-in) var(--ease-out);
}

.browser-resize {
    display: none;
}

@media (max-width: 1099px) {
    :root[data-tiling="on"] .browser.window {
        border: 0;
    }
    .browser.window::after {
        display: none !important;
    }
}

@media (min-width: 1100px) {
    .layout.browsing .browser {
        position: relative;
        inset: auto;
        z-index: auto;
        flex: 0 0 var(--browser-w, 46%);
        max-width: calc(100% - 440px);
        height: 100dvh;
        border-left: 1px solid var(--line);
        animation-delay: 90ms;
    }
    :root[data-tiling="on"] .layout.browsing .browser {
        height: auto;
    }
    .browser-resize {
        display: block;
        left: -7px;
        right: auto;
    }
}

.browser-bar {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    padding: calc(env(safe-area-inset-top) + 0.35rem) 0.35rem 0.35rem;
    border-bottom: 1px solid var(--line);
    background: var(--bg);
}

.browser-bar .icon-button {
    width: 34px;
    height: 34px;
}

.browser-bar .icon-button:disabled {
    opacity: 0.35;
    cursor: default;
    background: none;
    transform: none;
}

.browser-bar .icon-button.on,
.topbar .icon-button.on {
    color: var(--accent);
}

.browser-address {
    flex: 1;
    min-width: 0;
    margin: 0 0.25rem;
}

.browser-address input {
    height: 34px;
    padding: 0.3rem 0.6rem;
    font-size: 0.86rem;
    text-overflow: ellipsis;
}

.browser-address input[readonly] {
    color: var(--muted);
}

@media (pointer: coarse) {
    .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: center;
    justify-content: center;
    gap: 0.7rem;
    padding: 2rem 1.5rem;
    text-align: center;
    color: var(--muted);
    background: var(--bg);
    animation: fade var(--t-fade) var(--ease-almost);
}

.browser-note .browser-start {
    position: static;
    background: none;
    padding: 0;
}

.browser-start p {
    margin: 0;
    max-width: 26rem;
}

.browser-servers {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.6rem;
    max-width: 100%;
}

.browser-servers .chip {
    font-size: 0.82rem;
    padding: 0.35rem 0.7rem;
}

/* 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%, 340px);
    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: 0.5rem;
    padding: 0.25rem 0.4rem 0.25rem 0.8rem;
    border-bottom: 1px solid var(--line);
}

.browser-console .spacer {
    flex: 1;
}

.browser-console-lines {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 0.3rem 0.7rem;
    font-size: 0.78rem;
    line-height: 1.45;
}

.console-line {
    display: flex;
    gap: 0.6rem;
    padding: 0.15rem 0.3rem;
    margin: 0 -0.3rem;
    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: 0.3rem;
    padding: 0.15rem 0;
    border-bottom: 1px dashed var(--line);
    color: var(--faint);
    font-size: 0.72rem;
}

.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;
}

.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(--line);
    border-left: 2px solid var(--ok);
    border-radius: var(--radius);
    padding: 0.45rem 0.65rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.shell-card > .link {
    align-self: flex-start;
}

.shell-card.failed {
    border-left-color: var(--err);
}

.shell-row.pending .shell-card {
    border-left-color: var(--line-strong);
}

.shell-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.6rem;
    font-size: 0.84rem;
}

.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: 0.8rem;
    color: var(--body);
}

/* Changes: open a file or undo it. */
.changed-actions {
    display: flex;
    gap: 1rem;
    padding: 0 0 0.4rem 1.8rem;
}

.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: 0.78rem/1.5 var(--mono);
    background: var(--code-bg);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.4rem 0;
    overflow-x: auto;
}

.file-line {
    display: flex;
    min-width: 0;
}

.file-line .ln {
    flex: none;
    width: 3.2rem;
    padding-right: 0.7rem;
    text-align: right;
    color: var(--muted);
    user-select: none;
    opacity: 0.7;
}

.file-line .lt {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    min-width: 0;
    color: var(--body);
    padding-right: 0.6rem;
}

.file-line.on {
    background: var(--accent-soft);
}

.file-line.on .ln {
    color: var(--accent);
    opacity: 1;
}

.file-image {
    max-width: 100%;
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.file-entry {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

/* Find in session. */
.find-input {
    width: 100%;
    margin-bottom: 0.6rem;
}

.find-results {
    display: flex;
    flex-direction: column;
}

.find-result {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    text-align: left;
    padding: 0.5rem 0.6rem;
    border-left: 2px solid transparent;
    border-bottom: 1px solid var(--line);
    transition: background-color var(--t-hover) var(--ease-out);
}

.find-result:hover,
.find-result.on {
    background: var(--hover);
    border-left-color: var(--accent);
}

.find-who {
    font-size: 0.75rem;
    color: var(--muted);
}

.find-snippet {
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

.find-snippet mark {
    background: none;
    color: var(--accent);
    font-weight: 800;
}

/* 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;
    border: 1px solid var(--line);
}

.rich-tabs button,
.rich-run {
    padding: 0.1rem 0.5rem;
    font: inherit;
    color: var(--muted);
    transition:
        color var(--t-hover) var(--ease-out),
        background-color var(--t-hover) var(--ease-out);
}

.rich-tabs button + button {
    border-left: 1px solid var(--line);
}

.rich-tabs button:hover,
.rich-run:hover {
    color: var(--text);
    background: var(--hover);
}

.rich-tabs button.on {
    color: var(--accent);
    background: var(--accent-soft);
}

.rich-run {
    border: 1px solid var(--line);
    color: var(--ok);
}

.rich-run.on {
    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(--line);
    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;
}

.rich-svg {
    display: block;
    max-width: 100%;
    max-height: 70vh;
    padding: 0.6rem;
    border: 1px solid var(--line);
    background: #fff;
    cursor: zoom-in;
}

.code.rich > .dv-block {
    max-height: none;
}

.rich-note {
    margin: 0;
    padding: 0.6rem;
    border: 1px solid var(--line);
}

/* 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: 0.3rem;
    border-top: 1px solid var(--line);
    background: var(--card);
    color: var(--accent);
    font: 0.74rem var(--mono);
}

.code-more:hover {
    background: var(--hover);
}

.file-tools .button.on {
    color: var(--err);
}

/* ─── Phones: places, pushed screens, and going back ───────── */

/* The menu's tiles: the session's places, a thumb wide each, four to a row. */
.places {
    display: grid;
    /* Four to a row, or three where larger text would cut their names short. */
    grid-template-columns: repeat(auto-fill, minmax(max(4.6rem, 22%), 1fr));
    gap: 0.4rem;
    margin-bottom: 0.35rem;
}

.place {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-height: 68px;
    padding: 0.55rem 0.25rem 0.45rem;
    background: var(--card);
    border: 1px solid var(--line);
    color: var(--body);
    animation: rise-in 0.34s var(--ease-out) backwards;
    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);
}

.place:hover {
    border-color: var(--edge);
    background: var(--card-2);
    color: var(--text);
}

.place:active {
    background: var(--pressed);
    transform: scale(0.96);
}

.place.on {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}

.place-icon {
    position: relative;
    display: grid;
    place-items: center;
    width: 30px;
    height: 26px;
}

.place-icon .badge {
    top: -6px;
    right: -10px;
}

.place-icon .browser-dot {
    top: -2px;
    right: -4px;
}

.place-label {
    max-width: 100%;
    font-size: 0.74rem;
    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 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;
    }
    :root[data-route="forward"] .pane > .scroller {
        animation: route-forward 0.32s var(--ease-out);
    }
    :root[data-route="back"] .pane > .scroller,
    :root[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: 36px;
        height: 36px;
        color: var(--muted);
    }
    .composer-row .places-button .browser-dot {
        top: 6px;
        right: 6px;
    }
    /* 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 {
        display: none;
    }
    /* While Pi works the row is full: the mic takes Send's place while there is nothing to send, and gives it back once
       there is (staying 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;
    color: var(--text);
}

/*
 * 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 {
        animation: push-in 0.36s var(--ease-out);
    }
    :root .layout > .files-tile.window.leaving,
    :root .layout > .browser.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 {
        min-height: 44px;
        padding: 0.45rem 0.9rem;
        font-size: 0.88rem;
    }
    .ft-tools .icon-button,
    .ft-view-head .icon-button {
        width: 44px;
        height: 44px;
    }
    .ft-view-head {
        min-height: 48px;
        padding-left: 0.2rem;
    }
    .ft-view-name {
        font-size: 0.92rem;
    }
    .ft-filter {
        min-height: 42px;
    }
    .ft-tree {
        font-size: 0.92rem;
    }
    .ft-row {
        min-height: 44px;
        gap: 0.5rem;
        padding-left: calc(0.6rem + var(--depth, 0) * 1rem);
    }
    .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;
    }
    /* 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,
    .new-folder input,
    .launcher-input input {
        font-size: 16px;
    }
    /* Rows a thumb can take, and that answer the press. */
    .session {
        height: 40px;
    }
    .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 .chip,
    .composer-row .model-chip,
    .composer-row .mode-switch {
        min-height: 36px;
    }
    .composer-row .attach-button,
    .composer-row .composer-mic,
    .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, .composer-mic, .stop-button, .send-button) {
        position: relative;
    }
    .composer-row
        :is(.places-button, .attach-button, .composer-mic, .stop-button, .send-button)::before {
        content: "";
        position: absolute;
        inset: -4px -2px;
    }
    /* 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: -4px 0;
    }
    /* A group's line and a call's line, a little taller for a thumb. */
    .activity-head,
    .step-head {
        min-height: 36px;
    }
    .step-node {
        top: 16px;
    }
    .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: 0.6rem;
    }
    .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),
    .status-line .guard,
    .link.small,
    .running-head .link,
    .dr-branch {
        padding-block: 11px;
        margin-block: -11px;
    }
    .answer-actions > button:not(.reaction) {
        min-width: 40px;
        justify-content: center;
        padding-inline: 6px;
        margin-inline: -6px;
    }
    /* Narrow, the guard is its shield and a word: its hit area reaches past them, to the sides too. */
    .status-line .guard {
        min-width: 40px;
        justify-content: center;
        padding-inline: 8px;
        margin-inline: -8px;
    }
    .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 name keeps the first line beside
 * the fold, and the counts and the file's tools take the second.
 */
@media (max-width: 480px) {
    .dv-head {
        flex-wrap: wrap;
        row-gap: 0;
    }
    .dv-head > .dv-title {
        flex: 1 1 calc(100% - 5rem);
    }
    .dv-head > .dv-counts {
        margin-left: 2.4rem;
    }
    .dv-head > .dv-bar {
        margin-right: auto;
    }
    /* Going to a change (n, p) clears the header's two lines. */
    .dr .dv-row,
    .dr .dv-hunk {
        scroll-margin-top: 6.4rem;
    }
}

/*
 * 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(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    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(--line);
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--t-hover) var(--ease-out);
}

.pi-session:first-child {
    border-top: 0;
}

.pi-session:hover {
    background: var(--card-2);
}

.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: 999px;
    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-right: 2px solid var(--accent);
    border-radius: var(--radius);
    padding: 0.45rem 0.7rem;
}

.pi-reply {
    color: var(--body);
}

/* Continue stays in sight as the conversation scrolls under it. */
.pi-continue {
    position: sticky;
    bottom: -1rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin: 0 -1rem -1rem;
    padding: 0.7rem 1rem 1rem;
    background: var(--panel);
    border-top: 1px solid var(--line);
}

.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. The left edge is the accent while one works, then "done".
 */
.agents-bar {
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 2px solid var(--ok);
    border-radius: var(--radius);
    margin-bottom: 0.35rem;
    font-size: 0.82rem;
    overflow: hidden;
}

.agents-bar.busy {
    border-left-color: var(--accent);
}

.agents-top {
    display: flex;
    align-items: center;
    padding-right: 0.2rem;
}

.agents-summary {
    flex: 1;
    min-width: 0;
    min-height: 2.4rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.6rem;
    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: 0.78rem;
    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(--line);
    color: var(--warn);
    font-size: 0.76rem;
    line-height: 1.4;
}

.agents-held .link {
    font-size: inherit;
}

.agents-bar:has(.agents-held) {
    border-left-color: var(--warn);
}

.agents-list {
    max-height: min(40vh, 22rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    border-top: 1px solid var(--line);
}

.agent-row {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--line);
}

.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);
}

.agent-open:hover {
    background: var(--card-2);
}

.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: 999px;
    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: 0.78rem;
}

.agent-asked {
    color: var(--muted);
    font-size: 0.76rem;
}

.agent-stop {
    flex: none;
    margin-right: 0.2rem;
}

/* ─── 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 {
    --done-cell: color-mix(in srgb, var(--ok) 40%, var(--bg));
    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: 10px;
    padding: calc(env(safe-area-inset-top) + 0.35rem) 0.4rem 0.35rem 1rem;
    border-bottom: 1px solid var(--line);
}

.board-title {
    flex: 1;
    min-width: 0;
}

.board-title h2 {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.6;
    color: var(--text);
}

.board-title h2::before {
    content: "▪ ";
    color: var(--accent);
}

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

.board-search {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    width: 220px;
    height: 32px;
    padding: 0 8px;
    background: var(--card);
    border: 1px solid transparent;
    color: var(--muted);
    transition: border-color var(--t-hover) var(--ease-out);
}

.board-search.filled,
.board-search:focus-within {
    border-color: var(--accent);
}

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

.board-search-row {
    flex: none;
    padding: 10px 12px 0;
}

.board-search-row .board-search {
    width: 100%;
}

/* A state's mark: its fill and edge, with "!" for what needs you. */
.board-mark {
    flex: none;
    width: 12px;
    height: 12px;
    display: grid;
    place-items: center;
    border: 1px solid transparent;
    color: var(--accent-ink);
    font-size: 0.56rem;
    font-weight: 800;
    line-height: 1;
}

.board-mark.waiting,
.board-cell.waiting {
    background: var(--warn);
    border-color: var(--warn);
}

.board-mark.failed,
.board-cell.failed {
    background: var(--err);
    border-color: var(--err);
}

.board-mark.working,
.board-cell.working {
    background: var(--accent);
    border-color: var(--accent);
}

.board-mark.stopped,
.board-cell.stopped {
    background: transparent;
    border-color: var(--muted);
}

.board-mark.done,
.board-cell.done {
    background: var(--done-cell);
    border-color: var(--done-cell);
}

/* 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: 10px;
    padding: 14px 16px 10px;
    border-bottom: 1px solid var(--line);
}

.board-states {
    display: flex;
    gap: 2px;
    height: 10px;
}

.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(--done-cell);
}

.board-state.dim {
    opacity: 0.25;
}

.board-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
}

.board-filter {
    position: relative;
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 2px 0 5px;
    font-size: 0.76rem;
    color: var(--muted);
    transition: color var(--t-hover) var(--ease-out);
}

.board-filter:hover,
.board-filter.on {
    color: var(--text);
}

.board-filter.on::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--accent);
}

.board-filter .board-mark {
    width: 9px;
    height: 9px;
}

.board-filter-count {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.board-filter.waiting .board-filter-count {
    color: var(--warn);
}

.board-filter.failed .board-filter-count {
    color: var(--err);
}

.board-filter.working .board-filter-count {
    color: var(--accent);
}

.board-filter.stopped .board-filter-count {
    color: var(--muted);
}

.board-filter.done .board-filter-count {
    color: var(--ok);
}

.board-body {
    flex: 1;
    min-height: 0;
    display: flex;
}

.board-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.board-map {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 4px 16px 12px;
}

.board-empty {
    padding: 1.2rem 0;
    color: var(--muted);
    font-size: 0.85rem;
}

/* A session: its title and how its subagents are, then a square for each. */
.board-row {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 14px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
    transition: opacity var(--t-fade) var(--ease-almost);
}

.board-row.dim {
    opacity: 0.4;
}

.board-session {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
    text-align: left;
}

.board-session-title {
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 7px;
}

.board-session-name {
    min-width: 0;
    font-size: 0.8rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--t-hover) var(--ease-out);
}

.board-session:hover .board-session-name {
    color: var(--accent);
}

.board-summary {
    padding-left: 14px;
    font-size: 0.66rem;
    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 {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 3px;
    padding-top: 2px;
}

/* A session's finished subagents left off the board, counted: "+12". */
.board-older {
    align-self: center;
    margin-left: 3px;
    color: var(--muted);
    font-size: 0.7rem;
}

.board-cell {
    width: 18px;
    height: 18px;
    display: grid;
    place-items: center;
    border: 1px solid transparent;
    color: var(--accent-ink);
    font-size: 0.58rem;
    font-weight: 800;
    line-height: 1;
    outline-offset: 1px;
    transition: opacity var(--t-fade) var(--ease-almost);
}

.board-cell:hover {
    outline: 1px solid var(--body);
}

.board-cell.on {
    outline: 2px solid var(--text);
    outline-offset: 1px;
}

.board-cell.dim {
    opacity: 0.15;
}

/* 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 16px;
    border-top: 1px solid var(--line);
    background: var(--o-bg-dark);
    font-size: 0.72rem;
    white-space: nowrap;
    overflow: hidden;
}

.board-status .board-mark {
    width: 8px;
    height: 8px;
}

.board-status-name {
    font-weight: 600;
    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: 310px;
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 14px 16px;
    border-left: 1px solid var(--line);
    overflow-y: auto;
}

.board-needs {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.board-needs .label {
    margin: 0 0 2px;
}

.board-needs-count {
    color: var(--warn);
}

.board-need {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr);
    align-items: center;
    gap: 0 8px;
    padding: 6px 8px;
    text-align: left;
    border: 1px solid transparent;
    transition: background-color var(--t-hover) var(--ease-out);
}

.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: 0.8rem;
    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: 0.66rem;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-detail {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

.board-detail-head {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.board-detail-name {
    min-width: 0;
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-detail-state {
    flex: none;
    margin-left: auto;
    font-size: 0.72rem;
}

.board-detail-state.waiting {
    color: var(--warn);
}

.board-detail-state.failed {
    color: var(--err);
}

.board-detail-state.working {
    color: var(--accent);
}

.board-detail-state.stopped {
    color: var(--muted);
}

.board-detail-state.done {
    color: var(--ok);
}

.board-facts {
    display: grid;
    grid-template-columns: 62px minmax(0, 1fr);
    gap: 7px 10px;
    font-size: 0.78rem;
}

.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;
}

.board-link:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

.board-when {
    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 {
    color: var(--err);
    overflow-wrap: anywhere;
}

.board-detail .agent-chip {
    align-self: flex-start;
}

.board-actions {
    display: flex;
    gap: 6px;
}

.board-actions .button {
    padding: 0.3rem 0.65rem;
    font-size: 0.82rem;
}

.board-stop:hover {
    border-color: var(--err);
    color: var(--err);
}

/* 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: 0 12px 16px;
}

/* 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(--line);
}

.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 {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 0;
}

.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 {
    gap: 4px;
    padding-top: 0;
}

.board.phone .board-cell {
    width: 36px;
    height: 36px;
    font-size: 0.72rem;
}

.board-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 12px calc(env(safe-area-inset-bottom) + 14px);
    background: var(--bg);
    border-top: 2px solid transparent;
    border-image: var(--active) 1;
    animation: rise-in 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: 1rem;
}

.board-bar .board-detail-state {
    margin-left: 0;
}

.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;
    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: 0.8rem;
    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 pops in at 87% from 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(var(--gap-out) + env(safe-area-inset-right));
    bottom: calc(var(--gap-out) + env(safe-area-inset-bottom));
    width: min(420px, calc(100vw - 2 * var(--gap-out)));
    height: min(
        640px,
        calc(100dvh - var(--pip-top) - var(--gap-out) - env(safe-area-inset-bottom))
    );
    z-index: 18;
    display: flex;
    flex-direction: column;
    background: var(--panel);
    border: var(--border) solid transparent;
    border-image: var(--active) 1;
    transform-origin: bottom right;
    animation: popin 0.32s var(--ease-out);
}

.pip-panel.leaving {
    animation: popout var(--t-out) linear forwards;
}

.pip-head {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.45rem 0.3rem 0.4rem 0.8rem;
    position: relative;
    border-bottom: 1px solid var(--line);
}

.pip-head .grip {
    display: none;
}

.pip-head h2 {
    margin: 0 0 0 0.2rem;
    font-size: 0.95rem;
    color: var(--text);
}

.pip-status {
    flex: 1;
    min-width: 0;
    color: var(--muted);
    font-size: 0.78rem;
    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: 0.2rem;
    font: 0.72rem var(--mono);
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pip-context .meter {
    width: 28px;
}

.pip-mark {
    display: inline-grid;
    color: var(--accent);
}

.pip-mark.working .icon,
.pip-bubble.busy .icon,
.rail-pip.lit .icon {
    animation: pulse 1.6s ease-in-out infinite;
}

.pip-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.8rem 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
}

.pip-you {
    align-self: flex-end;
    max-width: 88%;
    padding: 0.4rem 0.7rem;
    background: var(--card-2);
    border-right: 2px solid var(--accent);
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    animation: rise-in var(--t-fade) var(--ease-out);
}

.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: 0.45rem;
    color: var(--muted);
    font-size: 0.78rem;
}

.pip-tick {
    width: 1ch;
    color: var(--faint);
    text-align: center;
}

.pip-error {
    color: var(--err);
    font-size: 0.85rem;
}

/* A report from a session PiP follows: three lines until opened. */
.pip-report {
    padding: 0.2rem 0.65rem 0.45rem;
    background: var(--card);
    border: 1px solid var(--line);
    color: var(--body);
}

.pip-report-head {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    width: 100%;
    min-height: 40px;
    color: var(--accent);
    font-size: 0.72rem;
}

.pip-report-head span {
    flex: 1;
    text-align: left;
}

.pip-report-fold {
    color: var(--muted);
    transition: transform var(--t-hover) var(--ease-out);
}

.pip-report.open .pip-report-fold {
    transform: rotate(180deg);
}

.pip-report-text {
    font-size: 0.85rem;
}

/* What a webhook posted: as it came, shown once the card is open. */
.pip-report-data {
    margin: 0.4rem 0 0;
    padding: 0.4rem 0.5rem;
    max-height: 16rem;
    overflow: auto;
    background: var(--bg);
    border: 1px solid var(--line);
    font-size: 0.75rem;
    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: 0.45rem;
}

.pip-hello {
    margin: 0;
    font-size: 1.05rem;
    color: var(--text);
}

.pip-intro {
    margin: 0;
    color: var(--muted);
    font-size: 0.88rem;
}

.pip-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.35rem;
}

.pip-chip {
    min-height: 40px;
    padding: 0.35rem 0.65rem;
    border: 1px solid var(--line-strong);
    color: var(--body);
    font-size: 0.84rem;
    text-align: left;
}

.pip-chip:hover {
    border-color: var(--accent);
    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: 0.45rem;
    padding: 0.35rem 0.5rem 0.35rem 0.85rem;
    border-top: 1px solid var(--line);
    color: var(--warn);
    font-size: 0.82rem;
}

.pip-approval .button {
    min-height: 40px;
}

.pip-composer {
    display: flex;
    align-items: flex-end;
    gap: 0.25rem;
    padding: 0.4rem 0.4rem 0.45rem 0.85rem;
    border-top: 1px solid var(--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: inherit;
    line-height: 1.45;
}

/* 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-send:not(:disabled) {
    color: var(--accent);
}

.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(--panel);
    color: var(--accent);
    border: var(--border) solid transparent;
    border-image: var(--active) 1;
    animation: popin 0.32s var(--ease-out);
}

.pip-bubble.leaving {
    animation: popout var(--t-out) linear forwards;
}

.pip-dot,
.rail-news {
    position: absolute;
    width: 7px;
    height: 7px;
    background: var(--accent);
}

.pip-dot {
    top: 5px;
    right: 5px;
}

.rail-news {
    right: 8px;
    bottom: 8px;
    width: 6px;
    height: 6px;
}

.rail-pip.lit {
    color: var(--accent);
}

.rail-pip.open {
    color: var(--text);
    background: var(--hover);
}

@media (max-width: 699px) {
    .pip-panel {
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 86dvh;
        border: 0;
        border-top: 2px solid transparent;
        border-image: var(--active) 1;
        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-top: 0.75rem;
    }

    .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: 0.35rem;
    padding: 0.6rem 0.7rem;
    margin-top: 0.5rem;
    background: var(--card);
    border: 1px solid var(--line);
}

.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);
}
