/* 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;
  --bg: #151515;
  --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;
  --accent: #e07d5a;
  --on-accent: #151515;
  --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;
  /* 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;
    --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;
    --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;
    --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%; }
body {
  margin: 0;
  background: var(--bg);
  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(--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: center; gap: 9px;
  font-size: 15px; font-weight: 650; letter-spacing: -0.01em;
  color: var(--text);
}
.wm-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); flex: none; }
.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 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. */
.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;
}
.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; }

.chat-list { flex: 1; min-height: 0; overflow-y: auto; 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, with a short fade */
[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) + 10px);
  background: linear-gradient(to bottom, var(--bg) calc(100% - 10px), transparent);
}
/* 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 { 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; }
.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); }
.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; }
  /* 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); }
.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); }
.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. The account's own bot wears a small badge at its corner, ringed in
 * the surface it sits on so it reads as its own disc. */
.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; }
.mark-badge {
  position: absolute; right: -2%; bottom: -2%;
  width: 40%; height: 40%; min-width: 14px; min-height: 14px;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--accent); color: #ffffff;
  box-shadow: 0 0 0 2px var(--bg);
}
.mark-badge svg.i { width: 62%; height: 62%; fill: currentColor; stroke: none; }
.mark.xs .mark-badge, .mark.sm .mark-badge { box-shadow: 0 0 0 1.5px var(--bg); }
.cl-row.current .mark-badge { box-shadow: 0 0 0 2px var(--selected); }

/* The open chat's head (268), as the reference's: it floats over the conversation, which scrolls
 * under it and fades out beneath the page's own background. 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(--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; }
.mark.head-mk .mark-badge { box-shadow: 0 0 0 2.5px var(--bg); }
.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; }
/* 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) draws the gift icon in the accent;
   327's in-chat gift is gone, so the shake and dot it used are gone with it */
.gift-btn { position: relative; color: var(--accent-tx); }
.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; }
.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; }

.welcome {
  min-height: 100dvh; display: flex; flex-direction: column; justify-content: center;
  gap: 20px; max-width: 460px; margin: 0 auto; padding: 32px 20px;
}
.welcome .wordmark { font-size: 17px; }
.w-h1 {
  margin: 0; font-size: 32px; line-height: 1.2; font-weight: 700;
  letter-spacing: -0.02em; max-width: 14ch; text-wrap: balance;
}
.w-h2 {
  margin: 0; font-size: 24px; line-height: 1.25; font-weight: 650;
  letter-spacing: -0.015em; text-wrap: balance;
}
.lead { margin: 0; color: var(--text-2); font-size: 16px; max-width: 38ch; }

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

.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%; justify-content: flex-start; padding: 0 14px; gap: 10px; }
.btn.provider .btn-txt { flex: 1; text-align: center; }
.btn.provider svg.pm { color: var(--icon); }
.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 welcome screen's bottom line: a plain link to the privacy policy, nothing else */
/* The Terms line (311) under the heading: what continuing agrees to, quiet, with both pages linked. */
.w-terms { margin: -8px 0 0; font-size: 13.5px; color: var(--text-2); max-width: 38ch; }
.w-terms a { color: inherit; text-underline-offset: 3px; }
.w-foot { margin: 4px 0 0; text-align: center; font-size: 14px; }
.w-foot a { text-underline-offset: 3px; }

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

/* ---------- 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); }
.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 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); }
.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 generated image's place in the thread (231d): the working state while the image is made, and
 * 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-working {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 9px;
  margin-top: 2px; padding: 9px 14px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--raised); color: var(--muted);
  font-size: 13.5px;
}
.a-working .work-spin {
  width: 14px; height: 14px; border-radius: 50%; flex: none;
  border: 2px solid rgba(63, 119, 193, 0.3); border-top-color: var(--ring);
  animation: turn 0.8s linear infinite;
}
.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; } }

/* 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 */
.hp-msgs .m-acts { 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%; }
.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, as the reference's messages:
 * the person's a bubble at the right in the accent blue with white words, the bot's a bubble at
 * the left on the neutral surface, with its markdown inside in the page's sans. What belongs to
 * the answer (tool cards, images, the Sources cards and "N sources", Copy) sits with its bubble,
 * and bubbles on one side stack tight. */
.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; }
.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;
}
.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; }
.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 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; }
.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; } }

/* 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 cards (243): the record of the steps a turn took, at the left before the
   answer, in the page's own raised-card language. A card is one folded line - mark, kind, the
   step's argument in the mono face, and the status word, never the state's color alone - and
   the output unfolds on tap in a bounded mono block. Done, failed and working are the page's
   own marks and hues (the -tx variants, the same hues at text contrast); no new color appears. */
.x .tk-section { margin-top: 18px; }
.tk-section { display: flex; flex-direction: column; gap: 8px; max-width: 640px; }
.tk-card { border-radius: 12px; background: var(--raised); border: 1px solid var(--line); 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(--text); border-radius: 12px;
}
@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="done"] { color: var(--add); }
.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; font-weight: 600; color: var(--text); 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; }
.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="done"] { color: var(--cl-high-tx); }
.tk-status[data-status="failed"] { color: var(--cl-low-tx); }
.tk-chev { flex: none; color: var(--faint); transition: transform 140ms ease-out; }
.tk-head[aria-expanded="true"] .tk-chev { transform: rotate(180deg); }
/* 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); } }
.tk-out { border-top: 1px solid var(--line); 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 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; }
}

.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; }
/* 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. */
.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 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); }
@media (hover: hover) { .ma-btn:hover { background: var(--hover-2); color: var(--text); } }
.ma-btn:active:not(.ok) { transform: scale(0.94); }

/* The cost note on the website rests under the last finished answer only (nothing at all in the
 * app); a price is no AI name. */
.a-meta { margin: 4px 0 0; padding-left: 8px; font-size: 12.5px; color: var(--muted); }
.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);
}
.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 { color: var(--link); font-size: 14px; font-weight: 600; text-decoration: none; }
.a-note button.up { border: 0; background: none; padding: 0; margin: 0; cursor: pointer; }
@media (hover: hover) { .a-note .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); }
.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 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;
}
.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; }
.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; }
.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); }
/* 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; }
  .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; }
  .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 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(--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 { 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. */
.add-host { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.add-host .f-avatar { width: 64px; height: 64px; font-size: 28px; }
.add-lead { margin: 0; color: var(--text-2); }
.add-note { margin: 0; color: var(--muted); }

/* 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 { min-height: 48px; }
.pf-alert {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; border-radius: 12px;
  background: var(--selected); color: var(--text); font-size: 14px;
}
.pf-alert-review { flex: none; }
.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; }
.p-trial .p-trial-start { margin: 8px 8px 0; }
.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 WhatsApp
 * step with its code, 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 { 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 .p-phone-code {
  align-self: flex-start; padding: 6px 12px; border-radius: 8px; background: var(--chip);
  font: 600 17px/1.3 var(--mono); color: var(--text); letter-spacing: 0.02em;
}
.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 { min-height: 56px; cursor: pointer; }
.p-phone-find .p-conn-name { flex: 1; font-size: 15px; font-weight: 400; }
.p-phone-find 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 { 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 { 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-row.cl-arch { min-height: 52px; padding: 6px 10px; }
.cl-arch-ic { flex: none; width: 52px; display: grid; place-items: center; color: var(--muted); }
.cl-arch-ic svg.i { width: 22px; height: 22px; }
.cl-arch-n { flex: none; margin-left: auto; font-size: 13px; font-weight: 600; color: var(--ring); font-variant-numeric: tabular-nums; }
.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; }

/* 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 */
.gm.draft.working { align-items: center; }
.gm.draft.working .gm-face { margin-top: 0; }
.gm-name.gm-working {
  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 { 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. */
.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;
  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; } }
.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); }
