/* The customer page. It shares nothing with Tether the service but the look, exactly: this page's
 * tokens are Tether's own (DESIGN.md names what each is for), and the values live only here, dark
 * first as Tether is. The layout and behaviour follow the product the slice is built from: an ask
 * box at the center, sources above a streamed answer, a thread rail and an account menu. */
:root {
  color-scheme: dark;
  /* true black everywhere a page sits (BLACK-EVERYWHERE): the chat list, groups, Needs you,
   * Archived, settings, profile, the agent pages and sheets' backdrops. Eric, 2026-10-25, of the
   * chat list: "the bg was only changed in a chat, fix the bg to be black here aswell". The raised
   * ladder below is unchanged: it was already a step up from #151515, so against true black it
   * reads as more distinct, not less, and every pairing still clears 4.5:1 (cloud/test/black-
   * everywhere.test.ts). */
  --bg: #000000;
  --side: #111111;
  --divider: #292929;
  --raised: #1f1f1f;
  --raised-2: #262626;
  --hover: #1c1c1c;
  --hover-2: #2a2a2a;
  --selected: #343434;
  --line: #2f2f2f;
  --line-2: #363636;
  --text: #f5f5f5;
  --text-2: #c1c2bf;
  --muted: #9c9c9a; /* 4.53:1 on the lightest surface under it, and more on the rest: its 12px hints need 4.5 */
  --faint: #5f5f5d;
  --shine: var(--text-2);
  --shine-peak: var(--text);
  --icon: #bebebc;
  --link: #81a6d7;
  --add: #53ca64;
  /* Code block syntax coloring (CODE-BLOCKS): muted hues for the common languages highlightCode()
   * (code-highlight.js) recognizes; comments stay --muted, nothing new. Each reads at least
   * 4.5:1 on --bg, which is what a code block's own background always is (.a-body pre, below). */
  --code-kw: #a99cf2; /* 7.59:1 on --bg */
  --code-str: #7fc995; /* 9.30:1 on --bg */
  --code-num: #d6a35e; /* 8.05:1 on --bg */
  --code-key: #7dc0d6; /* 9.03:1 on --bg */
  --accent: #e07d5a;
  --on-accent: #151515;
  /* the A of Align's mark, in the brand's own two inks: the icon's on charcoal (align-icon.svg), and
   * align-icon-light.svg's on light; its amber character and eyes are the same in both */
  --mark-ink: #f6f6f4;
  --blue: #2c7cda;
  --ring: #3f77c1;
  --track: #333333;
  --pro: #a096eb; /* the one violet: what a paid plan opens. Used for the picker's plan badges. */
  --pro-tint: rgba(160, 150, 235, 0.16);
  /* Confidence levels for a sourced answer's claims: the page's own semantic hues, never new
   * colors. Only the underline style and the level words carry a level; the colors are never
   * the only signal. The -tx variants are the same hues darkened to text contrast where the
   * accent fails AA on the page (the light theme), used only where a level word must be read. */
  --cl-high: var(--add);
  --cl-med: var(--warn);
  --cl-low: var(--err);
  --cl-high-tx: var(--add);
  --cl-med-tx: var(--warn);
  --cl-low-tx: #f0695d; /* --err on the raised surface reads 4.45:1; this lighter red reads 5.4 */
  --accent-tx: var(--accent);
  --warn: #d6a03d;
  --err: #e5534b;
  --danger: #c04742;
  --on-danger: #ffffff;
  --chip: #2d2d2d;
  --hollow: #4f4f4f;
  --shadow: 0 14px 44px rgba(0, 0, 0, 0.6), 0 2px 6px rgba(0, 0, 0, 0.4);
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  /* The answers' reading face, as the Claude app's chat draws them: a serif at a reading size.
   * "New York" is the Mac's own; the stack falls through system serifs where none is installed. */
  --serif: "New York", "Iowan Old Style", Charter, Georgia, "Times New Roman", serif;
  --col: 760px;
  /* A bot's mark (239): its colors are its identity, the same in both themes, sampled from the
   * character picker Eric's screenshot shows; the eyes are one near-black on every color. The edge
   * is the mark's outline, drawn only where a white mark would vanish into a white page. */
  --char-white: #fefefe;
  --char-brown: #8c6641;
  --char-red: #e94045;
  --char-orange: #eb702d;
  --char-amber: #f09c39;
  --char-green: #5bc57a;
  --char-teal: #54b9a7;
  --char-blue: #3c81f6;
  --char-purple: #885bf4;
  --char-pink: #e94699;
  --char-gray: #777777;
  --char-eye: #131313;
  --char-edge: transparent;
  /* the cards of a bot's page: a step up from the page, as the screenshots' grouped rows are */
  --card: var(--raised);
  /* A chat's messages (268), as the reference draws them: the person's in the accent blue with
   * white words (4.8:1), the bot's and other people's on a neutral step up from the page. The same
   * blue is the composer's send and the scroll-to-latest button. */
  --msg: #2a6fd6;
  --on-msg: #ffffff;
  --bub-in: #262626;
  /* A one-on-one chat's own background (#thread-view, #home; ONE-ON-ONE-LOOK) was true black while
   * the rest of the page stayed the muted --bg; now that --bg is black everywhere (BLACK-EVERYWHERE),
   * a group's and the list's own --bg already is what ONE-ON-ONE-LOOK carved out, so --thread-bg
   * folds into that one token instead of a second hardcoded value, kept only because #thread-view,
   * #home, .chat-head and .list-theme still read it by name. Light's own --thread-bg is --bg too. */
  --thread-bg: var(--bg);
  /* html, body and .col (BLACK-EDGES-WEB): --bg. Before BLACK-EVERYWHERE this needed an override
   * while a one-on-one chat or #home showed, so the ancestors painting a chat's rubber-band
   * overscroll matched --thread-bg's black rather than the page's then-grey --bg; with --thread-bg
   * now --bg itself there is nothing left for the override to switch between, so it's gone and
   * --root-bg is unconditionally --bg, kept only for the names below that still read it. */
  --root-bg: var(--bg);
  /* the floating glass of a chat's head and composer: the page's own surface, translucent and
   * blurred over what scrolls under it, with a hairline edge */
  --glass: rgba(38, 38, 38, 0.62);
  --glass-line: rgba(255, 255, 255, 0.09);
  --glass-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
  --knob: #fafafa;
  /* the agent bar's height above the bottom safe area while 269's bar shows (spaces.js sets it on
   * #app); the floating composer and the scroll-to-latest button sit above it */
  --agent-bar-h: 0px;
  /* the air the message-hold's three surfaces keep between them, the small gap the design uses */
  --hold-gap: 8px;
}
@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;
    --bg: #ffffff;
    --mark-ink: #151515;
    --side: #f7f7f6;
    --divider: #e6e6e4;
    --raised: #ffffff;
    --raised-2: #f1f1f0;
    --hover: #efefee;
    --hover-2: #ebebea;
    --selected: #e6e6e4;
    --line: #e3e3e1;
    --line-2: #d6d6d3;
    --text: #1a1a1a;
    --text-2: #3b3b39;
    --muted: #676764; /* 4.54:1 on the darkest surface under it, and more on the rest */
    --faint: #a8a8a5;
    --shine: var(--text);
    --shine-peak: color-mix(in srgb, var(--text) 30%, white);
    --icon: #5e5e5c;
    --link: #2d6cc0;
    --add: #1e9a44;
    --code-kw: #5e42cc; /* 6.72:1 on --bg */
    --code-str: #188046; /* 4.98:1 on --bg */
    --code-num: #9c5e15; /* 5.22:1 on --bg */
    --code-key: #176882; /* 6.29:1 on --bg */
    --accent: #d97757;
    --on-accent: #241914;
    --ring: #3f77c1;
    --track: #e4e4e2;
    --pro: #4a3aa7;
    --pro-tint: rgba(74, 58, 167, 0.1);
    --cl-high-tx: #0f7a33; /* --add on white reads 3.65:1; this darkened green reads 5.45 */
    --cl-med-tx: var(--warn);
    --cl-low-tx: var(--err);
    --accent-tx: #b3562b; /* --accent on white reads 3.12:1; this darkened accent reads 4.9 */
    --warn: #9a6b14;
    --err: #c92a2a;
    --danger: #c04742;
    --on-danger: #ffffff;
    --chip: #f0f0ef;
    --hollow: #b8b8b5;
    --shadow: 0 14px 44px rgba(20, 20, 20, 0.14), 0 2px 6px rgba(20, 20, 20, 0.08);
    /* on a white page a white mark keeps its edge and a hair of tone, or it would vanish */
    --char-white: #f6f6f4;
    --char-edge: rgba(20, 20, 20, 0.22);
    --card: #f3f3f2;
    --bub-in: #efefee;
    --thread-bg: var(--bg);
    --glass: rgba(250, 250, 249, 0.72);
    --glass-line: rgba(20, 20, 20, 0.08);
    --glass-shadow: 0 8px 28px rgba(20, 20, 20, 0.12);
    --hold-gap: 8px;
  }
}

* { box-sizing: border-box; }
html, body { height: 100%; background: var(--root-bg); }
body {
  margin: 0;
  color: var(--text);
  font: 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}
button, input, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
[hidden] { display: none !important; }
a { color: var(--link); }
:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 4px; }
::selection { background: rgba(63, 119, 193, 0.45); }

/* Icons are the inline SVG set in app.js (ICON), one stroke weight, sized to the text they sit with. */
svg.i { width: 16px; height: 16px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ic { display: inline-flex; }
.ic svg.i { display: block; }
/* the sign-in providers' marks: filled glyphs, one color, in the page's tokens, never a brand
 * color the page doesn't use. Sized like the icon set, a step larger than the 16px icons so a
 * mark reads as a mark. */
svg.pm { width: 17px; height: 17px; flex-shrink: 0; fill: currentColor; display: block; }

/* ---------- shell: the chat list and the open chat (239) ---------- */
/* A messenger's two panes: the list of chats with bots at the left, the open chat, a bot's page or
 * the usage at the right. Up to 760px wide one pane shows at a time (the phone block at the end).
 * The list column is 420px, not 360: the head holds five 44px controls (search, new, account and the
 * Invite friends button beside the title, which never shrinks), and 360 cannot carry them without
 * cutting the title short. The 390 phone width is unaffected: the phone block makes the shell one pane. */
.app { position: relative; height: 100dvh; }
.shell { display: grid; grid-template-columns: 420px minmax(0, 1fr); height: 100dvh; }
.rail {
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  background: var(--bg); border-right: 1px solid var(--divider);
}
.col { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--root-bg); }
.main { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.cl-spacer { flex: 1; }

.wordmark {
  display: inline-flex; align-items: baseline; gap: 0.32em;
  font-size: 15px; font-weight: 650; letter-spacing: -0.01em;
  color: var(--text);
}
/* Align's ribbon A, the icon's own drawing (index.html's #align-a), standing on the name's baseline
 * at its cap height: a baseline-aligned svg sits on its bottom edge, and 0.72em is the system
 * sans's capital at the name's weight, so the A reads as the name's first letter, not a badge. The
 * outer svg has no viewBox of its own: the symbol's maps the drawing into this box, and a second one
 * would shift it by the crop's origin (190, 169), lifting the A 3 px off the baseline */
.wm-a { width: auto; height: 0.72em; aspect-ratio: 644 / 663; flex: none; color: var(--mark-ink); overflow: visible; }
.wm-name { white-space: nowrap; }

/* The round buttons of a messenger's bars: the account's avatar, search, +, back and more. Each is
 * a 44px touch target on a raised disc with a hairline rim, as Eric's screenshots draw them. */
.round-btn, .avatar-btn {
  width: 44px; height: 44px; flex: none; padding: 0;
  display: grid; place-items: center;
  border: 1px solid var(--line-2); border-radius: 50%;
  background: var(--raised-2); color: var(--text);
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out;
}
.round-btn svg.i { width: 20px; height: 20px; stroke-width: 1.9; }
@media (hover: hover) { .round-btn:hover, .avatar-btn:hover { background: var(--selected); } }
.round-btn:active, .avatar-btn:active { transform: scale(0.94); }
.round-btn[aria-expanded="true"], .avatar-btn[aria-expanded="true"] { background: var(--selected); }
.avatar-letter { font-size: 17px; font-weight: 600; color: var(--text-2); line-height: 1; }

.cl-head {
  display: flex; align-items: center; gap: 10px;
  padding: max(14px, env(safe-area-inset-top)) 16px 10px;
}
/* The list's title, "Align Cloud", as Tether's Code list opens with "Code" (host .side-head-title):
 * the system serif at 26px, regular, 16px from the edge, centered in the head's 44px row, with the
 * page's own search, + and account at the row's right. Like the Code list's, it stays above the
 * list as the list scrolls and never shrinks. */
.cl-title {
  flex: 0 1 auto; min-width: 0; margin: 0;
  font-family: ui-serif, var(--serif); font-size: 26px; font-weight: 400; line-height: 44px; letter-spacing: -0.01em;
  color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The chat filters (CHAT-FILTERS): a row of chips under the head, like WhatsApp's filter bar; one
 * is selected at a time, All by default, and the choice is the person's own, remembered on this
 * browser. The row only shows once it earns its place (CHAT-FILTERS-GATE, app.js filtersEarnPlace):
 * 5 or more rows in the list, or already more than one of Groups, People and Agents among them;
 * short of that there is just the list. The row sits above the list's own scroller with the head,
 * so nothing moves on a pull. At a phone width it scrolls sideways, without wrapping and without a
 * scrollbar, and the selected chip is kept in view. The selected chip is the page's selected-pill
 * style (an accent tint with accent text, as the sources toggle's on state), the others neutral. A
 * row with more chips than its width fades at the edge it can still scroll toward (`.can-scroll-
 * right`, app.js updateFilterFade), gone once scrolled to the end or when it never overflowed. */
.cl-filters {
  display: flex; align-items: center; gap: 8px;
  padding: 0 16px 10px;
  overflow-x: auto; scrollbar-width: none;
  /* the chips' long-press menu (a WhatsApp-style hold) must survive the scroll row: claim the
     horizontal axis so WebKit never cancels the pointer of a stationary press (CUSTOM-LISTS) */
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  -webkit-mask-image: none; mask-image: none;
}
.cl-filters.can-scroll-right {
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 28px), transparent calc(100% - 4px));
  mask-image: linear-gradient(to right, black calc(100% - 28px), transparent calc(100% - 4px));
}
.cl-filters::-webkit-scrollbar { display: none; }
.cl-filters .cl-filter {
  flex: none; height: 44px; padding: 0 16px;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--muted);
  font-size: 14.5px; font-weight: 550;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  transition: color 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out, transform 140ms ease-out;
}
.cl-filters .cl-filter:not(:disabled):active { transform: scale(0.97); }
.cl-filters .cl-filter.selected {
  color: var(--accent-tx); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 13%, transparent);
}
@media (hover: hover) {
  .cl-filters .cl-filter:not(.selected):hover { background: var(--hover); color: var(--text-2); }
  .cl-filters .cl-filter.selected:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}
.cl-search {
  display: flex; align-items: center; gap: 8px;
  margin: 0 16px 8px; padding: 0 4px 0 12px; height: 44px;
  background: var(--raised); border: 1px solid var(--line); border-radius: 12px;
}
.cl-search:focus-within { border-color: var(--ring); }
.cl-search .ic { color: var(--muted); }
.cl-search input {
  flex: 1; min-width: 0; height: 100%; border: 0; outline: none; background: transparent;
  font-size: 16px; color: var(--text);
}
.cl-search input::placeholder { color: var(--faint); }
.cl-search input::-webkit-search-cancel-button { -webkit-appearance: none; }
.cl-cancel { flex: none; height: 40px; padding: 0 10px; border: 0; background: none; color: var(--link); font-size: 15px; border-radius: 8px; }
@media (hover: hover) { .cl-cancel:hover { background: var(--hover); } }
/* A custom list theme's ink (CUSTOM-LISTS): one class per theme, holding --lc-ink, the accent a
   themed conversation's own messages and a chip's dot take. The values are hand-picked to hold
   white text in both themes, as the page's own accent does; blue is the page's accent and gets no
   class. The chips carry the class too, so a list lights in its theme before it is ever opened. */
.lc-ink-green { --lc-ink: #1a8f4f; }
.lc-ink-teal { --lc-ink: #0f7f9c; }
.lc-ink-orange { --lc-ink: #c15406; }
.lc-ink-pink { --lc-ink: #c72d79; }
.lc-ink-purple { --lc-ink: #7c45d8; }
.lc-ink-red { --lc-ink: #c93a3a; }
.lc-ink-slate { --lc-ink: #5b6b80; }
/* The + that opens the new-list sheet and a list chip's theme dot (CUSTOM-LISTS): the + is an
   accent plus mark alone, like the new-list chip of a messenger, and the dot is the theme's ink.
   The custom chips are injected into a span that only groups them, never draws a box. */
.cl-custom { display: contents; }
.cl-filters .cl-filter.plus { padding: 0 15px; }
.cl-filters .cl-filter.list-chip { display: inline-flex; gap: 7px; }
.cl-filters .cl-filter .lc-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--lc-ink, var(--msg)); flex: none; }

/* renderThreads() always rebuilds the whole list (box.textContent = "" then fresh rows), never patches it in
 * place, so the browser's own scroll anchoring - meant for content that shifts incrementally - has nothing
 * useful to anchor to here and only gets in the way: toggling the pane hidden and back (WEB-CODE-CHIP, a chat's
 * own frame covering the list) let it nudge #threads's scrollTop a few px off, once the top lines (LIST-TOP-ROWS)
 * changed how tall the list is above the fold. The list already keeps its own scrollTop across a rebuild (the
 * same element, same content, same height) with no help needed; off here, that holds exactly. */
.chat-list { flex: 1; min-height: 0; overflow-y: auto; overflow-anchor: none; padding: 2px 8px 18px; display: flex; flex-direction: column; gap: 2px; }
/* Inside the app's web view no gesture may zoom the page: a pinch, a double tap or the focus zoom
 * would leave the person stuck in some other scale (LIST-SCROLL-MINIMIZES). The clamp is on the
 * web view's scroll view, every input is at least 16px, and the viewport meta is locked with
 * maximum-scale=1; touch-action: manipulation additionally takes away the double-tap zoom and its
 * tap delay, everywhere, while the website in a phone browser keeps its pinch zoom (no data-tether-app). */
[data-tether-app], [data-tether-app] * { touch-action: manipulation; }
/* Under the app's tab bar (262b): a pane that scrolls to the screen's bottom ends clear of the bar, so
 * its last row rests above the glass while the rest pass under it. An open chat's composer pads itself. */
[data-edges] .chat-list { padding-bottom: calc(env(safe-area-inset-bottom) + 18px); }
[data-edges] .col:has(> #composer-bar[hidden]) > .main { padding-bottom: env(safe-area-inset-bottom); }
/* and what scrolls up passes under the page's own background behind the clock, never fully opaque,
 * even right behind the status bar, and easing out smoothly over the whole band below it - never a
 * flat solid stretch and never a hard step partway down (TOPBAR-FADE-NO-SOLID, Eric 2026-10-26, of
 * TOPBAR-FADE-SOFT's own band, still solid behind the inset: "No it shouldnt be solid at any point
 * fix it"; the original ask, TOPBAR-FADE-SOFT, Eric: "The gradient at the top is strict switching
 * from transparent to solid it should change much softer it changes at like the bottom 10% instead
 * of across the 100% space vertically fix it"). --root-bg, true black on every view
 * (BLACK-EVERYWHERE), never a grey patch over its own black (BLACK-EDGES-WEB): the eased stops stay
 * var(--root-bg) at falling alpha (color-mix toward transparent), never a different hue (never the
 * "fully opaque to the bar's edge" 85%-band ghost text TOPBAR-FADE-2 rejected). The easing stops sit
 * at fixed 0/25/50/75/100% of the band's own height, not at fixed pixel offsets from the inset, so a
 * tall status-bar inset (Dynamic Island, ~59px) can't crowd the whole ease into the band's last
 * quarter: the 200px of fade below the inset keeps the inset itself under a quarter of the band's
 * total height for every real device. The top stop, at the band's very top (behind the status bar
 * too), is 80% alpha at most, never 100%, and every later stop is strictly lower, down to 0 only at
 * the band's own bottom. */
[data-edges] body::before {
  content: ""; position: fixed; top: 0; left: 0; right: 0; z-index: 30; pointer-events: none;
  height: calc(env(safe-area-inset-top) + 200px);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--root-bg) 80%, transparent) 0%,
    color-mix(in srgb, var(--root-bg) 53%, transparent) 25%,
    color-mix(in srgb, var(--root-bg) 31%, transparent) 50%,
    color-mix(in srgb, var(--root-bg) 14%, transparent) 75%,
    transparent 100%
  );
}
/* Under the app's own top bar (ALIGN-TOPBAR) and a chat's own head (293), where the app shows no edge
 * effect of WebKit's (CloudWebView.swift), the same eased band: never fully opaque, not even behind
 * the status bar's own inset, and a row eases in smoothly the whole way down, never a hard edge. No
 * band of another color and no line. The list's band and a chat's are the same rule (TOPBAR-FADE-SOFT:
 * they always matched by sharing body::before, and this slice keeps them matched). */
[data-edges][data-topbar] body::before {
  height: calc(env(safe-area-inset-top) + 200px);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--root-bg) 80%, transparent) 0%,
    color-mix(in srgb, var(--root-bg) 53%, transparent) 25%,
    color-mix(in srgb, var(--root-bg) 31%, transparent) 50%,
    color-mix(in srgb, var(--root-bg) 14%, transparent) 75%,
    transparent 100%
  );
}
/* The app's native Search and + (262): in the Chats tab where the app draws them on the tab bar, the
 * list's own buttons go, and on a phone the list scrolls the document instead of its own box, so the
 * tab bar follows the scroll (it minimizes on the way down). The head stays pinned, under the clock.
 * The new chat menus open upward from above the app's bar and its Search accessory: the page's bottom
 * safe area is the home indicator's alone, and the accessory's top stands about 104px over it (262c). */
[data-native-bar] #search-btn, [data-native-bar] #new-btn { display: none; }
/* The app's chat chrome (293): on iOS 26 and later the app draws a chat's head and composer in native
 * Liquid Glass, and the page hides its own. The app pads the web view's safe area by its top bar and its
 * composer, so the conversation already clears them; the menus of its + and Invite open from these
 * anchors, at the composer's top left and under the top bar's right. */
[data-native-chrome] #topbar, [data-native-chrome] #ask-form, [data-native-chrome] #composer-note, [data-native-chrome] #usage-notice { display: none; }
/* the page's own head and composer take no room: the safe area already holds the app's bars */
[data-native-chrome] #thread-view .t-inner, [data-native-chrome] #group-view .t-inner {
  padding-top: calc(env(safe-area-inset-top) + 8px); padding-bottom: calc(env(safe-area-inset-bottom) + 16px);
}
[data-native-chrome] #home { padding-top: calc(env(safe-area-inset-top) + 8px); padding-bottom: calc(env(safe-area-inset-bottom) + 16px); }
[data-native-chrome] .composer-bar { padding-bottom: 0; }
/* JUMP-BUTTON: .to-latest's "bottom: calc(100% + 10px)" below sits it 10px above #composer-bar's own
 * top, but the rule just above collapses that box to no height once #ask-form inside it is hidden, so
 * "100%" collapsed too and the chevron landed at the screen's very bottom, behind the app's bar or
 * composer glass (Eric's 2026-10-25 screenshot: "Fix the down arrow bug behind the liquid glass"). It
 * sits 10px above the safe area instead, the same idiom as .chrome-anchor.plus below: that inset is
 * exactly the composer's measured top, the bar's own share dropping out while the keyboard is up. */
[data-native-chrome] .to-latest { bottom: calc(env(safe-area-inset-bottom) + 10px); }
.chrome-anchor { display: none; }
[data-native-chrome] .chrome-anchor { display: block; position: fixed; width: 44px; height: 0; pointer-events: none; }
[data-native-chrome] .chrome-anchor.plus { left: 16px; bottom: env(safe-area-inset-bottom); }
[data-native-chrome] .chrome-anchor.invite { right: 16px; top: env(safe-area-inset-top); }
/* The app's shared top bar (ALIGN-TOPBAR): on iOS 26 and later the owner's three tabs, Calls, Chats
 * and Apps, share one native bar, the account's avatar at top leading, the tab's name centered and,
 * on the Chats list only, Invite and Tether at the right. The page then hides its own title rows and
 * head buttons: its lists' names (the Chats "Align Cloud", Calls and Apps titles) are the bar's own
 * center, and the account button is the bar's avatar. The head collapses to no height so no row sits
 * under the bar; the invite and Tether buttons are drawn invisibly in the bar's trailing corner, and
 * keep reporting their frames (postNativeGift/postNativeTether gate on hidden, never on these rules),
 * so the app's own trailing buttons only ever appear where the page would draw them, to the guest or
 * owner it would draw them for, and never over anything. The website and older builds keep the page's
 * own buttons and titles. */
[data-topbar] .cl-head { height: 0; padding: env(safe-area-inset-top) 16px 0; }
[data-topbar] #cl-title, [data-topbar] .calls-title, [data-topbar] .apps-title,
[data-topbar] #account, [data-topbar] #search-btn, [data-topbar] #new-btn { display: none; }
[data-topbar] #invite-home-btn, [data-topbar] #tether-home-btn {
  position: absolute; right: 0; top: 0; width: 44px; height: 44px;
  margin: 0; opacity: 0; pointer-events: none;
}
.new-anchor { display: none; }
[data-native-bar] .new-anchor {
  display: block; position: fixed; right: 20px; bottom: calc(env(safe-area-inset-bottom) + 112px);
  width: 44px; height: 0; pointer-events: none;
}
/* Pull to reload's spinner (this slice): only the app's list summons it (pullToReload, app.js), so it
 * is invisible at rest; each pull drives its opacity and rotation inline, and the ring is the page's
 * own tokens, so both themes carry it. */
#pull-spin { display: grid; place-items: center; pointer-events: none; opacity: 0; }
#pull-spin i {
  width: 22px; height: 22px; box-sizing: border-box; border-radius: 50%;
  border: 2px solid var(--faint); border-top-color: var(--ring); background: transparent;
}
/* The pinned list top is one unit under the app's bar (LIST-SCROLL-MINIMIZES): the head, the filter
   chips and the search ride in #cl-pin, which never leaves the top of the app's list, so the document
   below it can be the real scroller and the web view's own scroll view, panned by the person's finger,
   can make the app's glass tab bar fall away on a downward pull (tabBarMinimizeBehavior, OwnerRoot's
   ChatsBar). The wrapper is an id, never the .cl-pin class (that is a row's pin indicator). On the
   website the wrapper is display: contents, so it changes nothing there. */
#cl-pin { display: contents; }
@media (max-width: 760px) {
  /* The agent list's column under the app's bar (LIST-SCROLL-MINIMIZES): the head, the chips and the
   * search are pinned as one sticky unit (#cl-pin), and the rows ride the document beneath them, the
   * way the list read before 60b2ddb8 (Eric, 2026-10-09: "when I scroll the searchbar doesnt move down
   * like it did before, fix that"): the document is never locked, so the web view's own scroll view pans
   * under the person's finger and the glass tab bar can minimize on a downward pull. The web view bounces
   * nothing of its own (ios CloudWebView.swift, alwaysBounceVertical off), so a held pull at the top or
   * an overscroll at the bottom cannot move the pinned unit either: the document simply has no travel
   * past its ends (Eric: "I can still scroll past the topbar fix that it should be seperate from the
   * agent list"). Nothing is fixed or transformed, and no phantom exists: the rows scroll the document,
   * and only the pinned unit is sticky. */
  [data-native-bar] .app.pane-list, [data-native-bar] .app.pane-list .shell { height: auto; min-height: 100dvh; }
  /* the rows are in the document's flow, never their own box: the web view pans them directly */
  [data-native-bar] .app.pane-list .chat-list { flex: none; overflow: visible; padding-bottom: calc(env(safe-area-inset-bottom) + 24px); }
  /* The pinned head, chips and search (this slice): the one unit that the rows pass under is #cl-pin,
   * stuck to the top, its glass band and hairline drawn over the rows only once the list has scrolled,
   * never at rest, and gone the moment the person returns to its top (Eric, 2026-10-08: "The topbar
   * should work like claudes for some reason our topbar for the agent list scrolls fix that"). The band
   * uses the page's own glass tokens, so both themes are covered. */
  [data-native-bar] .app.pane-list #cl-pin { display: block; position: sticky; top: 0; z-index: 3; }
  [data-native-bar] .app.pane-list #cl-pin::before, [data-native-bar] .app.pane-list #cl-pin::after {
    content: ""; position: absolute; right: 0; left: 0; z-index: -1; pointer-events: none;
    opacity: 0; transition: opacity 150ms ease-out;
  }
  [data-native-bar] .app.pane-list #cl-pin::before {
    top: 0; bottom: 0;
    background: var(--glass);
    -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  }
  [data-native-bar] .app.pane-list #cl-pin::after { bottom: 0; height: 1px; background: var(--glass-line); }
  /* the band's state lives on the rail and only the document's own scroll sets it (see railBand, app.js) */
  [data-native-bar] .app.pane-list .rail[data-scrolled] #cl-pin::before,
  [data-native-bar] .app.pane-list .rail[data-scrolled] #cl-pin::after { opacity: 1; }
  /* under the app's shared top bar (ALIGN-TOPBAR) the bar's edge is the page's fade (body::before), as the Code
   * page's, so the pinned unit draws no band or line of its own over the rows */
  [data-native-bar][data-topbar] .app.pane-list #cl-pin::before,
  [data-native-bar][data-topbar] .app.pane-list #cl-pin::after { content: none; }
  /* the head keeps its small gap under it; the chips and the search are plain blocks in the same unit */
  [data-native-bar] .app.pane-list .cl-head { position: static; padding-bottom: 6px; }
  /* the search stays an ordinary block in the unit, never over the rows */
  [data-native-bar] .app.pane-list .cl-search { position: static; }
  /* pull to reload's spinner rides just under the pinned unit, over nothing until a pull summons it;
   * its opacity and ring follow the pull's distance (pullToReload, app.js), never a timer. It is drawn
   * inside the pinned unit, hung from its bottom edge, so it cannot be carried off by the document. */
  [data-native-bar] .app.pane-list #cl-pin #pull-spin {
    position: absolute; z-index: 4; left: 0; right: 0; top: 100%;
  }
}
.cl-row {
  display: flex; align-items: center; gap: 14px;
  width: 100%; min-height: 76px; padding: 10px 10px;
  border: 0; border-radius: 16px; background: transparent;
  text-align: left; color: var(--text);
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out;
}
@media (hover: hover) { .cl-row:not(.current):hover { background: var(--hover); } }
.cl-row:active { transform: scale(0.985); }
.cl-row.current { background: var(--selected); }
/* the list's own compact top lines (LIST-TOP-ROWS), Needs you and Archived (app.js listTopRow()): WhatsApp's
 * own shape for them, about half a chat row's height (40px against .cl-row's 76px), flat (no rounded card) with a
 * hairline under it, never the big tinted disc a project's or a bot's own mark wears (PROJECTS-AS-AGENTS). The
 * icon sits in the same leading column a mark would (52px, so the label lines up with the chat rows under it),
 * small and line-only, no filled circle. */
.cl-row.cl-compact { min-height: 40px; padding: 8px 10px; gap: 12px; border-radius: 0; border-bottom: 1px solid var(--line); }
.cl-compact-ic { flex: none; width: 52px; display: grid; place-items: center; color: var(--muted); }
.cl-compact-ic svg.i { width: 16px; height: 16px; }
.cl-compact .cl-name { font-size: 15px; font-weight: 500; letter-spacing: normal; color: var(--text-2); }
.cl-compact-trail { flex: none; margin-left: auto; display: inline-flex; align-items: center; color: var(--muted); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.cl-compact-trail svg.i { width: 16px; height: 16px; color: var(--faint); }
/* the owner's coding chat on the website (WEB-CODE-CHIP): his Code page fills the pane, with its own head and composer */
.code-view { height: 100%; }
.code-frame { display: block; width: 100%; height: 100%; border: 0; background: var(--bg); }
.code-note { display: grid; justify-items: center; gap: 12px; padding: 64px 24px; color: var(--muted); font-size: 14px; line-height: 1.5; text-align: center; }
.code-note .e-t { margin: 0; font-weight: 600; color: var(--text-2); }
/* a project row's state (CODE-CHIP-STATES, PROJECTS-AS-AGENTS) is the badge at its line's end, where an agent chat's
 * unread count sits (.cl-unread, below): an unread reply the same dot; waiting on you a pill in --warn, working an
 * outlined one in --muted, each with the Code page's dot (breathing while it works) and its word; an idle row has none */
.cl-unread.code-state:not(.dot) { display: inline-flex; align-items: center; gap: 5px; padding: 0 9px 0 8px; }
.cl-unread.code-state.ask { background: var(--warn); color: var(--bg); }
.cl-unread.code-state.run { background: transparent; color: var(--muted); box-shadow: inset 0 0 0 1px var(--line-2); }
.code-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.code-state.run .code-dot { animation: skpulse 1.2s ease-in-out infinite; }
.code-row.ask .cl-prev-text { color: var(--text-2); }
@media (prefers-reduced-motion: reduce) { .code-state.run .code-dot { animation: none; } }
.cl-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cl-top { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
/* the name and, where its bot has several chats, the chat's title inside the same span: the title
 * is what gives way, never the name (lesson L37) */
.cl-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 16.5px; font-weight: 600; letter-spacing: -0.01em; }
.cl-sub { margin-left: 6px; font-weight: 450; color: var(--muted); font-size: 15px; }
.cl-time { flex: none; font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.cl-prev { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 15px; color: var(--muted); }
.cl-prev .ic { flex: none; color: var(--muted); }
.cl-prev .ic svg.i { width: 15px; height: 15px; }
.cl-prev-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-list .empty { padding: 22px 14px; color: var(--muted); font-size: 14px; line-height: 1.5; text-align: center; }
.chat-list .empty .e-t { font-weight: 600; color: var(--text-2); }
/* a list that never loaded says so, with Try again under its line (CHAT-LOAD) */
.chat-list .empty .btn { margin-top: 12px; }
.chat-list .sk { height: 76px; margin: 2px 0; border-radius: 16px; background: var(--hover); animation: skpulse 1.6s ease-in-out infinite; }
@keyframes skpulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .chat-list .sk { animation: none; } }

/* A bot's mark (239): its shape in its color with two eyes, drawn by app.js characterSvg as SVG, at
 * the size its place gives it. */
.mark { position: relative; display: inline-grid; place-items: center; flex: none; width: 48px; height: 48px; }
.mark svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* a bot's 3D avatar (275): the library's image, trimmed to its character, drawn at the mark's size */
.mark .mark-img { display: block; width: 100%; height: 100%; object-fit: contain; user-select: none; -webkit-user-drag: none; }
.mark.xs { width: 24px; height: 24px; }
.mark.sm { width: 32px; height: 32px; }
.mark.md { width: 52px; height: 52px; }
.mark.lg { width: 76px; height: 76px; }
.mark.xl { width: 132px; height: 132px; }

/* The open chat's head (268), as the reference's: it floats over the conversation, which scrolls
 * under it and fades out beneath it - --thread-bg, true black in dark mode (ONE-ON-ONE-LOOK,
 * folded into --bg itself by BLACK-EVERYWHERE, so a group's head fades the same way now; the
 * group-only override this used to need is gone). The round glass back sits at the top left (on a
 * phone, where the list is a screen away), the bot's mark large in the middle with a glass capsule
 * under it for the name and the live status line, and Invite at the top right. */
.glass {
  background: var(--glass); border: 1px solid var(--glass-line);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  box-shadow: var(--glass-shadow);
}
.chat-head {
  position: absolute; top: 0; left: 0; right: 0; z-index: 20;
  display: grid; grid-template-columns: minmax(44px, 1fr) auto minmax(44px, 1fr); align-items: start; gap: 8px;
  padding: 12px 16px 26px;
  background: linear-gradient(to bottom, var(--thread-bg) calc(100% - 22px), transparent 100%);
  pointer-events: none;
}
.chat-head > * { pointer-events: auto; }
.chat-head .back-btn { display: none; grid-column: 1; justify-self: start; }
.round-btn.glass { background: var(--glass); border-color: var(--glass-line); }
@media (hover: hover) { .round-btn.glass:hover { background: var(--selected); } }
/* A back button the app replaced with its own native Liquid Glass (this slice): out of sight but kept in
   layout, so nothing of the screen shifts, while the app draws its circle exactly where the button was.
   visibility, not opacity: the native back overlay DOES receive taps, so a hidden button must not. */
.native-hidden { visibility: hidden; }
/* The list head's Invite button under the app's native gift (GIFT-CLEANUP: Eric, 2026-10-08, "the gift icons
   only surface in the list head"): invisible the same way, but still tappable. The offset-drawn native gift can
   not promise a hit target, so the page's own button must keep receiving the person's tap, whose action opens
   the invite sheet. opacity stops short of visibility, which would also stop the tap. */
.native-gift-hidden { opacity: 0; }
/* The website's back buttons, as close to real glass as a page can draw (this slice): the page's own --glass
   look on every back button a person can reach, matching the app's native Liquid Glass, never a plain circle. */
#bp-back, #instr-back, #rt-back, #usage-back, #friends-back, #gn-back, #gi-back {
  background: var(--glass);
  border-color: var(--glass-line);
  -webkit-backdrop-filter: blur(20px) saturate(1.6);
  backdrop-filter: blur(20px) saturate(1.6);
  box-shadow: var(--glass-shadow);
}
@media (hover: hover) {
  #bp-back:hover, #instr-back:hover, #rt-back:hover, #usage-back:hover, #friends-back:hover, #gn-back:hover, #gi-back:hover {
    background: var(--selected);
  }
}
.head-bot {
  grid-column: 2; display: flex; flex-direction: column; align-items: center; min-width: 0;
  padding: 0; border: 0; border-radius: 20px; background: transparent; color: var(--text); text-align: center;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.head-bot:not(:disabled):active { transform: scale(0.97); }
.head-bot:disabled { cursor: default; }
.mark.head-mk { width: 72px; height: 72px; }
.hb-text {
  display: flex; flex-direction: column; align-items: center; min-width: 0; max-width: min(300px, calc(100vw - 132px));
  margin-top: -6px; padding: 6px 16px 7px; border-radius: 18px;
  transition: background 140ms ease-out;
}
@media (hover: hover) { .head-bot:not(:disabled):hover .hb-text { background: var(--selected); } }
.hb-name { max-width: 100%; font-size: 15px; font-weight: 650; line-height: 1.3; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-sub { max-width: 100%; font-size: 14px; line-height: 1.3; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-sub:empty { display: none; }
/* Temporary chat marker (TEMP-CHATS), like ChatGPT's: plain text beside the chat's name, never a loud badge */
.hb-temp { max-width: 100%; font-size: 12px; line-height: 1.3; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* while the bot answers, its status line breathes, the page's thinking shimmer, never a spinner */
.chat-head.busy .hb-sub {
  background: linear-gradient(90deg, var(--shine) 0%, var(--shine) 40%, var(--shine-peak) 50%, var(--shine) 60%, var(--shine) 100%);
  background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; /* design-ok: the page's thinking shimmer, its --shine tokens */
  animation: hb-shine 1.8s linear infinite;
}
@keyframes hb-shine { from { background-position: 100% 0; } to { background-position: 0 0; } }
/* the head's right end: Invite */
.chat-head .head-end { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 8px; }
/* the list's Invite friends button (INVITE-FRIENDS-TOP-RIGHT): a round button like the others
   beside it, never singled out in the accent (design review 2026-10-21, Eric: not the loudest
   thing on the screen); 327's in-chat gift is gone, so the shake and dot it used are gone with it */
.gift-btn { position: relative; }
.gift-btn svg.i { width: 21px; height: 21px; }
.gift-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* the top row of a page in the right pane: a bot's page, its instructions, the usage */
.page-top { display: flex; align-items: center; gap: 10px; padding: max(14px, env(safe-area-inset-top)) 16px 8px; }
/* A build with the shared top bar draws a pushed page's head in the system toolbar (TOPBAR-FOLLOWUPS, app.js
   nativeHead): the row collapses to the safe area the toolbar fills, so the page shows one header. Its buttons stay
   in the page, unseen, and the toolbar's items click them. */
[data-head] .page-top { height: 0; padding: max(8px, env(safe-area-inset-top)) 0 0; overflow: hidden; }
[data-head] .page-top > * { display: none; }
.page-h1 { margin: 0; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }

/* ---------- boot and welcome ---------- */
.boot {
  height: 100dvh; display: flex; align-items: center; justify-content: center;
  gap: 12px;
}
.boot .wordmark { font-size: 18px; }
/* the service couldn't be reached at boot (CHAT-LOAD): its note and Try again under the wordmark */
.boot.unreachable { flex-direction: column; padding: 0 16px; text-align: center; }
.boot-note { display: flex; flex-direction: column; align-items: center; gap: 12px; color: var(--text-2); font-size: 15px; }
.boot-note p { margin: 0; }

.welcome {
  min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 24px; padding: 40px 20px; position: relative; isolation: isolate;
}
/* a quiet brand moment behind the wordmark, never a new color: a soft wash of the one accent,
 * fading into the page before the card takes over */
.welcome::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(480px 260px at 50% -40px, color-mix(in srgb, var(--accent) 8%, transparent), transparent 70%);
}
.w-top { display: flex; flex-direction: column; align-items: center; gap: 14px; width: 100%; max-width: 400px; }
.welcome .wordmark { font-size: 17px; }
.w-card {
  width: 100%; max-width: 400px; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 20px;
  background: var(--raised); border: 1px solid var(--line); border-radius: 20px;
  padding: 32px 28px; box-shadow: var(--shadow);
}
.w-h1 {
  margin: 0; font-size: 27px; line-height: 1.25; font-weight: 700;
  letter-spacing: -0.02em; text-align: center; text-wrap: balance;
}
.w-h2 {
  margin: 0; font-size: 21px; line-height: 1.3; font-weight: 650;
  letter-spacing: -0.015em; text-align: center; text-wrap: balance;
}
.lead { margin: 0; color: var(--text-2); font-size: 15.5px; text-align: center; }
.w-card .lead { max-width: 32ch; margin-left: auto; margin-right: auto; }

.signin { display: flex; flex-direction: column; gap: 8px; }
.signin label { font-size: 13.5px; font-weight: 600; color: var(--text-2); }
.signin-row { display: flex; gap: 10px; }
.signin-row input {
  flex: 1; min-width: 0; height: 44px; padding: 0 14px;
  border: 1px solid var(--line-2); border-radius: 9px;
  background: var(--raised); color: var(--text);
  font-size: 16px; /* 16px on a phone so it doesn't zoom into the field */
}
.signin-row input::placeholder { color: var(--faint); }
.signin-row input:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px rgba(63, 119, 193, 0.25); }
.signin-row .btn { white-space: nowrap; }
#get-started { height: 44px; }
/* the welcome and join forms stack the field above the button, full width, inside the card; the
 * handle dialog keeps the shared .signin-row's own row layout (its @ marker needs it) */
#signin .signin-row, #join-form .signin-row { flex-direction: column; }
#signin .signin-row input, #join-form .signin-row input { background: var(--bg); flex: none; }
#get-started, #join-submit { width: 100%; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 18px;
  border: 0; border-radius: 9px;
  font-size: 15px; font-weight: 600;
  text-decoration: none;
  transition: transform 140ms ease-out, background 140ms ease-out, color 140ms ease-out;
}
.btn.primary { background: var(--accent); color: var(--on-accent); }
@media (hover: hover) { .btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, var(--text)); } }
.btn:active { transform: scale(0.97); }
.btn.secondary {
  background: var(--raised);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--line);
}
@media (hover: hover) { .btn.secondary:hover { background: var(--raised-2); color: var(--text); box-shadow: inset 0 0 0 1px var(--line-2); } }
.btn.secondary:disabled { color: var(--muted); cursor: default; }
@media (hover: hover) { .btn.secondary:disabled:hover { background: var(--raised); box-shadow: inset 0 0 0 1px var(--line); } }

/* the sign-in with a provider: two full-width secondary buttons with the providers' marks, then
 * a divider, then the email form stays last. A provider is never a fallback. */
.signin-providers { display: flex; flex-direction: column; gap: 10px; }
.btn.provider {
  width: 100%; height: 44px; padding: 0 14px; border-radius: 10px;
  display: grid; grid-template-columns: 20px 1fr 20px; align-items: center; column-gap: 10px;
}
.btn.provider svg.pm { color: var(--icon); grid-column: 1; }
.btn.provider .btn-txt { grid-column: 2; text-align: center; }
.signin-or {
  display: flex; align-items: center; gap: 12px;
  color: var(--muted); font-size: 13px;
}
.signin-or::before, .signin-or::after { content: ""; flex: 1; height: 1px; background: var(--divider); }

.notice { margin: 0; font-size: 14px; color: var(--text-2); }
.notice.err { color: var(--err); }
.linklike { border: 0; background: none; padding: 0; color: var(--link); font-size: 14px; text-decoration: underline; text-underline-offset: 3px; }
@media (hover: hover) { .linklike:hover { color: var(--ring); } }

/* The Terms line (311) under the form: what continuing agrees to, quiet, with both pages linked
 * once (the footer no longer repeats them). Centered with the rest of the card's content. */
.w-terms { margin: 0; font-size: 13px; color: var(--muted); text-align: center; }
.w-terms a { color: inherit; text-underline-offset: 3px; }
/* the welcome screen's bottom line, outside the card: a plain link to Support, nothing else */
.w-foot { margin: 0; text-align: center; font-size: 14px; }
.w-foot a { color: var(--muted); text-underline-offset: 3px; }

/* the "check your email" state (CHECKMAIL): a calm confirmation inside the same card, with a
 * quiet accent-ringed check mark standing in for the illustration the plain word-stack lacked */
/* the provider buttons and "or" divider stay visible above it (app.js only hides the email row),
 * so a hairline marks where the form ends and the confirmation begins */
.checkmail { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; padding-top: 20px; border-top: 1px solid var(--line); }
.check-mark {
  width: 48px; height: 48px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 16%, var(--raised)); color: var(--accent);
}
.check-mark svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- home: an empty thread with the composer docked below ---------- */
.home { min-height: 100%; display: flex; align-items: center; justify-content: center; padding: 24px 16px 8px; }
.home-inner {
  width: 100%; max-width: min(var(--col), 92vw);
  display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
}
.home-h1 { margin: 0; font-size: 28px; line-height: 1.25; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; }
.home-lead { margin: 0; color: var(--text-2); font-size: 16px; }

/* Starter prompts: a few real things to ask, so the empty home screen isn't just a field waiting
 * for one. Each sends on tap, exactly as typing it and pressing send would. */
.home-starters { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 4px; }
.home-starter {
  max-width: 280px; min-height: 44px; padding: 10px 16px;
  border: 1px solid var(--line-2); border-radius: 14px;
  background: var(--raised); color: var(--text);
  font: inherit; font-size: 14px; line-height: 1.35; text-align: left; cursor: pointer;
  transition: transform 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
@media (hover: hover) { .home-starter:hover { background: var(--raised-2); border-color: var(--line); } }
.home-starter:active { transform: scale(0.97); }
.home-starter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Temporary chat (TEMP-CHATS): a plain pill beside the home screen's own controls, borderless
 * until it's on, like ChatGPT's. */
.temp-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  height: 36px; padding: 0 14px; margin-top: 4px;
  border: 0; border-radius: 999px;
  background: transparent; color: var(--text-2);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
  transition: transform 140ms ease-out, color 140ms ease-out, background 140ms ease-out;
}
.temp-toggle svg.i { width: 15px; height: 15px; }
.temp-toggle[aria-pressed="true"] { color: var(--accent-tx); background: color-mix(in srgb, var(--accent) 13%, transparent); }
.temp-toggle:active { transform: scale(0.97); }
.temp-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: hover) {
  .temp-toggle:hover { background: var(--hover); }
  .temp-toggle[aria-pressed="true"]:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}

/* ---------- the one composer: a floating glass capsule (268) ---------- */
/* As the reference's: one capsule over the conversation, which scrolls under it, holding the "+",
 * the field and send (Stop while an answer streams). It lifts by the bottom safe area (the app's
 * own bar, 262b) and by the agent bar's height when 269's bar shows (--agent-bar-h, set on #app).
 * Sources, Search and the brain live in the "+" menu, each showing its state. */
.composer-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 20;
  padding: 0 max(16px, calc((100% - var(--col)) / 2)) calc(var(--agent-bar-h, 0px) + max(14px, env(safe-area-inset-bottom)));
  pointer-events: none;
}
.composer-bar > * { pointer-events: auto; }
.ccard {
  max-width: var(--col); margin: 0 auto;
  display: flex; flex-direction: column; gap: 4px;
  border-radius: 26px; padding: 5px;
  background: var(--glass); border: 1px solid var(--glass-line);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  box-shadow: var(--glass-shadow);
  transition: border-color 140ms ease-out, box-shadow 140ms ease-out;
}
.ccard:focus-within { border-color: var(--ring); box-shadow: var(--glass-shadow), 0 0 0 3px rgba(63, 119, 193, 0.22); }
/* A file (or photo) dragged over the page (ATTACH-FILES): the same ring .ccard:focus-within
 * already uses, so a drop reads as "into the composer" with no new visual language. */
.ccard.drop-on { border-color: var(--ring); box-shadow: var(--glass-shadow), 0 0 0 3px rgba(63, 119, 193, 0.22); }
.cc-row { display: flex; align-items: flex-end; gap: 4px; }
.ccard .ask {
  flex: 1; min-width: 0; height: 44px; min-height: 44px; max-height: 180px;
  border: 0; outline: none; background: transparent; resize: none;
  color: var(--text); font-size: 16px; line-height: 22px;
  padding: 11px 4px; caret-color: var(--msg);
}
.ccard .ask::placeholder { color: var(--muted); }
.cc-spacer { flex: 1; }

/* The "+": a round 44px button at the capsule's left that opens the attach and settings menu. */
.cc-plus {
  flex: none; width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--text);
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out;
}
.cc-plus svg.i { width: 22px; height: 22px; stroke-width: 1.8; }
@media (hover: hover) { .cc-plus:not(:disabled):hover { background: var(--hover-2); } }
.cc-plus[aria-expanded="true"] { background: var(--hover-2); }
.cc-plus:not(:disabled):active { transform: scale(0.94); }
.cc-plus:disabled { opacity: 0.45; cursor: default; }

/* The round "scroll to latest" chevron, centred over the capsule while the reader is scrolled up. */
.to-latest {
  position: absolute; left: 50%; bottom: calc(100% + 10px); margin-left: -22px;
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: var(--msg); color: var(--on-msg);
  box-shadow: var(--glass-shadow);
  animation: latest-in 180ms cubic-bezier(0.23, 1, 0.32, 1);
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.to-latest svg.i { width: 20px; height: 20px; stroke-width: 2.2; }
.to-latest:active { transform: scale(0.94); }
@keyframes latest-in { from { opacity: 0; transform: translateY(6px) scale(0.95); } to { opacity: 1; transform: none; } }

/* The quiet weekly-usage notice (LIMIT-WARNING): plain and borderless, a normal-flow child of
 * #composer-bar that sits above the glass card (not inside it), so its own height pushes
 * .to-latest up with it for free - both read "100%" off the same box. */
.usage-notice {
  display: flex; align-items: center; gap: 8px;
  max-width: var(--col); margin: 0 auto 8px; padding: 0 10px;
}
.usage-notice[hidden] { display: none; }
.un-text { flex: 1; min-width: 0; font-size: 13px; line-height: 18px; color: var(--muted); }
.un-x {
  flex: none; width: 28px; height: 28px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: transparent; color: var(--muted);
  transition: background 140ms ease-out, color 140ms ease-out, transform 140ms ease-out;
}
.un-x svg.i { width: 14px; height: 14px; }
@media (hover: hover) { .un-x:hover { background: var(--hover-2); color: var(--text); } }
.un-x:active { transform: scale(0.9); }

/* The side chat (BTW-SIDE-QUESTION-UI, host's own btw.css): a card over the conversation's bottom
 * right, 320px wide and up to 340px tall, 8px above the message box at the column's right edge.
 * Opened and closed with Ctrl+;/Cmd+; (app.js sideChatToggle()). */
.btw {
  position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 3;
  /* #composer-bar's own height is its content's, not the viewport's, so the cap is a max-height
   * (not a percentage of a container with no definite height of its own) */
  width: 320px; max-width: 100%; max-height: 340px;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--raised); border: 1px solid var(--line-2); border-radius: 12px; box-shadow: var(--shadow);
}
@media (max-width: 760px) { .btw { left: 0; width: auto; } }
/* under native chrome #ask-form collapses to no height (JUMP-BUTTON's own fix, above), so the
 * card is clear of the safe area instead, the same idiom as .to-latest */
[data-native-chrome] .btw { bottom: calc(env(safe-area-inset-bottom) + 8px); }

.btw-head { flex-shrink: 0; display: flex; align-items: center; gap: 2px; height: 40px; padding: 0 6px 0 14px; border-bottom: 1px solid var(--line); }
.btw-title { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 600; color: var(--text); }
.btw-icon {
  flex: none; width: 28px; height: 28px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: transparent; color: var(--muted);
  transition: background 140ms ease-out, color 140ms ease-out, transform 140ms ease-out;
}
.btw-icon svg.i { width: 14px; height: 14px; }
@media (hover: hover) { .btw-icon:hover { background: var(--hover-2); color: var(--text); } }
.btw-icon:active { transform: scale(0.9); }

.btw-list { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 16px; padding: 12px 14px; font-size: 14px; line-height: 1.6; }
/* a question and what came of it, closer to each other than to the next */
.btw-item { display: flex; flex-direction: column; gap: 8px; }
.btw-empty { padding: 12px 14px; border-radius: 10px; background: var(--raised-2); color: var(--muted); font-size: 13px; line-height: 1.5; text-wrap: pretty; }
/* the question: the conversation's own bubble, a size down */
.btw-q { align-self: flex-end; max-width: 85%; padding: 7px 12px; border-radius: 14px; background: var(--raised-2); white-space: pre-wrap; overflow-wrap: anywhere; }
/* the answer: plain paragraphs, a size down from the conversation's own */
.btw-a { margin: 0; font-size: 14px; line-height: 1.6; color: var(--text); }
.btw-a p { margin: 0 0 10px; }
.btw-a p:last-child { margin-bottom: 0; }
/* waiting: the working line's spark and clock, as the conversation's own turn shows */
.btw-wait { display: flex; align-items: center; min-height: 24px; color: var(--text-2); font-size: 13.5px; font-variant-numeric: tabular-nums; }
.btw-wait .spark { width: 16px; margin-right: 10px; font-size: 16px; text-align: center; }
.btw-clock:not(:empty)::after { content: "·"; padding: 0 6px; }
.btw-wait > :last-child { animation: btw-breathe 2s ease-in-out 3s infinite; }
@keyframes btw-breathe { 50% { opacity: 0.6; } }
@media (prefers-reduced-motion: reduce) { .btw-wait > :last-child { animation: none; } }
.btw-note { color: var(--muted); font-size: 13px; }
.btw-err { flex-shrink: 0; margin: 0; padding: 0 14px 8px; color: var(--err); font-size: 13px; line-height: 1.45; }

/* its own message box: the composer's look, compact */
.btw-box { flex-shrink: 0; display: flex; align-items: flex-end; gap: 6px; margin: 0 8px 8px; padding: 5px 5px 5px 12px; border: 1px solid var(--line-2); border-radius: 12px; background: var(--bg); transition: border-color 140ms ease-out; }
.btw-box:focus-within { border-color: var(--faint); }
.btw-box textarea { flex: 1; min-width: 0; min-height: 28px; max-height: 120px; padding: 4px 0; border: 0; outline: none; resize: none; background: transparent; color: var(--text); font: inherit; font-size: 16px; line-height: 20px; }
.btw-box textarea::placeholder { color: var(--muted); }
.btw-send { flex-shrink: 0; width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: 8px; background: transparent; color: var(--icon); transition: background 140ms ease-out, color 140ms ease-out, transform 140ms ease-out; }
.btw-send svg.i { width: 17px; height: 17px; }
.btw-send.ready { color: var(--text); }
.btw-send.stop { border-radius: 50%; background: var(--text); color: var(--bg); }
.btw-send.stop svg.i { width: 13px; height: 13px; }
.btw-send:focus-visible, .btw-icon:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
@media (hover: hover) { .btw-send.ready:hover { background: var(--hover-2); } }
.btw-send:active { transform: scale(0.97); }

/* under a finger: 44px to tap, and a 16px field, so focusing it doesn't zoom the page */
@media (pointer: coarse) {
  .btw-head { height: 48px; gap: 8px; }
  .btw-icon { position: relative; width: 36px; height: 36px; }
  .btw-icon::before { content: ""; position: absolute; inset: -4px; }
  .btw-send { position: relative; width: 32px; height: 32px; }
  .btw-send::before { content: ""; position: absolute; inset: -6px; }
  .btw-box textarea { line-height: 22px; }
}

/* The strip of attached photos inside the composer card, between the input and the tools row:
 * 64px thumbnails, each with a remove button that shows on hover or focus (always on touch). Only
 * the page this card is drawn on has it: a guest never sees the composer. */
.photo-strip { display: flex; gap: 8px; overflow-x: auto; padding: 6px 8px 2px; }
.photo-tile {
  flex: none; width: 64px; height: 64px; position: relative;
  border-radius: 8px; overflow: hidden;
  background: var(--raised-2); border: 1px solid var(--line-2);
}
.photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-tile.has-failed { border-color: var(--err); }

/* A file tile (ATTACH-FILES): the photo tile's own height and surface, but a row of a mark, name
 * and kind instead of a thumbnail, since there's nothing to show a preview of. No tap-to-open:
 * there is no route that serves a file's bytes. */
.file-tile {
  flex: none; width: auto; max-width: 220px; padding: 0 10px 0 8px;
  display: flex; align-items: center; gap: 8px;
}
.ft-mark { flex: none; display: grid; place-items: center; color: var(--muted); }
.ft-mark svg.i { width: 18px; height: 18px; }
.ft-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ft-name { font-size: 13px; line-height: 16px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ft-kind { font-size: 11px; line-height: 14px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.file-tile .photo-x { position: static; margin-left: 2px; opacity: 1; }
.photo-x {
  position: absolute; top: 3px; right: 3px;
  width: 20px; height: 20px; border: 0; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, 0.62); color: #fff;
  cursor: pointer;
  transition: transform 140ms ease-out, background 140ms ease-out, opacity 140ms ease-out;
}
.photo-x svg.i { width: 11px; height: 11px; }
.photo-tile .photo-x { opacity: 0; }
.photo-tile:hover .photo-x, .photo-tile:focus-within .photo-x, .photo-tile .photo-x:focus-visible { opacity: 1; }
@media (pointer: coarse) { .photo-tile .photo-x { opacity: 1; } }
.photo-x:hover { background: rgba(0, 0, 0, 0.8); }
.photo-x:active { transform: scale(0.9); }

/* A plain note under the composer card, for the one refusal a person can fix before sending:
 * a chosen model that cannot read photos (231b), or image generation on a plan that has none
 * (231d). It reads like the page's other notices and carries the model's own name from the
 * page's words. */
.cc-note { max-width: var(--col); margin: 10px auto 0; font-size: 13px; color: var(--muted); text-align: center; }
.cc-note .cc-up { color: var(--link); font-weight: 600; text-decoration: none; }
@media (hover: hover) { .cc-note .cc-up:hover { text-decoration: underline; text-underline-offset: 3px; } }

/* The Image chip (231d): the composer's mode pill, on while the next send makes an image, ring
 * tinted as an on-state is, at the row's control size with the same 44px touch target as the
 * other controls. The whole chip turns the mode off; its × is never a second target. */
.image-chip {
  flex: none; align-self: center;
  display: inline-flex; align-items: center; gap: 5px;
  height: 32px; padding: 0 8px 0 10px; position: relative;
  border: 1px solid var(--ring); border-radius: 999px;
  background: rgba(63, 119, 193, 0.12); color: var(--ring);
  font-size: 13px; font-weight: 600;
  transition: transform 140ms ease-out, background 140ms ease-out, color 140ms ease-out, border-color 140ms ease-out;
}
.image-chip::before { content: ""; position: absolute; inset: -8px; }
.image-chip svg.i { width: 13px; height: 13px; }
.image-chip .chip-x { display: inline-flex; color: inherit; opacity: 0.85; }
.image-chip:not(:disabled):active { transform: scale(0.97); }
@media (hover: hover) { .image-chip:hover { background: rgba(63, 119, 193, 0.2); } }

/* The leading icon of a + menu item (231d): quiet, at the menu's size, never a second color. */
.menu-item .mi-ic { display: inline-flex; color: var(--muted); flex: none; }
.menu-item .mi-ic svg.i { width: 15px; height: 15px; }
.menu-item .mi-ic.mark-slot { width: 28px; justify-content: center; }
.menu-item:disabled { color: var(--faint); cursor: default; }
.menu-item:disabled .mi-ic, .menu-item:disabled .mi-name { color: inherit; }

/* A person's bubble's own photos (231b): the same 64px thumbnails, at the top of the bubble,
 * each opening the full image. A thread's read-back and an invite's guest view draw the same
 * tiles, from the photo's own /api/photos id. */
/* A sent message's photos as thumbnails: whole and framed like the Chat page's photo tiles, never
 * cropped (231c). Each opens at full size on tap; a photo-only message is never given words. */
.photo-thumbs { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 8px; }
.xbub .photo-thumbs { justify-content: flex-end; }
/* A photo-only message has no bubble, but it is still the person's turn and sits at the right,
 * exactly where the bubble messages do (231c). */
.x > .photo-thumbs { align-self: flex-end; justify-content: flex-end; }

/* A bot chat's working row (346, 231d): the bot's face and its words on one line, with no box, the
 * words in the thinking shimmer a group's bot with no words yet uses (.gm-working, below). */
.a-working { align-self: flex-start; display: inline-flex; align-items: center; gap: 10px; margin-top: 2px; }
.a-working .work-face { flex: none; }
/* The model's own reasoning, where it streamed one (THINKING-LIVE): the same quiet, muted, no-box
   line PROJECT-STEPS-LOOK-2 gave a tool run (.tk-run-head) - a chevron that starts right and
   turns down on open - so a turn's "Thought for Ns" never moves once later steps draw below it.
   The live label shimmers in the page's own thinking shimmer (--shine tokens) while it's still
   running; once closed it's plain muted text, like the run line's own kind word. */
.think-section { margin-top: 18px; max-width: 640px; }
.x .think-section { margin-top: 18px; }
.think-head {
  display: flex; align-items: center; gap: 6px; width: fit-content; max-width: 100%;
  padding: 4px 8px; margin: 0 -8px; border: 0; background: none; border-radius: 8px;
  color: var(--muted); font-size: 13.5px; text-align: left; cursor: pointer;
}
@media (pointer: coarse) { .think-head { min-height: 44px; } }
@media (hover: hover) { .think-head:hover { color: var(--text-2); } }
.think-head:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.think-label { flex: none; }
.think-label.think-live {
  background: linear-gradient(90deg, var(--shine) 0%, var(--shine) 40%, var(--shine-peak) 50%, var(--shine) 60%, var(--shine) 100%);
  background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; /* design-ok: the page's thinking shimmer, its --shine tokens */
  animation: hb-shine 1.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .think-label.think-live { animation: none; background: none; color: var(--text-2); } }
.think-latest { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--muted); }
.think-chev { flex: none; color: var(--faint); transition: transform 140ms ease-out; transform: rotate(-90deg); }
.think-head[aria-expanded="true"] .think-chev { transform: rotate(0deg); }
.think-body { margin-top: 2px; padding: 2px 8px; font-size: 14px; line-height: 1.5; color: var(--muted); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 240px; overflow: auto; }
/* A generated image's place in the thread (231d): the finished image at the left where an answer
 * would come, framed and whole, opening full size on tap. The actions under it are the page's own
 * quiet 28px .ma-btn row, 44px under a finger. */
.a-img { align-self: flex-start; max-width: min(72%, 520px); display: flex; flex-direction: column; }
.a-img .img-btn {
  padding: 0; border: 1px solid var(--line-2); border-radius: 12px; overflow: hidden;
  background: var(--bg); cursor: zoom-in;
  transition: transform 140ms ease-out, border-color 140ms ease-out;
}
.a-img .img-btn img { display: block; max-width: 100%; max-height: 420px; object-fit: contain; }
.a-img .img-btn:not(:disabled):active { transform: scale(0.98); }
@media (hover: hover) { .a-img .img-btn:not(:disabled):hover { border-color: var(--ring); } }
.a-img .m-acts a.ma-btn { color: var(--muted); text-decoration: none; }
@media (hover: hover) { .a-img .m-acts a.ma-btn:hover { background: var(--hover-2); color: var(--text); } }
.thumb-btn {
  width: 120px; height: 120px; padding: 0; flex: none;
  border: 1px solid var(--line-2); border-radius: 12px; overflow: hidden;
  background: var(--bg); cursor: zoom-in;
  transition: transform 140ms ease-out, border-color 140ms ease-out;
}
.thumb-btn img { width: 100%; height: 100%; object-fit: contain; display: block; }
.thumb-btn:not(:disabled):active { transform: scale(0.96); }
@media (hover: hover) { .thumb-btn:not(:disabled):hover { outline: 2px solid var(--ring); outline-offset: 1px; } }

/* A sent message's files (ATTACH-FILES): quiet cards above the words, outside the bubble and
 * aligned with it, no border (CARD-QUIET) - there's nothing to open, so no hover or press state. */
.file-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
.file-chip {
  display: flex; align-items: center; gap: 8px; min-height: 44px; max-width: 280px;
  padding: 0 12px; border-radius: 12px; background: var(--raised-2); color: var(--muted);
}
.file-chip .ft-mark { color: var(--muted); }
.file-chip .ft-name { color: var(--text); }

/* The full-size viewer (231b): the photo over everything, dark, closed by a click or Escape.
 * A viewer never sells and never navigates. */
.img-view {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, 0.92);
  cursor: zoom-out;
}
.img-view img {
  max-width: 92vw; max-height: 92vh;
  border-radius: 4px; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
  cursor: default;
}
@media (min-width: 560px) { .img-view img { max-width: min(92vw, 1200px); } }

/* A photo tile's owned states: uploading shows a small spinner, the upload refusal names itself
 * (never a status code) and offers a retry, and a ready tile carries nothing more than the photo. */
.tile-spin {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(0, 0, 0, 0.35);
}
.tile-spin::after {
  content: ""; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35); border-top-color: #fff;
  animation: turn 0.8s linear infinite;
}
.tile-note {
  position: absolute; left: 4px; right: 4px; bottom: 4px;
  font-size: 10.5px; line-height: 1.1; color: #ffd5d1;
  text-align: center; pointer-events: none;
}
.tile-retry {
  position: absolute; top: 22px; left: 50%; transform: translateX(-50%);
  width: 22px; height: 22px; border: 0; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, 0.55); color: #fff; cursor: pointer;
  transition: transform 140ms ease-out;
}
.tile-retry svg.i { width: 12px; height: 12px; }
.tile-retry:not(:disabled):active { transform: translateX(-50%) scale(0.9); }

/* A model that cannot read photos while one is attached, in the picker: its row stays but reads
 * unable, and cannot be picked. No model on sale is in this state today (231b probed them all),
 * but the row is real for the one that is. */
.menu-item.no-img { color: var(--muted); }
.menu-item.no-img .no-img-note {
  margin-left: auto; padding-left: 8px;
  font-size: 11.5px; color: var(--faint); white-space: nowrap;
}

.send {
  border: 0; background: var(--msg); color: var(--on-msg);
  display: grid; place-items: center;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out, opacity 140ms ease-out;
}
.send svg.i { width: 18px; height: 18px; stroke-width: 2.1; }
@media (hover: hover) { .send:not(:disabled):hover { background: color-mix(in srgb, var(--msg) 86%, var(--text)); } }
.send:active:not(:disabled) { transform: scale(0.94); }
.send:disabled { background: var(--selected); color: var(--faint); cursor: default; }

/* the composer's send is the capsule's 44px round, the stop square while an answer streams */
.ccard .send { width: 44px; height: 44px; border-radius: 50%; flex: none; }
.ccard .send:not(:disabled) svg.i { width: 19px; height: 19px; }

.search-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--muted);
  font-size: 14px; font-weight: 600;
  transition: transform 140ms ease-out, color 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
.search-toggle .st-label { white-space: nowrap; }
.search-toggle.on { color: var(--ring); border-color: var(--ring); background: rgba(63, 119, 193, 0.12); }
.search-toggle:disabled, .search-toggle[aria-disabled="true"] { opacity: 0.5; cursor: default; }
.search-toggle:not(:disabled):active { transform: scale(0.97); }
@media (hover: hover) { .search-toggle:not(:disabled):hover { background: var(--hover); } .search-toggle.on:hover { background: rgba(63, 119, 193, 0.16); } }

/* The Sources toggle sits beside Search in the composer. Its on state is the page's accent,
 * never a color alone: the switch reads "Sources". */
.sources-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--muted);
  font-size: 14px; font-weight: 600;
  transition: transform 140ms ease-out, color 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
.sources-toggle .st-label { white-space: nowrap; }
.sources-toggle.on {
  color: var(--accent-tx); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 13%, transparent);
}
.sources-toggle:not(:disabled):active { transform: scale(0.97); }
@media (hover: hover) {
  .sources-toggle:not(:disabled):hover { background: var(--hover); }
  .sources-toggle.on:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}

/* The model pill opens the page's own model picker, unchanged in what it lists; inside the
 * composer it is a quiet pill, not the standalone button of the old ask box. */
.model-btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; max-width: 260px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--text-2);
  font-size: 14px;
  transition: transform 140ms ease-out, background 140ms ease-out;
}
.m-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.m-chev { color: var(--muted); display: inline-flex; }
.m-chev svg.i { width: 13px; height: 13px; }
.model-btn[aria-expanded="true"] { border-color: var(--line-2); background: var(--hover); }
@media (hover: hover) { .model-btn:hover { background: var(--hover); } }
.model-btn:active:not(:disabled) { transform: scale(0.97); }

/* ---------- menus (model picker, account) ---------- */
.menu-layer { position: fixed; inset: 0; z-index: 50; pointer-events: none; }
/* A held chat row (320): the list blurred under a scrim, the chat's latest messages in a card on
 * the page's own background, and the chat's menu (in .menu-layer, above) under it, as WhatsApp's.
 * The layer takes every touch, so the list never scrolls under it. */
.hp-layer {
  position: fixed; inset: 0; z-index: 49; touch-action: none; overscroll-behavior: contain;
  padding: max(12px, env(safe-area-inset-top)) 12px max(12px, env(safe-area-inset-bottom));
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
.hp-scrim {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--bg) 40%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4);
}
.hp-card {
  position: absolute; left: 50%; width: min(440px, calc(100vw - 24px)); translate: -50% 0;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); border: 1px solid var(--line); border-radius: 18px; box-shadow: var(--shadow);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.hp-card:active { scale: 0.99; }
.hp-card:focus { outline: none; }
/* the app's native bar and its Search accessory stand over the page's foot (262c): the menu stays above them */
[data-native-bar] .hp-layer { padding-bottom: calc(env(safe-area-inset-bottom) + 112px); }
.hp-head {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: 10px 14px; border-bottom: 1px solid var(--line);
}
.hp-head .hp-mark { flex: none; }
.hp-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 600; color: var(--text); }
/* the latest messages, read-only, sit at the card's foot; older ones fall off its top */
.hp-msgs {
  flex: 1; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 14px;
  padding: 12px 14px 14px; pointer-events: none;
}
.hp-msgs > .x { margin-bottom: 0; flex: none; }
.hp-msgs > .gm, .hp-msgs > .t-divider { flex: none; }
.hp-msgs > .loading { margin: auto; color: var(--muted); font-size: 14px; }
/* a preview reads, so an answer's Copy stays with the open chat, as WhatsApp's preview shows none;
 * REGENERATE's own switcher is the same kind of action chrome, so it stays there too */
.hp-msgs .m-acts, .hp-msgs .m-versions { display: none; }
.hp-layer.in .hp-scrim { animation: hp-fade 200ms cubic-bezier(0.23, 1, 0.32, 1); }
.hp-layer.in .hp-card { animation: hp-in 220ms cubic-bezier(0.23, 1, 0.32, 1); }
@keyframes hp-fade { from { opacity: 0; } }
@keyframes hp-in { from { opacity: 0; scale: 0.96; } }
/* The same card as the app's preview of a held row (CHAT-MENU): measured off screen at the preview's width,
 * then a page of its own that fills the system's preview, the latest message at its foot. */
.hp-measure { position: fixed; left: -10000px; top: 0; visibility: hidden; pointer-events: none; }
.hp-card.hp-peek { position: static; width: auto; translate: none; cursor: default; }
.hp-measure .hp-card.hp-peek { border: 0; border-radius: 0; box-shadow: none; }
.hp-peek-page { height: 100%; overflow: hidden; }
.hp-peek-page .hp-card.hp-peek { height: 100%; border: 0; border-radius: 0; box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  .hp-layer.in .hp-card { animation: hp-fade 160ms ease-out; }
  .hp-card:active { scale: none; }
}
.menu {
  position: fixed; min-width: 248px; max-width: min(320px, calc(100vw - 32px));
  max-height: calc(100dvh - 20px); overflow-y: auto;
  background: var(--raised); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow);
  padding: 6px;
  pointer-events: auto; /* the layer behind is click-through; the menu itself must take real pointers */
  animation: menu-in 150ms cubic-bezier(0.23, 1, 0.32, 1);
}
@keyframes menu-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
.menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 40px; padding: 7px 10px;
  border: 0; border-radius: 8px; background: transparent;
  font-size: 14px; text-align: left; color: var(--text-2); text-decoration: none;
}
.menu-item .mi-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.mi-name { font-weight: 600; color: var(--text); font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mi-prov { font-size: 12px; color: var(--muted); }
.mi-check { color: var(--ring); }
.mi-check svg.i { width: 14px; height: 14px; }
/* a row that leads on to more rows in the same menu (CHAT-MENU's Add to list) */
.mi-chev { display: inline-flex; color: var(--muted); }
.mi-chev svg.i { width: 14px; height: 14px; }
.menu-item .badge {
  font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
  padding: 2px 7px; border-radius: 999px;
  background: var(--pro-tint); color: var(--pro);
  text-transform: uppercase; flex: none;
}
.menu-item.locked { color: var(--muted); }
.menu-item.locked .mi-name { color: var(--muted); font-weight: 550; }
@media (hover: hover) { .menu-item:hover { background: var(--hover-2); } }
.menu-item:active { transform: scale(0.98); }
.menu-item.locked { cursor: pointer; }
/* The "+" menu (268): the attach rows, then the composer's settings, each showing its state: Sources
 * and Search as switches (Search locked on while Sources is on), the brain with its setting. */
.plus-menu { min-width: 288px; }
.menu-sep { height: 1px; margin: 6px 4px; background: var(--line); }
.menu .pm-row {
  height: auto; min-height: 44px; max-width: none; padding: 7px 10px; gap: 10px;
  border: 0; border-radius: 8px; background: transparent; color: var(--text-2);
  font-size: 14px; font-weight: 400;
}
.menu .pm-row.on, .menu .pm-row[aria-expanded="true"] { background: transparent; border: 0; color: var(--text-2); }
@media (hover: hover) { .menu .pm-row:hover, .menu .pm-row.on:hover { background: var(--hover-2); } }
.menu .pm-row .mi-ic svg.i { width: 15px; height: 15px; }
.menu .pm-row[aria-disabled="true"] { opacity: 1; cursor: default; }
.menu .pm-row[aria-disabled="true"] .pm-switch { opacity: 0.55; }
.pm-switch {
  position: relative; flex: none; width: 38px; height: 23px; border-radius: 999px;
  background: var(--track); transition: background 160ms ease-out;
}
.pm-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 19px; height: 19px; border-radius: 50%;
  background: var(--knob); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 180ms cubic-bezier(0.23, 1, 0.32, 1);
}
.pm-row[aria-checked="true"] .pm-switch { background: var(--msg); }
.pm-row[aria-checked="true"] .pm-switch::after { transform: translateX(15px); }
.pm-val { flex: none; max-width: 130px; font-size: 13.5px; font-weight: 500; color: var(--muted); }
.menu-cap { display: block; font-size: 12px; font-weight: 600; color: var(--muted); padding: 8px 10px 4px; text-transform: uppercase; letter-spacing: 0.02em; }
.acct-email-line { display: block; padding: 10px 12px 6px; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The brain control (247): the composer's pill, the same pill the model picker used, whose mark
 * is the brain icon; and the sheet, the same menu surface with the level and effort rows and the
 * estimate line beneath them. The estimate line is a fact, never a pitch, so it uses the quiet
 * note style and the page's own tokens. */
.model-btn .ic { display: inline-flex; color: var(--muted); }
.sheet { width: 300px; }
.sheet-note { display: block; margin: 6px 10px 8px; padding-top: 8px; border-top: 1px solid var(--line); font-size: 12.5px; line-height: 1.45; color: var(--muted); }

/* ---------- the thread: a conversation in bubbles (268) ---------- */
.thread { min-height: 100%; }
/* A one-on-one chat's own background (#thread-view: a bot's chat or a project's; #home: the same
 * chat before its first message), true black in dark mode (ONE-ON-ONE-LOOK, Eric 2026-10-25, "like
 * chatgpt ... the bg being black"); a group keeps --bg too, now the same true black everywhere a
 * page sits (BLACK-EVERYWHERE), so --thread-bg is just --bg and nothing here forks on which view
 * shows. html, body, .col and the app's edge fade (above, BLACK-EDGES-WEB) need no override for
 * that either - they were already --root-bg, and --root-bg is just --bg too. */
#thread-view, #home { background: var(--thread-bg); }
.t-inner {
  max-width: var(--col); margin: 0 auto;
  padding: 30px 20px 40px;
  display: flex; flex-direction: column; gap: 22px;
}
/* a chat's conversation starts under the floating head and ends above the floating composer */
#thread-view .t-inner, #group-view .t-inner {
  padding-top: calc(var(--head-h, 140px) + 4px);
  padding-bottom: calc(var(--composer-h, 76px) + 20px);
}
/* One exchange is the person's turn and the answer that follows it. The person's is always a
 * bubble at the right, in the accent blue with white words. In a one-on-one chat (never a group's,
 * ONE-ON-ONE-LOOK) the answer carries no bubble of its own: plain text spanning the column, the
 * page's own sans, like ChatGPT's reference, with no inset of its own since the column's padding
 * is its margin. What belongs to the answer (tool cards, images, the Sources cards and "N
 * sources", Copy) still sits right under it. */
.x { display: flex; flex-direction: column; margin: 0 0 18px; }
.x:last-child { margin-bottom: 0; }
.xbub {
  position: relative; align-self: flex-end; max-width: min(80%, 520px);
  background: var(--msg); color: var(--on-msg);
  border-radius: 20px;
  padding: 10px 15px; font-size: 16px; line-height: 1.45;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.xbub .photo-thumbs { margin: 2px 0 6px; }
.xbub .photo-thumbs:last-child { margin-bottom: 2px; }
/* The bubble below is a group's answer now (.gm-body) and the message-hold preview's peek
 * (#hp-msgs .a-body, drawn by the same renderExchange): a one-on-one chat's own #thread-view
 * overrides it to plain text, right after (ONE-ON-ONE-LOOK). */
.x > .a-body, .gm-body {
  align-self: flex-start; max-width: min(88%, 640px); min-width: 0;
  background: var(--bub-in); color: var(--text);
  border-radius: 20px; padding: 10px 16px;
}
#thread-view .x > .a-body {
  align-self: stretch; max-width: none;
  background: transparent; border-radius: 0; padding: 0;
}
.x > .xbub + .a-body, .x > .photo-thumbs + .a-body, .x > .x-routine + .a-body { margin-top: 14px; }
.x > .xbub ~ .tk-section, .x > .xbub ~ .src-section, .x > .xbub ~ .a-working, .x > .xbub ~ .a-img { margin-top: 14px; }
.x > .tk-section + .a-body, .x > .cv-card + .a-body, .x > .src-section + .a-body,
.x > .tk-section + .cv-card, .x > .cv-card + .tk-section { margin-top: 6px; }
/* Cards an agent puts in its chat (276): a choice card and a capability request, on the bot's side
 * under its words, a bubble's surface and radius, as the reference draws them. A choice's options
 * are rows; once answered the chosen one is outlined with a check, the rest dashed and quiet. */
.x > .cc-card { margin-top: 6px; }
.x > .m-acts + .cc-card { margin-top: 2px; }
.cc-card {
  align-self: flex-start; width: min(88%, 440px);
  background: var(--bub-in); color: var(--text);
  border-radius: 22px; padding: 14px 16px 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.cc-q { margin: 0; font-size: 16px; line-height: 1.45; overflow-wrap: anywhere; }
.cc-opts { display: flex; flex-direction: column; gap: 8px; }
.cc-opt {
  display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 10px 0 14px;
  border: 1px solid var(--line-2); border-radius: 12px; background: transparent;
  color: var(--text); font: inherit; font-size: 16px; text-align: left; cursor: pointer;
  transition: transform 140ms ease-out, border-color 140ms ease-out, background 140ms ease-out;
}
.cc-opt-t { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.cc-check {
  flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--text); color: var(--bg); opacity: 0; transform: scale(0.95);
  transition: opacity 160ms cubic-bezier(0.23, 1, 0.32, 1), transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}
.cc-check .i { width: 14px; height: 14px; stroke-width: 2.2; }
.cc-opt.on { border: 1.5px solid var(--text); }
.cc-opt.on .cc-check { opacity: 1; transform: none; }
.cc-opt.off { border-style: dashed; color: var(--muted); }
.cc-opt:disabled { cursor: default; }
.cc-opt:not(:disabled):active { transform: scale(0.98); }
@media (hover: hover) { .cc-opt:not(:disabled):hover { background: var(--hover); border-color: var(--text-2); } }
.cc-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cc-send { align-self: flex-end; }

/* The intro's naming question: small chips in one wrapping row, once it shows after the first
 * answer, rather than the choice card's usual stack of full-width rows. */
.cc-opts-chips { flex-direction: row; flex-wrap: wrap; }
.cc-opt-chip { flex: none; min-height: 44px; width: auto; padding: 0 14px; border-radius: 999px; gap: 6px; }
.cc-opt-chip .cc-check { width: 18px; height: 18px; }
.cc-opt-chip .cc-check .i { width: 11px; height: 11px; }
/* A card ask (CARDS-FREE): the one thing an agent never types itself, entered on the page and
   filled by ref. The plain inputs carry the autocomplete hints a browser's saved cards answer;
   the question and the Pay button name the site, and none of the digits are ever stored. */
.cc-card-ask .cc-card-amount { margin: 0; font-size: 14px; color: var(--muted); }
.cc-card-fields { display: flex; flex-direction: column; gap: 10px; }
.cc-card-field { display: flex; flex-direction: column; gap: 5px; font-size: 13.5px; color: var(--text-2); }
.cc-card-field input {
  height: 46px; padding: 0 12px; border: 1px solid var(--line-2); border-radius: 12px;
  background: var(--bg); color: var(--text); font: inherit; font-size: 16px;
}
.cc-card-field input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-color: var(--accent); }
.cc-card-note { margin: 0; font-size: 13px; color: var(--text-2); line-height: 1.45; }
.cc-card-pay { align-self: flex-end; min-height: 44px; }
.cc-card-done { display: flex; flex-direction: column; gap: 6px; font-size: 14px; }
.cc-card-done-row { display: flex; gap: 6px; align-items: center; color: var(--text-2); }
.cc-card-done-row.on { color: var(--text); }
.cc-cap-head { display: flex; align-items: center; gap: 12px; }
.cc-cap-ic {
  flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center;
  background: var(--bg); color: var(--text-2);
}
.cc-cap[data-kind="apple_health"] .cc-cap-ic { color: var(--accent); }
.cc-cap-title { margin: 0; font-size: 16px; font-weight: 600; }
.cc-cap-why { margin: 0; font-size: 15px; line-height: 1.45; overflow-wrap: anywhere; }
.cc-cap-reads { margin: -4px 0 0; font-size: 13.5px; color: var(--muted); }
.cc-cap-acts { display: flex; gap: 8px; }
.cc-cap-btn { flex: 1; height: 44px; }
.cc-cap-done { margin: 0; display: flex; align-items: center; gap: 6px; font-size: 14px; color: var(--text-2); }
.cc-cap-done .i { width: 15px; height: 15px; }
.cc-cap-note { margin: 0; font-size: 13.5px; color: var(--text-2); }
/* A confirm card (OWNER-RIG-HANDOFF): the capability card's frame around what the owner's agent would
   do once he taps it. The task is his words in full, line breaks kept; a long one scrolls in place
   so the buttons stay in reach. */
.cc-confirm-text {
  margin: 0; font-size: 15px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere;
  max-height: 240px; overflow-y: auto; padding: 10px 12px; border-radius: 12px; background: var(--bg);
}
.cc-confirm[data-state="done"] .cc-cap-done { color: var(--text); }
/* A product card the agent put in the chat (PRODUCT-CARDS): products as tiles to browse and pick
 * from. The tiles run sideways, scrolling in place on a narrow screen and laid as a grid where
 * there is width. A tile's picture comes from the product-images proxy; where none could be, a
 * quiet placeholder stands in its place. Picked, the tile is outlined with the answered line and
 * the rest dashed and quiet, the same answered language as a choice card. */
.cc-products { width: min(100%, 580px); }
.cc-prods {
  display: flex; gap: 10px; overflow-x: auto; padding-bottom: 2px;
  scroll-snap-type: x proximity; scrollbar-width: thin;
}
.cc-prod {
  flex: 0 0 168px; scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 10px;
  border: 1px solid var(--line-2); border-radius: 12px; padding: 10px;
  background: var(--bg);
}
.cc-prod.on { border: 1.5px solid var(--text); padding: 9.5px; }
.cc-prod.off { border-style: dashed; }
/* An app card (CHAT-APPS): the small page app_show wrote, running inline at a capped height that
 * scrolls inside past it, with a control to open it full screen beside its title. The frame is
 * sandboxed to its own scripts in an opaque origin (chat-files.ts fileHeaders' CSP), so nothing
 * inside it reads this page's cookie, storage or DOM. */
.cc-app { width: min(100%, 480px); }
.cc-app-bar { display: flex; align-items: center; gap: 8px; }
.cc-app-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-app-frame {
  display: block; width: 100%; height: 320px; border: 1px solid var(--line-2);
  border-radius: 12px; background: #fff;
}
.cc-pic {
  position: relative; aspect-ratio: 4 / 3; border-radius: 8px; overflow: hidden;
  display: grid; place-items: center; background: var(--raised-2); color: var(--faint);
}
.cc-pic img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cc-pic-ph { display: grid; place-items: center; }
.cc-pic-ph .i { width: 26px; height: 26px; }
.cc-p-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cc-p-name {
  margin: 0; font-size: 15px; line-height: 1.35; overflow-wrap: break-word;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  /* The name is exactly two lines, never more: the clamp draws the ellipsis where Chrome and
   * WebKit honor it, and the fixed two-line region crops to the same bound on an engine that
   * ignores the legacy clamp, so no client can push the price and store over a third and fourth
   * line. The full name is always reachable in the tile's title attribute. The fixed region also
   * makes every tile in a row the same height, name length or not. */
  overflow: hidden; min-height: 2.7em; max-height: 2.7em;
}
.cc-p-price { margin: 0; font-size: 15px; font-weight: 600; }
.cc-p-store { margin: 0; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-p-acts { display: flex; align-items: center; gap: 8px; margin-top: auto; min-height: 44px; }
.cc-open { display: inline-flex; align-items: center; min-height: 44px; font-size: 14px; color: var(--link); }
.cc-pick {
  height: 44px; min-width: 76px; padding: 0 16px; margin-left: auto;
  border: 1px solid var(--line-2); border-radius: 10px; background: transparent;
  color: var(--text); font: inherit; font-size: 15px; cursor: pointer;
  transition: transform 140ms ease-out, border-color 140ms ease-out, background 140ms ease-out;
}
.cc-pick:disabled { cursor: default; }
.cc-pick:not(:disabled):active { transform: scale(0.97); }
@media (hover: hover) { .cc-pick:not(:disabled):hover { background: var(--hover); border-color: var(--text-2); } }
.cc-pick:focus-visible, .cc-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (min-width: 780px) {
  .cc-prods { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); overflow: visible; scroll-snap-type: none; }
  .cc-prod { flex: none; }
}
/* In a group (276b) a card sits in its bot's column, under its words; everyone else reads whose it
 * is above the question. A step's tool cards sit above the words, as in a bot's chat. */
.gm-col > .cc-card { margin-top: 6px; width: min(100%, 440px); }
.gm-col > .tk-section { margin: 2px 0 6px; align-self: stretch; max-width: min(100%, 600px); min-width: 0; }
.cc-for { margin: 0 0 -4px; font-size: 13px; color: var(--muted); }
.gm-bub { position: relative; }
.gm-bub:has(> .x-react) { margin-bottom: 14px; }
/* The bot's emoji on the person's message: a small badge on the bubble's lower corner. */
.xbub:has(> .x-react), .photo-thumbs:has(> .x-react) { margin-bottom: 14px; }
.photo-thumbs:has(> .x-react) { position: relative; }
.x-react {
  position: absolute; right: 10px; bottom: -16px;
  min-width: 30px; height: 30px; padding: 0 5px; border-radius: 15px;
  display: grid; place-items: center; font-size: 16px; line-height: 1;
  background: var(--bub-in); box-shadow: 0 0 0 2px var(--bg);
}
@media (prefers-reduced-motion: reduce) { .cc-check { transition: none; } }
/* Study cards (STUDY-CARDS, docs/design/cloud-study-cards.md): a quiz question and a flashcard on
 * the choice card's surface and rows. A quiz's choices are lettered rows; picked, the right row is
 * outlined in --add with a check and a wrong pick in --err with a cross, the rest dashed and quiet
 * as a choice card's are, then the result, the explanation and the trap under a hairline. A
 * flashcard's front leads; its back sits under a hairline once turned over, then the grade. */
/* a question with a fact pattern reads better wide: the column's width on a phone, and more of it
 * where there is room, in a chat and in a group's column alike */
.cc-qz, .gm-col > .cc-qz { width: min(100%, 560px); }
.cc-topic { margin: 0 0 -6px; font-size: 13px; font-weight: 500; color: var(--muted); overflow-wrap: anywhere; }
.cc-qz-q, .cc-fc-back { white-space: pre-line; }
.cc-qz-q, .cc-qz-opt .cc-opt-t { text-wrap: pretty; }
.cc-qz-opt { align-items: flex-start; padding: 10px 10px 10px 10px; line-height: 1.4; }
.cc-qz-opt .cc-opt-t { padding-top: 3px; }
.cc-qz-l {
  flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--line-2); font-size: 13px; font-weight: 600; color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.cc-qz-opt.on .cc-qz-l { border-color: var(--text); color: var(--text); }
.cc-qz-opt.off .cc-qz-l { color: var(--muted); }
.cc-qz-opt.right { border: 1.5px solid var(--add); }
.cc-qz-opt.wrong { border: 1.5px solid var(--err); }
.cc-mark {
  flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  color: var(--bg);
}
.cc-mark.right { background: var(--add); }
.cc-mark.wrong { background: var(--err); }
.cc-mark .i { width: 14px; height: 14px; stroke-width: 2.4; }
.cc-qz-key { display: flex; flex-direction: column; gap: 8px; padding-top: 14px; border-top: 1px solid var(--line); }
.cc-qz-res { margin: 0 0 2px; display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 600; }
.cc-qz-res .cc-mark { width: 24px; height: 24px; }
.cc-qz-why, .cc-qz-trap { margin: 0; font-size: 15px; line-height: 1.5; overflow-wrap: anywhere; }
.cc-qz-trap { color: var(--text-2); }
.cc-qz-trap-h { margin: 4px 0 -4px; font-size: 13px; font-weight: 600; color: var(--muted); }
.cc-fc-front { font-size: 17px; font-weight: 600; line-height: 1.4; }
.cc-fc-back { margin: 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 16px; line-height: 1.5; overflow-wrap: anywhere; }
.cc-fc-back:focus { outline: none; }
.cc-fc-show { width: 100%; height: 44px; }
.cc-fc .cc-cap-btn .i { width: 15px; height: 15px; stroke-width: 2; }
.cc-fc .cc-cap-acts { scroll-margin: calc(var(--head-h, 140px) + 8px) 0 calc(var(--composer-h, 76px) + 20px); }
.cc-fc-done { margin: 0; display: flex; align-items: center; gap: 10px; font-size: 15px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.cc-fc-done .cc-mark { width: 24px; height: 24px; }
/* quiz_make's whole-quiz card (CHAT-QUIZ): a title, then one question at a time with quizCard's own
 * question and key styles, ending on a score screen. */
.cc-qs-title { font-size: 17px; font-weight: 600; }
.cc-qs-next, .cc-qs-again { width: 100%; height: 44px; }
.cc-qs-score { margin: 4px 0 0; font-size: 28px; font-weight: 700; font-variant-numeric: tabular-nums; }
.cc-qs-note { margin: 2px 0 0; }
/* the grade and when the card comes back, each kept whole: beside Undo on a phone the date takes its
 * own line, and the dot before it, in the strip the row clips at each line's start, goes with it */
.cc-fc-grade { flex: 1; min-width: 0; overflow: hidden; }
.cc-fc-parts { display: flex; flex-wrap: wrap; margin-left: -0.9em; }
.cc-fc-parts > span { white-space: nowrap; }
.cc-fc-parts > span::before { content: ""; display: inline-block; width: 0.9em; text-align: center; }
.cc-fc-parts > span + span::before { content: "·"; }
/* Undo at the graded row's end, while the service would take it: the card's own secondary button,
 * as tall as its grades, so the row keeps one height on a phone */
.cc-fc-undo { flex: none; height: 44px; padding: 0 16px; }
.cc-fc-note { margin-top: -4px; }

/* A quiet centred time at the start and between messages more than 15 minutes apart. */
.t-divider { margin: 2px 0 14px; text-align: center; font-size: 12.5px; font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; }
.gm-list > .t-divider { margin: 4px 0 0; }
.x .src-section { margin-top: 18px; }
.src-section { display: flex; flex-direction: column; gap: 10px; }
.src-label { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted); }
.src-label .src-count { color: var(--muted); font-weight: 500; }
.src-row { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin; }
.src-card {
  flex: 0 0 218px; display: flex; flex-direction: column; gap: 8px;
  padding: 12px; border-radius: 12px;
  background: var(--raised); border: 1px solid var(--line);
  text-decoration: none; color: var(--text);
  transition: transform 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
.src-ic {
  width: 28px; height: 28px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  background: var(--pro-tint); color: var(--pro);
  font-size: 14px; font-weight: 700;
}
.src-t { font-size: 13.5px; line-height: 1.4; color: var(--text); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.src-d { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (hover: hover) { .src-card:hover { border-color: var(--line-2); background: var(--raised-2); } }
.src-card:active { transform: scale(0.97); }
.src-cl { font-size: 12px; font-weight: 600; color: var(--link); }
/* "Cited, not checked" is neutral information, never a support claim: muted, not the accent. */
.src-cl.unck { color: var(--muted); }

/* A coding bot's tool calls (243, PROJECT-STEPS-LOOK, PROJECT-STEPS-LOOK-2): several calls sum
   into one quiet line, the way the Code page sums one ("Ran 2 commands, used a tool") - no
   border, no fill, muted text, starting closed with a right-pointing chevron that turns to point
   down on open (`.tk-run-head`), like the Code page's; a lone call skips that line and names
   itself, as the Code page's does. Open, a card is a plain line - kind, the step's argument in
   the mono face - with no mark and no status word for a plain finished call; running, missing
   and failed keep theirs (a spinner, the muted dash and "Not found", or the alert mark and
   "Failed"), worth seeing at a glance. The output unfolds on tap in a bounded mono block.
   Nothing is ever green: failed and missing keep their existing hues (the -tx variants, the same
   hues at text contrast), never a new color. */
.x .tk-section { margin-top: 18px; }
.tk-section { display: flex; flex-direction: column; gap: 8px; max-width: 640px; }
.tk-run-head {
  display: flex; align-items: center; gap: 6px; width: fit-content; max-width: 100%;
  padding: 4px 8px; margin: 0 -8px; border: 0; background: none; border-radius: 8px;
  color: var(--muted); font-size: 13.5px; text-align: left; cursor: pointer;
}
@media (pointer: coarse) { .tk-run-head { min-height: 44px; } }
@media (hover: hover) { .tk-run-head:hover { color: var(--text-2); } }
.tk-run-head:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
/* the run's own chevron: always there when grouped, since there's always something to open
   (never .tk-chev, a card's own, shown only when it has something to open) - right when closed,
   down when open, the same turn as a card's own (PROJECT-STEPS-LOOK-2) */
.tk-run-chev { flex: none; color: var(--faint); transition: transform 140ms ease-out; transform: rotate(-90deg); }
.tk-run-head[aria-expanded="true"] .tk-run-chev { transform: rotate(0deg); }
.tk-run-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.tk-card { overflow: hidden; }
.tk-head {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; background: none; border: 0;
  text-align: left; color: var(--muted); border-radius: 8px;
}
@media (pointer: coarse) { .tk-head { min-height: 44px; } }
@media (hover: hover) { .tk-head:hover { background: var(--hover); } }
.tk-head:active { transform: scale(0.99); }
.tk-head:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.tk-mark { display: inline-flex; flex: none; color: var(--muted); }
.tk-mark[data-status="failed"] { color: var(--err); }
.tk-mark svg.i { width: 14px; height: 14px; }
.tk-spin { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--track); border-top-color: var(--icon); animation: tkspin 800ms linear infinite; }
@keyframes tkspin { to { transform: rotate(360deg); } }
.tk-line { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex: 1; }
.tk-kind { font-size: 13.5px; color: var(--muted); white-space: nowrap; }
/* a registry tool's card words (265) are the whole line, so they're the part that's cut to fit */
.tk-kind.tk-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* an AskUserQuestion's title is the question itself (ASK-WAITING-SHOWN): the one line he has to
   read, so it wraps in full rather than cutting off like every other step's title */
.tk-kind.tk-ask-q { white-space: normal; overflow: visible; text-overflow: unset; }
.tk-head:has(.tk-ask-q) { align-items: flex-start; }
.tk-arg { font: 12px/1.4 var(--mono); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.tk-status { font-size: 12px; font-weight: 600; color: var(--muted); flex: none; }
.tk-status[data-status="failed"] { color: var(--cl-low-tx); }
.tk-chev { flex: none; color: var(--faint); transition: transform 140ms ease-out; transform: rotate(-90deg); }
.tk-head[aria-expanded="true"] .tk-chev { transform: rotate(0deg); }
/* a tool's card that made a bot or a group opens it (272) */
.tk-foot { padding: 0 12px 10px 36px; }
.tk-open { background: var(--selected); color: var(--text); }
@media (hover: hover) { .tk-open:hover { background: var(--hover); } }
/* a made document's link (TUTOR-DOCX): its name, as a row tapped to open the file */
.tk-file {
  display: flex; align-items: center; gap: 10px; min-height: 44px; max-width: 100%; box-sizing: border-box;
  padding: 6px 12px 6px 10px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg); color: var(--text); text-decoration: none;
  transition: background-color 140ms ease-out, transform 120ms ease-out;
}
.tk-foot > .tk-file { display: inline-flex; }
@media (hover: hover) { .tk-file:hover { background: var(--hover); } }
.tk-file:active { transform: scale(0.98); }
.tk-file:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.tk-file[aria-busy="true"] { opacity: 0.6; }
.tk-file-mark { display: inline-flex; flex: none; color: var(--accent); }
.tk-file-mark svg.i { width: 20px; height: 20px; }
.tk-file-words { display: flex; flex-direction: column; min-width: 0; }
.tk-file-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tk-file-kind { font-size: 12px; color: var(--muted); }
.tk-out { padding: 10px 12px; }
.tk-cmd { font: 12px/1.5 var(--mono); color: var(--text-2); white-space: pre-wrap; word-break: break-all; margin-bottom: 8px; }
.tk-out pre { margin: 0; font: 12px/1.5 var(--mono); color: var(--text-2); white-space: pre-wrap; word-break: break-word; max-height: 240px; overflow: auto; }
/* a read that found nothing (TUTOR-STEPS): the muted dash and "Not found", never the check */
.tk-mark[data-status="missing"], .tk-status[data-status="missing"] { color: var(--muted); }
/* a project's agent waiting on him (PROJECT-ASK-SHOWN): the accent, not the error hue - it's a
   question, not a failure */
.tk-mark[data-status="ask"], .tk-status[data-status="ask"] { color: var(--accent); }
.tk-ask { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
/* ASK-ANSWER: each choice is a real button (.cc-opt's own pattern: default/hover/focus-visible/
 * active/disabled states, same tokens), so tapping it answers the question from the cloud chat. */
.tk-ask-btn {
  display: flex; flex-direction: column; width: 100%; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--bg); color: var(--text); font: inherit; text-align: left;
  cursor: pointer; transition: transform 140ms ease-out, border-color 140ms ease-out, background 140ms ease-out;
}
.tk-ask-btn:disabled { cursor: default; opacity: 0.7; }
.tk-ask-btn:not(:disabled):active { transform: scale(0.98); }
@media (hover: hover) { .tk-ask-btn:not(:disabled):hover { background: var(--hover); border-color: var(--text-2); } }
.tk-ask-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tk-ask-btn.picked { border: 1.5px solid var(--text); }
.tk-ask-label { font-size: 13.5px; font-weight: 600; color: var(--text); }
.tk-ask-desc { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.tk-ask-err { font-size: 12.5px; color: var(--muted); margin-top: 6px; }
/* what a read read, in the body face: its name, where it's from, then its text in a bounded block */
.tk-view-head { margin: 0; font-size: 14px; font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.tk-view-sub { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); }
.tk-view-text { margin-top: 8px; font-size: 14px; line-height: 1.5; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 240px; overflow: auto; }
/* a fold's steps (TUTOR-STEPS) are rows inside its card, set in a step, never cards in a card */
.tk-steps { margin-top: 2px; }
.tk-steps .tk-head { border-radius: 0; padding-left: 24px; }
.tk-steps .tk-out { padding-left: 24px; }

/* A coding bot's computer (248): one quiet raised card like the tool cards', its screen at the
   desktop's own 16:10, live while the bot works and the last screenshot after; the step it's on
   in mono beside the status word, never the state's color alone. */
.cv-card { max-width: 640px; border-radius: 12px; background: var(--raised); border: 1px solid var(--line); overflow: hidden; }
.cv-head { display: flex; align-items: center; gap: 10px; padding: 10px 12px; min-width: 0; }
.cv-mark { display: inline-flex; flex: none; color: var(--icon); }
.cv-mark svg.i { width: 16px; height: 16px; }
.cv-title { font-size: 13.5px; font-weight: 600; color: var(--text); flex: none; }
.cv-step { font: 12px/1.4 var(--mono); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1; }
.cv-screen {
  display: block; width: 100%; padding: 0; border: 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  background: var(--raised-2); cursor: zoom-in; border-radius: 0;
}
.cv-screen:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.cv-holder { position: relative; aspect-ratio: 16 / 10; display: grid; place-items: center; overflow: hidden; }
.cv-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; background: var(--raised-2); }
/* The live screen (345): the account's screenshots streamed over the computer action, drawn in
   the card like the stored shots. A shot never takes the card's own click away: it passes
   through unless the person holds the computer (then it is the computer the person clicks). The
   state lives on the holder, never on the frame (COMPUTER-LIVE-STEADY): the frame is recreated
   on every swap, so it must never carry or lose the control, busy or reconnecting marks. */
.cv-live { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; pointer-events: none; background: var(--raised-2); }
.cv-holder.cv-control-on, .cv-full-screen.cv-control-on { cursor: crosshair; }
.cv-holder.cv-live-busy .cv-live, .cv-full-screen.cv-live-busy .cv-live { opacity: 0.6; }
/* Over a kept frame of a screen that stopped coming back: the quiet word in the page's muted
   text on the raised surface, until a frame arrives or the turn ends. The pill is solid, never
   the translucent glass, so it reads over a bright frame too (the glass over one was 1.62:1);
   raised-2 with muted reads 5.5:1 dark, 5:1 light, whatever the frame shows. Never over the
   starting line, never over a blank. */
.cv-holder.cv-reconnecting::after, .cv-full-screen.cv-reconnecting::after {
  content: "Reconnecting…";
  position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%);
  padding: 3px 10px; border-radius: 999px;
  font: 12px/1.4 var(--sans); color: var(--muted);
  background: var(--raised-2); border: 1px solid var(--glass-line); box-shadow: var(--glass-shadow);
  pointer-events: none; white-space: nowrap; z-index: 2;
}
.cv-shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.cv-empty { margin: 0; font-size: 13px; color: var(--muted); }
.cv-foot { display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 8px 12px; flex-wrap: wrap; }
.cv-foot .btn svg.i { width: 14px; height: 14px; }
.cv-note { margin: 0 auto 0 0; font-size: 13px; color: var(--text-2); min-width: 0; }
.cv-note[data-error="true"] { color: var(--cl-low-tx); }
.cv-note[hidden], .cv-foot .btn[hidden] { display: none; }

/* The full view (248): the page's own surface over everything, the bar with the step and Take
   control, and the screen as large as fits at 16:10. Taken control, the frame takes input. */
.cv-full {
  position: fixed; inset: 0; z-index: 60; display: flex; flex-direction: column;
  background: var(--bg); min-height: 100dvh;
}
.cv-full[hidden] { display: none; }
.cv-full-bar {
  display: flex; align-items: center; gap: 10px; padding: 10px 16px;
  padding-top: max(10px, env(safe-area-inset-top)); border-bottom: 1px solid var(--line);
}
.cv-full-words { flex: 1; min-width: 0; }
.cv-full-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); }
.cv-full-step { margin: 2px 0 0; font: 12px/1.4 var(--mono); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cv-full > .cv-note { margin: 10px 16px 0; }
.cv-full-screen {
  position: relative; flex: 1; min-height: 0; margin: 12px auto 16px;
  width: min(calc(100vw - 32px), calc((100dvh - 120px) * 1.6)); max-height: calc((100vw - 32px) / 1.6);
  aspect-ratio: 16 / 10; border-radius: 10px; overflow: hidden; background: var(--raised-2); border: 1px solid var(--line);
}
.cv-full-screen .cv-frame { pointer-events: auto; }
@media (max-width: 559px) {
  .cv-full-bar { padding-left: 12px; padding-right: 12px; }
  /* a phone fits the desktop to its width, at the desktop's own 16:10 */
  .cv-full-screen { flex: none; width: calc(100vw - 24px); height: auto; max-height: none; margin: 12px auto; }
}

/* The files an answer names (CHAT-ARTIFACTS): a row of cards right under its words, each its preview over its name
 * and kind, 240px wide at every width, so a phone has one to a row and a desktop sets them side by side. The card
 * itself carries no border or fill (CARD-QUIET, Eric 2026-10-25 of this same boxed look elsewhere: "it looked
 * better without the borders and bg color"; the lead's own note on this card's approval asked for plain text under
 * the preview, no box). Its preview alone keeps a hairline frame and radius - a PDF's white page needs an edge
 * against a dark surface - with hover, the focus ring and the pressed scale on the preview alone; a PDF's first
 * page sits whole on it like paper on a desk, an image covers the box, and a page's first screen shows from its
 * top. The name and kind sit under it as plain text. */
.fc-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.fc-row:empty { display: none; }
.fc {
  width: 240px; max-width: 100%; padding: 0; display: flex; flex-direction: column; text-align: left;
  border: none; background: transparent; color: var(--text); font: inherit; cursor: pointer;
}
@media (hover: hover) { .fc:not(:disabled):hover .fc-prev { background: var(--hover); } }
.fc:not(:disabled):active .fc-prev { transform: scale(0.98); }
.fc:focus-visible .fc-prev { outline: 2px solid var(--ring); outline-offset: 2px; }
.fc:disabled { cursor: default; }
.fc[aria-busy="true"] { cursor: progress; }
.fc-prev {
  height: 180px; display: grid; place-items: center; overflow: hidden; border-radius: 12px;
  background: var(--raised-2); border: 1px solid var(--line);
  transition: background-color 140ms ease-out, transform 120ms ease-out;
}
.fc-prev img { display: block; }
.fc-prev[data-kind="pdf"] img { max-width: calc(100% - 48px); max-height: calc(100% - 28px); box-shadow: 0 0 0 1px var(--line-2), 0 2px 8px rgba(0, 0, 0, 0.12); }
.fc-prev[data-kind="image"] img, .fc-prev[data-kind="html"] img, .fc-prev[data-kind="folder"] img { width: 100%; height: 100%; object-fit: cover; }
.fc-prev[data-kind="html"] img { object-position: top; }
/* while its preview comes, the box breathes; nothing moves for a reader who asked for less motion */
.fc-prev.loading { animation: fc-wait 1.4s ease-in-out infinite; }
@keyframes fc-wait { 50% { opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) { .fc-prev.loading { animation: none; } }
.fc-mark { display: inline-flex; color: var(--muted); }
.fc-mark svg.i { width: 28px; height: 28px; stroke-width: 1.4; }
.fc-words { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 9px 12px 10px; }
.fc-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fc-kind { font-size: 12px; color: var(--muted); }
.fc-off .fc-name { color: var(--text-2); }

/* A file opened full screen (CHAT-ARTIFACTS): the page's own surface over everything, as the computer's full view is
 * (.cv-full), with its bar (the name, its kind and size, Share, Download and Close) over the file on the raised
 * surface: a PDF's pages in one column at most 900px wide, an image fit to the screen, or a page in its frame. The
 * zoom box scrolls, so a zoomed image or column pans by scrolling; its pinch is the viewer's own (pan-x pan-y). */
.file-view { position: fixed; inset: 0; z-index: 60; display: flex; flex-direction: column; background: var(--bg); min-height: 100dvh; }
.file-view[hidden] { display: none; }
.file-view-bar {
  display: flex; align-items: center; gap: 8px; padding: 10px 16px;
  padding-top: max(10px, env(safe-area-inset-top)); border-bottom: 1px solid var(--line);
}
.file-view-words { flex: 1; min-width: 0; }
.file-view-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-view-sub { margin: 2px 0 0; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-view-bar a.round-btn { color: var(--text); text-decoration: none; }
.file-view-bar .round-btn[hidden] { display: none; }
.file-view-bar .round-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.file-view-body { flex: 1; min-height: 0; display: flex; background: var(--raised-2); padding-bottom: env(safe-area-inset-bottom); }
.fv-zoom { flex: 1; min-width: 0; display: flex; overflow: auto; position: relative; overscroll-behavior: contain; cursor: zoom-in; }
.file-view .fv-zoom { touch-action: pan-x pan-y; }
.fv-zoom.zoomed { cursor: zoom-out; }
.fv-zoom:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.fv-stage { flex: none; margin: auto; }
.fv-img { display: block; width: 100%; height: 100%; box-shadow: 0 2px 16px rgba(0, 0, 0, 0.18); }
.fv-pages { display: flex; flex-direction: column; gap: 12px; padding: 12px 0 24px; }
.fv-page { display: block; width: 100%; height: auto; background: var(--raised); box-shadow: 0 0 0 1px var(--line-2), 0 2px 10px rgba(0, 0, 0, 0.1); }
/* a page's own canvas is white, as a browser draws one with no background of its own */
.fv-frame { flex: 1; width: 100%; height: 100%; border: 0; background: white; }
.fv-note { margin: auto; padding: 24px; max-width: 420px; text-align: center; font-size: 14px; color: var(--text-2); }
.fv-pages > .fv-note { margin: 0 auto; padding: 8px 16px; }
/* a folder's own file that opens only as a download (SHARE-FOLDER): a plain named row among its images and pages */
.fv-download-row { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 10px; background: var(--raised); box-shadow: 0 0 0 1px var(--line-2); color: var(--text); text-decoration: none; }
@media (hover: hover) { .fv-download-row:hover { background: var(--hover-2); } }
.fv-download-row:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.fv-download-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 559px) {
  .file-view-bar { padding-left: 12px; padding-right: 12px; gap: 6px; }
}

.a-body { display: flex; flex-direction: column; gap: 10px; max-width: 640px; font-family: var(--sans); }
.a-body p { margin: 0; font-size: 16px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; }
/* a message the page couldn't draw is its words alone (CHAT-LOAD), its own line breaks kept */
.a-body.plain p { white-space: pre-line; }
/* The answer's safe Markdown subset: emphasis and structure built from the page's own tokens,
   never a second color or font family, and never innerHTML. Sizes stay within the answer scale;
   headings are styled text, never page headings; code stays in the mono face. */
.a-body strong { font-weight: 700; }
.a-body em { font-style: italic; }
.a-body del { color: var(--muted); text-decoration: line-through; text-decoration-thickness: 1.5px; }
.a-body code {
  font-family: var(--mono); font-size: 0.88em;
  background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  padding: 0.5px 5px;
}
.a-body pre {
  margin: 0; max-width: 100%; overflow-x: auto;
  padding: 10px 12px; background: var(--bg); border: 1px solid var(--line); border-radius: 12px;
}
.a-body pre code {
  font-family: var(--mono); font-size: 13.5px; line-height: 1.6;
  background: transparent; border: 0; padding: 0; border-radius: 0;
}
.a-body p.a-h1, .a-body p.a-h2, .a-body p.a-h3 { color: var(--text); }
.a-body .a-h1 { font-size: 19px; line-height: 1.35; font-weight: 650; }
.a-body .a-h2 { font-size: 17.5px; line-height: 1.35; font-weight: 650; }
.a-body .a-h3 { font-size: 16px; line-height: 1.4; font-weight: 650; }
.a-body ul, .a-body ol { margin: 0; padding-left: 22px; }
.a-body li { font-size: 16px; line-height: 1.5; color: var(--text); }
.a-body li + li { margin-top: 6px; }
/* a table (268) scrolls sideways in its own frame inside the bubble, never the page */
.a-table { max-width: 100%; overflow-x: auto; }
.a-table table { border-collapse: collapse; font-size: 14.5px; line-height: 1.4; font-variant-numeric: tabular-nums; }
.a-table th, .a-table td { padding: 6px 12px 6px 0; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line-2); }
.a-table th { font-weight: 650; color: var(--text); white-space: nowrap; }
.a-table tr:last-child td { border-bottom: 0; }
.a-body li.task { list-style: none; margin-left: -24px; }
.a-body li.task input { margin: 0 8px 0 0; vertical-align: -1px; width: 15px; height: 15px; }
.a-body blockquote {
  margin: 0; padding: 2px 0 2px 14px;
  border-left: 3px solid var(--line); color: var(--text-2);
}
/* a callout (ANSWER-EXPRESSION): a block quote whose first line is a [!NOTE]/[!TIP]/[!IMPORTANT]/
 * [!WARNING] marker. It keeps the quote's shape and tokens, never a second surface or color; the
 * label is the only element that reads stronger, so a callout cannot be mistaken for prose. */
.a-body .a-callout { margin: 0; padding: 2px 0 2px 14px; border-left: 3px solid var(--line); color: var(--text-2); line-height: 1.5; }
.a-body .a-callout-label { font-weight: 650; color: var(--text); font-size: 15px; line-height: 1.4; padding-bottom: 1px; }
/* a labelled code block (ANSWER-EXPRESSION): the language a model named after the fence is one
 * muted label above the block, never part of the code. Every block carries a Copy button
 * (CODE-BLOCKS) in the same head row, lang or not: .a-code-copy mirrors .ma-btn's small
 * icon-button shape, sized for this slimmer row, its ::before still widening the tap to 44px. */
.a-body .a-code { margin: 0; }
.a-body .a-code-head { display: flex; align-items: center; padding: 0 2px 4px; }
.a-body .a-code-lang { font: 12px/1.4 var(--mono); color: var(--muted); }
.a-body .a-code-copy {
  position: relative; margin-left: auto; width: 20px; height: 20px; flex: none;
  border: 0; border-radius: 5px; background: transparent;
  color: var(--muted); display: grid; place-items: center; cursor: pointer;
  transition: transform 140ms ease-out, background 140ms ease-out, color 140ms ease-out;
}
.a-body .a-code-copy::before { content: ""; position: absolute; inset: -12px; }
.a-body .a-code-copy svg.i { width: 12px; height: 12px; }
.a-body .a-code-copy.ok { color: var(--add); }
@media (hover: hover) { .a-body .a-code-copy:hover { background: var(--hover-2); color: var(--text); } }
.a-body .a-code-copy:active:not(.ok) { transform: scale(0.94); }
/* CODE-BLOCKS: the vendored highlighter (code-highlight.js) tokenizes a recognized language's
 * code into these spans; an unnamed or unrecognized language leaves the code element's plain
 * text alone, so it keeps reading in the ordinary code color with none of these classes present. */
.a-body .tok-kw { color: var(--code-kw); }
.a-body .tok-str { color: var(--code-str); }
.a-body .tok-num { color: var(--code-num); }
.a-body .tok-key { color: var(--code-key); }
.a-body .tok-com { color: var(--muted); }
.a-body ol.a-steps { padding-left: 28px; }
.a-body ol.a-steps > li::marker { color: var(--text-2); font-weight: 700; }
.a-body a.a-link { color: var(--link); text-decoration: none; }
@media (hover: hover) { .a-body a.a-link:hover { text-decoration: underline; text-underline-offset: 3px; } }
.cite {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 5px; box-sizing: border-box;
  margin: 0 2px; border-radius: 10px; vertical-align: 1px;
  background: var(--raised); border: 1px solid var(--line);
  color: var(--link); font-size: 12px; font-weight: 650; line-height: 1;
  cursor: pointer;
  transition: transform 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
@media (hover: hover) { .cite:hover { border-color: var(--line-2); background: var(--raised-2); } }
.cite:active { transform: scale(0.95); }
/* The quiet "N sources" control under a Sources-off answer: one plain line that opens the full
   list, never a second copy of the sources beside the inline chips. */
.ct-list-btn {
  align-self: flex-start; margin-top: 6px; padding: 2px 8px; border: 0; background: transparent;
  color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: transparent;
}
@media (hover: hover) { .ct-list-btn:hover { color: var(--text-2); text-decoration-color: var(--line-2); } }
/* The citation popover is a small card: a source's title and site, never a 400px claim sheet. */
#ct-pop { max-width: 320px; }

/* The actions row rides under a finished answer: Copy (and, when the page has one, Retry), quiet
 * 28px buttons in the muted tone, 44px under a finger through the widened ::before. */
.m-acts { display: flex; gap: 2px; margin-top: 4px; padding-left: 4px; }
.ma-btn {
  position: relative; width: 32px; height: 32px;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--muted); display: grid; place-items: center; cursor: pointer;
  transition: transform 140ms ease-out, background 140ms ease-out, color 140ms ease-out;
}
.ma-btn::before { content: ""; position: absolute; inset: -6px; }
.ma-btn svg.i { width: 15px; height: 15px; }
.ma-btn.ok { color: var(--add); }
.ma-btn:disabled { opacity: 0.45; cursor: default; }
@media (hover: hover) { .ma-btn:not(:disabled):hover { background: var(--hover-2); color: var(--text); } }
.ma-btn:active:not(.ok):not(:disabled) { transform: scale(0.94); }

/* REGENERATE: the "1/2" version switcher under an answer with earlier versions, quiet like
 * ct-list-btn beside it; its arrows are .ma-btn's own, so their size, hit area and states match
 * Copy and Regenerate exactly. */
.m-versions { display: flex; align-items: center; gap: 2px; margin-top: 2px; padding-left: 4px; }
.mv-count { font-size: 12.5px; color: var(--muted); }

/* Edit (EDIT-RESEND): the person's own latest message's own actions row, under its bubble's time
 * and checks, at the right; its own class, never .m-acts, so a selector scoped to one exchange's
 * answer-side actions (assuming at most the one row .m-acts has always been) never also matches
 * this one. */
.x-acts { display: flex; gap: 2px; margin-top: 4px; align-self: flex-end; }

.a-stopped { margin: 6px 0 0; padding-left: 8px; font-size: 13px; color: var(--muted); }

.a-note {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--raised); border: 1px solid var(--line);
}
/* The every-account-at-its-limit card and the generic failed-turn card (LIMIT-CARD-NOBOX): no
 * box, as the Code page's own `.limit-note` draws the same notice - the padding stays, so the
 * spacing around the card doesn't change, only its fill and border. */
.a-note.plain { background: none; border: 0; }
.a-note.plain .note-msg { color: var(--text-2); }
.note-tag { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 650; color: var(--warn); }
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.dot.warn { background: var(--warn); }
.a-note .note-msg { margin: 0; color: var(--text); font-size: 15px; }
.a-note .note-msg small { color: var(--text-2); }
.a-note .note-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.a-note .note-reset { margin: 0; font-size: 13.5px; color: var(--text-2); flex: 1; min-width: 0; }
.a-note .note-corr { margin: 0; font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.a-note .up, .bp-cap .up { color: var(--link); font-size: 14px; font-weight: 600; text-decoration: none; }
.a-note button.up, .bp-cap button.up { border: 0; background: none; padding: 0; margin: 0; cursor: pointer; }
@media (hover: hover) { .a-note .up:hover, .bp-cap .up:hover { text-decoration: underline; text-underline-offset: 3px; } }

/* ---------- Sources mode: claims, confidence and the per-claim UI ---------- */
/* A sourced answer's claims are spans in place, genuinely inline so the text flows with the
 * prose (a <button> is atomic in the layout and cannot compute display:inline, which would push
 * a list item's bullet beside its last line and drop the marks onto their own line; 220b). Each
 * claim is a control whose underline's style and color differ by level (high solid, medium
 * dashed, low dotted; never color alone - the level is read in words on focus and in the
 * popover). An unchecked claim (214b/220b: the verifier could not run) gets no level hue: a thin
 * neutral dotted line from the muted token, the quiet "Not checked" words, and its marks still
 * show. Until the confidence arrives a claim carries a subtle checking chip instead of a level. */
.clu { display: inline; }
.cl {
  display: inline; margin: 0; padding: 0; border: 0; background: transparent;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1.5px;
  text-underline-offset: 3px; text-decoration-skip-ink: auto;
  border-radius: 3px;
}
.cl.cl-high { text-decoration-style: solid; text-decoration-color: var(--cl-high); }
.cl.cl-medium { text-decoration-style: dashed; text-decoration-color: var(--cl-med); }
.cl.cl-low { text-decoration-style: dotted; text-decoration-color: var(--cl-low); }
.cl.cl-unchecked { text-decoration-style: dotted; text-decoration-color: var(--muted); }
.cl.cl-checking { text-decoration: none; }
.cl .cl-lv {
  display: none; margin-left: 6px;
  font-size: 13px; font-weight: 650; color: var(--text-2);
}
.cl:focus-visible .cl-lv { display: inline; }
.cl-check {
  display: inline-flex; align-items: center; gap: 5px;
  margin-left: 7px; color: var(--muted);
  font-size: 12.5px; font-weight: 550;
}
.cl-check-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--muted);
  animation: clchk 1.3s ease-in-out infinite;
}
@keyframes clchk { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

.cm {
  display: inline; /* never atomic: an inline "[n]" between the claim's words leaves no line
                    break opportunity for a strand of its own, at any face or width (231) */
  margin: 0 1px; padding: 0 1px;
  border: 0; background: transparent;
  color: var(--link); font-size: 13px; font-weight: 600;
  text-decoration: none; vertical-align: 1px; cursor: pointer;
}
@media (hover: hover) { .cm:hover { text-decoration: underline; text-underline-offset: 3px; } }
.cm.ns { color: var(--muted); font-weight: 500; }

/* The one-line summary at the top of a sourced answer; it opens the claims grouped by level.
 * The dot is never decoration: its color is the weakest checked level present (low, medium, or
 * high from the same tokens as the underlines, never the page's accent), the level is named in
 * the pill's accessible label too, and an answer with no checked claim (all unchecked) carries
 * a quiet neutral dot from the muted token, never a false weakness. */
.cl-summary {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 9px;
  height: 40px; padding: 0 15px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--text-2);
  font-size: 14px; font-weight: 600;
  transition: transform 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
.cl-summary::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted); flex: none;
}
.cl-summary.lv-high::before { background: var(--cl-high); }
.cl-summary.lv-medium::before { background: var(--cl-med); }
.cl-summary.lv-low::before { background: var(--cl-low); }
@media (hover: hover) { .cl-summary:hover { background: var(--hover); border-color: var(--line-2); color: var(--text); } }
.cl-summary:active { transform: scale(0.97); }

/* The claim popover and the summary's list: floating cards over the page, a sheet at phone
 * width (see the phone block). The overlay itself never takes pointers; only the cards do. */
.cl-layer { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.clp {
  position: fixed; pointer-events: auto;
  min-width: 280px; max-height: min(560px, calc(100dvh - 20px));
  overflow-y: auto;
  background: var(--raised); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: var(--shadow);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px;
  animation: menu-in 150ms cubic-bezier(0.23, 1, 0.32, 1);
}
.clp-head { display: flex; flex-direction: column; gap: 3px; margin-bottom: 4px; }
.clp-level { margin: 0; font-size: 15px; font-weight: 650; }
.clp-high { color: var(--cl-high-tx); }
.clp-med { color: var(--cl-med-tx); }
.clp-low { color: var(--cl-low-tx); }
.clp-unchecked { color: var(--muted); }
.clp-checking { color: var(--muted); }
.clp-reason { margin: 0; font-size: 13.5px; color: var(--text-2); }
.clp-note { margin: 0; font-size: 13.5px; color: var(--muted); font-style: italic; }
.clp-cap {
  margin: 8px 0 0; padding: 0 2px;
  font-size: 12px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.02em;
}
.clp-sp { display: flex; flex-direction: column; gap: 7px; padding: 11px 0 3px; border-top: 1px solid var(--divider); }
.clp-sp-head { display: flex; align-items: center; gap: 10px; }
.clp-sp-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.clp-sp-t { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--text); line-height: 1.4; }
.clp-sp-d { margin: 0; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clp-vt { display: inline-flex; align-items: center; gap: 6px; flex: none; font-size: 12.5px; font-weight: 650; }
.clp-vt-supports { color: var(--cl-high-tx); }
.clp-vt-partly { color: var(--cl-med-tx); }
.clp-vt-contradicts { color: var(--cl-low-tx); }
.dot.supports { background: var(--add); }
.dot.partly { background: var(--warn); }
.dot.contradicts { background: var(--err); }
.clp-quote { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-2); }
.clp-open {
  align-self: flex-start;
  color: var(--link); font-size: 13px; font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px;
}
.clp-srcnum { color: var(--link); font-size: 13px; font-weight: 600; }
.cls-row {
  display: block; width: 100%; text-align: left;
  border: 0; background: transparent; border-radius: 8px;
  padding: 8px 10px; cursor: pointer;
}
@media (hover: hover) { .cls-row:hover { background: var(--hover); } }
.cls-row:active { transform: scale(0.99); }
.cls-t {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: 13.5px; line-height: 1.5; color: var(--text-2);
}

/* ---------- plans ---------- */
.plans {
  min-height: 100dvh; display: flex; flex-direction: column; justify-content: center;
  gap: 14px; max-width: 880px; margin: 0 auto; padding: 40px 20px 48px;
}
.plans .wordmark { margin-bottom: 6px; }
.p-h1 { margin: 0; font-size: 32px; line-height: 1.2; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; }
.p-lead { margin: 0; color: var(--text-2); max-width: 52ch; }
.plan-cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(198px, 1fr));
  gap: 12px; margin-top: 10px;
}
.pl-card {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; border-radius: 12px;
  background: var(--raised); border: 1px solid var(--line);
}
/* The account's own card is called out with a strong neutral border, never a second accent color
   next to the orange one, and the "Current plan" pill (PLANS-TRUE). */
.pl-card.current { border-color: var(--text-2); box-shadow: 0 0 0 1px var(--text-2) inset; }
/* Pro is written as Recommended and drawn apart for everyone not already on it; the account's own
   card is called current instead, never sold the plan it has. */
.pl-card.recommended:not(.current) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset, var(--shadow); }
.pl-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.pl-tags { display: flex; gap: 6px; flex: none; }
.pl-name { margin: 0; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.pl-until { margin: 0; font-size: 13px; color: var(--muted); }
/* The current subscription's card (WEB-AUTORENEW): "Renews monthly." reads like the paid lines,
   and the manage and keep buttons take the card's pad at the bottom, same width as an upgrade
   control, never a second full-width CTA beside the plan's own price. */
.pl-renew { margin: 0; font-size: 13px; color: var(--text-2); }
.pl-manage { margin-top: auto; width: 100%; }
.current-tag {
  font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
  padding: 2px 8px; border-radius: 999px;
  background: var(--selected); color: var(--text-2);
  text-transform: uppercase; flex: none;
}
.pl-rec {
  font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
  padding: 2px 8px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent);
  text-transform: uppercase; flex: none;
}
.pl-price { display: flex; flex-direction: column; gap: 2px; }
.pl-price .pl-m { margin: 0; font-size: 22px; font-weight: 650; letter-spacing: -0.01em; }
.pl-price .pl-m:not(:first-child) { font-size: 13px; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.pl-pitch { margin: 0; font-size: 14px; line-height: 1.45; color: var(--text-2); }
.pl-feats { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
.pl-feats li { display: flex; align-items: baseline; gap: 7px; font-size: 14px; line-height: 1.45; color: var(--text-2); }
.pl-feats .pl-check { flex: none; align-self: center; color: var(--accent-tx); }
.pl-feats .pl-check svg.i { width: 13px; height: 13px; stroke-width: 2; }
.pl-feats .pl-feats-head { font-weight: 650; color: var(--text); }
.pl-cta { margin-top: auto; width: 100%; }
.plans-acts { display: flex; gap: 10px; margin-top: 10px; }
.plans-acts .btn { align-self: flex-start; }
#plans-back { background: var(--selected); color: var(--text); }
@media (hover: hover) { #plans-back:hover { background: var(--selected); color: var(--text); } }
.u-empty { margin: 0; color: var(--muted); }
.up-note { margin: 0; font-size: 14px; color: var(--text-2); }
/* The one free week of Pro (355, PLANS-TRUE): above the paid plans the panel offers it with no
   card, never again - or, once used, says it was used. What Free includes lives in the Free
   card's own checklist, never re-stated above the cards. Nothing here sells a card. */
.pl-trial { display: flex; flex-direction: column; gap: 6px; }
.pl-trial .pl-cta { margin-top: 4px; align-self: flex-start; }
.pl-nocard { margin: 0; font-size: 13px; color: var(--muted); }
.pl-trial-used { margin: 0; font-size: 14px; color: var(--text); }
.pl-trial-note { margin: 0; }

/* ---------- usage ---------- */
.usage { min-height: 100%; }
.u-inner {
  max-width: var(--col); margin: 0 auto;
  padding: 34px 20px 60px;
  display: flex; flex-direction: column; gap: 18px;
}
.u-h1 { margin: 0; font-size: 30px; line-height: 1.2; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; }
.u-plan { margin: 0; color: var(--text-2); }
.usage-bars { display: flex; flex-direction: column; gap: 20px; }
.bar { display: flex; flex-direction: column; gap: 8px; }
.bar-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.bar-label { font-size: 15px; font-weight: 600; color: var(--text); }
.bar-value { font-size: 14px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.bar-track { height: 8px; border-radius: 999px; background: var(--track); overflow: hidden; }
.bar-fill { height: 100%; border-radius: 999px; background: var(--add); transition: width 200ms ease-out; }
.bar.reached .bar-fill { background: var(--warn); }
.bar-reset { margin: 0; font-size: 12.5px; color: var(--muted); }
.u-reached { margin: 0; font-size: 14px; color: var(--warn); font-weight: 600; }
.u-cta { align-self: flex-start; }
/* Extra usage (242): the balance and its credit list on the usage view, a raised card like the
   page's other cards. In the app the amounts read as plain numbers, never dollars, like the
   rest of the app's usage view. */
.u-extra {
  display: flex; flex-direction: column; gap: 10px;
  border: 1px solid var(--line); border-radius: 12px;
  padding: 14px 16px; background: var(--raised);
}
.u-extra-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.u-extra-label { font-size: 15px; font-weight: 600; color: var(--text); }
.u-extra-value { font-size: 14px; font-weight: 600; color: var(--add); font-variant-numeric: tabular-nums; }
.u-credits { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.u-credit {
  display: flex; align-items: baseline; gap: 8px;
  padding: 8px 0; border-top: 1px solid var(--divider);
  font-size: 13.5px;
}
.u-credit:first-child { border-top: 0; }
.u-credit-who { color: var(--text-2); }
.u-credit-amt { color: var(--text); font-variant-numeric: tabular-nums; }
.u-credit-at { margin-left: auto; color: var(--muted); font-size: 12.5px; }

/* ---------- the owner's errors list (ERROR-REPORTING) ---------- */
.errors-list { display: flex; flex-direction: column; gap: 12px; }
.err-row {
  display: flex; flex-direction: column; gap: 4px;
  border: 1px solid var(--line); border-radius: 12px;
  padding: 14px 16px; background: var(--raised);
}
.err-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.err-kind { font-size: 15px; font-weight: 600; color: var(--text); }
.err-count { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.err-message { margin: 0; font-size: 14px; color: var(--text-2); }
.err-location { margin: 0; font-family: var(--mono); font-size: 12.5px; color: var(--muted); word-break: break-all; }
.err-seen { margin: 0; font-size: 12.5px; color: var(--muted); }

/* the rail's Usage entry: a quiet row under New thread */


/* ---------- the invite's guest and the inviter's menu ---------- */
/* The thread's top row holds the guest note (read-only invites) on the left and the Invite
 * affordance (a signed-in thread's owner) on the right. Never both at once. */
.thread-top { display: flex; flex-direction: column; gap: 12px; }
.guest-note {
  margin: 0; align-self: stretch;
  font-size: 15px; font-weight: 600; color: var(--text-2);
  display: flex; align-items: center; gap: 9px;
}
.guest-note::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); flex: none;
}

/* ---------- PIN-MESSAGE: the chat or group's one pinned message ---------- */
/* A thin bar, plain, no card: it sits just under the floating head and stays there while the
 * thread scrolls under it, same as the head itself. Tapping its quote scrolls to the message and
 * flashes it (the quote block it reuses, .xq); its own x unpins, and so does a hold or right
 * click on the bar. */
.pin-bar {
  position: sticky; top: var(--head-h, 140px); z-index: 15;
  display: flex; align-items: center; gap: 4px;
  margin: 0 0 10px; padding: 0 2px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
}
.pin-bar-tap.xq { flex: 1; min-width: 0; margin: 0; max-width: none; padding: 5px 8px; background: transparent; color: var(--text); }
.pin-bar-tap.xq .xq-bar { background: var(--accent); }
@media (hover: hover) { .pin-bar-tap.xq:hover { background: var(--hover); } }
.pin-bar-x {
  flex: none; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  border-radius: 50%; color: var(--muted);
  transition: background 140ms ease-out, color 140ms ease-out;
}
.pin-bar-x .i { width: 16px; height: 16px; }
@media (hover: hover) { .pin-bar-x:hover { background: var(--hover); color: var(--text); } }
.pin-bar-x:active { transform: scale(0.94); }
.pin-bar-x:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

.invite-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 44px; padding: 0 18px;
  border: 1px solid var(--glass-line); border-radius: 999px;
  background: var(--glass); color: var(--text);
  font-size: 15px; font-weight: 600;
  transition: transform 140ms ease-out, background 140ms ease-out, border-color 140ms ease-out;
}
.invite-btn svg.i { width: 15px; height: 15px; color: var(--muted); }
.invite-btn[aria-expanded="true"] { background: var(--selected); }
@media (hover: hover) { .invite-btn:hover { background: var(--selected); } }
.invite-btn:active { transform: scale(0.97); }

#home-note { margin-top: 14px; text-align: center; }

#invite-menu { min-width: 304px; }
.btn.small { height: 32px; padding: 0 12px; font-size: 13.5px; border-radius: 8px; }
.invite-form { display: flex; gap: 8px; padding: 6px 6px 8px; }
.invite-field {
  flex: 1; min-width: 0; height: 38px; padding: 0 12px;
  border: 1px solid var(--line-2); border-radius: 8px;
  background: var(--raised-2); color: var(--text);
  font-size: 14px;
}
.invite-field::placeholder { color: var(--faint); }
.invite-field:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px rgba(63, 119, 193, 0.25); }
.invite-form .btn.small { height: 38px; background: var(--accent); color: var(--on-accent); }
@media (hover: hover) { .invite-form .btn.small:hover { background: color-mix(in srgb, var(--accent) 88%, var(--text)); } }
.menu-note { display: block; margin: 0; padding: 6px 10px 8px; font-size: 12.5px; line-height: 1.45; color: var(--muted); }
.invite-made { padding: 2px 6px 6px; display: flex; flex-direction: column; gap: 2px; }
.invite-made-row { display: flex; align-items: center; gap: 8px; padding: 4px 4px; }
.invite-link {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: 13px; color: var(--text-2);
  background: var(--raised-2); border: 1px solid var(--line);
  border-radius: 8px; padding: 7px 10px; user-select: all;
}
.invite-made-row .btn.small { flex: none; background: var(--selected); color: var(--text); }
.invite-list { display: flex; flex-direction: column; }
.invite-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; min-height: 44px; }
.invite-row + .invite-row { border-top: 1px solid var(--divider); }
.invite-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.invite-name { font-size: 14px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-meta { font-size: 12px; color: var(--muted); }
.invite-status {
  font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
  padding: 2px 8px; border-radius: 999px;
  background: var(--hover); color: var(--muted);
  text-transform: uppercase; flex: none;
}
.btn.small.danger-link { background: var(--hover); color: var(--err); }
@media (hover: hover) { .btn.small.danger-link:hover { background: var(--hover-2); color: var(--err); } }

/* ---------- a bot's page (239) ---------- */
.bot-page, .instr { min-height: 100%; }
.bp-inner { max-width: 560px; margin: 0 auto; padding: 0 16px 56px; display: flex; flex-direction: column; }
.bp-hero { display: grid; place-items: center; padding: 4px 0 22px; }
.bp-card { background: var(--card); border-radius: 18px; }
.bp-names { display: flex; flex-direction: column; overflow: hidden; }
.bp-name, .bp-title {
  width: 100%; border: 0; outline: none; background: transparent; text-align: center; color: var(--text);
}
.bp-name { height: 60px; padding: 0 16px; font-size: 22px; font-weight: 650; letter-spacing: -0.015em; }
.bp-title { height: 54px; padding: 0 16px; font-size: 16px; color: var(--text-2); border-top: 1px solid var(--divider); margin: 0 20px; width: calc(100% - 40px); }
.bp-title::placeholder { color: var(--faint); }
.bp-name:focus-visible, .bp-title:focus-visible { outline: 2px solid var(--ring); outline-offset: -4px; border-radius: 12px; }
#bp-err { margin: 10px 0 0; }
.bp-tabs { display: flex; margin: 28px 0 0; border-bottom: 1px solid var(--divider); }
.bp-tab {
  position: relative; flex: 1; height: 48px; border: 0; background: none;
  font-size: 15.5px; color: var(--muted);
}
.bp-tab[aria-selected="true"] { color: var(--text); font-weight: 550; }
.bp-tab[aria-selected="true"]::after { content: ""; position: absolute; left: 12%; right: 12%; bottom: -1px; height: 2px; border-radius: 2px; background: var(--text); }
@media (hover: hover) { .bp-tab:not([aria-selected="true"]):hover { color: var(--text-2); } }
.bp-panel { display: flex; flex-direction: column; }
.bp-label { margin: 24px 18px 8px; font-size: 13.5px; color: var(--muted); }
.bp-cap { margin: 8px 18px 0; font-size: 13px; color: var(--muted); }
.bp-character { padding: 18px 16px 4px; }
.bp-shapes { display: grid; grid-template-columns: repeat(4, 64px); justify-content: center; gap: 12px 18px; }
.shape-btn, .color-btn {
  position: relative; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: transparent;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.shape-btn { width: 64px; height: 64px; }
.shape-btn .mark { width: 46px; height: 46px; }
.color-btn { width: 46px; height: 46px; }
.color-btn .swatch { width: 34px; height: 34px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--char-edge); }
.shape-btn[aria-checked="true"], .color-btn[aria-checked="true"] { box-shadow: 0 0 0 2.5px var(--muted); }
.shape-btn:active, .color-btn:active { transform: scale(0.94); }
@media (hover: hover) { .shape-btn:not([aria-checked="true"]):hover, .color-btn:not([aria-checked="true"]):hover { box-shadow: 0 0 0 2px var(--line-2); } }
.bp-colors { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 16px; max-width: calc(6 * 46px + 5 * 16px); margin: 22px auto 14px; }
.bp-sep { height: 1px; background: var(--divider); }
.bp-character .bp-sep { margin: 0 -16px 0 0; }
.bp-link {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 50px; padding: 0;
  border: 0; background: none; text-align: left; font-size: 16px; color: var(--link);
}
.bp-link:disabled { cursor: default; color: color-mix(in srgb, var(--link) 55%, var(--raised)); }
@media (hover: hover) { .bp-link:not(:disabled):hover { text-decoration: underline; text-underline-offset: 3px; } }
.bp-row, .bp-switch {
  display: flex; align-items: center; gap: 14px; width: 100%; min-height: 62px; padding: 10px 18px;
  border: 0; text-align: left; color: var(--text);
}
.bp-row { margin-top: 22px; background: var(--card); }
.bp-switch { background: transparent; }
.bp-row .ic, .bp-row .bp-chev { color: var(--muted); }
.bp-row svg.i { width: 20px; height: 20px; }
@media (hover: hover) { .bp-row:hover { background: var(--hover-2); } .bp-switch:hover { background: var(--hover-2); } }
.bp-switches { overflow: hidden; }
/* a row inside the Answers card (the brain) sits on the card itself, as the switches do */
.bp-switches .bp-row { margin-top: 0; background: transparent; }
.bp-switches .bp-sep { margin-left: 18px; }
.bp-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.bp-row-name { font-size: 16px; }
.bp-row-sub { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bp-row-sub:empty { display: none; }
/* a connector's name with its kind beside it (TUTOR-CANVAS-CONNECTOR): "Canvas" and a quiet "Custom" pill,
   the pill a step smaller than the name and in the card's own neutrals, never the accent, since it labels
   rather than acts */
.bp-conn-name { display: flex; align-items: center; gap: 8px; }
.bp-tag {
  font-size: 12px; font-weight: 600; line-height: 1.4;
  padding: 1px 8px; border-radius: 999px;
  background: var(--selected); color: var(--text-2); flex: none;
}
.sw { position: relative; flex: none; width: 46px; height: 28px; border-radius: 999px; background: var(--track); transition: background 150ms ease-out; }
.sw::after { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #ffffff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); transition: transform 150ms cubic-bezier(0.23, 1, 0.32, 1); }
.bp-switch[aria-checked="true"] .sw { background: var(--ring); }
.bp-switch[aria-checked="true"] .sw::after { transform: translateX(18px); }
.bp-empty { margin: 0; padding: 16px 18px; font-size: 16px; color: var(--muted); }
.bp-add { padding: 0 18px; }
.bp-add svg.i { width: 18px; height: 18px; }
.soon { margin-left: auto; font-size: 12px; padding: 2px 9px; border-radius: 999px; background: var(--hover-2); color: var(--muted); }

/* a coding bot's projects (243): rows on the card itself, as the Answers card's are, and a
   file's text in the mono face the tool cards' output uses */
.bp-proj { overflow: hidden; }
.bp-proj .bp-row { margin-top: 0; background: transparent; }
.bp-proj .bp-row:focus-visible { outline-offset: -2px; }
.bp-proj .bp-sep { margin-left: 18px; }
.bp-proj a.bp-link { text-decoration: none; }
.bp-proj .bp-link svg.i { width: 18px; height: 18px; }
.bp-proj-where { margin: 0; padding: 12px 18px 10px; font: 13px/1.4 var(--mono); color: var(--muted); overflow-wrap: anywhere; }
/* A project's next steps (RECOMMENDED-NEXT): the best one first, a few backups under it, each a
   quiet block with its tier, title, why and cost, and the place in the project it comes from in mono. */
.ns { padding: 4px 18px 14px; }
.ns-head { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.ns-title { margin: 0; flex: none; font-size: 15px; font-weight: 600; }
.ns-when { flex: 1; min-width: 0; font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ns-refresh { flex: none; width: auto; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; font-size: 14px; }
.ns-refresh svg.i { width: 16px; height: 16px; }
.ns-note { margin: 0 0 8px; font-size: 14px; line-height: 1.45; color: var(--text-2); overflow-wrap: anywhere; }
.ns-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ns-step { padding: 12px 0; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ns-step + .ns-step { border-top: 1px solid var(--divider); }
.ns-first { margin-bottom: 6px; padding: 12px 14px; border-radius: 12px; background: color-mix(in srgb, var(--accent) 8%, var(--card)); }
.ns-first + .ns-step { border-top: 0; }
.ns-tier { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.ns-first .ns-tier, .ns-tier[data-tier="Blocking"] { color: var(--accent); }
.ns-step-title { margin: 0; font-size: 15.5px; line-height: 1.35; overflow-wrap: anywhere; }
.ns-first .ns-step-title { font-size: 16.5px; font-weight: 600; }
.ns-why { margin: 0; font-size: 13.5px; line-height: 1.4; color: var(--text-2); overflow-wrap: anywhere; }
.ns-cite { margin-top: 4px; align-self: flex-start; max-width: 100%; font: 12.5px/1.4 var(--mono); color: var(--muted); overflow-wrap: anywhere; white-space: pre-wrap; }
.bp-file { padding: 0 18px 14px; }
.bp-file pre {
  margin: 0; max-height: 320px; overflow: auto; padding: 12px 14px; border-radius: 10px;
  background: var(--raised-2); font: 12.5px/1.5 var(--mono); color: var(--text-2); white-space: pre;
}
.bp-file pre:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* what a bot's chats hold: the Links, Media and Files tabs */
.lib { display: flex; flex-direction: column; padding-top: 12px; }
.lib-empty { margin: 34px 0 0; text-align: center; color: var(--muted); font-size: 15px; line-height: 1.5; }
.lib-empty .e-t { display: block; color: var(--text-2); font-weight: 600; }
.lib-row {
  display: flex; align-items: center; gap: 13px; min-height: 64px; padding: 9px 10px;
  border-radius: 14px; color: var(--text); text-decoration: none; background: transparent; border: 0; text-align: left; width: 100%;
}
@media (hover: hover) { .lib-row:hover { background: var(--hover); } }
.lib-tile {
  flex: none; width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center;
  background: var(--raised-2); color: var(--text-2); font-size: 17px; font-weight: 650; overflow: hidden;
}
.lib-tile img { width: 100%; height: 100%; object-fit: cover; }
.lib-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lib-name { font-size: 15.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-sub { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
.lib-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding-top: 12px; }
.lib-media { position: relative; aspect-ratio: 1; border: 0; padding: 0; border-radius: 8px; overflow: hidden; background: var(--raised-2); }
.lib-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lib-media .lib-kind { position: absolute; left: 6px; bottom: 6px; padding: 1px 7px; border-radius: 999px; font-size: 11.5px; background: rgba(0, 0, 0, 0.55); color: #ffffff; }
@media (hover: hover) { .lib-media:hover { outline: 2px solid var(--ring); outline-offset: -2px; } }

/* a bot's instructions: one large field, saved as it is typed */
.instr .page-top .page-h1 { flex: 1; text-align: center; }
.instr-status { min-width: 44px; font-size: 13px; color: var(--muted); text-align: right; }
.instr-inner { max-width: 680px; margin: 0 auto; padding: 4px 16px 40px; display: flex; flex-direction: column; gap: 10px; }
.instr-lead { margin: 0; color: var(--text-2); font-size: 15px; }
.instr-text {
  min-height: 52vh; resize: vertical; padding: 14px 16px; border-radius: 16px;
  background: var(--raised); border: 1px solid var(--line-2); color: var(--text);
  font-size: 16px; line-height: 1.6; outline: none;
}
.instr-text:focus { border-color: var(--ring); box-shadow: 0 0 0 3px rgba(63, 119, 193, 0.22); }
.instr-text::placeholder { color: var(--faint); }
.instr-count { margin: 0; font-size: 13px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }

/* a bot's routines (245): the list on its page, each with its pause switch, and the editor */
.bp-routines { overflow: hidden; }
.rt-list:empty { display: none; }
.rt-row { position: relative; display: flex; align-items: stretch; }
.rt-row + .rt-row::before { content: ""; position: absolute; top: 0; left: 18px; right: 0; height: 1px; background: var(--divider); }
.rt-open {
  flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 2px;
  min-height: 64px; padding: 10px 6px 10px 18px; border: 0; background: none; text-align: left; color: var(--text);
}
.rt-row .bp-switch { width: auto; flex: none; min-height: 64px; padding: 10px 18px 10px 10px; }
.rt-row.paused .bp-row-name { color: var(--text-2); }
.rt-open:focus-visible, .rt-row .bp-switch:focus-visible { outline: 2px solid var(--ring); outline-offset: -3px; border-radius: 14px; }
@media (hover: hover) { .rt-open:hover { background: var(--hover-2); } }
.rt-page { min-height: 100%; }
.rt-page .page-top .page-h1 { flex: 1; text-align: center; }
.rt-top-end { flex: none; width: 44px; }
.rt-inner { max-width: 560px; margin: 0 auto; padding: 0 16px 48px; display: flex; flex-direction: column; }
.rt-inner .bp-label { display: block; }
.rt-prompt, .rt-field {
  width: 100%; padding: 13px 16px; border-radius: 16px; background: var(--raised); border: 1px solid var(--line-2);
  color: var(--text); font-size: 16px; line-height: 1.5; outline: none;
}
.rt-prompt { min-height: 116px; resize: vertical; }
.rt-prompt:focus, .rt-field:focus { border-color: var(--ring); box-shadow: 0 0 0 3px rgba(63, 119, 193, 0.22); }
.rt-prompt::placeholder, .rt-field::placeholder { color: var(--faint); }
.rt-when { overflow: hidden; }
.rt-when .bp-sep { margin-left: 18px; }
.rt-set { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 6px 12px 6px 18px; }
.rt-set-name { flex: 1; font-size: 16px; }
.rt-set select, .rt-set input {
  min-height: 40px; padding: 0 10px; border-radius: 10px; border: 1px solid var(--line-2);
  background: var(--raised); color: var(--text); font: inherit; font-size: 16px; font-variant-numeric: tabular-nums;
}
.rt-set select:focus-visible, .rt-set input:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
.rt-where { display: flex; align-items: center; gap: 14px; min-height: 64px; padding: 12px 18px; }
.rt-where .ic { color: var(--muted); }
.rt-where svg.i { width: 20px; height: 20px; }
.rt-wrap { white-space: normal; }
#rt-err { margin: 16px 2px 0; }
.rt-acts { display: flex; flex-direction: column; gap: 12px; margin-top: 26px; }
.rt-acts .btn.primary { min-height: 48px; }
.rt-acts #rt-delete { align-self: center; }
/* a routine's answer in its chat: a quiet label where the person's bubble would be */
.x-routine { display: inline-flex; align-items: center; gap: 6px; margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.x-routine svg.i { width: 14px; height: 14px; }
.x-note { margin: 0; font-size: 15px; line-height: 1.55; color: var(--text-2); }
/* a project's own session notice (ONE-CHAT-VIEW (i)): a quiet line between turns, never a bubble,
   same voice as a time divider's (t-divider) rather than a routine's left-aligned label, since
   nothing here answered the person - it's the session itself, saying what happened to it */
.x-boundary { margin: 4px 0 8px; text-align: center; font-size: 12.5px; font-weight: 500; color: var(--muted); }
/* code access between bots (244): the bot page's Access rows, the request's card in the asked
   bot's chat, and the list's badge for a request waiting */
.ac-row { display: flex; align-items: center; gap: 12px; min-height: 64px; padding: 10px 12px 10px 18px; }
.ac-row .bp-row-main { flex: 1; min-width: 0; }
.ac-row .bp-row-sub { white-space: normal; }
.ac-row .btn { flex: none; }
.x-access {
  border: 1px solid var(--line-2); border-radius: 18px; background: var(--raised);
  padding: 16px 18px; max-width: 560px;
}
.x-access-head { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.x-access-head svg.i { width: 14px; height: 14px; }
.x-access-text { margin: 0; font-size: 15.5px; line-height: 1.55; color: var(--text); overflow-wrap: anywhere; }
.x-access-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 14px; }
.x-access-acts select {
  min-height: 40px; padding: 0 10px; border-radius: 10px; border: 1px solid var(--line-2);
  background: var(--bg); color: var(--text); font: inherit; font-size: 15px;
}
.x-access-acts select:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
.x-access-state { margin: 12px 0 0; font-size: 14px; color: var(--text-2); }
.cl-badge {
  flex: none; padding: 1px 8px; border-radius: 999px; background: var(--accent); color: var(--on-accent);
  font-size: 12px; font-weight: 600; line-height: 18px; font-variant-numeric: tabular-nums;
}

/* the + menu's group row, kept visible and off until group chats come */
.menu-item .mi-sub { font-size: 12px; color: var(--muted); }
.menu-item .mark { width: 28px; height: 28px; }

/* ---------- phone ---------- */
@media (max-width: 760px) {
  /* one pane at a time, as a messenger on a phone: the list, or the open chat, page or usage */
  .shell { grid-template-columns: minmax(0, 1fr); }
  .rail { border-right: 0; }
  .app.pane-list .col { display: none; }
  .app.pane-main .rail { display: none; }
  .chat-head { padding: max(10px, env(safe-area-inset-top)) 12px 24px; }
  .chat-head .back-btn { display: grid; }
  /* THREAD-HEAD-COMPACT (design review 2026-10-21): one 52px row, a 32px avatar beside the name
     and status, in place of the desktop width's 72px mark stacked over a text capsule below it
     (about 118 by 101px) - too tall for a phone's head. The row still sits in the grid's centered
     middle column; only what's inside it changes from a centered stack to a left-flowing pair. */
  .head-bot { flex-direction: row; align-items: center; justify-content: flex-start; height: 52px; gap: 10px; text-align: left; }
  .mark.head-mk { width: 32px; height: 32px; }
  .hb-text { align-items: flex-start; max-width: calc(100vw - 180px); margin-top: 0; padding: 4px 10px; }
  .color-btn { width: 40px; height: 40px; }
  .color-btn .swatch { width: 31px; height: 31px; }
  .bp-colors { gap: 10px 11px; max-width: calc(6 * 40px + 5 * 11px); }
  .bp-shapes { grid-template-columns: repeat(4, 60px); gap: 10px 14px; }
  .shape-btn { width: 60px; height: 60px; }
  .shape-btn .mark { width: 44px; height: 44px; }
  .home { align-items: center; padding-top: 0; }
  .t-inner { padding: 22px 16px 40px; gap: 22px; }
  .src-card { flex-basis: 196px; }
  /* the capsule keeps its 44px "+" and send at every width, 12px from the screen's edges */
  .composer-bar { padding-left: 12px; padding-right: 12px; padding-bottom: calc(var(--agent-bar-h, 0px) + max(10px, env(safe-area-inset-bottom))); }
  /* the + and each photo's remove keep a 44px touch floor on a phone: the buttons are smaller,
     their ::before pads to 44px */
  .photo-tile .photo-x { width: 24px; height: 24px; }
  .photo-tile .photo-x::before { content: ""; position: absolute; inset: -10px; }
  .photo-tile { width: 56px; height: 56px; }
  .thumb-btn { width: 56px; height: 56px; }
  .file-tile .photo-x { width: 24px; height: 24px; }
  .file-tile .photo-x::before { content: ""; position: absolute; inset: -10px; }
  .file-tile { height: 56px; max-width: 180px; }
  .home-h1 { font-size: 26px; }
  /* the 44px touch floor on a phone-first page: standalone controls grow, never shrink */
  .send, .search-toggle, .model-btn, .btn { height: 44px; }
  .send { width: 44px; }
  .menu-item { min-height: 44px; }
  .invite-btn { height: 44px; }
  .invite-field { height: 44px; }
  .invite-form .btn.small, .invite-made-row .btn.small, .invite-row .btn.small { height: 44px; }
  .plans { justify-content: flex-start; padding: 28px 16px 44px; }
  .plans-acts { flex-wrap: wrap; }
  .u-inner { padding: 22px 16px 44px; }
  .u-cta { width: 100%; }
  .p-h1 { font-size: 28px; }
  .u-h1 { font-size: 26px; }
  /* The claim popover and the summary's list become bottom sheets on a phone: full width, up
   * from the safe area, never a floating card (the desktop width's "top" never holds). */
  .clp {
    left: 0 !important; top: auto !important;
    bottom: max(0px, env(safe-area-inset-bottom));
    width: 100%; max-width: none; min-width: 0;
    max-height: 78dvh;
    border-radius: 16px 16px 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---------- deleting the account ---------- */

/* The account menu's destructive row reads as irreversible before anything is clicked. */
.menu-item.danger { color: var(--danger); }
@media (hover: hover) { .menu-item.danger:hover { color: var(--danger); background: var(--hover-2); } }

/* The confirm dialog: one card over the dimmed page, with the destructive action as a solid
 * danger button and Cancel as the calm way out. Tokens only; both themes are automatic. */
.dialog {
  position: fixed; inset: 0; z-index: 60;
  background: color-mix(in srgb, var(--side) 55%, transparent);
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.dialog-card {
  width: min(100%, 380px);
  background: var(--raised); border: 1px solid var(--line); border-radius: 14px;
  padding: 20px; box-shadow: var(--shadow);
}
.d-h2 { margin: 0 0 6px; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.d-lead { margin: 0 0 14px; color: var(--text-2); }
.d-acts { display: flex; gap: 10px; justify-content: flex-end; }
/* The AI consent card (AI-CONSENT): what goes, then to whom, in the dialog's own type; the list is
   the card's one structure, so its items sit tight under the lead and the providers read as prose. */
/* In the iPhone app the native head and message box float over the web view and set its safe-area insets
   (the keyboard's too), so the card is centred in what they leave, never under them, and scrolls if that's short. */
#ai-consent-dialog { padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom)); }
.ai-card { max-height: min(100%, 640px); overflow-y: auto; }
.ai-sends { margin: -6px 0 12px; padding-left: 20px; color: var(--text); }
.ai-sends li + li { margin-top: 4px; }
.ai-who { margin: 0 0 12px; font-size: 13.5px; color: var(--text-2); }
.ai-who a { color: var(--link); }
.ai-card .d-acts { margin-top: 16px; }
.ai-card .d-acts .btn { min-height: 44px; }
/* A bot's routines while the account hasn't allowed AI models: one plain line, the card a tap away. */
.rt-consent { margin: 8px 0 0; font-size: 13px; color: var(--text-2); }
.rt-consent-btn { padding: 12px 0; border: 0; background: none; color: var(--link); font: inherit; font-weight: 600; cursor: pointer; }
@media (hover: hover) { .rt-consent-btn:hover { text-decoration: underline; text-underline-offset: 3px; } }
.rt-consent-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 4px; }
/* The custom-list editor (CUSTOM-LISTS), the page's fallback for the app's native sheet: the page's
   own dialog card, a header row of its own, and the theme, tone and membership pickers below it.
   The Align Pro section is inert on a Free account: the swatches and tones keep their sizes and
   show what Pro holds, dimmed, with a note naming the door. */
.lc-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 2px; }
.lc-bar .d-h2 { margin-bottom: 0; }
.list-card { max-height: min(86vh, 640px); overflow-y: auto; }
.lc-label { display: block; margin: 14px 0 6px; font-size: 13.5px; font-weight: 600; color: var(--text-2); }
.lc-name {
  display: block; width: 100%; height: 44px; padding: 0 14px;
  border: 1px solid var(--line-2); border-radius: 10px; background: var(--raised-2); color: var(--text);
  font: inherit; font-size: 16px;
}
.lc-name:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 25%, transparent); }
.lc-pro { margin-top: 14px; padding: 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--raised-2); }
.lc-pro.locked { opacity: 0.82; }
.lc-pro-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.lc-pro-t { font-size: 14.5px; font-weight: 650; color: var(--text); }
.lc-pro-link {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; flex: none;
  border: 0; border-radius: 999px; background: var(--msg); color: var(--on-msg);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.lc-pro-link .ic { width: 14px; height: 14px; }
@media (hover: hover) { .lc-pro-link:hover { background: color-mix(in srgb, var(--msg) 86%, var(--text)); } }
.lc-pro-note { margin: 6px 0 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
.lc-field { border: 0; padding: 0; margin: 14px 0 0; }
.lc-field legend { padding: 0; margin-bottom: 8px; font-size: 13.5px; font-weight: 600; color: var(--text-2); }
.lc-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.lc-swatch {
  width: 42px; height: 42px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; background: var(--lc-ink, var(--msg)); color: var(--on-msg); cursor: pointer;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--line) 60%, transparent);
}
.lc-swatch .ic { width: 18px; height: 18px; }
.lc-swatch.picked { outline: 3px solid var(--ring); outline-offset: 2px; }
.lc-swatch:disabled { cursor: default; }
.lc-tones { display: flex; flex-direction: column; gap: 6px; }
.lc-tone {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 44px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: 11px; background: var(--raised); color: var(--text);
  font: inherit; font-size: 15px; text-align: left; cursor: pointer;
}
.lc-tone .lc-tone-check { display: grid; place-items: center; width: 20px; height: 20px; color: var(--msg); opacity: 0; }
.lc-tone.picked .lc-tone-check { opacity: 1; }
.lc-tone:disabled { cursor: default; }
.lc-chats { display: flex; flex-direction: column; gap: 2px; max-height: 260px; overflow-y: auto; }
.lc-chat {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 56px; padding: 6px 10px; border: 0; border-radius: 12px;
  background: transparent; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
@media (hover: hover) { .lc-chat:hover { background: var(--hover); } }
.lc-chat-mark { flex: none; display: grid; place-items: center; }
.lc-chat-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.lc-chat-name { font-size: 15px; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lc-chat-sub { font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lc-chat-tick {
  flex: none; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--line-2); color: transparent;
}
.lc-chat.picked .lc-chat-tick { background: var(--msg); color: var(--on-msg); box-shadow: none; }
.lc-chat-tick .ic { width: 14px; height: 14px; }
.lc-flex { flex: 1; }
/* A conversation in a themed custom list (CUSTOM-LISTS): the list's ink becomes the person's own
   messages' and the input's accent, and the thread takes a faint wash of it, so the chat reads in
   its theme while no other surface changes. A group's own messages carry the ink too; the people's
   names and the rest of the group keep the page's own colors. */
#thread-view.list-theme, #group-view.list-theme { --msg: var(--lc-ink); }
#thread-view.list-theme { background: color-mix(in srgb, var(--lc-ink) 5%, var(--thread-bg)); }
#group-view.list-theme .gm.mine .gm-bub { background: var(--lc-ink); color: var(--on-msg); }
/* The report dialog (311): one reason from a short list, a line of the reporter's own, then thanks. */
.rp-reasons { border: 0; padding: 0; margin: 0 0 12px; }
.rp-reasons legend { font-size: 13.5px; font-weight: 600; color: var(--text-2); padding: 0; margin-bottom: 6px; }
.rp-reason { display: flex; align-items: center; gap: 10px; min-height: 40px; font-size: 15px; cursor: pointer; }
.rp-reason input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); }
.rp-label { display: block; font-size: 13.5px; font-weight: 600; color: var(--text-2); margin-bottom: 6px; }
.rp-note {
  width: 100%; height: 44px; padding: 0 14px; margin-bottom: 14px;
  border: 1px solid var(--line-2); border-radius: 9px; background: var(--raised); color: var(--text);
  font: inherit; font-size: 16px;
}
.rp-note:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px rgba(63, 119, 193, 0.25); }
#report-dialog .notice { margin: 0 0 12px; }
/* the thanks takes the focus so a screen reader reads it; it is no control, so no ring */
#report-done-title:focus { outline: none; }
.btn.danger { background: var(--danger); color: var(--on-danger); }
@media (hover: hover) { .btn.danger:hover { background: color-mix(in srgb, var(--danger) 88%, var(--text)); } }

/* ---------- friends (240) ---------- */

/* The avatar palette a person picks from: the same ids and values as the bots' characters
 * (239), defined here so the picker can run before that slice ships. Identical to 239's; when
 * both are in the tree either definition draws the same color. The inks are fixed per color so
 * an initial never sits at poor contrast, in either theme. */
:root {
  --char-white: #FEFEFE; --char-brown: #8C6641; --char-red: #E94045;
  --char-orange: #EB702D; --char-amber: #F09C39; --char-green: #5BC57A;
  --char-teal: #54B9A7; --char-blue: #3C81F6; --char-purple: #885BF4;
  --char-pink: #E94699; --char-gray: #777777;
}
.av-white { --av-bg: var(--char-white, #FEFEFE); --av-ink: #131313; }
.av-brown { --av-bg: var(--char-brown, #8C6641); --av-ink: #FEFEFE; }
.av-red { --av-bg: var(--char-red, #E94045); --av-ink: #FEFEFE; }
.av-orange { --av-bg: var(--char-orange, #EB702D); --av-ink: #131313; }
.av-amber { --av-bg: var(--char-amber, #F09C39); --av-ink: #131313; }
.av-green { --av-bg: var(--char-green, #5BC57A); --av-ink: #131313; }
.av-teal { --av-bg: var(--char-teal, #54B9A7); --av-ink: #131313; }
.av-blue { --av-bg: var(--char-blue, #3C81F6); --av-ink: #FEFEFE; }
.av-purple { --av-bg: var(--char-purple, #885BF4); --av-ink: #FEFEFE; }
.av-pink { --av-bg: var(--char-pink, #E94699); --av-ink: #FEFEFE; }
.av-gray { --av-bg: var(--char-gray, #777777); --av-ink: #FEFEFE; }

/* A person's avatar: their initial on the color they picked, round like the messenger's
 * avatars, at the rail's own size and never larger than the row it sits in. */
.f-avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--av-bg, var(--chip)); color: var(--av-ink, var(--text-2));
  font-size: 15px; font-weight: 700; letter-spacing: 0.01em;
}

/* The friends view: one calm column like the usage view, with the same rhythm. */
.friends { min-height: 100%; }
.f-inner {
  max-width: var(--col); margin: 0 auto;
  padding: 34px 20px 60px;
  display: flex; flex-direction: column; gap: 22px;
}
.f-h1 { margin: 0; font-size: 30px; line-height: 1.2; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; }
.f-head { display: flex; flex-direction: column; gap: 14px; }
.f-self {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--raised); padding: 14px;
}
.f-self-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.f-handle { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--text); }
.f-self-note { margin: 0; font-size: 12.5px; color: var(--muted); }
.f-edit, .f-share, .f-share-handle { flex: none; }

.f-sec { display: flex; flex-direction: column; gap: 10px; }
.f-sec-h {
  margin: 0; font-size: 13px; font-weight: 650; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.02em;
}
.f-rows { display: flex; flex-direction: column; gap: 0; border: 1px solid var(--line); border-radius: 14px; overflow: clip; }
/* A row's actions wrap under the name when they don't fit beside it (a friend's Report, Block and
 * Remove at phone width), so the handle is never squeezed to a letter a line. */
.f-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 11px 14px; min-height: 58px;
  border-bottom: 1px solid var(--line);
}
.f-row:last-child { border-bottom: 0; }
.f-row .f-who { flex: 1 1 9rem; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* A friend's three actions on a phone go together on a line of their own, under the name. */
@media (max-width: 520px) {
  .f-row:has(> .btn ~ .btn ~ .btn) .f-who { flex-basis: calc(100% - 50px); }
  .f-row:has(> .btn ~ .btn ~ .btn) .f-who + .btn { margin-left: 46px; }
}
.f-row .f-name { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.f-row .f-sub { margin: 0; font-size: 12.5px; color: var(--muted); }
.f-row .btn { flex: none; }
.f-row .f-stand { flex: none; font-size: 13px; color: var(--muted); }
.f-empty { padding: 18px 14px; color: var(--muted); font-size: 14px; border: 1px dashed var(--line); border-radius: 14px; }

/* Searching by handle: a labeled field like the sign-in one, with the @ fixed in the row. */
.f-search { display: flex; flex-direction: column; gap: 8px; }
.f-search label { font-size: 14px; color: var(--text-2); }
.f-search-row { display: flex; align-items: center; gap: 0; }
.f-at {
  color: var(--muted); font-size: 16px; padding: 0 10px;
  border: 1px solid var(--line); border-right: 0; border-radius: 8px 0 0 8px;
  height: 44px; display: grid; place-items: center;
  background: var(--raised);
}
.f-search-row input {
  font: inherit; color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-right: 0; border-radius: 0;
  padding: 10px 12px; min-height: 44px; min-width: 0; flex: 1;
}
.f-search-row input:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.f-search-row .btn { border-radius: 0 8px 8px 0; margin: 0; }
.f-results { display: flex; flex-direction: column; gap: 0; border: 1px solid var(--line); border-radius: 14px; overflow: clip; }
.f-results .f-row:first-child { border-top: 0; }
.f-result-same { padding: 12px 14px; color: var(--muted); font-size: 14px; }

/* The handle picker's swatches: 44px targets, the chosen one ringed in the accent. */
.av-pick { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 0; border: 0; padding: 0; }
.av-pick legend { font-size: 14px; color: var(--text-2); padding: 0; margin-bottom: 8px; }
.av-swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.av-swatch {
  width: 38px; height: 38px; border-radius: 50%; border: 2px solid transparent;
  cursor: pointer; padding: 0;
  background: var(--av-bg); box-shadow: inset 0 0 0 1px var(--line-2);
}
.av-swatch[aria-pressed="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
@media (hover: hover) { .av-swatch:hover { box-shadow: inset 0 0 0 2px var(--accent); } }
.av-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The invite landing a signed-out reader sees: the host's avatar and handle in the welcome's
 * own shape, and the same sign-in path into the app. Centered with the card's heading and lead. */
.add-host { display: flex; flex-direction: column; gap: 12px; align-items: center; text-align: center; }
.add-host .f-avatar {
  width: 64px; height: 64px; font-size: 26px;
  box-shadow: 0 0 0 3px var(--accent);
}
.add-lead { margin: 0; color: var(--text-2); }
.add-note { margin: 0; color: var(--muted); font-size: 13.5px; max-width: 34ch; }

/* The handle dialog's input row: the @ marker, then the field and Set handle in one line. */
.signin-row-inner { flex: 1; min-width: 0; display: flex; gap: 0; }
.signin-row-inner input {
  font: inherit; color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-radius: 8px 0 0 8px;
  padding: 10px 12px; min-height: 44px; min-width: 0; flex: 1;
}
.signin-row-inner input:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.signin-row-inner .btn { border-radius: 0 8px 8px 0; margin: 0; }

/* The who column and the self identity are buttons (240b) that open profiles; a button must not
 * look like one. They keep the flex layout the row gave them, and only the focus ring and the
 * hover betray that they are tappable. */
.f-row .f-who, .f-self-id {
  appearance: none; margin: 0; padding: 6px;
  border: 0; border-radius: 10px;
  text-align: left; font: inherit; color: inherit;
  background: none; cursor: pointer;
}
.f-row .f-who:focus-visible, .f-self-id:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (hover: hover) {
  .f-row .f-who:hover, .f-self-id:hover { background: var(--hover); }
  .f-row .f-who:active, .f-self-id:active { background: var(--hover-2); }
}

/* At phone width the self identity takes the full row and the buttons fold beneath, so the long
 * "You haven't picked a handle yet" line never squeezes to one word per line (240b). */
@media (max-width: 560px) {
  .f-self { flex-wrap: wrap; }
  .f-self-id { flex: 1 1 100%; }
}

/* Profiles (240b): one calm column like the friends view, drawing the person's own editor or
 * another person's. The avatar is larger than a list row's, and a profile photo fills it. Nothing
 * here ever shows an email (240). */
.profile { min-height: 100%; }
.p-self { display: flex; align-items: center; gap: 14px; min-width: 0; }
.p-avatar {
  width: 64px; height: 64px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--av-bg, var(--chip)); color: var(--av-ink, var(--text-2));
  font-size: 26px; font-weight: 700; letter-spacing: 0.01em;
  overflow: clip;
}
.p-avatar.has-photo { background-size: cover; background-position: center; }
.p-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
/* The own profile's head (246c) reads as one unit: the handle is the row's title at the avatar's top,
 * its caption muted under it, then Change handle. Without its own rule the caption was a bare <p> with
 * the browser's margins, which made the column taller than the avatar, and centering then floated the
 * handle above the avatar. Another person's head stays centered: its column is one line. */
.p-self.own { align-items: flex-start; }
.p-self.own .p-id { padding-top: 6px; }
.p-id .f-handle { overflow-wrap: anywhere; }
.p-id .f-sub { margin: 0; font-size: 13px; color: var(--muted); }
.p-pick { align-self: flex-start; margin-top: 8px; }
.p-form { display: flex; flex-direction: column; gap: 18px; margin-top: 4px; }
/* The iPhone app's Profile tab (246): the account's items under the profile as one card of rows, the
 * avatar menu's own rows (accountItems) at a touch's height. In the app's tabs the list has no avatar
 * button, since the Profile tab holds the account. The card sits under its Account heading
 * (PROFILE-UI-FRIENDS), whose section's spacing belongs to .p-conns. */
.p-account {
  display: flex; flex-direction: column; padding: 4px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
}
.p-account .menu-item { min-height: 48px; }
/* The own profile's Friends card (PROFILE-UI-FRIENDS): the Add a friend and Invite a friend
 * actions lead the card, and the friend rows below carry a Message button that opens the direct
 * chat in one tap. Nothing here ever shows an email. */
.p-friends-acts { display: flex; flex-wrap: wrap; gap: 10px; }
.p-friends-add { flex: 1 1 12rem; min-height: 48px; }
.p-friends-invite, .p-friends-share-handle { min-height: 48px; }
.pf-more {
  display: block; width: 100%; padding: 12px 14px; background: none;
  border: 0; border-top: 1px solid var(--line);
  color: var(--accent); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
  border-radius: 0; min-height: 44px;
}
@media (hover: hover) { .pf-more:hover { background: var(--hover); } }
.pf-retry { width: 100%; background: none; font: inherit; text-align: left; cursor: pointer; }
/* Profile's Connections (276): what an agent may use, one card of rows, each its mark, its name over
 * its state, and what the person can do. Connected reads in the page's green; the rest is muted. */
.p-conns { margin-top: 28px; display: flex; flex-direction: column; gap: 10px; }
.p-conns-h { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); }
/* Profile's plan card (355): the trial's words in the page's plain copy, or nothing at all when
   there is no trial story to tell. While it runs the line names the day Pro ends; when one may
   start, the offer is free and no card is needed; once used, it is never offered again. */
.p-trial-line { margin: 0; font-size: 14px; line-height: 1.45; color: var(--text); padding: 11px 12px; }
/* The plans page's .pl-cta is width: 100%; in the card's padded column that plus these margins ran past its
 * edge (PROFILE-ON-IPHONE), so the button stretches to the row instead: 12px from the border, as its words are. */
.p-trial .p-trial-start { width: auto; margin: 8px 8px 0; }
/* the US app's Upgrade (PRO-US-LINK): the card's last control, so it keeps the card's bottom inset */
.p-trial .p-upgrade { margin-bottom: 8px; }
.p-trial .p-nocard { margin: 6px 12px 10px; font-size: 13px; color: var(--muted); }
.p-trial .p-trial-note { margin: 4px 12px 10px; }
.p-conn-list {
  display: flex; flex-direction: column; padding: 4px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
}
.p-conn { display: flex; align-items: center; gap: 12px; min-height: 60px; padding: 8px 10px; }
.p-conn + .p-conn { border-top: 1px solid var(--line); }
.p-conn-ic {
  flex: none; width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center; background: var(--chip); color: var(--text-2);
}
.p-conn[data-kind="apple_health"] .p-conn-ic { color: var(--accent); }
.p-conn-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.p-conn-name { font-size: 15px; font-weight: 500; color: var(--text); }
.p-conn-state { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
.p-conn-state.on { color: var(--text-2); }
.p-conn-acts { flex: none; display: flex; gap: 8px; }
.p-conn-btn { height: 34px; padding: 0 12px; font-size: 14px; }
.p-conn-sk { height: 120px; border-radius: 10px; background: var(--hover); animation: skpulse 1.6s ease-in-out infinite; }
@media (max-width: 420px) {
  .p-conn { flex-wrap: wrap; }
  .p-conn-acts { width: 100%; padding-left: 46px; }
}
/* Profile's Phone number (328): the Connections card's rows, then the number field, the code
 * step with its six digits, or who may find you by it. */
.p-phone .p-conn-sk { height: 68px; }
.p-phone-form, .p-phone-step { display: flex; flex-direction: column; gap: 8px; padding: 4px 10px 12px 56px; }
.p-phone-form label, .p-phone-step label { font-size: 14px; color: var(--text-2); }
.p-phone-row { display: flex; gap: 8px; }
.p-phone-row input {
  flex: 1; min-width: 0; min-height: 44px; padding: 10px 12px;
  font: inherit; font-size: 16px; color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-radius: 10px; font-variant-numeric: tabular-nums;
}
.p-phone-row input::placeholder { color: var(--faint); }
.p-phone-row input:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.p-phone-row .btn { flex: none; min-height: 44px; }
.p-phone-cancel { align-self: flex-start; }
.p-phone-step p { margin: 0; font-size: 14px; color: var(--text-2); }
.p-phone-step > .btn { align-self: flex-start; min-height: 44px; padding: 0 16px; }
/* The six digits: one field, wide, centred, in the code typeface, spaced apart. */
#p-phone-code {
  width: 100%; min-height: 52px; padding: 10px 12px; text-align: center;
  font: 600 22px/1 var(--mono); color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-radius: 10px; letter-spacing: 0.35em;
  font-variant-numeric: tabular-nums;
}
#p-phone-code::placeholder { color: var(--faint); }
#p-phone-code:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.p-phone-step .p-muted { font-size: 13px; color: var(--muted); }
.p-phone-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.p-phone-acts .btn { height: 44px; display: inline-flex; align-items: center; text-decoration: none; }
.p-phone-find, .p-pay-way { min-height: 56px; cursor: pointer; }
.p-phone-find .p-conn-name, .p-pay-way .p-conn-name { flex: 1; font-size: 15px; font-weight: 400; }
.p-phone-find select, .p-pay-way select {
  flex: none; min-height: 40px; padding: 0 10px; border-radius: 10px; border: 1px solid var(--line-2);
  background: var(--raised); color: var(--text); font: inherit; font-size: 15px;
}
.p-phone-find select:focus-visible, .p-pay-way select:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
@media (max-width: 420px) {
  .p-phone-form, .p-phone-step { padding-left: 10px; }
  .p-phone-row { flex-direction: column; }
  .p-phone-find, .p-pay-way { flex-wrap: nowrap; }
}
/* A search that is a number has no @ in front of it. */
.f-search-row.num .f-at { display: none; }
.f-search-row.num input { border-radius: 8px 0 0 8px; }
[data-app-tab] #account { display: none; }
.p-field { display: flex; flex-direction: column; gap: 8px; }
.p-field label, .p-photo-label { font-size: 14px; color: var(--text-2); }
.p-field input, .p-field textarea {
  font: inherit; color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; width: 100%;
}
.p-field input { min-height: 44px; }
.p-field textarea { resize: vertical; min-height: 96px; line-height: 1.45; }
.p-field input:focus-visible, .p-field textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.p-count { margin: 0; font-size: 12.5px; color: var(--muted); }
.p-photo-acts { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.p-about { margin: 0; font-size: 14px; color: var(--text); line-height: 1.5; overflow-wrap: anywhere; }
.p-acts { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.p-stand { font-size: 14px; color: var(--muted); }
.p-muted { margin: 0; font-size: 13.5px; color: var(--muted); }
.p-note { margin: 0; }

/* The rail avatar shows its initial unless the account has a profile photo, which fills the round
 * button instead; the letter never survives a photo that replaces it. */
.avatar-letter.has-photo { display: block; width: 100%; height: 100%; border-radius: 50%; background-size: cover; background-position: center; }

/* ---------- group chats (241) ---------- */

/* A group's avatar with no character of its own: two members' faces overlapping, the first at the
 * top left and the second in front at the bottom right, cut out of the first by a ring of the
 * surface it sits on, as Eric's screenshot draws a group. A person's face is their initial. */
.mark.pair { display: block; }
.mark.pair .gf { position: absolute; display: grid; place-items: center; width: 68%; height: 68%; border-radius: 50%; }
.mark.pair .gf.a { left: 0; top: 0; }
.mark.pair .gf.b { right: 0; bottom: 0; box-shadow: 0 0 0 2px var(--ring-bg, var(--bg)); background: var(--ring-bg, var(--bg)); }
.mark.pair .gf svg { width: 100%; height: 100%; overflow: visible; }
.mark.pair .gf.p { background: var(--av-bg, var(--chip)); color: var(--av-ink, var(--text-2)); font-weight: 700; line-height: 1; }
.mark.pair .gf.b.p { background: var(--av-bg, var(--chip)); }
/* the back face's initial sits in the part the front face leaves showing, its top left */
.mark.pair .gf.a.p { padding: 0 24% 24% 0; }
/* a group of one other face (New group before anyone is picked) draws that face whole */
.mark.pair .gf.a:only-child { width: 100%; height: 100%; padding: 0; }
.mark.md.pair .gf.a.p:only-child { font-size: 22px; }
.mark.lg.pair .gf.a.p:only-child { font-size: 32px; }
.mark.xl.pair .gf.a.p:only-child { font-size: 56px; }
.mark.sm.pair .gf.a.p:only-child { font-size: 14px; }
.mark.pair .gf.bot.b svg { width: 88%; height: 88%; }
.mark.sm.pair .gf.p { font-size: 11px; }
.mark.md.pair .gf.p { font-size: 16px; }
.mark.lg.pair .gf.p { font-size: 24px; }
.mark.xl.pair .gf.p { font-size: 40px; }
.mark.pair:not(.sm):not(.md):not(.lg):not(.xl) .gf.p { font-size: 15px; }
.cl-row.current .mark.pair { --ring-bg: var(--selected); }
.bp-card .mark.pair, .shape-btn .mark.pair { --ring-bg: var(--card); }

/* the list's unread count, in the accent like a messenger's; the time turns the accent too */
.cl-unread {
  flex: none; margin-left: auto; min-width: 22px; height: 22px; padding: 0 7px;
  border-radius: 999px; background: var(--ring); color: var(--on-accent);
  font-size: 12.5px; font-weight: 700; line-height: 22px; text-align: center; font-variant-numeric: tabular-nums;
}
.cl-row.unread .cl-time { color: var(--ring); }
.cl-row.unread .cl-prev-text { color: var(--text-2); }
/* a row marked unread by hand (318): the badge as a dot, no number */
.cl-unread.dot { min-width: 12px; width: 12px; height: 12px; padding: 0; }
/* a pinned row's pin, at the end of its second line under the time, before any badge */
.cl-pin { flex: none; margin-left: auto; display: inline-flex; color: var(--muted); }
.cl-pin svg.i { width: 15px; height: 15px; }
.cl-pin + .cl-unread { margin-left: 0; }

/* A row's actions (318), behind it as WhatsApp's: pulled from the left, Unread and Pin; from the
 * right, More and Archive. Unread and Archive in the page's green, Pin and More in its gray. The row
 * takes only sideways drags, so a vertical one scrolls the list. */
.cl-swipe { position: relative; flex: none; overflow: hidden; border-radius: 16px; touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.cl-swipe > .cl-row { position: relative; z-index: 1; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; transition: background 140ms ease-out; }
.cl-swipe.moved > .cl-row:not(.current) { background: var(--bg); }
.cl-swipe.moved > .cl-row:active { transform: none; }
.cl-swipe.animating > .cl-row { transition: transform 240ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out; }
.cl-swipe.animating > .cl-acts { transition: width 240ms cubic-bezier(0.23, 1, 0.32, 1); }
.cl-acts { position: absolute; top: 0; bottom: 0; display: flex; width: 0; overflow: hidden; }
.cl-acts.start { left: 0; }
.cl-acts.end { right: 0; }
.cl-swipe:not(.moved) > .cl-acts { visibility: hidden; }
.cl-act {
  flex: 1 1 0; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  border: 0; padding: 0; font-size: 12.5px; font-weight: 600; white-space: nowrap;
  transition: flex-grow 160ms cubic-bezier(0.23, 1, 0.32, 1);
}
.cl-act .ic svg.i { width: 22px; height: 22px; stroke-width: 1.8; }
.cl-act.go { background: var(--add); color: var(--on-accent); }
.cl-act.gray { background: var(--hollow); color: var(--text); }
.cl-act:active { filter: brightness(0.92); }
.cl-act:focus-visible { outline-offset: -3px; }
/* a full pull: the outer action takes the whole width */
.cl-acts.start.full > .cl-act:last-child, .cl-acts.end.full > .cl-act:first-child { flex-grow: 0; }
@media (prefers-reduced-motion: reduce) {
  .cl-swipe.animating > .cl-row, .cl-swipe.animating > .cl-acts, .cl-act { transition: none; }
}

/* The Archived row at the top of the list while any chat is archived, and the archived view's head */
.cl-arch-head { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 8px; padding: 2px 2px 10px; }
.cl-arch-title { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.cl-arch-note { grid-column: 1 / -1; margin: 6px 8px 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
/* a chat menu's Exit group in red, its icon too */
#chat-menu .menu-item.danger .mi-name, #chat-menu .menu-item.danger .mi-ic { color: var(--danger); }
.cl-note { margin: 0 16px 8px; padding: 8px 12px; border-radius: 10px; background: var(--chip); color: var(--text); }

/* a message's checks (300): one check sent, two delivered, both gray, and two in the accent read,
 * the same accent as the unread count and its time; a row's sit before its words */
.ck { flex: none; display: inline-flex; color: var(--muted); }
.ck svg.i { width: 16px; height: 16px; stroke-width: 1.7; }
.ck-read { color: var(--ring); }
.cl-prev .ck { margin-right: -2px; }
/* who is typing in place of the preview, in italics as a messenger draws it */
.cl-prev-text.cl-typing { font-style: italic; color: var(--text-2); }
/* one's own message's time and checks, under its bubble at the right */
.xmeta {
  align-self: flex-end; display: flex; align-items: center; gap: 3px;
  margin: 3px 4px 0 0; font-size: 12px; line-height: 16px; color: var(--muted); font-variant-numeric: tabular-nums;
}
.xmeta .ck svg.i { width: 15px; height: 15px; }
.x > .xmeta + .a-body, .x > .xmeta + .x-routine { margin-top: 10px; }
.x > .xmeta ~ .tk-section, .x > .xmeta ~ .src-section, .x > .xmeta ~ .a-working, .x > .xmeta ~ .a-img { margin-top: 10px; }

/* a message a true network failure kept from going out (SEND-RETRY): dimmed like iMessage's own
 * "sending" bubble while the page keeps trying it on its own, no spinner and no box. Once the
 * retries are spent, the bubble returns to its normal weight and a quiet line takes its own place
 * under it, in .xmeta's own slot, naming the failure and offering the one way to try again. */
.x.sending > .xbub, .x.sending > .photo-thumbs { opacity: 0.55; }
.x.sending > .xmeta { color: var(--muted); }
.send-fail {
  align-self: flex-end; margin: 3px 4px 0 0; font-size: 12px; line-height: 16px; color: var(--danger);
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
}
.send-fail:hover, .send-fail:focus-visible { text-decoration: underline; }
.send-fail:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 4px; }

/* the group chat: one's own messages at the right as the bot chat's bubble; someone else's at the
 * left under their name; a bot's answer at the left as the answer's own prose, a little smaller */
.gm-list { display: flex; flex-direction: column; gap: 14px; }
.gm { display: flex; gap: 10px; align-items: flex-start; }
.gm.mine { flex-direction: column; align-items: flex-end; }
.gm.mine > .photo-thumbs { justify-content: flex-end; }
.gm.cont { margin-top: -10px; }
.gm.cont .gm-name { display: none; }
.gm.cont .gm-face { visibility: hidden; }
.gm-face { flex: none; margin-top: 2px; }
.f-avatar.gm-av { width: 32px; height: 32px; font-size: 14px; }
.gm-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.gm-name { margin: 0; font-size: 13px; font-weight: 600; color: var(--text-2); }
.gm-to { margin-left: 6px; font-weight: 450; color: var(--muted); }
.gm-bub {
  max-width: min(84%, 520px); background: var(--bub-in); color: var(--text);
  border-radius: 20px; padding: 10px 15px;
  font-size: 16px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere;
}
.gm-body { max-width: min(92%, 600px); }
.gm-only { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); }
/* A message the owner removed after a report (311): the bubble stays where it was, its words gone. */
.gm-bub.removed, .xbub.removed { background: transparent; border: 1px dashed var(--line-2); color: var(--muted); font-style: italic; }
/* A long press opens the message's menu (311), so the system's own callout and selection stay out of it. */
.gm.other .gm-bub, .x.reportable .xbub { -webkit-touch-callout: none; }
/* a bot answering with no words yet (321): its face and "<Name> is working" on one line, in the
 * page's thinking shimmer, until its words stream in under its name; a bot chat's working row
 * (.a-working, 346) draws its words in the same shimmer */
.gm.draft.working { align-items: center; }
.gm.draft.working .gm-face { margin-top: 0; }
.gm-name.gm-working, .a-working .work-words {
  font-size: 14px; font-weight: 500;
  background: linear-gradient(90deg, var(--shine) 0%, var(--shine) 40%, var(--shine-peak) 50%, var(--shine) 60%, var(--shine) 100%);
  background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; /* design-ok: the page's thinking shimmer, its --shine tokens */
  animation: hb-shine 1.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .gm-name.gm-working, .a-working .work-words { animation: none; background: none; color: var(--text-2); } }
.gm-empty { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 48px 0 12px; text-align: center; color: var(--muted); font-size: 14.5px; }
.gm-empty .mark { margin-bottom: 12px; }
.gm-empty p { margin: 0; }
.gm-empty .e-t { font-size: 17px; font-weight: 650; color: var(--text); }

/* New group and the members page share the bot page's column, cards and rows */
.group-page .page-top .page-h1 { flex: none; }
.gn-shapes { grid-template-columns: repeat(3, 64px); }
@media (min-width: 420px) { .gn-shapes { grid-template-columns: repeat(5, 64px); } }
.pick-row { min-height: 60px; }
.pick-row .f-avatar, .gi-row .f-avatar { width: 36px; height: 36px; }
.pick-check {
  flex: none; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--line-2); color: transparent;
  transition: background 140ms ease-out, box-shadow 140ms ease-out;
}
.pick-check svg.i { width: 14px; height: 14px; stroke-width: 2.2; }
.pick-row[aria-checked="true"] .pick-check { background: var(--ring); box-shadow: none; color: var(--on-accent); }
.pick-row:focus-visible, .gi-row .gi-act:focus-visible, #gi-mentions:focus-visible, .gi-leave:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.gn-friends-link { padding: 0 18px; }
.gi-row { margin-top: 0; background: transparent; min-height: 60px; }
@media (hover: hover) { .gi-row:hover { background: transparent; } }
.gi-act { flex: none; min-height: 36px; }
.gi-mentions { margin-top: 22px; }
#gi-mentions[aria-disabled="true"] { cursor: default; }
#gi-mentions[aria-disabled="true"] .sw { opacity: 0.55; }
.gi-leave { margin-top: 28px; padding: 0 18px; color: var(--err); justify-content: center; }
@media (hover: hover) { .bp-link.gi-leave:hover { background: var(--hover-2); text-decoration: none; } }
.gi-loading { padding: 40px 20px; text-align: center; color: var(--muted); }
.menu-item .mark.xs { width: 24px; height: 24px; }
.menu-item .f-avatar { width: 28px; height: 28px; font-size: 13px; }

/* Home under the floating head and above the floating composer (268): the head shows the bot's
 * mark, so home's own mark goes, and its invitation sits in the space between them. */
#home { padding: calc(var(--head-h, 140px) + 8px) 16px calc(var(--composer-h, 76px) + 16px); }
#home-mark { display: none; }

/* ---------- a bot's look (275) ---------- */
/* The Look picker: the simple mark first, then the 3D characters, in a grid of named tiles. */
.look-card { width: min(100%, 560px); max-height: min(86dvh, 720px); display: flex; flex-direction: column; padding: 18px 18px 14px; }
.look-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.look-head .d-h2 { margin: 0; }
.look-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px;
  /* rows keep their tiles' height and the grid scrolls, rather than squeezing them to fit the card */
  grid-auto-rows: max-content; align-content: start;
  overflow-y: auto; margin: 0 -4px; padding: 4px; min-height: 0;
}
.look-opt {
  display: flex; flex-direction: column; align-items: center; gap: 6px; min-height: 44px;
  padding: 10px 6px 8px; border: 1px solid transparent; border-radius: 14px;
  background: var(--chip); color: var(--text-2); font-size: 13px;
  transition: background 140ms ease-out, border-color 140ms ease-out, transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.look-opt .mark { width: 64px; height: 64px; }
.look-opt .look-name { max-width: 100%; text-align: center; line-height: 1.25; overflow-wrap: anywhere; }
.look-opt[aria-checked="true"] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--chip)); color: var(--text); }
@media (hover: hover) and (pointer: fine) { .look-opt:not([aria-checked="true"]):hover { background: color-mix(in srgb, var(--text) 6%, var(--chip)); } }
.look-opt:active { transform: scale(0.97); }
.look-sk { height: 104px; animation: skpulse 1.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .look-sk { animation: none; } .look-opt { transition: none; } }
@media (max-width: 760px) {
  .dialog:has(> .look-card) { align-items: flex-end; padding: 0; }
  .look-card { width: 100%; max-height: 82dvh; border-radius: 22px 22px 0 0; padding-bottom: max(14px, env(safe-area-inset-bottom)); }
  .look-grid { grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); }
  .look-opt .mark { width: 56px; height: 56px; }
}

/* ---------- the invite sheet (326, INVITE-AS-GIFT, CLIFF: 2026-10-09, as Claude's gift card;
 * INVITE-GIFT-CARD: 2026-10-09, exact to Claude's reference) ----------
 * The giving card, faithful to Claude's reference: on a phone it is a near-full-height sheet whose
 * top sits just under the safe area with rounded top corners, and at a wide width the same card
 * stands tall and centered (INVITE-SHEET-ABOVE-BARS steps the app's own bars aside while it is
 * open). Its face is Claude's gift card, per Eric (INVITE-LIKE-CLAUDE: "Make it look more like
 * claudes entirely"; INVITE-GIFT-CARD: make these changes against 10.jpg): a round glass close at
 * the top left, a band a shade lighter than the sheet that draws a hand-drawn gift box with a tag,
 * the serif "Give the gift of Align", the deal with Terms apply inline and underlined, calm space and
 * one full-width Share pill in the page's inverted text. There are no tickets and no invites-left
 * line anywhere (INVITE-NATIVE-SHEET): the card is the gift, the words and the one Share. There is
 * no link field, QR or Copy link; Share
 * opens the system share sheet (navigator.share) with the account's own link, and where none exists
 * the link is copied instead and the card says "Link copied". There is no invites-left count,
 * because Align puts no limit on the links an account may send (referrals.ts caps earned credits at
 * MONTHLY_CREDIT_CAP, never the invites themselves). */
#invite-dialog.invite { align-items: center; justify-content: center; padding: 16px; }
.invite-card {
  width: min(100%, 440px); height: min(92dvh, 860px); padding: 0;
  border-radius: 24px; border-bottom: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: stretch; text-align: center; position: relative;
  animation: inv-in 260ms cubic-bezier(0.23, 1, 0.32, 1);
}
@supports (backdrop-filter: blur(20px)) {
  .invite-card { background: color-mix(in srgb, var(--raised) 84%, transparent); backdrop-filter: blur(20px) saturate(1.5); }
}
@keyframes inv-in { from { opacity: 0; transform: translateY(24px); } }
@keyframes inv-fade { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .invite-card { animation-name: inv-fade; } }
/* The close is the page's round glass control, as the messenger bars draw it (INVITE-GIFT-CARD): a
 * filled circular target at the card's top left, on the band, not the bare x from before. Its face
 * comes from round-btn.glass; this rule only places it and sizes its glyph. */
.inv-close { position: absolute; top: 16px; left: 16px; right: auto; }
.inv-close svg.i { width: 18px; height: 18px; }
.inv-close:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
/* The gift band (INVITE-GIFT-CARD), the card's one memorable element: a full-width band a shade
 * lighter than the sheet, about a third of the card, holding only a hand-drawn white gift box with
 * a tag hanging off it (a fair copy of Claude's reference drawing, in --text strokes with round
 * caps). The title, deal and tickets stay in the page's calm type and tokens; nothing else is
 * drawn, and no ribbon sits in the band. */
.inv-band {
  flex: none; width: 100%; height: 31%;
  background: var(--raised-2); border-bottom: 1px solid var(--line);
  border-radius: 24px 24px 0 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.inv-gift { height: 62%; width: auto; color: var(--text); }
.inv-gift .ig, .inv-gift circle { fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
/* The card's body: title and deal, centered in the calm space under the band, with the one control
 * pinned at the bottom (INVITE-GIFT-CARD). No tickets, no invites-left line (INVITE-NATIVE-SHEET). */
.inv-body { flex: 1; min-height: 0; overflow-y: auto; padding: 8px 20px 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
#invite-title { margin: 8px 0 0; font-family: var(--serif); font-size: 30px; font-weight: 450; letter-spacing: -0.01em; text-wrap: balance; }
.inv-deal { margin: 14px 0 0; color: var(--text-2); font-size: 14.5px; line-height: 1.55; max-width: 38ch; text-wrap: pretty; }
.inv-terms { color: var(--text-2); text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }
@media (hover: hover) { .inv-terms:hover { color: var(--text); } }
.inv-terms:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 2px; }
/* No tickets, no invites-left line, no "Unlimited" (INVITE-NATIVE-SHEET): the card's calm body ends
 * at the Share pill. A ticket is never drawn. */
.inv-body #inv-err { width: 100%; max-width: 380px; margin: 18px auto 0; }
/* The card's one full-width call, pinned at the bottom, in the page's inverted text (INVITE-GIFT-CARD):
 * white with the page's dark text in the dark theme, and the page's near-black with white text in
 * light, matching a neutral share control, never the accent. It opens the system share sheet
 * (navigator.share) with the account's link; the fallback copies the link. */
.inv-cta-wrap { width: 100%; max-width: 400px; align-self: center; padding: 22px 0 24px; }
.inv-cta {
  width: 100%; height: 52px; border: 0; border-radius: 999px;
  background: var(--text); color: var(--bg); font: inherit; font-size: 16px; font-weight: 650;
  cursor: pointer;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out;
}
@media (hover: hover) { .inv-cta:hover { background: color-mix(in srgb, var(--text) 88%, var(--bg)); } }
.inv-cta:active { transform: scale(0.98); }
.inv-cta:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
/* "Link copied" and any error float above the pill, transient, never taking the card's layout
 * (the fallback reports a copy only where there is no system share sheet). */
.inv-status { position: absolute; left: 12px; right: 12px; bottom: calc(108px + env(safe-area-inset-bottom)); text-align: center; font-size: 13px; color: var(--text-2); pointer-events: none; }
/* A phone: the same card fills the width and height as a near-full-height sheet whose top sits
 * just under the safe area, rounded only at the top, still with the one Share pill at its bottom */
@media (max-width: 520px) {
  #invite-dialog.invite { align-items: flex-end; padding: 0; }
  .invite-card { width: 100%; height: calc(100dvh - 48px); padding: 0; border-radius: 24px 24px 0 0; }
  .inv-body { padding: 8px 16px 0; }
  #invite-title { font-size: 26px; }
  .inv-deal { font-size: 14px; }
  /* the pill sits 16pt in from each side on a phone, as Claude's reference card does; its bottom
   * docking stays (INVITE-GIFT-DETAILS, the 1440 card already insets 20px via its max-width) */
  .inv-cta-wrap { padding: 20px 16px 16px; }
}

/* the sign-in screen of a friend who opened a share link (326) */
.w-invited {
  display: flex; align-items: center; gap: 12px; max-width: 40ch;
  padding: 10px 14px 10px 10px; border-radius: 14px; background: var(--raised); border: 1px solid var(--line);
}
.w-invited img { width: 44px; height: 44px; flex: none; }
.w-inv-who { margin: 0; font-size: 15px; font-weight: 650; }
.w-inv-deal { margin: 2px 0 0; font-size: 13.5px; line-height: 1.4; color: var(--text-2); }

/* ---------- a message held (HOLD-AND-REACT) ---------- */

/* The whole page under a long-held message: the chat dimmed and blurred, the held bubble lifted at
 * its own place, the reaction bar and the message's menu over it, as WhatsApp's. The layer takes
 * every touch, so nothing under it scrolls or acts while a message is held. */
.hv-layer {
  position: fixed; inset: 0; z-index: 62;
  touch-action: none; overscroll-behavior: contain;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  /* --hold-dy: the distance the open stack moves to fit the area, set on this layer in JS; resting is 0 */
  --hold-dy: 0px;
}
.hv-scrim {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--bg) 40%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4);
}
/* The lifted bubble: a clone carried from the message's place, raised with the page's own shadow.
 * The whole stack (bar, bubble, menu) slides to the nearest place where all three fit as its open:
 * --hold-dy (set on the layer in JS) is the distance the stack must travel, so the bubble, the bar
 * and the menu move together and never detach on the way. Settled, the stack is exactly where the
 * page placed it, at its own size, so a measured rect is the real one.
 * The shadow rides the clone the message's own surface carries (liftLook), never this container:
 * this box has no radius, and a shadow cast here would read as a faint square behind any bubble. */
.hv-bub {
  position: absolute;
  max-width: calc(100vw - 16px);
  transform: translateY(var(--hold-dy, 0px)) scale(0.95); opacity: 0;
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 200ms cubic-bezier(0.23, 1, 0.32, 1);
}
.hv-layer.in .hv-bub { transform: translateY(0) scale(1); opacity: 1; }
.hv-layer.closing .hv-bub { transition-duration: 120ms; }

/* The glass reaction bar, the grid "+" opens in its place, and the message's menu: the page's own
 * glass surfaces, which never fight each other for the reader's eye. They ride the same --hold-dy
 * as the bubble on the open, so a stack that must move holds together while it moves. */
.hv-bar, .hv-grid, .hv-menu {
  position: absolute;
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-shadow);
  transform: translateY(var(--hold-dy, 0px));
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1), background 140ms ease-out;
}
.hv-layer.in .hv-bar, .hv-layer.in .hv-grid, .hv-layer.in .hv-menu { transform: translateY(0); }
.hv-layer.closing .hv-bar, .hv-layer.closing .hv-grid, .hv-layer.closing .hv-menu { transition-duration: 120ms; }
.hv-bar, .hv-grid { border-radius: 999px; padding: 4px; display: flex; gap: 2px; }
.hv-menu { min-width: 200px; padding: 5px; border-radius: 14px; display: flex; flex-direction: column; }
.hv-grid { flex-wrap: wrap; max-width: min(352px, calc(100vw - 16px)); border-radius: 18px; }
/* The bar's emoji and "+", at the page's 44px control size: a hold opens them and a thumb is
 * already over the page, so each is a whole target, never a sliver. */
.hv-emo {
  width: 44px; height: 44px; padding: 0; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--text);
  font-size: 24px; line-height: 1;
  cursor: pointer;
  transition: background 140ms ease-out, transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.hv-gemo { font-size: 21px; }
.hv-emo.mine { background: var(--selected); }
.hv-emo:not(:disabled):active { transform: scale(0.94); }
@media (hover: hover) { .hv-emo:not(:disabled):hover { background: var(--hover-2); } }
.hv-more {
  border-left: 1px solid var(--glass-line); border-radius: 50%;
  margin-left: 2px; color: var(--muted); font-size: 21px;
}
.hv-menu .menu-item { width: 100%; }

/* An answer with no bubble of its own (a photo, a card): the hold's own glass surface and the
 * message radius, so the lifted copy never reads as a flat grey box on the blurred chat. */
.hv-naked {
  background: var(--glass); border-radius: 20px; padding: 10px 16px;
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
}
/* An answer taller than the safe area allows: the lifted copy is capped to the room the stack
 * leaves, and scrolls inside itself. Its scroll never reaches the chat's own, so holding one never
 * closes; the bar stays above and the menu below all the while. */
.hv-bub.hv-long {
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  touch-action: pan-y; overscroll-behavior: contain; scrollbar-width: thin;
}

/* The reactions drawn on a message (WhatsApp's pill): the emoji and each count, hanging off the
 * bubble's lower corner, tapped to lift the message to the same bar again. A held message has no
 * such pill: the held clone never draws one, so nothing on the lifted copy can be pressed. */
.x-pill {
  position: absolute; right: 10px; bottom: -16px;
  height: 30px; padding: 0 8px; display: inline-flex; align-items: center; gap: 4px;
  border: 0; border-radius: 15px;
  background: var(--bub-in); box-shadow: 0 0 0 2px var(--bg);
  cursor: pointer;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.x-pill:not(:disabled):active { transform: scale(0.94); }
.xp-em { font-size: 15px; line-height: 1; }
.xp-c { font-size: 12.5px; font-weight: 650; color: var(--text-2); font-variant-numeric: tabular-nums; }
/* A pill hangs off its corner, so its bubble needs the room; the bubble the pill is on is never
 * mistaken for a control itself. Never draw a pill on a message that is already gone. */
.gm-bub:has(> .x-pill), .xbub:has(> .x-pill), .photo-thumbs:has(> .x-pill),
.x > .a-body:has(> .x-pill), .gm-body:has(> .x-pill), .a-img:has(> .x-pill) { margin-bottom: 14px; }
.photo-thumbs:has(> .x-pill), .x > .a-body:has(> .x-pill), .gm-body:has(> .x-pill), .a-img:has(> .x-pill) { position: relative; }
/* a bot's badge and a reader's pill never cover each other: the pill steps left of the badge */
.gm-bub:has(> .x-react) .x-pill, .xbub:has(> .x-react) .x-pill, .photo-thumbs:has(> .x-react) .x-pill { right: 44px; }
@media (pointer: coarse) { .holdable { -webkit-touch-callout: none; } }
@media (prefers-reduced-motion: reduce) {
  /* only the fade, never the slide to a fitted place or the lift */
  .hv-bub, .hv-bar, .hv-grid, .hv-menu { transform: translateY(0); }
  .hv-bub { transition: opacity 160ms ease-out; }
  .hv-layer.closing .hv-bub { transition-duration: 120ms; }
}

/* ---------- reply, forward and delete (HOLD-REPLY-FORWARD-DELETE) ---------- */

/* A message deleted for everyone reads like a removed one (311), never a live bubble: its own
 * words, photos and reaction are gone, and only the row's sender stays. */
.gm-bub.removed, .xbub.removed, .gm-bub.deleted, .xbub.deleted, .a-body.deleted, .gm-body.deleted { background: transparent; border: 1px dashed var(--line-2); color: var(--muted); font-style: italic; }

/* The reply in progress above the composer: a glass card the page's own field heights never
 * cover, carrying the quoted message's sender and words and an × to drop it. It rides inside the
 * composer capsule's own column, so it lines up with the field and never overlaps the page. An
 * edit in progress (EDIT-RESEND) shares this exact card for its own #edit-strip: no sender name,
 * just a plain line saying so, since the words themselves already sit in the field below it. */
.reply-strip {
  max-width: var(--col); margin: 0 auto 8px;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px 8px 12px;
  border-radius: 14px;
  background: var(--glass); border: 1px solid var(--glass-line);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  box-shadow: var(--glass-shadow);
}
.reply-strip[hidden] { display: none; }
.rs-in { flex: 1; min-width: 0; display: flex; align-items: stretch; gap: 10px; }
.rs-bar { flex: none; width: 3px; border-radius: 2px; background: var(--line-2); }
/* the reader's own quoted words may never carry the sender's color, so the bar shows no color here */
.rs-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.rs-name { margin: 0; font-size: 12.5px; font-weight: 650; color: var(--muted); }
.rs-body { margin: 0; font-size: 13.5px; line-height: 1.35; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.rs-x {
  flex: none; width: 32px; height: 32px; border: 0; border-radius: 50%;
  display: grid; place-items: center;
  background: transparent; color: var(--muted); cursor: pointer;
  transition: background 140ms ease-out, transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.rs-x svg.i { width: 14px; height: 14px; }
@media (hover: hover) { .rs-x:hover { background: var(--hover-2); } }
.rs-x:not(:disabled):active { transform: scale(0.92); }

/* The quoted block on a message that answers another (WhatsApp's reply): the sender's name on a
 * bar in their color, and the quoted words, one line, the whole block a tap that brings the
 * quoted message into view and flashes it. A quote of a message deleted for everyone keeps the
 * sender's name and the plain line it now carries. */
.xq {
  flex: none; display: flex; align-items: stretch; gap: 8px;
  margin: 0 0 6px; max-width: min(100%, 420px);
  padding: 5px 10px 5px 4px;
  /* a <button>: none of the browser's own border or bevel, only the tint below */
  border: 0; -webkit-appearance: none; appearance: none;
  border-radius: 10px;
  background: color-mix(in srgb, currentColor 10%, transparent);
  text-align: left; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.xq-bar { flex: none; width: 3px; border-radius: 2px; margin-left: 6px; background: var(--line-2); }
.xq-in { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.xq-name { font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.xq-text { font-size: 13px; line-height: 1.3; opacity: 0.92; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.xq.deleted .xq-name, .xq.deleted .xq-text { opacity: 0.72; }
.xq:not(:disabled):active { transform: scale(0.99); }
@media (hover: hover) { .xq:hover { outline: 1px solid color-mix(in srgb, currentColor 22%, transparent); outline-offset: -1px; } }
/* the keyboard ring in the bubble's own text color (the page's --ring blue all but vanishes on an own
 * blue bubble), kept over the hover line when the pointer rests on a focused quote */
.xq:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.xq .xq-bar { background: var(--q-color, var(--line-2)); }
.xq.timeout .xq-name, .xq.timeout .xq-text { cursor: default; }

/* The flash a tapped quote brings to the quoted message: the page's warn wash, once, never a
 * repeated animation, so scrolling away and back does not set it off again. */
.q-flash { animation: q-flash 1.1s ease-out; }
@keyframes q-flash { 0% { background: color-mix(in srgb, var(--warn) 38%, transparent); } 100% { background: transparent; } }
@media (prefers-reduced-motion: reduce) { .q-flash { animation: none; } }

/* The small Forwarded label on a forwarded copy: the quietest grey tag, five letters, never an
 * explanation. Only a message that was actually forwarded carries it. */
.xfwd { display: block; margin: 2px 0 1px; font-size: 11px; font-weight: 650; letter-spacing: 0.01em; color: var(--muted); }
.xbub > .xfwd { color: color-mix(in srgb, var(--on-msg) 62%, transparent); }

/* The delete sheet's scope rows: one or two plain lines, never radio buttons, the second one the
 * dangerous choice. The option the service would refuse (Delete for everyone on another's message
 * or one too old) is not drawn at all, so the sheet never offers what cannot be done. */
.md-opts { display: flex; flex-direction: column; gap: 8px; margin: 0 0 14px; }
.md-opt {
  display: flex; align-items: center; gap: 10px; min-height: 44px;
  padding: 8px 12px;
  border: 1px solid var(--line-2); border-radius: 10px;
  background: transparent; color: var(--text); font: inherit; font-size: 15px; text-align: left;
  cursor: pointer;
  transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), border-color 140ms ease-out;
}
.md-opt.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.md-opt .md-ic { flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; background: var(--chip); color: var(--text-2); }
.md-opt.on .md-ic { background: var(--accent); color: var(--on-accent); }
.md-opt .md-ic svg.i { width: 14px; height: 14px; }
.md-opt .md-why { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.md-opt .md-name { font-weight: 600; }
.md-opt .md-sub { font-size: 12.5px; color: var(--muted); }
.md-opt.danger .md-name { color: var(--danger); }
.md-opt:not(:disabled):active { transform: scale(0.98); }
@media (hover: hover) { .md-opt:not(:disabled):hover { border-color: var(--line); } }

/* The forward sheet: a wider card, the search above the list, the rows of chats, agents, friends
 * and groups as one scrollable list, each a check on the right and a count on the Send button. */
.fwd-card { width: min(100%, 460px); }
.fwd-search-row { margin: 0 0 12px; }
.fwd-search { margin-bottom: 0; }
.fwd-list {
  display: flex; flex-direction: column; gap: 2px;
  max-height: min(52dvh, 420px); overflow-y: auto;
  margin: 0 0 12px; padding-right: 2px;
}
.fwd-cap { display: block; font-size: 12px; font-weight: 650; color: var(--muted); padding: 8px 4px 4px; text-transform: uppercase; letter-spacing: 0.02em; }
.fwd-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; padding: 6px 10px;
  border: 0; border-radius: 10px; background: transparent;
  font: inherit; font-size: 15px; text-align: left; color: var(--text);
  cursor: pointer;
  transition: background 140ms ease-out, transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
@media (hover: hover) { .fwd-row:hover { background: var(--hover-2); } }
.fwd-row:not(:disabled):active { transform: scale(0.98); }
.fwd-row .fwd-mark { flex: none; }
.fwd-row .fwd-name { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fwd-row .fwd-sub { font-size: 12.5px; color: var(--muted); font-weight: 450; }
.fwd-check {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  background: transparent; color: transparent;
  transition: background 160ms cubic-bezier(0.23, 1, 0.32, 1), color 160ms cubic-bezier(0.23, 1, 0.32, 1);
}
.fwd-check svg.i { width: 14px; height: 14px; stroke-width: 2.2; }
.fwd-row.on .fwd-check { background: var(--accent); color: var(--on-accent); }
.fwd-row:disabled { color: var(--faint); cursor: default; }
.fwd-row:disabled .fwd-check { color: var(--faint); }
.fwd-row:disabled .fwd-check svg.i { display: none; }
.fwd-empty { padding: 14px 4px; color: var(--muted); font-size: 14px; }
#fwd-note { margin: 0 0 12px; }
#fwd-note.err { color: var(--err); }
.fwd-send-n { margin-left: 4px; font-weight: 400; opacity: 0.85; }

/* Calls in a direct group (CALLS, docs/design/cloud-calls.md): the voice and video buttons in a
 * two-person chat's head, the full-screen in-call screen, and the centred line a call leaves in
 * the group. Drawn entirely in the page's own tokens; the media is the person's, never the
 * service's. */
.call-rm {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: var(--bg); color: var(--text);
  overflow: hidden;
}
.call-rm[hidden] { display: none; }
/* a faint wash of the product colour behind the ghost, never a gradient-text or neon: the screen
   reads as the product's, not as a decorated panel */
.call-wash {
  position: absolute; inset: 0;
  background: radial-gradient(70% 55% at 50% 16%, color-mix(in srgb, var(--msg) 14%, transparent), transparent 68%);
  pointer-events: none;
}
.call-ghost {
  position: relative; display: grid; justify-items: center; gap: 16px;
  padding: 24px; max-width: min(88vw, 460px); text-align: center;
}
.call-ghost.behind { opacity: 0.92; }
.call-name { margin: 0; font-size: 26px; font-weight: 600; color: var(--text); letter-spacing: -0.01em; text-wrap: balance; }
.call-status { margin: 0; font-size: 14.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.call-remote { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--raised-2); }
.call-remote[hidden] { display: none; }
.call-local {
  position: absolute; right: 14px; top: 14px; width: 104px; height: 140px;
  border-radius: 16px; object-fit: cover;
  background: var(--raised-2); border: 1px solid var(--glass-line); box-shadow: var(--glass-shadow);
}
.call-local[hidden] { display: none; }
.call-acts {
  position: absolute; left: 0; right: 0; bottom: 34px;
  display: flex; justify-content: center; gap: 28px;
}
.call-act { width: 58px; height: 58px; background: var(--glass); border-color: var(--glass-line); box-shadow: var(--glass-shadow); }
.call-act svg.i { width: 26px; height: 26px; stroke-width: 1.8; }
.call-act.hold { background: var(--msg); color: var(--on-msg); border-color: transparent; }
.call-act.drop { background: var(--danger); color: #fff; border-color: transparent; }
.call-act[aria-pressed="true"] { background: var(--msg); color: var(--on-msg); border-color: transparent; }
.call-act:disabled { opacity: 0.55; }
@media (max-width: 560px) {
  .call-local { right: 12px; top: 12px; width: 88px; height: 118px; border-radius: 14px; }
  .call-acts { bottom: 26px; gap: 22px; }
  .call-name { font-size: 22px; }
}
/* A call's record in a group (CALLS): the centred line a call leaves, never a bubble, as the
   page's message channel draws the service's row. A missed or declined call in the product's
   danger tone: the exact hue is never the only signal, the word is. */
.gm-call {
  flex: none; align-self: center;
  display: inline-flex; align-items: center; gap: 8px;
  margin: 4px 0; padding: 6px 14px; border-radius: 999px;
  background: var(--raised-2); color: var(--muted);
  font-size: 13px; font-variant-numeric: tabular-nums;
}
.gm-call .gm-call-ic { width: 15px; height: 15px; color: var(--muted); flex: none; }
.gm-call.miss .gm-call-words { color: var(--err); font-weight: 550; }
/* A transient note only this page draws in a group (CALLS): the video-Pro note and such, centred
   and quiet, never a message, gone when the group's next open clears the page's own list. */
.gm-note { flex: none; align-self: center; margin: 2px 0; padding: 4px 12px; text-align: center; font-size: 13px; color: var(--muted); }
