
/* bc-splash styles live in /static/boot-splash.css (first-paint; keep CSP style-src 'self'). */


:root {
  --kb: 0px;
  --owner-accent: #e0a458;
  color-scheme: dark;
  --bg: #10141a;
  --card: #1a212b;
  --line: #354153;
  --text: #f2f6fb;
  --muted: #c3cedb;
  --mine: #3c92ea;
  --mine-text: #fff;
  --other: #3a4250;
  --other-text: #f2f6fb;
  --accent: #9ec0ff;
  --on-accent: #071018;
  --danger: #ff5d5d;
  --pill: #243140;
  --shade: rgba(0, 0, 0, .55);
  --shadow: 0 10px 30px rgba(0, 0, 0, .32);
}
html[data-scheme="light"] {
  color-scheme: light;
  --owner-accent: #a15c1c;
  --shade: rgba(20, 28, 38, .45);
  --shadow: 0 10px 30px rgba(28, 36, 48, .12);
}
html[data-scheme="dark"] { color-scheme: dark; }
html[data-palette="huzz"][data-scheme="light"] {
  --bg: #f3f6fb; --card: #ffffff; --line: #d5deea; --text: #1c2430; --muted: #526173;
  --mine: #3c92ea; --mine-text: #fff; --other: #e7eef6; --other-text: #1c2430;
  --accent: #1d4e89; --on-accent: #fff; --danger: #b42318; --pill: #e7eef6;
}
html[data-palette="glacier"][data-scheme="dark"] {
  --bg: #0e1621; --card: #17212b; --line: #243444; --text: #f5f5f5; --muted: #8b9aab;
  --mine: #2b5278; --mine-text: #fff; --other: #182533; --other-text: #f5f5f5;
  --accent: #6ab2f2; --on-accent: #0e1621; --danger: #e53935; --pill: #232e3c;
}
html[data-palette="glacier"][data-scheme="light"] {
  --bg: #d7e4ee; --card: #ffffff; --line: #c5d5e4; --text: #222222; --muted: #60788c;
  --mine: #effdde; --mine-text: #1d2a16; --other: #ffffff; --other-text: #222222;
  --accent: #3390ec; --on-accent: #fff; --danger: #d32f2f; --pill: #ffffff;
}
html[data-palette="nebula"][data-scheme="dark"] {
  --bg: #313338; --card: #2b2d31; --line: #3f4147; --text: #f2f3f5; --muted: #b5bac1;
  --mine: #5865f2; --mine-text: #fff; --other: #232428; --other-text: #f2f3f5;
  --accent: #5865f2; --on-accent: #fff; --danger: #f23f43; --pill: #1e1f22;
}
html[data-palette="nebula"][data-scheme="light"] {
  --bg: #ffffff; --card: #f2f3f5; --line: #e3e5e8; --text: #060607; --muted: #5c5e66;
  --mine: #5865f2; --mine-text: #fff; --other: #e9eaee; --other-text: #060607;
  --accent: #5865f2; --on-accent: #fff; --danger: #da373c; --pill: #e3e5e8;
}
html[data-palette="lagoon"][data-scheme="dark"] {
  --bg: #0b141a; --card: #111b21; --line: #233138; --text: #e9edef; --muted: #8696a0;
  --mine: #005c4b; --mine-text: #e9edef; --other: #202c33; --other-text: #e9edef;
  --accent: #00a884; --on-accent: #041410; --danger: #f15c6d; --pill: #202c33;
}
html[data-palette="lagoon"][data-scheme="light"] {
  --bg: #efeae2; --card: #ffffff; --line: #d1d7db; --text: #111b21; --muted: #667781;
  --mine: #d9fdd3; --mine-text: #111b21; --other: #ffffff; --other-text: #111b21;
  --accent: #008069; --on-accent: #fff; --danger: #ea0038; --pill: #ffffff;
}
html[data-palette="bubble"][data-scheme="dark"] {
  --bg: #000000; --card: #1c1c1e; --line: #38383a; --text: #ffffff; --muted: #8e8e93;
  --mine: #0a84ff; --mine-text: #fff; --other: #262628; --other-text: #ffffff;
  --accent: #0a84ff; --on-accent: #fff; --danger: #ff453a; --pill: #2c2c2e;
}
html[data-palette="bubble"][data-scheme="light"] {
  --bg: #ffffff; --card: #f2f2f7; --line: #d1d1d6; --text: #000000; --muted: #6c6c70;
  --mine: #007aff; --mine-text: #fff; --other: #e9e9eb; --other-text: #000000;
  --accent: #007aff; --on-accent: #fff; --danger: #ff3b30; --pill: #e9e9eb;
}
html[data-palette="aubergine"][data-scheme="dark"] {
  --bg: #1a1d21; --card: #222529; --line: #393d42; --text: #e7e7e7; --muted: #ababad;
  --mine: #1d9bd1; --mine-text: #fff; --other: #2c2f33; --other-text: #e7e7e7;
  --accent: #36c5f0; --on-accent: #041016; --danger: #e01e5a; --pill: #2c2f33;
}
html[data-palette="aubergine"][data-scheme="light"] {
  --bg: #ffffff; --card: #f8f8f8; --line: #e2e2e2; --text: #1d1c1d; --muted: #616061;
  --mine: #007a5a; --mine-text: #fff; --other: #f4f3f1; --other-text: #1d1c1d;
  --accent: #4a154b; --on-accent: #fff; --danger: #e01e5a; --pill: #f4efe8;
}
html[data-palette="vinyl"][data-scheme="dark"] {
  --bg: #121212; --card: #181818; --line: #282828; --text: #ffffff; --muted: #b3b3b3;
  --mine: #1db954; --mine-text: #041208; --other: #282828; --other-text: #ffffff;
  --accent: #1db954; --on-accent: #041208; --danger: #f3727f; --pill: #282828;
}
html[data-palette="vinyl"][data-scheme="light"] {
  --bg: #ffffff; --card: #f6f6f6; --line: #e0e0e0; --text: #121212; --muted: #5c5c5c;
  --mine: #1db954; --mine-text: #041208; --other: #efefef; --other-text: #121212;
  --accent: #1db954; --on-accent: #041208; --danger: #c4142b; --pill: #efefef;
}
html[data-palette="graphite"][data-scheme="dark"] {
  --bg: #0d1117; --card: #161b22; --line: #30363d; --text: #e6edf3; --muted: #8d96a0;
  --mine: #1f6feb; --mine-text: #fff; --other: #21262d; --other-text: #e6edf3;
  --accent: #58a6ff; --on-accent: #0d1117; --danger: #f85149; --pill: #21262d;
}
html[data-palette="graphite"][data-scheme="light"] {
  --bg: #ffffff; --card: #f6f8fa; --line: #d0d7de; --text: #1f2328; --muted: #656d76;
  --mine: #0969da; --mine-text: #fff; --other: #f6f8fa; --other-text: #1f2328;
  --accent: #0969da; --on-accent: #fff; --danger: #d1242f; --pill: #eaeef2;
}
html[data-text="small"] body { font-size: 14px; }
html[data-text="large"] body { font-size: 22px; }
* { box-sizing: border-box; }
html, body { height: 100%; min-height: 100%; min-height: 100dvh; }
/* 6110fe: kill Android WebView (and iOS) default tap flash. Press feedback stays on :active/:focus-visible. */
html { -webkit-tap-highlight-color: transparent; }
body {
  margin: 0;
  /* 26.10.5 (iPad fix): the app is exactly as tall as the part of the screen you can see. app.js measures that
     (window.visualViewport) and sets --app-h; 100dvh is only the fallback before the script runs. --app-top moves the
     app down to follow iOS when it slides the page up behind the keyboard, so the header never hides off the top. */
  height: var(--app-h, 100dvh);
  margin-top: var(--app-top, 0px);
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font: 17px/1.45 "Segoe UI", "Noto Sans", "Liberation Sans", sans-serif;
  /* 26.10.5: no keyboard padding any more: --app-h already leaves out the keyboard, and adding both is what squashed the
     whole app into the top of an iPad screen. */
}
button, input, textarea, select { font: inherit; color: inherit; }
/* iphone-zoom: stop accidental double-tap zoom (pinch is blocked in JS). Single-finger pan/scroll still works.
   Surfaces that own their own pinch (lightbox, avatar crop, camera, media editor) keep touch-action: none below. */
html, body { touch-action: manipulation; }
/* iOS zooms the page when a focused field is under 16px. Keep larger text sizes (1em) when the user picked Large. */
input, textarea, select, [contenteditable="true"], [contenteditable=""] {
  font-size: max(16px, 1em);
}

button { cursor: pointer; }
header {
  position: relative;
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}
.brand { display: flex; align-items: center; gap: 8px; min-width: 0; }
.brand-col { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.brand img { width: 32px; height: 32px; border-radius: 8px; object-fit: cover; flex: none; background: #000; }
/* Wordmark is a transparent PNG — never paint a black plate behind it */
.brand img.bc-wordmark {
  width: auto; height: 28px; border-radius: 0; object-fit: contain;
  background: transparent; box-shadow: none;
  -webkit-mask: none; mask: none; filter: none;
}
header strong { font-size: 18px; }
#who { color: var(--muted); font-size: 14px; }
/* secure-ok / secure-bad: icon-only after the version line (setSecure). Green closed lock vs red open lock.
   Checking/unknown stays non-green (no .led.on). Tip via data-tip attr, never innerHTML. */
#secure { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; margin-top: 2px; }
#secure.secure-ok,
#secure.secure-bad {
  display: inline-flex; align-items: center; gap: 0; margin: 0 0 0 .35em; padding: 0;
  font-size: 0; line-height: 0; vertical-align: middle; position: relative;
}
#secure.secure-ok #secure-text[hidden],
#secure.secure-bad #secure-text[hidden] { display: none !important; }
.led {
  width: 18px; height: 18px; border-radius: 50%; flex: none;
  display: inline-grid; place-items: center;
  background: #8b97a6; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .18);
}
.led.on { background: #3ddc84; box-shadow: 0 0 8px #3ddc84; }
.led svg { width: 11px; height: 11px; fill: #1c2430; }
#secure .led { background: #ff4d4d; box-shadow: 0 0 8px #ff4d4d; }
#secure .led.on { background: #3ddc84; box-shadow: 0 0 8px #3ddc84; }
#secure.secure-ok .led svg { fill: #083018; }
#secure.secure-bad .led svg { fill: #2a0808; }
/* Lock tip (encrypted / not-encrypted): fixed string via data-tip (attr), never innerHTML. Hover, focus-visible, .tip-on. */
#secure-led[data-tip] { position: relative; outline: none; cursor: default; }
#secure-led[data-tip]::after {
  content: attr(data-tip); position: absolute; left: 50%; top: calc(100% + 8px); z-index: 30;
  transform: translateX(-50%) translateY(-4px); white-space: nowrap; padding: 7px 13px; border-radius: 14px;
  font-size: 13px; font-style: italic; font-weight: 400; line-height: 1.3;
  color: var(--text); background: color-mix(in srgb, var(--card) 70%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.12); box-shadow: 0 6px 20px rgba(0,0,0,.35); text-shadow: 0 1px 3px rgba(0,0,0,.4);
  opacity: 0; pointer-events: none; transition: opacity .25s ease, transform .25s ease;
}
#secure-led[data-tip]:hover::after,
#secure-led[data-tip]:focus-visible::after,
#secure-led[data-tip].tip-on::after { opacity: 1; transform: translateX(-50%) translateY(0); }
html[data-scheme="light"] #secure-led[data-tip]::after {
  background: color-mix(in srgb, var(--card) 80%, transparent); border-color: rgba(255,255,255,.6);
  box-shadow: 0 6px 18px rgba(0,0,0,.15); text-shadow: none;
}
@media (prefers-reduced-motion: reduce) {
  #secure-led[data-tip]::after { transition: none; transform: translateX(-50%); }
  #secure-led[data-tip]:hover::after,
  #secure-led[data-tip]:focus-visible::after,
  #secure-led[data-tip].tip-on::after { transform: translateX(-50%); }
}
.header-actions { margin-left: auto; position: relative; display: flex; align-items: center; }
.burger-btn {
  width: 48px; height: 44px; padding: 6px 8px; border-radius: 12px;
  background: transparent; border: 1px solid var(--line);
  display: inline-grid; place-items: center;
}
.burger-btn[aria-expanded="true"] { border-color: var(--accent); }
/* bare-hamburger (Luke): the header burger icon itself is the button. No ring, border, outline halo or boxed
   background; the 48x44 hit area stays but is invisible. Feedback is a slight opacity change only. */
#menu-open.burger-btn {
  min-width: 44px; min-height: 44px; padding: 0; border-radius: 0;
  background: transparent !important; border: 0 !important; box-shadow: none !important; filter: none !important;
  outline: none; -webkit-tap-highlight-color: transparent; transition: opacity .12s ease;
}
#menu-open.burger-btn .burger { filter: none !important; }
#menu-open.burger-btn:hover, #menu-open.burger-btn[aria-expanded="true"] { opacity: .8; }
#menu-open.burger-btn:active { opacity: .6; }
#menu-open.burger-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
.burger { width: 28px; height: 22px; display: flex; flex-direction: column; justify-content: center; gap: 1px; }
.bun-top {
  position: relative; height: 8px; background: #f0b429;
  border-radius: 12px 12px 3px 3px; box-shadow: inset 0 -2px 0 #d89210;
}
.bun-top::before, .bun-top::after {
  content: ""; position: absolute; top: 2px; width: 3px; height: 3px;
  border-radius: 50%; background: #fff4cc;
}
.bun-top::before { left: 6px; }
.bun-top::after { right: 6px; }
.lettuce {
  height: 4px; background: #57b84a;
  clip-path: polygon(0 55%, 10% 0, 18% 80%, 30% 10%, 42% 90%, 54% 5%, 66% 85%, 78% 15%, 90% 80%, 100% 20%, 100% 100%, 0 100%);
}
.patty { height: 5px; background: #7a4324; border-radius: 3px; }
.bun-bottom { height: 6px; background: #e39b16; border-radius: 2px 2px 8px 8px; }
#app-menu[hidden], #theme-choices[hidden] { display: none !important; }
#app-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 7;
  /* 26.10.2 fix: a fixed width again. The menu used to only have a minimum width, so it grew to fit its widest
     content laid out on one line; the Delete animations picker (ten buttons in a wrapping row) asked for ~950px, which made
     the menu about 985px wide on desktop (420px, the old minimum, was still a third of a laptop screen). Now it is a fixed
     360px, or the screen width minus a small margin on phones; long rows wrap inside it and the menu scrolls. */
  width: min(360px, calc(100vw - 20px)); min-width: 0; max-width: calc(100vw - 20px); max-height: min(78dvh, 640px);
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); padding: 6px; display: flex; flex-direction: column;
  overflow: auto;
}
#app-menu button {
  text-align: left; background: transparent; border: 0; border-radius: 10px; padding: 10px 12px;
}
#app-menu button:hover, #app-menu button[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
#app-menu .menu-label { color: var(--muted); font-size: 13px; padding: 10px 12px 4px; }
#app-menu .choice-row { padding: 2px 8px 8px; }
#app-menu .bubble-btn {
  text-align: center; padding: 8px 10px;
  border: 1px solid color-mix(in srgb, var(--text) 18%, var(--line));
  background: linear-gradient(180deg, color-mix(in srgb, white 28%, var(--card)), var(--card) 58%, color-mix(in srgb, black 8%, var(--card)));
  box-shadow: 0 3px 0 color-mix(in srgb, black 28%, var(--line)), inset 0 1px 0 color-mix(in srgb, white 55%, transparent);
}
#app-menu .bubble-btn:hover {
  background: linear-gradient(180deg, color-mix(in srgb, white 28%, var(--card)), var(--card) 58%, color-mix(in srgb, black 8%, var(--card)));
}
#app-menu .bubble-btn[aria-pressed="true"],
#app-menu .bubble-btn[aria-pressed="true"]:hover {
  background: linear-gradient(180deg, color-mix(in srgb, black 10%, var(--card)), color-mix(in srgb, black 4%, var(--card)));
  box-shadow: inset 0 3px 6px color-mix(in srgb, black 35%, transparent);
  transform: translateY(2px);
}
#app-menu button.text-link, #app-menu button.text-link:hover {
  padding: 0; background: transparent; box-shadow: none; border: 0; text-align: left;
}
#app-menu button.solid, #app-menu button.solid:hover {
  background: var(--accent); color: var(--on-accent); text-align: center; padding: 8px 12px;
}
#app-menu button.ghost {
  border: 1px solid var(--line); text-align: center; padding: 8px 12px;
}
#menu-profile-picture { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 0 12px 8px; }
#menu-photo {
  width: 72px; height: 72px; border-radius: 16px; object-fit: cover; background: #f5c518; display: block;
}
#bg-note { margin: 0 12px 8px; }
#menu-notify { display: flex; flex-direction: column; gap: 6px; padding: 6px 6px 2px; }
#menu-notify span { color: var(--muted); font-size: 13px; padding: 4px 6px 0; }
#notify-mute {
  width: 100%; font: inherit; color: var(--text); background: var(--bg);
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px;
}
#notify-enable[hidden] { display: none !important; }
#notify-hint { color: var(--muted); font-size: 12px; line-height: 1.35; margin: 0; padding: 0 8px 6px; }
#notify-hint[hidden] { display: none !important; }
/* Align with brand-col text (version / #who); amber matches Notifications menu "Blocked" (.notify-state.off → --owner-accent).
   Font matches header .ver (strong is 18px, .ver is .62em of that). */
#notify-setup {
  margin: 2px 0 0; max-width: 28rem; padding: 0; text-align: left; color: var(--owner-accent);
  font-size: calc(18px * 0.62); font-weight: 500; letter-spacing: .02em; line-height: normal; /* match header .ver */
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 .55em;
}
#notify-setup[hidden] { display: none !important; }
#notify-setup-text { min-width: 0; }
#notify-setup-dismiss {
  flex: none; border: 0; background: transparent; padding: 0; margin: 0;
  font: inherit; color: inherit; text-decoration: underline; cursor: pointer; opacity: .85;
}
#notify-setup-dismiss:hover { opacity: 1; }
#notify-setup-dismiss:focus { outline: none; }
#notify-setup-dismiss:focus-visible { opacity: 1; outline: 2px solid var(--owner-accent); outline-offset: 2px; }
#menu-update[hidden], html.bc-has-updater #menu-a2hs, #desktop-autostart-row[hidden], #desktop-close-row[hidden] { display: none !important; }   /* 26.10.10b: desktop-app-only rows (.radio-row display beat [hidden]) */
#theme-choices { display: flex; flex-direction: column; padding-left: 8px; max-height: min(42dvh, 320px); overflow: auto; }
#theme-choices button { display: flex; align-items: center; gap: 10px; }
.swatches {
  width: 54px; height: 16px; border-radius: 8px; overflow: hidden; flex: none;
  display: inline-flex; border: 1px solid var(--line);
}
.swatches i { flex: 1; display: block; height: 100%; }
html[data-scheme="dark"] [data-palette="huzz"] .swatches i:nth-child(1) { background: #10141a; }
html[data-scheme="dark"] [data-palette="huzz"] .swatches i:nth-child(2) { background: #3c92ea; }
html[data-scheme="dark"] [data-palette="huzz"] .swatches i:nth-child(3) { background: #9ec0ff; }
html[data-scheme="light"] [data-palette="huzz"] .swatches i:nth-child(1) { background: #f3f6fb; }
html[data-scheme="light"] [data-palette="huzz"] .swatches i:nth-child(2) { background: #3c92ea; }
html[data-scheme="light"] [data-palette="huzz"] .swatches i:nth-child(3) { background: #1d4e89; }
html[data-scheme="dark"] [data-palette="glacier"] .swatches i:nth-child(1) { background: #0e1621; }
html[data-scheme="dark"] [data-palette="glacier"] .swatches i:nth-child(2) { background: #2b5278; }
html[data-scheme="dark"] [data-palette="glacier"] .swatches i:nth-child(3) { background: #6ab2f2; }
html[data-scheme="light"] [data-palette="glacier"] .swatches i:nth-child(1) { background: #d7e4ee; }
html[data-scheme="light"] [data-palette="glacier"] .swatches i:nth-child(2) { background: #effdde; }
html[data-scheme="light"] [data-palette="glacier"] .swatches i:nth-child(3) { background: #3390ec; }
html[data-scheme="dark"] [data-palette="nebula"] .swatches i:nth-child(1) { background: #313338; }
html[data-scheme="dark"] [data-palette="nebula"] .swatches i:nth-child(2) { background: #232428; }
html[data-scheme="dark"] [data-palette="nebula"] .swatches i:nth-child(3) { background: #5865f2; }
html[data-scheme="light"] [data-palette="nebula"] .swatches i:nth-child(1) { background: #ffffff; }
html[data-scheme="light"] [data-palette="nebula"] .swatches i:nth-child(2) { background: #e9eaee; }
html[data-scheme="light"] [data-palette="nebula"] .swatches i:nth-child(3) { background: #5865f2; }
html[data-scheme="dark"] [data-palette="lagoon"] .swatches i:nth-child(1) { background: #0b141a; }
html[data-scheme="dark"] [data-palette="lagoon"] .swatches i:nth-child(2) { background: #005c4b; }
html[data-scheme="dark"] [data-palette="lagoon"] .swatches i:nth-child(3) { background: #00a884; }
html[data-scheme="light"] [data-palette="lagoon"] .swatches i:nth-child(1) { background: #efeae2; }
html[data-scheme="light"] [data-palette="lagoon"] .swatches i:nth-child(2) { background: #d9fdd3; }
html[data-scheme="light"] [data-palette="lagoon"] .swatches i:nth-child(3) { background: #008069; }
html[data-scheme="dark"] [data-palette="bubble"] .swatches i:nth-child(1) { background: #000000; }
html[data-scheme="dark"] [data-palette="bubble"] .swatches i:nth-child(2) { background: #262628; }
html[data-scheme="dark"] [data-palette="bubble"] .swatches i:nth-child(3) { background: #0a84ff; }
html[data-scheme="light"] [data-palette="bubble"] .swatches i:nth-child(1) { background: #ffffff; }
html[data-scheme="light"] [data-palette="bubble"] .swatches i:nth-child(2) { background: #e9e9eb; }
html[data-scheme="light"] [data-palette="bubble"] .swatches i:nth-child(3) { background: #007aff; }
html[data-scheme="dark"] [data-palette="aubergine"] .swatches i:nth-child(1) { background: #1a1d21; }
html[data-scheme="dark"] [data-palette="aubergine"] .swatches i:nth-child(2) { background: #1d9bd1; }
html[data-scheme="dark"] [data-palette="aubergine"] .swatches i:nth-child(3) { background: #36c5f0; }
html[data-scheme="light"] [data-palette="aubergine"] .swatches i:nth-child(1) { background: #ffffff; }
html[data-scheme="light"] [data-palette="aubergine"] .swatches i:nth-child(2) { background: #007a5a; }
html[data-scheme="light"] [data-palette="aubergine"] .swatches i:nth-child(3) { background: #4a154b; }
html[data-scheme="dark"] [data-palette="vinyl"] .swatches i:nth-child(1) { background: #121212; }
html[data-scheme="dark"] [data-palette="vinyl"] .swatches i:nth-child(2) { background: #1db954; }
html[data-scheme="dark"] [data-palette="vinyl"] .swatches i:nth-child(3) { background: #1ed760; }
html[data-scheme="light"] [data-palette="vinyl"] .swatches i:nth-child(1) { background: #ffffff; }
html[data-scheme="light"] [data-palette="vinyl"] .swatches i:nth-child(2) { background: #1db954; }
html[data-scheme="light"] [data-palette="vinyl"] .swatches i:nth-child(3) { background: #169c46; }
html[data-scheme="dark"] [data-palette="graphite"] .swatches i:nth-child(1) { background: #0d1117; }
html[data-scheme="dark"] [data-palette="graphite"] .swatches i:nth-child(2) { background: #1f6feb; }
html[data-scheme="dark"] [data-palette="graphite"] .swatches i:nth-child(3) { background: #58a6ff; }
html[data-scheme="light"] [data-palette="graphite"] .swatches i:nth-child(1) { background: #ffffff; }
html[data-scheme="light"] [data-palette="graphite"] .swatches i:nth-child(2) { background: #0969da; }
html[data-scheme="light"] [data-palette="graphite"] .swatches i:nth-child(3) { background: #0550ae; }
#menu-mode {
  display: flex; align-items: center; gap: 8px;
  margin-top: 4px; padding: 6px 2px 2px;
  border-top: 1px solid var(--line);
  position: sticky; bottom: 0; background: var(--card);
}
#app-menu #mode-system { flex: 1; }
#app-menu #mode-toggle {
  width: 56px; height: 30px; flex: none; margin-left: auto;
  padding: 3px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--bg); display: inline-flex; align-items: center;
}
#app-menu #mode-toggle:hover { background: var(--bg); }
#mode-toggle .mode-knob {
  width: 24px; height: 24px; border-radius: 50%; background: var(--text);
  display: block; transform: translateX(0); transition: transform .16s ease;
}
html[data-scheme="dark"] #app-menu #mode-toggle { background: var(--accent); border-color: transparent; }
html[data-scheme="dark"] #app-menu #mode-toggle:hover { background: var(--accent); }
html[data-scheme="dark"] #mode-toggle .mode-knob { transform: translateX(26px); background: var(--on-accent); }
select, input, textarea {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 10px;
}
button.solid, button.ghost {
  border-radius: 10px;
  padding: 8px 12px;
}
button.solid { background: var(--accent); color: var(--on-accent); border: 0; }
button.ghost { background: transparent; border: 1px solid var(--line); }
/* crypto-hardening: a disabled action must look disabled (e.g. "Save key backup" until "I saved it" is ticked). */
button.solid:disabled, button.ghost:disabled, .bc-trust-dialog button:disabled { opacity: .45; cursor: not-allowed; filter: saturate(.4); }
button.danger { background: var(--danger); color: white; border: 0; border-radius: 10px; padding: 8px 12px; }
button.icon { width: 40px; height: 40px; padding: 8px; display: inline-flex; align-items: center; justify-content: center; }
button.icon svg { display: block; }
#remove-dialog .check { display: flex; gap: 10px; align-items: flex-start; margin-top: 12px; color: var(--text); line-height: 1.45; }
#remove-dialog .check input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; }
#nav-open { display: none; }
#shell { flex: 1; min-height: 0; display: flex; }
#sidebar {
  width: min(320px, 100%);
  border-right: 1px solid var(--line);
  background: var(--card);
  overflow: hidden;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#people {
  flex: 1;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.row, .person {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 12px;
  padding: 10px;
}
.person, #thread-title { display: flex; align-items: center; gap: 8px; }
#lobby-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  column-gap: 8px;
}
#lobby-row .sub { grid-column: 2; }
#lobby-led { grid-row: 1 / span 2; }
#lobby-row .unread { grid-column: 3; grid-row: 1 / span 2; }
/* 3001 hotfix: unread list badge ~1.5×+ and higher contrast (phone + desktop). */
.unread {
  margin-left: auto; min-width: 28px; height: 28px; padding: 0 8px;
  border-radius: 14px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 14px; font-weight: 700; line-height: 28px; text-align: center; flex: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--on-accent) 55%, transparent),
              0 2px 8px color-mix(in srgb, var(--accent) 55%, transparent);
}
html[data-scheme="light"] .unread {
  box-shadow: 0 0 0 2px #fff, 0 2px 8px color-mix(in srgb, var(--accent) 45%, transparent);
}
/* In-chat "New messages" divider — same contrast bump as the list badge. */
.log-unread-sep {
  align-self: stretch; display: flex; align-items: center; gap: 10px;
  margin: 6px 0; padding: 0 4px; color: var(--accent); font-size: 13px; font-weight: 700;
  letter-spacing: .02em; text-transform: uppercase; user-select: none;
}
.log-unread-sep::before, .log-unread-sep::after {
  content: ""; flex: 1; height: 3px; border-radius: 2px;
  background: var(--accent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--on-accent) 40%, transparent);
}
.row.active, .person.active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
/* .row/.person are excluded from the global button sink; keep a light press wash so taps don't feel dead after 6110fe. */
.row:active, .person:active { background: color-mix(in srgb, var(--text) 8%, transparent); }
.row.active:active, .person.active:active { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.sub { color: var(--muted); font-size: 13px; display: block; }
.dot { width: 8px; height: 8px; border-radius: 99px; display: inline-block; background: #6b7785; margin-right: 6px; }
.dot.on { background: #3ddc84; }
.dot.idle { background: #faa61a; }
.dot.dnd { background: #f04747; }
#me-dock { flex: none; margin-top: auto; border-top: 1px solid var(--line); padding-top: 8px; position: relative; }
#me-bar {
  display: flex; align-items: center; gap: 4px;
  padding: 6px; border-radius: 14px;
  background: color-mix(in srgb, var(--text) 6%, transparent);
}
#me-open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  background: transparent; border: 0; color: var(--text); text-align: left; padding: 2px;
  cursor: pointer; border-radius: 999px; font: inherit;
}
#me-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#me-avatar-wrap { position: relative; width: 40px; height: 40px; flex: none; }
#me-photo {
  width: 40px; height: 40px; border-radius: 50%; object-fit: cover; background: #f5c518; display: block;
}
#me-status-dot {
  position: absolute; right: -1px; bottom: -1px; width: 14px; height: 14px; border-radius: 50%;
  background: #3ddc84; box-shadow: 0 0 0 3px var(--card); border: 0;
}
#me-status-dot[data-status="idle"] { background: #faa61a; }
#me-status-dot[data-status="dnd"] {
  background: #f04747;
  background-image: linear-gradient(transparent 40%, #fff 40%, #fff 60%, transparent 60%);
}
#me-status-dot[data-status="invisible"] {
  background: var(--card);
  box-shadow: 0 0 0 2px #8b97a6, 0 0 0 3px var(--card);
}
#me-name-wrap { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
#me-name { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#me-status-label { font-size: 12px; color: var(--muted); line-height: 1.2; }
#me-gear {
  width: 32px; height: 32px; flex: none; border: 0; background: transparent;
  color: var(--muted); opacity: 0.62; border-radius: 8px; display: grid; place-items: center; padding: 0;
  cursor: pointer;
}
#me-gear:hover { opacity: 1; background: color-mix(in srgb, var(--text) 8%, transparent); }
/* Desktop status picker (approved mockup) */
#status-picker {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 8px); z-index: 40;
  background: var(--card); color: var(--text); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); padding: 8px;
}
#status-picker[hidden] { display: none !important; }
#status-picker .pick-head {
  padding: 6px 10px 8px; font-size: 12px; font-weight: 650; letter-spacing: .02em;
  text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); margin-bottom: 6px;
}
#status-picker button.opt {
  width: 100%; display: flex; align-items: center; gap: 12px; padding: 10px;
  border: 0; border-radius: 10px; background: transparent; color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
}
#status-picker button.opt:hover,
#status-picker button.opt:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
#status-picker button.opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
#status-picker button.opt[aria-checked="true"] {
  background: color-mix(in srgb, var(--accent) 16%, transparent); font-weight: 650;
}
#status-picker .opt-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--text) 12%, transparent);
}
#status-picker .opt-dot.online { background: #3ddc84; box-shadow: 0 0 0 2px color-mix(in srgb, #3ddc84 35%, transparent), 0 0 8px color-mix(in srgb, #3ddc84 45%, transparent); }
#status-picker .opt-dot.idle { background: #faa61a; }
#status-picker .opt-dot.dnd {
  background: #f04747;
  background-image: linear-gradient(transparent 40%, #fff 40%, #fff 60%, transparent 60%);
}
#status-picker .opt-dot.invisible {
  background: transparent; box-shadow: inset 0 0 0 2px #8b97a6;
}
#status-picker .opt-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
#status-picker .opt-text strong { font-size: 15px; font-weight: 650; }
#status-picker .opt-text span { font-size: 12px; color: var(--muted); }
#add-friend { display: flex; gap: 8px; flex: none; }
#add-friend input { flex: 1; min-width: 0; width: auto; }
#friend-note { flex: none; margin: 6px 0 0; }
#friend-note:empty { display: none; }
#profile-pop[hidden] { display: none !important; }
#profile-pop {
  position: fixed; z-index: 8; overflow: auto;
  background: var(--card); color: var(--text);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow); padding: 14px;
}
#profile-pop h3 { margin: 16px 0 6px; font-size: 16px; }
#profile-pop label { display: block; margin-top: 8px; }
#profile-pop input { width: 100%; }
#profile-pop #add-friend input { width: auto; }
.profile-rule { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }
.request { display: flex; justify-content: space-between; gap: 8px; align-items: center; }
main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
#thread-head {
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  gap: 4px;
  align-items: center;
}
#transcript { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
#chat-bg {
  /* Faded and a little gray so the picture sits behind the messages. */
  position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  filter: saturate(0.55) grayscale(0.22);
}
/* 0.21.04: the picture is a top-anchored layer of stable height (app.js sets --bg-h to the tallest the chat has
   been at this width), so the keyboard or the emoji panel only covers its bottom; it never rescales or moves. */
#chat-bg::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: var(--bg-h, 100%);
  background-image: var(--bg-img, none); background-size: cover; background-position: center;
}
#chat-bg::after {
  content: ""; position: absolute; inset: 0;
  background: color-mix(in srgb, var(--bg) 62%, transparent);
}
#chat-bg[hidden] { display: none !important; }
#log { position: relative; z-index: 1; flex: 1; min-height: 0; overflow-x: hidden; overflow-y: auto; overflow-anchor: none; padding: 14px; display: flex; flex-direction: column; gap: 8px; background: transparent; }
/* Chromium scroll-anchoring picks a descendant anchor below a growing mid row and
   bumps scrollTop (gate images_no_scroll_jump). Disable anchoring on all #log descendants. */
#log, #log * { overflow-anchor: none; }
/* Wide pre / tables scroll inside themselves. Long URLs already wrap
   (overflow-wrap: anywhere on .bubble, word-break: break-all on .msg-link).
   #log { overflow-x: hidden } is only a 1–2px / subpixel backstop; it must
   not clip this content. Jump-to-bottom, the new-message pill, and
   reaction / context menus are not #log children, so they stay unclipped. */
#log pre,
#log table {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
}
#log table {
  display: block;
}

#log-jump {
  position: absolute; z-index: 5; left: 50%; bottom: 10px;
  --log-jump-press: 1;
  transform: translateX(-50%) scale(var(--log-jump-press));
  transform-origin: center center;
  margin: 0; padding: 7px 14px; border: 0; border-radius: 999px; cursor: pointer;
  max-width: calc(100% - 24px);
  background: var(--accent); color: var(--on-accent, #fff);
  font: 600 13px/1.2 system-ui, sans-serif;
  box-shadow: 0 6px 16px rgba(0,0,0,.28);
}
#log-jump[hidden] { display: none !important; }
.day { align-self: center; background: var(--pill); color: var(--muted); border-radius: 999px; padding: 2px 10px; font-size: 13px; }
.msg { display: flex; flex-direction: column; min-width: 0; max-width: min(78%, 640px); cursor: pointer; }
.msg:active:not(.removed) { filter: brightness(.93); }
.msg.removed { cursor: default; }
.msg.mine { align-self: flex-end; align-items: flex-end; }
.msg.other { align-self: flex-start; align-items: flex-start; }
.bubble { position: relative; border-radius: 16px; padding: 8px 10px 24px; white-space: pre-wrap; overflow-wrap: anywhere; min-width: 128px; max-width: 100%; }
.msg.mine .bubble { background: var(--mine); color: var(--mine-text); }
.msg.other .bubble { background: var(--other); color: var(--other-text); }
.msg.removed .bubble {
  min-width: 0; background: transparent; color: var(--muted);
  border: 1px dashed var(--line); font-style: italic; padding: 8px 12px;
}
.name { font-size: 13px; color: var(--accent); margin: 0 8px 2px; }
.time { position: absolute; right: 8px; bottom: 5px; max-width: calc(100% - 16px); font-size: 11px; opacity: .58; white-space: normal; overflow-wrap: anywhere; text-align: right; line-height: 1.25; }
.time.unverified-mark { opacity: .85; }
/* Long unverified labels wrap inside the bubble instead of clipping at the edge. */
.bubble:has(> .time.unverified-mark),
.caption-bubble:has(> .time.unverified-mark),
.media-bubble > .caption-bubble:has(> .time.unverified-mark) { padding-bottom: 36px; }
#log .msg .bubble.jumbo:has(> .time.unverified-mark),
#log .msg .bubble.sticker-bubble:has(> .time.unverified-mark) { padding-bottom: 36px !important; }
/* Key changes: the blocked message says so and offers a re-confirm (app.js rejectedNotice / reconfirmDevice). */
.bubble.key-changed { font-style: italic; }
.bubble.key-changed .reconfirm-btn { margin-top: 6px; padding: 4px 12px; font-style: normal; }
.edited { display: block; margin-top: 4px; font-size: 11px; opacity: .75; }
.media { display: block; max-width: 100%; max-height: 240px; border-radius: 12px; object-fit: cover; }
/* 541491: keep max-height from .media; HTML width/height attrs reserve aspect before decode.
   Do not set aspect-ratio from attr() here — it can defeat max-height:240px (Firefox after-run ch≈392). */
.media[width][height] { height: auto; max-width: 100%; max-height: 240px; aspect-ratio: var(--media-ar, auto); }
/* fix/gif-natural-ar: GIFs only — ignore reserved --media-ar / width-height box; natural AR. Photos/videos unchanged. */
img.media.media-gif,
img.media.media-gif[width][height] {
  width: auto;
  height: auto;
  aspect-ratio: auto;
  object-fit: contain;
}
.media-bubble .media-wrap > img.media.media-gif { min-height: 0; }
.media-ph {
  display: block; box-sizing: border-box; width: min(100%, 360px); max-width: 100%; max-height: 240px;
  margin: 0; padding: 0; border: 0; border-radius: 14px; cursor: pointer;
  background: color-mix(in srgb, var(--card, #222) 78%, #666 22%);
  color: var(--muted, #aaa); font: 600 13px/1.2 system-ui, sans-serif;
  aspect-ratio: var(--media-ar, 4 / 3);
}
html[data-scheme="light"] .media-ph { background: color-mix(in srgb, var(--card, #eee) 70%, #bbb 30%); color: var(--muted, #666); }
/* Reserved photo shell uses the same media-bubble chrome as a decoded img. */
.media-bubble .media-wrap > .media-ph {
  display: block; width: min(100%, 360px); max-width: 100%; max-height: 240px;
  border-radius: 14px; box-shadow: 0 10px 18px -8px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.25);
}

.file-chip, .video-chip { display: inline-flex; gap: 8px; align-items: center; }
.shade {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: var(--shade); color: white; border-radius: 16px; font-weight: 600;
}
#composer {
  flex-shrink: 0;
  border-top: 1px solid var(--line);
  padding: 10px 12px calc(16px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#text { width: 100%; resize: none; min-height: 4.4em; max-height: 4.4em; }
.tools { display: flex; gap: 8px; align-items: center; }
.tools .spacer { flex: 1; }
#send { min-width: 46px; }
#attach-name, #send-note { color: var(--muted); }
#attach-name:empty, #send-note:empty { display: none; }
#emoji-pop[hidden], #gif-pop[hidden] { display: none !important; }
/* 0.21.01: the emoji and GIF lists live in the composer panel (#picker); see the end of this file. */
#emoji-pop button { border: 0; background: transparent; font-size: 26px; width: 100%; height: 44px; border-radius: 8px; padding: 0; line-height: 1; }
#emoji-pop button:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
#react-pop[hidden] { display: none !important; }
#react-pop {
  position: fixed; z-index: 6; left: 8px; top: 8px;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); padding: 6px; max-width: min(320px, calc(100vw - 16px));
}
#react-pop:not([hidden]) { display: block; }
#react-quick { display: flex; flex-wrap: wrap; gap: 2px; align-items: center; }
#react-quick button, #react-grid button {
  border: 0; background: transparent; font-size: 22px; width: 36px; height: 36px;
  border-radius: 8px; padding: 0;
}
#react-quick button:hover, #react-grid button:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
#react-quick button.react-more { font-size: 20px; font-weight: 700; color: var(--muted); }
#react-extra[hidden] { display: none !important; }
#react-extra:not([hidden]) { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; min-height: 0; }
#react-search { width: 100%; flex: none; }
#react-search-row { display: flex; align-items: center; gap: 0; width: 100%; }
#react-search-row #react-search { flex: 1; min-width: 0; width: auto; }
#react-search-back {
  flex: none; position: relative; width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  margin: 0; padding: 0; border: 0; border-radius: 10px; background: transparent; color: var(--muted); cursor: pointer;
}
#react-search-back[hidden] { display: none !important; }
#react-search-back::before {
  content: ""; position: absolute; left: 50%; top: 50%; width: 10px; height: 10px;
  border-left: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translate(-30%, -50%) rotate(45deg);
}
#react-search-back:hover, #react-search-back:focus-visible { color: var(--text); background: color-mix(in srgb, var(--accent) 14%, transparent); outline: none; }
/* Coarse only: the back control is for phone OSK/sheet dismiss; desktop keeps the chevron on #react-plus. */
@media (pointer: fine) {
  #react-search-back { display: none !important; }
}
#react-grid { display: flex; flex-wrap: wrap; gap: 2px; max-height: min(40dvh, 280px); overflow: auto; min-height: 0; flex: 1 1 auto; }
#react-note { margin: 4px 4px 0; }
#react-note:empty { display: none; }
.reactions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; max-width: 100%; }
.react-chip {
  border: 1px solid var(--line); background: var(--pill); color: var(--text);
  border-radius: 999px; padding: 1px 7px; font-size: 14px; line-height: 1.4;
}
.react-chip.mine { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, var(--pill)); }
#gif-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); grid-auto-rows: 108px; gap: 6px; }
#gif-grid button { padding: 0; border: 0; background: var(--bg); border-radius: 8px; overflow: hidden; }
#gif-grid img { width: 100%; height: 108px; object-fit: cover; display: block; }
dialog { border: 1px solid var(--line); border-radius: 16px; background: var(--card); color: var(--text); padding: 18px; width: min(440px, calc(100% - 24px)); }
dialog::backdrop { background: rgba(0, 0, 0, .45); }
dialog h2 { margin: 0 0 8px; font-size: 20px; }
#friend-dialog input { width: 100%; }
.profile-row { display: flex; align-items: flex-end; gap: 14px; }
.profile-main { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.profile-photo, .profile-scales img {
  object-fit: cover; border-radius: 16px; background: #f5c518; display: block;
}
.profile-photo { width: 112px; height: 112px; }
.profile-scales { display: flex; align-items: flex-end; gap: 8px; }
.profile-scales img:nth-child(1) { width: 72px; height: 72px; border-radius: 14px; }
.profile-scales img:nth-child(2) { width: 48px; height: 48px; border-radius: 12px; }
.profile-scales img:nth-child(3) { width: 32px; height: 32px; border-radius: 10px; }
button.text-link {
  margin: 0; padding: 0; border: 0; background: transparent; color: var(--accent);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer; font: inherit;
}
/* 0.23.0: text links on the menu and Profile panels ("Change profile picture") are mixed toward the text colour so they
   reach WCAG AA (4.5:1) in every theme; pure accent was 3.0:1 on Nebula dark and 4.0:1 on light. */
#profile-pop button.text-link, #app-menu button.text-link { color: color-mix(in srgb, var(--accent) 55%, var(--text)); }
#profile-actions[hidden], #menu-profile-actions[hidden], #react-delete[hidden], #react-edit[hidden],
#totp-off[hidden], #totp-on[hidden], #totp-setup[hidden] { display: none !important; }
#profile-note:empty { display: none; }
.choice-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.choice-row.end { justify-content: flex-end; }
.bubble-btn {
  color: var(--text); font: inherit; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--text) 18%, var(--line));
  border-radius: 14px;
  background: linear-gradient(180deg, color-mix(in srgb, white 28%, var(--card)), var(--card) 58%, color-mix(in srgb, black 8%, var(--card)));
  box-shadow: 0 3px 0 color-mix(in srgb, black 28%, var(--line)), inset 0 1px 0 color-mix(in srgb, white 55%, transparent);
}
.bubble-btn[aria-pressed="true"] {
  background: linear-gradient(180deg, color-mix(in srgb, black 10%, var(--card)), color-mix(in srgb, black 4%, var(--card)));
  box-shadow: inset 0 3px 6px color-mix(in srgb, black 35%, transparent);
  transform: translateY(2px);
}
.size-btn { width: 52px; height: 52px; padding: 8px; }
.size-btn svg { width: 100%; height: 100%; display: block; }
.size-btn[data-size="small"] svg { stroke: currentColor; stroke-width: 1; fill: none; stroke-linecap: round; }
.size-btn[data-size="medium"] svg { stroke: currentColor; stroke-width: 1.7; fill: none; stroke-linecap: round; }
.size-btn[data-size="large"] svg { stroke: currentColor; stroke-width: 2.6; fill: none; stroke-linecap: round; }
.palette-btn { display: inline-flex; align-items: center; gap: 8px; padding: 8px 10px; }
.bg-btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 8px; }
.bg-swatch {
  width: 28px; height: 28px; border-radius: 8px; display: block; flex: none;
  background-size: cover; background-position: center; border: 1px solid var(--line);
}
.fold { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 8px; }
.fold summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  cursor: pointer; font-weight: 650; list-style: none; color: var(--text);
}
.fold summary::-webkit-details-marker { display: none; }
.fold summary::after {
  content: ""; width: 8px; height: 8px; flex: none; margin-right: 4px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
}
.fold[open] summary::after { transform: rotate(225deg); margin-top: 6px; }
#react-edit, #react-delete {
  display: block; width: 100%; margin-top: 6px; text-align: left;
  background: transparent; border: 0; border-radius: 8px; padding: 8px;
}
#react-edit { color: var(--text); }
#react-delete { color: var(--danger); }
#edit-msg-text { width: 100%; min-height: 88px; }
#totp-secret, #backup-codes { font-family: ui-monospace, monospace; word-break: break-all; }
#totp-uri { word-break: break-all; }
#totp-note:empty, #export-note:empty, #edit-msg-note:empty { display: none; }
dialog p { color: var(--muted); }
.actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 12px; }
#passphrase { font-family: ui-monospace, monospace; font-size: 18px; letter-spacing: .04em; }
#lightbox { width: min(960px, calc(100% - 24px)); }
#lightbox img, #lightbox video { max-width: 100%; max-height: 70dvh; display: block; margin: 0 auto; background: #000; }
#prepare { display: grid; gap: 8px; justify-items: center; padding: 24px 8px; }
progress { width: min(360px, 100%); }
@media (max-width: 800px) {
  #nav-open { display: inline-flex; }
  #sidebar {
    position: fixed; z-index: 4; inset: 58px auto 0 0; width: min(86vw, 340px);
    transform: translateX(-105%); transition: transform .36s ease; box-shadow: var(--shadow);
  }
  #sidebar.open { transform: none; }
  .header-actions button.ghost { padding: 8px; }
}

/* Color theme buttons: left-aligned, uniform size (2026-10-10) */
#palette-choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  justify-content: start;
  justify-items: stretch;
}
#palette-choices .palette-btn {
  width: 100%;
  min-height: 40px;
  justify-content: flex-start;
  white-space: nowrap;
}

/* Profile picture moved to Profile settings (2026-10-10) */
#menu-profile-picture[hidden], #app-menu .menu-label[hidden] { display: none !important; }

/* ===== Glass UI (2026-10-10): faded forest backdrop, UI floats in focus ===== */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: bc-fade-out 450ms ease both; }
::view-transition-new(root) { animation: bc-fade-in 600ms ease both; }
@keyframes bc-fade-out { to { opacity: 0; transform: scale(0.98); filter: blur(4px); } }
@keyframes bc-fade-in { from { opacity: 0; transform: scale(1.02); filter: blur(4px); } }
.bc-leaving { animation: bc-fade-out 450ms ease forwards; }
.bc-app-enter { animation: bc-fade-in 600ms ease both; }
html { background: #0f1117; }
body::before {
  content: ""; position: fixed; inset: -40px; z-index: -2; pointer-events: none;
  background: url("/static/forest-bg.webp?v=26.11.1007-763b3d5b") center / cover no-repeat;
  filter: blur(6px) saturate(0.95) brightness(0.85); transform: scale(1.05);
}
body::after {
  /* 26.11 bg-scale-gap: slight bleed past the viewport so DPR / CSS zoom / Windows 125%
     never leave a 1px hairline of html background at the edges. */
  content: ""; position: fixed; inset: -3px; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse at 50% 40%, rgba(15,17,23,0.3), rgba(15,17,23,0.65) 75%), rgba(15,17,23,0.15);
}
html[data-scheme="light"] body::before { filter: blur(10px) saturate(0.7) brightness(1.1); opacity: .55; }
html[data-scheme="light"] body::after { background: radial-gradient(ellipse at 50% 40%, rgba(243,246,251,0.35), rgba(243,246,251,0.75) 75%); }
.ver { font-size: .62em; font-weight: 500; letter-spacing: .06em; color: var(--muted); opacity: .7; margin-left: .35em; vertical-align: .12em; }
body { background: transparent; }
header { z-index: 10; background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: 0 1px 0 color-mix(in srgb, var(--line) 70%, transparent); }
#sidebar, main, dialog, #profile-pop, #app-menu {
  background: color-mix(in srgb, var(--card) 62%, transparent);
  backdrop-filter: blur(8px) saturate(1.15); -webkit-backdrop-filter: blur(8px) saturate(1.15);
  box-shadow: 0 8px 30px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.06);
}
#sidebar { border-right-color: rgba(255,255,255,.08); }
dialog { border-color: rgba(255,255,255,.1); background: color-mix(in srgb, var(--card) 85%, transparent); }
select, input, textarea { background-color: color-mix(in srgb, var(--bg) 70%, transparent); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  #sidebar, main, dialog, #profile-pop, #app-menu { background: color-mix(in srgb, var(--card) 94%, transparent); }
}
@media (prefers-reduced-transparency: reduce) {
  body::before, body::after { display: none; }
  body { background: var(--bg); }
  #sidebar, main, dialog, #profile-pop, #app-menu { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; }
  select, input, textarea { background-color: var(--bg); }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root), .bc-leaving, .bc-app-enter { animation: none; }
}

/* Chat area glass: let the forest show through the main panel. */
main { background: color-mix(in srgb, var(--card) 36%, transparent); backdrop-filter: blur(5px) saturate(1.15); -webkit-backdrop-filter: blur(5px) saturate(1.15); }
#chat-bg { opacity: .5; }
#chat-bg::after { background: color-mix(in srgb, var(--bg) 35%, transparent); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { main { background: color-mix(in srgb, var(--card) 94%, transparent); } }
@media (prefers-reduced-transparency: reduce) { main { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; } #chat-bg { opacity: 1; } }

/* Gapped glass layout to match the mockup: each area is its own rounded box with forest showing in the gaps. */
#shell { gap: 12px; padding: 12px; }
#sidebar, main { border-radius: 16px; border: 1px solid rgba(255,255,255,.1); overflow: hidden; }
#sidebar { border-right: 1px solid rgba(255,255,255,.1); }
#profile-pop, #app-menu, dialog { border-radius: 14px; }
@media (max-width: 800px) {
  #shell { gap: 0; padding: 8px; }
  #sidebar { inset: 66px auto 8px 8px; }
}

/* Date stamps: shadowed pill, brighter tinted wording. */
.day { box-shadow: 0 2px 8px rgba(0,0,0,.45); color: color-mix(in srgb, var(--accent) 45%, #f2f5fa); text-shadow: 0 1px 3px rgba(0,0,0,.6); font-weight: 600; }
#who:empty { display: none; }

/* Light mode glass: keep the forest and frosted panels visible instead of washing out to white. */
html[data-scheme="light"] body::before { filter: blur(6px) saturate(1) brightness(1); opacity: 1; }
html[data-scheme="light"] body::after { background: radial-gradient(ellipse at 50% 40%, rgba(243,246,251,0.08), rgba(243,246,251,0.32) 75%); }
html[data-scheme="light"] #sidebar, html[data-scheme="light"] main, html[data-scheme="light"] #profile-pop, html[data-scheme="light"] #app-menu {
  background: color-mix(in srgb, var(--card) 34%, transparent);
  backdrop-filter: blur(10px) saturate(1.3); -webkit-backdrop-filter: blur(10px) saturate(1.3);
  border: 1px solid rgba(255,255,255,.55);
  box-shadow: 0 8px 28px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.6);
}
html[data-scheme="light"] dialog { background: color-mix(in srgb, var(--card) 60%, transparent); }
html[data-scheme="light"] select, html[data-scheme="light"] input, html[data-scheme="light"] textarea { background-color: rgba(255,255,255,.6); }
html[data-scheme="light"] .day { color: color-mix(in srgb, var(--accent) 55%, #1a2030); text-shadow: 0 1px 2px rgba(255,255,255,.7); box-shadow: 0 2px 8px rgba(0,0,0,.2); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  html[data-scheme="light"] #sidebar, html[data-scheme="light"] main { background: color-mix(in srgb, var(--card) 92%, transparent); }
}
@media (prefers-reduced-transparency: reduce) {
  html[data-scheme="light"] #sidebar, html[data-scheme="light"] main, html[data-scheme="light"] #profile-pop, html[data-scheme="light"] #app-menu { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Sidebar "Conversations" header, thin divider like the profile dock. */
#conv-head { flex: none; font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); padding: 0 4px 4px; margin-bottom: 6px; border-bottom: 1px solid var(--line); }

/* Sidebar collapse (desktop). */
#conv-head { display: flex; align-items: center; justify-content: space-between; }
#side-collapse, #side-expand { font: 600 20px/1 inherit; color: var(--muted); background: transparent; border: 0; padding: 0 6px 2px; cursor: pointer; border-radius: 8px; }
#side-collapse:hover, #side-expand:hover { color: var(--text); background: rgba(127,127,127,.15); }
#side-expand { display: none; align-self: flex-start; margin-top: 4px; padding: 10px 6px; background: color-mix(in srgb, var(--card) 50%, transparent); border: 1px solid rgba(255,255,255,.1); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
html.side-collapsed #sidebar { display: none; }
html.side-collapsed #side-expand { display: block; }
@media (max-width: 800px) { #side-collapse, #side-expand { display: none !important; } html.side-collapsed #sidebar { display: flex; } }

/* Sidebar profile pictures with online glow and corner lock. */
.pfp { position: relative; flex: none; width: 36px; height: 36px; border-radius: 50%; display: inline-block; box-shadow: 0 0 0 2px #8b97a6, 0 0 8px rgba(139,151,166,.6); }
.pfp.on { box-shadow: 0 0 0 2px #3ddc84, 0 0 10px #3ddc84; }
.pfp.idle { box-shadow: 0 0 0 2px #faa61a, 0 0 10px #faa61a; }
.pfp.dnd { box-shadow: 0 0 0 2px #f04747, 0 0 10px #f04747; }
.pfp img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; background: #f5c518; }
.pfp-lock { position: absolute; right: -3px; bottom: -3px; width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center; background: #8b97a6; box-shadow: 0 0 0 2px var(--card); }
.pfp.on .pfp-lock { background: #3ddc84; }
.pfp-lock svg { width: 10px; height: 10px; fill: #1c2430; }

/* Collapsed sidebar: a narrow rail of pictures. */
@media (min-width: 801px) {
  html.side-collapsed #sidebar { display: flex; width: 64px; padding: 10px 6px; align-items: center; }
  html.side-collapsed #side-expand { display: none; }
  html.side-collapsed #conv-head { justify-content: center; padding: 0 0 4px; width: 100%; }
  html.side-collapsed #conv-head > span { display: none; }
  html.side-collapsed #side-collapse { transform: rotate(180deg); }
  html.side-collapsed #lobby-row { display: flex; justify-content: center; padding: 8px 0; }
  html.side-collapsed #lobby-row strong, html.side-collapsed #lobby-row .sub { display: none; }
  html.side-collapsed .person { justify-content: center; padding: 8px 0; font-size: 0; position: relative; }
  html.side-collapsed .person .unread {
    position: absolute; top: 0; right: 0; min-width: 22px; height: 22px; padding: 0 6px;
    border-radius: 11px; font-size: 12px; line-height: 22px;
  }
  html.side-collapsed #requests { display: none; }
  html.side-collapsed #me-name, html.side-collapsed #me-gear { display: none; }
  html.side-collapsed #me-bar { justify-content: center; }
}

/* Lobby row: no subtitle, bigger shadowed title. */
#lobby-sub { display: none; }
#lobby-row strong { grid-row: 1 / span 2; font-size: 1.2em; text-shadow: 0 1px 4px rgba(0,0,0,.55); }
html[data-scheme="light"] #lobby-row strong { text-shadow: 0 1px 3px rgba(0,0,0,.25); }

/* Message bubbles: subtle, slightly offset soft shadow. */
.msg:not(.removed) .bubble { box-shadow: 0 3px 10px rgba(0,0,0,.22); }
html[data-scheme="light"] .msg:not(.removed) .bubble { box-shadow: 0 3px 10px rgba(0,0,0,.12); }

/* Lobby group icon: stream, tent and fire from the forest scene. */
#lobby-led { position: relative; width: 36px; height: 36px; background: url("/static/lobby-icon.webp?v=26.11.1007-763b3d5b") center / cover no-repeat; box-shadow: 0 0 0 2px #8b97a6, 0 0 8px rgba(139,151,166,.6); }
#lobby-led.on { background: url("/static/lobby-icon.webp?v=26.11.1007-763b3d5b") center / cover no-repeat; box-shadow: 0 0 0 2px #3ddc84, 0 0 10px #3ddc84; }
#lobby-led svg { position: absolute; right: -3px; bottom: -3px; width: 16px; height: 16px; padding: 3px; border-radius: 50%; background: #8b97a6; box-shadow: 0 0 0 2px var(--card); box-sizing: border-box; }
#lobby-led.on svg { background: #3ddc84; }
#conv-head > span { color: color-mix(in srgb, var(--accent) 35%, var(--text) 65%); opacity: .85; }

/* Soft text shadow (Lobby style) on title, usernames, and menu items. */
header strong, .person, #me-name, .name, #thread-title, #app-menu button, #app-menu a, #profile-pop button, #conv-head > span { text-shadow: 0 1px 4px rgba(0,0,0,.55); }
html[data-scheme="light"] :is(header strong, .person, #me-name, .name, #thread-title, #app-menu button, #app-menu a, #profile-pop button, #conv-head > span) { text-shadow: 0 1px 3px rgba(0,0,0,.25); }

/* Footer: verse and memorial, subtle glass strip. */
#bc-footer { flex: none; margin: 0 12px 10px; padding: 6px 14px; text-align: center; border-radius: 14px; background: color-mix(in srgb, var(--card) 40%, transparent); border: 1px solid rgba(255,255,255,.08); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); color: var(--muted); font-size: 12px; line-height: 1.4; text-shadow: 0 1px 4px rgba(0,0,0,.55); }
#bc-footer p { margin: 0; }
#bc-footer .verse { font-style: italic; }
#bc-footer .ref { font-style: normal; opacity: .8; margin-left: .3em; }
#bc-footer .memorial { opacity: .85; font-size: 11px; }
#shell { padding-bottom: 8px; }
html[data-scheme="light"] #bc-footer { border-color: rgba(255,255,255,.55); text-shadow: 0 1px 3px rgba(255,255,255,.6); color: color-mix(in srgb, var(--text) 70%, transparent); }
@media (max-width: 800px) { #bc-footer { margin: 0 8px 6px; padding: 4px 10px; font-size: 11px; } #bc-footer .memorial { font-size: 10px; } }
@media (prefers-reduced-transparency: reduce) { #bc-footer { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; } }
html[data-scheme="light"] #bc-footer { color: color-mix(in srgb, var(--text) 48%, transparent); text-shadow: 0 1px 2px rgba(255,255,255,.45); }
#bc-footer { width: fit-content; max-width: calc(100% - 24px); align-self: center; margin-left: auto; margin-right: auto; padding: 5px 12px; box-sizing: border-box; }
html[data-scheme="light"] #bc-footer { text-shadow: 0 1px 3px rgba(0,0,0,.22); background: color-mix(in srgb, var(--card) 22%, transparent); }
html:not([data-scheme="light"]) #bc-footer { color: color-mix(in srgb, var(--muted) 80%, #000 20%); }
html[data-scheme="light"] #bc-footer { color: color-mix(in srgb, var(--text) 58%, transparent); }
.ver { vertical-align: baseline; }

/* Two-tone Twigum wordmark (option B). */
@font-face { font-family: "BC Outfit"; src: url("/static/outfit.woff?v=26.11.1007-763b3d5b") format("woff"); font-weight: 100 900; font-display: swap; }
.bc-logo { font-family: "BC Outfit", "Segoe UI", "Noto Sans", sans-serif; font-size: 1.3em; letter-spacing: -.005em; text-shadow: 0 1px 4px rgba(0,0,0,.55); }
.bc-logo b { font-weight: 700; }
.bc-logo i { font-style: normal; font-weight: 300; color: #7cc98c; }
html[data-scheme="light"] .bc-logo { text-shadow: 0 1px 3px rgba(0,0,0,.25); }
html[data-scheme="light"] .bc-logo i { color: #2e7d48; }
/* Approved wordmark (Oct 19 2026, as in the email mock-ups): bold "Branch", thin green "Chat", small TM, no space.
   Light theme: "Branch" in near-black #1b2a20 (mock-up colour) instead of the page text colour. */
html[data-scheme="light"] .bc-logo b { color: #1b2a20; }
.ver { vertical-align: baseline; }
header .brand { gap: 10px; } header .brand img { width: 40px; height: 40px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,.45), 0 0 0 1px rgba(255,255,255,.12); } html[data-scheme="light"] header .brand img { box-shadow: 0 2px 8px rgba(0,0,0,.18), 0 0 0 1px rgba(0,0,0,.06); }

/* Soft glass tooltip on the banner icon. */
.bc-icon { position: relative; display: inline-flex; flex: none; border-radius: 10px; outline: none; }
.bc-icon::after {
  content: attr(data-tip); position: absolute; left: 0; top: calc(100% + 10px); z-index: 30;
  white-space: nowrap; padding: 7px 13px; border-radius: 14px; font-size: 13px; font-style: italic; font-weight: 400;
  color: var(--text); background: color-mix(in srgb, var(--card) 70%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.12); box-shadow: 0 6px 20px rgba(0,0,0,.35); text-shadow: 0 1px 3px rgba(0,0,0,.4);
  opacity: 0; transform: translateY(-4px); pointer-events: none; transition: opacity .25s ease, transform .25s ease;
}
.bc-icon:hover::after, .bc-icon:focus-visible::after { opacity: 1; transform: none; }
html[data-scheme="light"] .bc-icon::after { background: color-mix(in srgb, var(--card) 80%, transparent); border-color: rgba(255,255,255,.6); box-shadow: 0 6px 18px rgba(0,0,0,.15); text-shadow: none; }
@media (prefers-reduced-motion: reduce) { .bc-icon::after { transition: none; transform: none; } }

/* Subtle raised buttons that sink when pressed (bubble feel). */
:where(button):not(.person, .row, .linkish, #side-collapse, #side-expand, .palette-btn, .bg-btn, .size-btn) {
  box-shadow: 0 2px 5px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,255,255,.10), inset 0 -1px 0 rgba(0,0,0,.18);
  transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
}
:where(button):not(.person, .row, .linkish, #side-collapse, #side-expand, .palette-btn, .bg-btn, .size-btn):active {
  transform: translateY(1px) scale(.97);
  box-shadow: inset 0 2px 5px rgba(0,0,0,.35), inset 0 -1px 0 rgba(255,255,255,.06);
  filter: brightness(.95);
}
html[data-scheme="light"] :where(button):not(.person, .row, .linkish, #side-collapse, #side-expand, .palette-btn, .bg-btn, .size-btn) {
  box-shadow: 0 2px 5px rgba(0,0,0,.12), inset 0 1px 0 rgba(255,255,255,.7), inset 0 -1px 0 rgba(0,0,0,.08);
}
html[data-scheme="light"] :where(button):not(.person, .row, .linkish, #side-collapse, #side-expand, .palette-btn, .bg-btn, .size-btn):active {
  box-shadow: inset 0 2px 5px rgba(0,0,0,.18);
}
@media (prefers-reduced-motion: reduce) { button { transition: none !important; } button:active { transform: none !important; } }

/* #log-jump is centered with translateX(-50%). The generic button :active
   rule above sets transform: translateY(1px) scale(.97), which replaces that
   translate and slides the pill to the right (left: 50% becomes the left
   edge). Keep the translate in every state and scale in place. A transparent
   ::after grows just enough on press that the hit box still covers the rest
   size after the scale. */
#log-jump:hover,
#log-jump:focus,
#log-jump:focus-visible {
  transform: translateX(-50%) scale(var(--log-jump-press, 1));
}
#log-jump:active {
  --log-jump-press: 0.96;
  transform: translateX(-50%) scale(var(--log-jump-press));
}
#log-jump::after {
  content: "";
  position: absolute;
  inset: calc((1 - var(--log-jump-press, 1)) / var(--log-jump-press, 1) * -50%);
}
@media (prefers-reduced-motion: reduce) {
  #log-jump:active {
    --log-jump-press: 1;
    transform: translateX(-50%) !important;
  }
}
.bc-icon.tip-on::after { opacity: 1; transform: none; }

/* Softer icon edges: feathered mask, shadow moved to the wrapper so it survives the mask. */
header .brand img {
  box-shadow: none; filter: blur(.25px);
  -webkit-mask: linear-gradient(to right, transparent, #000 3px, #000 calc(100% - 3px), transparent), linear-gradient(to bottom, transparent, #000 3px, #000 calc(100% - 3px), transparent);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
header .brand img.bc-wordmark {
  width: auto; height: 26px; border-radius: 0; object-fit: contain;
  background: transparent !important; box-shadow: none !important;
  filter: none; -webkit-mask: none !important; mask: none !important;
}
header .bc-icon { filter: drop-shadow(0 2px 5px rgba(0,0,0,.45)); }
html[data-scheme="light"] header .brand img { box-shadow: none; }
html[data-scheme="light"] header .bc-icon { filter: drop-shadow(0 2px 5px rgba(0,0,0,.18)); }

/* Softer profile dock: no hard button box, rounded glass pill. */
#me-open, #me-open:active { box-shadow: none !important; transform: none !important; filter: none !important; border-radius: 999px; }
#me-gear { border-radius: 50%; }
#me-bar { border-radius: 999px; padding: 6px 8px; background: color-mix(in srgb, var(--text) 5%, transparent); border: 1px solid rgba(255,255,255,.07); box-shadow: inset 0 1px 0 rgba(255,255,255,.05), 0 2px 10px rgba(0,0,0,.18); }
html[data-scheme="light"] #me-bar { background: rgba(255,255,255,.35); border-color: rgba(255,255,255,.6); box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 2px 8px rgba(0,0,0,.08); }
html[data-scheme="light"] #me-bar { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.3); box-shadow: inset 0 1px 0 rgba(255,255,255,.35), 0 2px 6px rgba(0,0,0,.05); }

/* Chat images and videos grow with the window, capped on very wide screens. */
.media { max-height: clamp(240px, 52vh, 560px); }
.msg:has(.media) { max-width: min(78%, clamp(640px, 55vw, 1000px)); }
@media (max-width: 800px) { .media { max-height: clamp(220px, 45vh, 380px); } }

/* Background previews (inline styles are blocked by the page security policy, so they live here). */
/* 26.10.3: picker thumbnails show the current approved paintings (the old flat .svg pictures are gone) */
#themes-panel .bg-btn[data-bg="dusk"] .bg-swatch { background-image: url("/static/bg/dusk-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="dusk"] .bg-swatch { background-image: url("/static/bg/dusk-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="ember"] .bg-swatch { background-image: url("/static/bg/ember-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="ember"] .bg-swatch { background-image: url("/static/bg/ember-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="linen"] .bg-swatch { background-image: url("/static/bg/linen-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="linen"] .bg-swatch { background-image: url("/static/bg/linen-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="meadow"] .bg-swatch { background-image: url("/static/bg/meadow-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="meadow"] .bg-swatch { background-image: url("/static/bg/meadow-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="mist"] .bg-swatch { background-image: url("/static/bg/mist-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="mist"] .bg-swatch { background-image: url("/static/bg/mist-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="night"] .bg-swatch { background-image: url("/static/bg/night-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="night"] .bg-swatch { background-image: url("/static/bg/night-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="pines"] .bg-swatch { background-image: url("/static/bg/pines-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="pines"] .bg-swatch { background-image: url("/static/bg/pines-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="tide"] .bg-swatch { background-image: url("/static/bg/tide-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="tide"] .bg-swatch { background-image: url("/static/bg/tide-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="valentine"] .bg-swatch { background-image: url("/static/bg/seasonal/valentine-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="valentine"] .bg-swatch { background-image: url("/static/bg/seasonal/valentine-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="easter"] .bg-swatch { background-image: url("/static/bg/seasonal/easter-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="easter"] .bg-swatch { background-image: url("/static/bg/seasonal/easter-dark-swatch.webp?v=26.11.1007-763b3d5b"); }
#themes-panel .bg-btn[data-bg="fourth-july"] .bg-swatch { background-image: url("/static/bg/seasonal/fourth-july-light-swatch.webp?v=26.11.1007-763b3d5b"); }
html[data-scheme="dark"] #themes-panel .bg-btn[data-bg="fourth-july"] .bg-swatch { background-image: url("/static/bg/seasonal/fourth-july-dark-swatch.webp?v=26.11.1007-763b3d5b"); }

/* Performance: pre-blurred backdrop (no live filter), own compositor layer, lighter live blurs. */
body::before { background-image: url("/static/forest-bg-dark.webp?v=26.11.1007-763b3d5b"); filter: none; transform: translateZ(0) scale(1.02); will-change: transform; }
html[data-scheme="light"] body::before { background-image: url("/static/forest-bg-light.webp?v=26.11.1007-763b3d5b"); filter: none; opacity: 1; }
body::after { transform: translateZ(0); }
#sidebar, #profile-pop, #app-menu { backdrop-filter: blur(6px) saturate(1.1); -webkit-backdrop-filter: blur(6px) saturate(1.1); }
html[data-scheme="light"] #sidebar, html[data-scheme="light"] main, html[data-scheme="light"] #profile-pop, html[data-scheme="light"] #app-menu { backdrop-filter: blur(6px) saturate(1.2); -webkit-backdrop-filter: blur(6px) saturate(1.2); }
#log { contain: content; will-change: scroll-position; }
#bc-footer { backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }

/* Custom uploaded chat background: solid chat area, picture shown cleanly. */
html[data-chatbg="upload"] main { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; }
html[data-chatbg="upload"] #chat-bg { opacity: 1; filter: none; }
html[data-chatbg="upload"] #chat-bg::after { display: none; }
html[data-chatbg="upload"] main { background: color-mix(in srgb, var(--card) 95%, transparent); }
html[data-chatbg="upload"] #chat-bg { opacity: .95; }

/* Transparency slider for the chat area. */
#transp-row { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
#transp-val { color: var(--muted); font-variant-numeric: tabular-nums; }
#transp { width: 100%; accent-color: var(--accent); }
html[data-transp] main { background: color-mix(in srgb, var(--card) calc(100% - var(--transp)), transparent) !important; }
/* Oct 2026: the chat background is site-wide now and always shown at full strength (see the end of this file); the
   slider only sets how see-through the chat pane is. */
@media (prefers-reduced-transparency: reduce) { html[data-transp] main { background: var(--card) !important; } }

/* Menu section labels: readable, soft outline, gentle shadow. */
#app-menu :is(.menu-label, #notify-label, #bg-note, #transp-row) {
  color: color-mix(in srgb, var(--text) 82%, transparent); font-weight: 600; opacity: 1;
  text-shadow: 0 0 1px rgba(0,0,0,.7), 0 0 2px rgba(0,0,0,.45), 0 1px 4px rgba(0,0,0,.4);
}
#app-menu #bg-note { font-weight: 500; }
html[data-scheme="light"] #app-menu :is(.menu-label, #notify-label, #bg-note, #transp-row) {
  color: color-mix(in srgb, var(--text) 80%, transparent);
  text-shadow: 0 0 1px rgba(255,255,255,.9), 0 0 2px rgba(255,255,255,.7), 0 1px 3px rgba(0,0,0,.15);
}

/* Notification hint: readable but secondary. */
#notify-hint { font-size: 12px; color: color-mix(in srgb, var(--text) 75%, transparent); opacity: 1; text-shadow: 0 1px 3px rgba(0,0,0,.4); }
html[data-scheme="light"] #notify-hint { color: color-mix(in srgb, var(--text) 72%, transparent); text-shadow: none; }
/* Light mode menu dropdown: more opaque. */
html[data-scheme="light"] #app-menu { background: color-mix(in srgb, var(--card) 78%, transparent) !important; }

/* Plain menu rows and the mode switch should not get the raised button box. */
#app-menu button:not(.bubble-btn, .solid, .ghost), #app-menu button:not(.bubble-btn, .solid, .ghost):active { box-shadow: none !important; filter: none !important; transform: none !important; }
#app-menu #mode-toggle { box-shadow: inset 0 1px 3px rgba(0,0,0,.25) !important; }

/* No stray scroll bars in menus and dialogs: only scroll when content truly overflows vertically. */
#app-menu, #profile-pop, dialog { overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
#app-menu *, #profile-pop *, dialog * { box-sizing: border-box; max-width: 100%; }
#app-menu .choice-row, #palette-choices, #bg-choices, #text-size-choices { padding-bottom: 3px; }

/* Circled X close button. */
dialog, #app-menu, #profile-pop { position: relative; }
dialog { position: fixed; }
.x-close {
  position: absolute; top: 10px; right: 10px; z-index: 2; width: 30px; height: 30px; padding: 0 !important;
  display: grid; place-items: center; border-radius: 50% !important; cursor: pointer;
  color: var(--text); background: color-mix(in srgb, var(--card) 55%, transparent) !important;
  border: 1px solid rgba(255,255,255,.18) !important; box-shadow: 0 1px 4px rgba(0,0,0,.25) !important;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); opacity: .85; transition: opacity .15s ease, transform .1s ease;
}
.x-close:hover { opacity: 1; }
.x-close:active { transform: scale(.92) !important; }
html[data-scheme="light"] .x-close { border-color: rgba(0,0,0,.12) !important; box-shadow: 0 1px 3px rgba(0,0,0,.1) !important; }
dialog > h2:first-of-type, dialog > :is(h2,h3,p):first-of-type { padding-right: 40px; }
#app-menu { padding-top: 44px; }
#profile-pop { padding-top: 40px; }

/* Restore pop-up positioning (the close-button change wrongly made these relative, which pushed the menu into the banner). */
#app-menu { position: absolute; }
#profile-pop { position: fixed; }

/* Keep pop-ups inside the visible area below the banner; long ones scroll inside. */
dialog[open] { margin: 84px auto 16px; max-height: calc(100dvh - 104px); overflow-y: auto; overscroll-behavior: contain; }
#profile-pop { max-height: calc(100vh - var(--header-h, 64px) - 96px); max-height: calc(100dvh - var(--header-h, 64px) - 96px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)); overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; transform: none; }

/* Retired Close buttons stay hidden even when button styles set display. */
dialog button[hidden], dialog .actions[hidden] { display: none !important; }

/* Send symbol scales with the button. */
#send { display: grid; place-items: center; line-height: 1; font-size: max(1.6em, 22px); font-weight: 600; padding-top: 0; padding-bottom: 0; }

/* Roomier send button. */
#send { min-width: 58px; min-height: 48px; padding-left: 16px; padding-right: 16px; align-self: stretch; }

/* Profile Settings title with the Conversations-style divider; the circled X sits on this row. */
#profile-pop { padding-top: 12px; }
#profile-head { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; min-height: 30px; display: flex; align-items: center; padding: 0 44px 6px 4px; margin-bottom: 12px; border-bottom: 1px solid var(--line); }
#profile-head > span { color: color-mix(in srgb, var(--accent) 35%, var(--text) 65%); opacity: .85; text-shadow: 0 1px 4px rgba(0,0,0,.55); }
html[data-scheme="light"] #profile-head > span { text-shadow: 0 1px 3px rgba(0,0,0,.15); }
#profile-pop > .x-close { top: 8px; right: 8px; }

/* Profile pop-up: invite label, size captions, scale alignment. */
.invite-label { display: block; font-size: 12px; font-weight: 600; letter-spacing: .04em; color: var(--muted); margin: 0 4px 6px; }
.profile-row { align-items: flex-start !important; }
.profile-scales { display: flex !important; align-items: flex-end !important; gap: 10px; height: 112px; padding-bottom: 0; align-self: flex-start; }
.scale-fig { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.scale-fig img { display: block; }
.scale-fig figcaption { font-size: 11px; line-height: 1; color: var(--muted); }

/* display name */
.dispname-form { display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 260px; margin-top: 6px; }
.dispname-form[hidden] { display: none !important; }
.dispname-form input { width: 100%; box-sizing: border-box; }
#dispname-note:empty { display: none; }

/* Previews removed; the big photo itself opens Change profile picture. */
.profile-scales { display: none !important; }
#profile-photo { cursor: pointer; transition: filter .15s ease, box-shadow .15s ease, transform .1s ease; }
#profile-photo:hover, #profile-photo:focus-visible { filter: brightness(1.08); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent), 0 4px 14px rgba(0,0,0,.3); outline: none; }
#profile-photo:active { transform: scale(.97); }

/* display name color */
.dispname-line { position: relative; display: flex; align-items: center; gap: 8px; }
.namecolor-swatch {
  width: 22px; height: 22px; min-width: 22px; padding: 0; border-radius: 7px; cursor: pointer;
  background: var(--namecolor, var(--text));
  border: 1px solid color-mix(in srgb, var(--text) 35%, transparent);
  box-shadow: 0 1px 4px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.35);
}
.namecolor-pop {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 60;
  display: grid; grid-template-columns: repeat(5, 30px); gap: 8px; padding: 10px;
  border-radius: 14px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--card) 72%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.2); backdrop-filter: blur(14px) saturate(1.2);
  box-shadow: 0 10px 28px rgba(0,0,0,.35);
}
.namecolor-pop[hidden] { display: none !important; }
.namecolor-pop button {
  width: 30px; height: 30px; padding: 0; border-radius: 8px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--text) 30%, transparent);
  box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.namecolor-pop button.on { outline: 2px solid var(--text); outline-offset: 2px; }
.namecolor-pop button.default {
  grid-column: span 5; width: auto; height: 30px; color: var(--text); font: inherit; font-size: .9em;
  background: color-mix(in srgb, var(--card) 60%, transparent);
}
.dname {
  text-shadow: -1px 0 0 rgba(0,0,0,.6), 1px 0 0 rgba(0,0,0,.6), 0 -1px 0 rgba(0,0,0,.6), 0 1px 0 rgba(0,0,0,.6), 0 1px 4px rgba(0,0,0,.45);
}
html[data-scheme="light"] .dname {
  text-shadow: -1px 0 0 rgba(0,0,0,.28), 1px 0 0 rgba(0,0,0,.28), 0 -1px 0 rgba(0,0,0,.28), 0 1px 0 rgba(0,0,0,.28), 0 1px 4px rgba(0,0,0,.2);
}

/* display name editor */
.dispname-line, .dispname-form, .namecolor-pop { display: none !important; }
.profile-namebox { display: flex; align-items: center; gap: 8px; min-width: 0; align-self: center; }
.profile-dname { font-size: 19px; font-weight: 600; overflow-wrap: anywhere; }
.dname-edit {
  width: 30px; height: 30px; min-width: 30px; padding: 0; border-radius: 50%; cursor: pointer;
  display: inline-grid; place-items: center; color: var(--text);
  border: 1px solid color-mix(in srgb, var(--text) 22%, transparent);
  background: color-mix(in srgb, var(--card) 55%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: 0 2px 6px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.3);
}
.dname-edit:active { transform: scale(.94); }
#dname-dialog { max-width: 340px; }
#dname-dialog input { width: 100%; box-sizing: border-box; }
.dname-palette { display: grid; grid-template-columns: repeat(7, 30px); gap: 8px; margin: 12px 0 4px; }
.dname-palette button {
  width: 30px; height: 30px; padding: 0; border-radius: 8px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--text) 30%, transparent); box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.dname-palette button.on { outline: 2px solid var(--text); outline-offset: 2px; }
.dname-palette button.default {
  grid-column: span 7; width: auto; color: var(--text); font: inherit; font-size: .9em;
  background: color-mix(in srgb, var(--card) 60%, transparent);
}
.dname-preview { font-size: 19px; font-weight: 600; min-height: 1.4em; overflow-wrap: anywhere; }

/* contact opt-ins */
.check-row { display: flex; align-items: center; gap: 8px; margin: 10px 0 4px; }
#dname-dialog input[type="checkbox"] { width: auto; }
.contact-meta { margin-left: 10px; font-size: .78em; font-weight: 400; color: var(--muted, color-mix(in srgb, var(--text) 62%, transparent)); overflow-wrap: anywhere; }

/* center palette */
.dname-palette { justify-content: center; width: fit-content; margin-inline: auto; }

/* Display name dialog layout. */
#dname-dialog > h2 { padding-bottom: 10px; margin-bottom: 14px; border-bottom: 1px solid var(--line); }
#dname-dialog .dname-label { display: inline-block; font-size: 12px; font-weight: 600; color: var(--muted); padding: 3px 10px; margin: 0 0 8px; border-radius: 999px; background: color-mix(in srgb, var(--card) 40%, transparent); border: 1px solid var(--line); }
#dname-dialog #dname-input { margin-top: 0; }
.dname-preview-bubble { margin: 12px 0; padding: 10px 14px; border-radius: 14px; background: color-mix(in srgb, var(--card) 55%, transparent); border: 1px solid rgba(255,255,255,.14); box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 2px 8px rgba(0,0,0,.18); }
html[data-scheme="light"] .dname-preview-bubble { border-color: rgba(0,0,0,.1); box-shadow: 0 2px 6px rgba(0,0,0,.08); }
.dname-preview-bubble > .sub { margin: 0 0 4px; font-size: 11px; }

/* snap delete */
.snap-gap { overflow: hidden; pointer-events: none; }
.snap-gap > .msg { margin-top: 0; margin-bottom: 0; }
canvas.snap-dust {
  position: fixed; z-index: 80; pointer-events: none;
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important; filter: none !important;
}
.snap-chip {
  position: fixed; left: 50%; bottom: 96px; transform: translateX(-50%); z-index: 90;
  padding: 8px 16px; border-radius: 999px; font: inherit; cursor: pointer; color: var(--text);
  border: 1px solid var(--line); background: color-mix(in srgb, var(--card) 70%, transparent);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); box-shadow: 0 6px 18px rgba(0,0,0,.3);
}

/* snap character */
.snap-figure {
  position: fixed; z-index: 85; width: 72px; height: 80px; pointer-events: none;
  background: transparent !important; border: 0 !important; box-shadow: none !important; outline: 0 !important;
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important; border-radius: 0 !important; padding: 0 !important;
  animation: snap-in .28s cubic-bezier(.3,1.5,.5,1) both;
}
.snap-figure svg { display: block; background: transparent !important; overflow: visible; }
.snap-figure .fig { filter: drop-shadow(0 2px 3px rgba(0,0,0,.35)); }
.snap-figure .hand { transform-box: view-box; transform-origin: 42px 36px; }
.snap-figure .spark { opacity: 0; transform-box: fill-box; transform-origin: center; }
.snap-figure.snap-go .hand { animation: snap-hand .35s ease-in-out; }
.snap-figure.snap-go .spark { animation: snap-spark .45s ease-out .18s; }
.snap-figure.snap-out { animation: snap-leave .45s ease-in forwards; }
@keyframes snap-in { from { opacity: 0; transform: translateY(10px) scale(.6); } to { opacity: 1; transform: none; } }
@keyframes snap-hand { 0% { transform: none; } 45% { transform: rotate(-14deg); } 70% { transform: rotate(8deg); } 100% { transform: none; } }
@keyframes snap-spark { 0% { opacity: 0; transform: scale(.3); } 40% { opacity: 1; transform: scale(1.6) rotate(25deg); } 100% { opacity: 0; transform: scale(.8) rotate(60deg); } }
@keyframes snap-leave { to { opacity: 0; transform: translateY(-6px) scale(.85); } }

/* snap fix: aligned gap, staged character */
.snap-gap { display: flex; flex-direction: column; }
.snap-stage {
  z-index: 85; overflow: hidden; pointer-events: none;
  background: transparent !important; border: 0 !important; box-shadow: none !important; outline: 0 !important;
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important; padding: 0 !important; border-radius: 0 !important;
}
.snap-stage .snap-figure {
  position: absolute !important; left: 6px !important; top: auto !important; bottom: 0; width: 140px; height: 101px;
  animation: snap-enter 1s cubic-bezier(.25,1.4,.5,1) both;
}
.snap-stage .snap-figure svg { overflow: hidden; }
.snap-stage .snap-figure .hand { transform-origin: 42px 36px; }
.snap-stage .snap-figure.snap-go .hand { animation: snap-raise 0.9s ease-in-out forwards; }
.snap-stage .snap-figure.snap-out { animation: snap-exit 1s ease-in forwards; }
@keyframes snap-enter { 0% { transform: translate(-90px, 110px); } 75% { transform: translate(5px, -5px); } 100% { transform: none; } }
@keyframes snap-raise { 0% { transform: none; } 40% { transform: rotate(-22deg); } 70% { transform: rotate(-8deg); } 100% { transform: rotate(-14deg); } }
@keyframes snap-exit { from { transform: none; opacity: 1; } to { transform: translate(-90px, 110px); opacity: .9; } }

/* polish: tone picker, toggles */
#menu-notify .menu-sub { display: block; margin-top: 8px; font-size: .9em; opacity: .85; }
.tone-row { display: flex; gap: 8px; align-items: center; }
.tone-row select { flex: 1; min-width: 0; }
#app-menu .check-row { display: flex; align-items: center; gap: 8px; margin: 8px 0 4px; cursor: pointer; }
#app-menu .check-row input { width: auto; margin: 0; }

/* welcome state when no chat is selected */
#welcome { display: none; }
html.no-chat #welcome {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  flex: 1; min-height: 0; padding: 24px; gap: 6px;
}
html.no-chat #thread-head, html.no-chat #log, html.no-chat #log-jump, html.no-chat #composer, html.no-chat #chat-bg { display: none !important; }
.welcome-title {
  margin: 0; font-size: clamp(1.4em, 4vw, 2em); font-weight: 700; color: var(--text);
  text-shadow: 0 1px 4px rgba(0,0,0,.35);
}
html[data-scheme="light"] .welcome-title { text-shadow: 0 1px 3px rgba(255,255,255,.6); }
.welcome-sub { margin: 0; color: var(--muted, color-mix(in srgb, var(--text) 62%, transparent)); }

/* Small trademark mark at the top right of the T in Chat. */
.bc-logo .tm { font-size: .32em; font-weight: 500; font-style: normal; letter-spacing: .02em; vertical-align: top; position: relative; top: .25em; margin-left: .08em; opacity: .7; color: inherit; line-height: 1; }

/* Footer trademark line: smallest and quietest. */
#bc-footer .legal { font-size: .78em; opacity: .7; margin-top: 2px; }

/* Version label links to patch notes. */
a.ver { text-decoration: none; color: inherit; } a.ver:hover { text-decoration: underline; }

#bc-footer .legal a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* About link in the hamburger menu, styled like the menu buttons. */
#app-menu a.menu-link { display: block; text-align: left; font: inherit; color: var(--text); text-decoration: none; border-radius: 10px; padding: 10px 12px; }
#app-menu a.menu-link:hover, #app-menu a.menu-link:focus-visible { background: color-mix(in srgb, var(--accent) 16%, transparent); }
#app-menu a.menu-support .menu-support-heart { color: var(--accent); margin-left: 4px; font-size: .9em; }

/* Media viewer: [hidden] must win over display rules, so the unused video, progress and download never show. */
#lightbox [hidden] { display: none !important; }
#lightbox[open] { overflow: hidden; scrollbar-width: none; }
#lightbox.is-image[open] {
  width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; inset: 0; padding: 0;
  border: 0; border-radius: 0; background: transparent !important; backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: none;
  display: flex; align-items: center; justify-content: center;
}
#lightbox.is-image::backdrop { background: rgba(0,0,0,.85); }
#lightbox.is-image #light-img { max-width: calc(100vw - 24px); max-height: calc(100dvh - 24px); width: auto; height: auto; object-fit: contain; background: transparent; margin: 0; border-radius: 8px; }
#lightbox.is-image .actions { display: none !important; }
#lightbox.is-image > .x-close { position: fixed; top: 12px; right: 12px; }

/* Volume sliders, styled like Transparency. */
.vol-row { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; color: var(--muted); font-size: 13px; padding: 0 12px; }
.vol-row output { font-variant-numeric: tabular-nums; }
.vol-range { width: calc(100% - 24px); margin: 4px 12px 6px; accent-color: var(--accent); }
/* Dark mode button: one clean rounded button, no strip behind it. */
#menu-mode { background: transparent !important; box-shadow: none !important; position: static; }
#menu-mode::before, #menu-mode::after, #app-menu #mode-system::before, #app-menu #mode-system::after { content: none !important; }
#app-menu #mode-system, #app-menu #mode-system:hover, #app-menu #mode-system[aria-pressed="true"] {
  flex: 1; text-align: center; border-radius: 999px !important; border: 1px solid var(--line) !important;
  background: color-mix(in srgb, var(--card) 50%, transparent) !important; box-shadow: none !important; outline-offset: 2px;
}
#app-menu #mode-system[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) 22%, transparent) !important; }

.invite-linkbox { display: flex; gap: 8px; margin: 8px 0; }
.invite-linkbox[hidden] { display: none; }
.invite-linkbox input { flex: 1; min-width: 0; width: auto; }
#menu-invite { white-space: normal; overflow-wrap: anywhere; text-align: left; max-width: 100%; }
#app-menu { overflow-x: hidden; }
.friend-help { margin: 4px 4px 0; font-size: 12px; color: var(--muted); }

/* links-yt */
.bubble a.msg-link { color: inherit; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 2px; font-weight: 600; word-break: break-all; }
.link-card { display: block; width: min(340px, 72vw); margin: 8px 0 2px; border-radius: 12px; overflow: hidden; background: rgba(0,0,0,.16); border-left: 3px solid currentColor; color: inherit; text-decoration: none; white-space: normal; }
html[data-scheme="light"] .link-card { background: rgba(0,0,0,.06); }
.yt-box { position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; min-height: 0; padding: 0; border: 0; border-radius: 0; background: #111; cursor: pointer; box-shadow: none; contain: layout paint size; overflow: hidden; }
.yt-box > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.yt-box img { width: 100%; height: 100%; object-fit: cover; display: block; background: #111; }
.yt-box.no-thumb img { visibility: hidden; }
.yt-play { position: absolute; left: 50%; top: 50%; width: 64px; height: 44px; transform: translate(-50%, -50%); border-radius: 12px; background: rgba(230,0,0,.92); box-shadow: 0 2px 8px rgba(0,0,0,.4); }
.yt-play::after { content: ""; position: absolute; left: 26px; top: 12px; border-style: solid; border-width: 10px 0 10px 17px; border-color: transparent transparent transparent #fff; }
.yt-frame { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; background: #000; }
.link-foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 6px 10px; }
.link-site { font-size: 12px; font-weight: 700; opacity: .8; }
.link-open { color: inherit; font-size: 13px; font-weight: 600; text-decoration: underline; }
.web-card img { display: block; width: 100%; max-height: 180px; object-fit: cover; }
.web-body { display: flex; flex-direction: column; gap: 2px; padding: 7px 10px 8px; }
.web-title { font-weight: 700; font-size: 14px; line-height: 1.3; }
.web-desc { font-size: 13px; line-height: 1.35; opacity: .85; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* Friend picker: in the popover's flow so it is never clipped */
#friend-pick-wrap { flex: 1; min-width: 0; display: flex; }
#friend-pick-wrap input { flex: 1; min-width: 0; }
#friend-pick { margin: 6px 0 0; padding: 4px 0; list-style: none; max-height: 200px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--card); border: 1px solid var(--line); border-radius: 10px; }
#friend-pick[hidden] { display: none !important; }
#friend-pick li { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 8px 12px; cursor: pointer; }
#friend-pick li:hover:not(.pick-off, .pick-empty), #friend-pick li:focus { background: var(--pill); outline: none; }
#friend-pick li.pick-off, #friend-pick li.pick-empty { cursor: default; color: var(--muted); }
#friend-pick .pick-tag { font-size: 12px; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--line); }
/* Owner Admin Tools */
#owner-tools[hidden] { display: none !important; }
.owner-fold { border-top-color: var(--owner-accent); }
.fold summary.owner-head { color: var(--owner-accent); }
.owner-fold summary::after { border-color: var(--owner-accent); }
.owner-fold[open] > summary { margin-bottom: 8px; }
#profile-pop .owner-head { color: var(--owner-accent); }
.owner-invite { display: flex; gap: 6px; margin-bottom: 8px; }
.owner-invite input { flex: 1; min-width: 0; width: auto; }
#owner-search { width: 100%; box-sizing: border-box; }
#owner-list { list-style: none; margin: 6px 0 0; padding: 0; max-height: 320px; overflow-y: auto; }
.owner-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.owner-row.is-disabled strong { opacity: .55; text-decoration: line-through; }
.owner-info { display: flex; flex-direction: column; min-width: 0; }
.owner-actions { display: flex; gap: 4px; flex-wrap: wrap; }
.owner-actions button { padding: 4px 8px; font-size: 13px; }

/* Menu open fade (2026-10-14) moved to motion.css in 0.23.3-beta.4: menus slide, pop-ups fade, both ways. */
@media (max-width: 800px) {
  #sidebar { opacity: 0; transition: transform .36s cubic-bezier(.2,.8,.2,1), opacity .3s ease-out; }
  #sidebar.open { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #sidebar { transition: none !important; }
}

/* Invite state tags in Admin Tools: text label plus color */
.inv-tag { display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px; font-size: 12px; font-weight: 600; vertical-align: middle; border: 1px solid; }
.inv-pending { color: #67e8f9; background: rgba(6,182,212,.16); border-color: rgba(103,232,249,.45); }
.inv-expired { color: #fca5a5; background: rgba(239,68,68,.16); border-color: rgba(252,165,165,.45); }
html[data-scheme="light"] .inv-pending { color: #0e6377; background: rgba(8,145,178,.12); border-color: rgba(14,99,119,.4); }
html[data-scheme="light"] .inv-expired { color: #a3261d; background: rgba(220,38,38,.10); border-color: rgba(163,38,29,.4); }
.owner-row.is-expired .owner-info { opacity: .72; }
.role-pill { display: inline-block; padding: 0 7px; border-radius: 999px; font-size: 12px; font-weight: 600; border: 1px solid; }
.role-admin { color: #bfdbfe; background: #1e3a8a; border-color: #3b5cc4; }
.role-member { color: #86efac; background: rgba(34,197,94,.16); border-color: rgba(134,239,172,.45); }
html[data-scheme="light"] .role-admin { color: #1e3a8a; background: #dbeafe; border-color: #93b4f5; }
html[data-scheme="light"] .role-member { color: #166534; background: #dcfce7; border-color: #86c99c; }
/* Role pills: 1px shade outline + drop shadow */
.role-pill { border-width: 1px; border-style: solid; box-shadow: 0 2px 5px rgba(0,0,0,.5), 0 1px 1px rgba(0,0,0,.3); }
.role-admin { border-color: #60a5fa; }
.role-member { border-color: #4ade80; }
html[data-scheme="light"] .role-pill { box-shadow: 0 2px 4px rgba(0,0,0,.35), 0 1px 1px rgba(0,0,0,.2); }
html[data-scheme="light"] .role-admin { border-color: #1e40af; }
html[data-scheme="light"] .role-member { border-color: #15803d; }

#owner-confirm .danger { background: var(--danger); color: #fff; border: 0; }
#owner-confirm .danger:disabled { opacity: .45; cursor: not-allowed; }
#owner-confirm-typebox[hidden] { display: none; }
#owner-confirm-type { width: 100%; margin-top: 6px; }
/* Narrower conversations pane (2026-10-14): desktop 320px -> 224px; drawer min(86vw,340px) -> min(72vw,284px). */
#sidebar { width: min(224px, 100%); flex: none; }
@media (max-width: 800px) { #sidebar { width: min(72vw, 284px); } }
@media (min-width: 801px) { html.side-collapsed #sidebar { width: 64px; } }
.person { min-width: 0; }
.person > span:not(.unread):not(.pfp), .person .dname, #lobby-row strong, #lobby-row .sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person img, .person .unread, .person .led { flex: none; }

/* Avatars: steady, no placeholder flash; lock badge sits on the corner above the ring. */
.pfp { overflow: visible; }
.pfp img { background: transparent; transition: none; animation: none; }
.pfp-lock { z-index: 1; }
/* Footer contrast (2026-10-14): solid-ish card background and bright text, no dimming. */
#bc-footer { color: #e6edf5 !important; background: color-mix(in srgb, var(--card) 88%, transparent) !important; text-shadow: none !important; }
#bc-footer .ref, #bc-footer .memorial, #bc-footer .legal { opacity: 1 !important; }
html[data-scheme="light"] #bc-footer { color: #1f2937 !important; background: color-mix(in srgb, #ffffff 88%, transparent) !important; border-color: rgba(0,0,0,.10) !important; }

/* YouTube player: roomy enough that YouTube keeps full controls; nothing transforms or overlays it.
   Use .yt-row / .yt-playing (set in JS) instead of :has() — :has(.yt-card) style recalc stalled scroll on attach. */
/* YouTube preview tiers (boss OK 2026-11-02): fixed 16:9 thumb sizes by viewport.
   max-width:100% keeps the card inside narrow chat columns. No contain:size (0104 blank-row bug). */
.link-card.yt-card { width: min(400px, 100%); max-width: 100%; contain: layout style paint; }
.link-card.yt-card:not(.yt-short) .yt-box { width: 100%; height: 225px; aspect-ratio: 16 / 9; object-fit: cover; }
.link-card.yt-card:not(.yt-short) .yt-box > img,
.link-card.yt-card:not(.yt-short) .yt-box img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 1280px) {
  .link-card.yt-card:not(.yt-short) { width: min(360px, 100%); }
  .link-card.yt-card:not(.yt-short) .yt-box { height: 203px; }
}
@media (max-width: 768px) {
  .link-card.yt-card:not(.yt-short) { width: min(320px, 100%); }
  .link-card.yt-card:not(.yt-short) .yt-box { height: 180px; }
}
@media (max-width: 480px) {
  .link-card.yt-card:not(.yt-short) { width: min(300px, 100%); }
  .link-card.yt-card:not(.yt-short) .yt-box { height: 169px; }
}
.msg.yt-row { min-width: 0; max-width: min(92%, 520px); }
.yt-frame { width: 100%; height: auto; aspect-ratio: 16 / 9; position: relative; z-index: 1; }
.yt-card, .msg.yt-playing, .msg.yt-playing .bubble { transform: none !important; filter: none !important; }

/* 0.20.00: "Choose where to share" banner at the top of the chat list (themed with the palette variables). */
#share-pick[hidden] { display: none !important; }
#share-pick {
  flex: none; display: flex; align-items: center; gap: 10px;
  margin: 0 0 8px; padding: 8px 10px; border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 16%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line));
  color: var(--text);
}
#share-pick .share-pick-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
#share-pick strong { font-size: 14px; line-height: 1.25; }
#share-pick-link { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#share-pick-cancel { flex: none; padding: 4px 12px; font-size: 13px; border-radius: 999px; }
/* 0.20.01: while a shared link waits, show nothing but the chat list, centered on a black page. */

/* Android app 0.19.02+: its page shim marks <html> with bc-app, and kb-open while the
   keyboard is up. Hide the footer then so the message box sits on the keyboard.
   (The shim's own <style> is blocked by this site's CSP; web users never get bc-app.) */
html.bc-app.kb-open #bc-footer { display: none !important; }

/* ===== 0.21: Telegram-style navigation =====
   Home is the chat list. Phones (<= 800px): home fills the screen; a chat fills the
   screen with its own top bar (Back, picture, name, actions, menu) and the global
   header folds away. Wide screens: list left, chat right. Plain flex layout, so the
   list can never sit under the header. */
#chat-back, #chat-menu { display: none; }
#thread-head { justify-content: flex-start; }
#thread-head .thread-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
#thread-title { min-width: 0; }
#thread-title > span:not(.led) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 26.10.5: nothing sits beside the friend's name any more, so the name keeps all the room the header has
   (it only shortens with "…" when the name itself is longer than the screen). */
#thread-title { display: flex; align-items: center; max-width: 100%; }
#thread-title > .dname { flex: 0 1 auto; min-width: 0; }
#thread-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#thread-pic { flex: none; display: inline-flex; }
#thread-pic:empty { display: none; }
#thread-pic .lobby-pic {
  width: 36px; height: 36px; border-radius: 50%; display: inline-block;
  background: url("/static/lobby-icon.webp?v=26.11.1007-763b3d5b") center / cover no-repeat;
  box-shadow: 0 0 0 2px #8b97a6, 0 0 8px rgba(139,151,166,.6);
}
#thread-actions { flex: none; display: flex; align-items: center; gap: 6px; }
#chat-back, #chat-menu, #search-btn {
  flex: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0 !important; border-radius: 50% !important;
  background: transparent; border: 0; color: var(--text); box-shadow: none !important;
}
#chat-back:hover, #chat-menu:hover, #search-btn:hover,
#chat-back:focus-visible, #chat-menu:focus-visible, #search-btn:focus-visible,
#chat-back:active, #chat-menu:active, #search-btn:active { background: color-mix(in srgb, var(--text) 10%, transparent); }
/* 26.10.2: the back arrow beside the chat's picture shows on every screen size, not only phones. On wide
   screens it closes the chat and the right pane shows the welcome screen (the list stays left); on phones it is the
   same Back as before. The chat menu button stays phone-only. */
html:not(.no-chat) #chat-back { display: inline-flex; margin-right: 2px; }

@media (max-width: 800px) {
  #nav-open { display: none !important; }
  /* Home: the list fills the space between the header and the footer. */
  #shell { padding: 8px !important; gap: 0 !important; }
  #sidebar {
    position: static !important; inset: auto !important; transform: none !important; opacity: 1 !important;
    transition: none !important; width: 100% !important; max-width: none !important; max-height: none !important;
    flex: 1 1 auto; min-height: 0; box-shadow: none !important; display: flex !important;
  }
  #side-collapse, #side-expand { display: none !important; }
  html.no-chat main { display: none !important; }

  /* In a chat: only the chat. (0.21.04: header/main/footer rules scoped to the app page, so About and Patch notes keep their header.) */
  html:not(.no-chat) #sidebar { display: none !important; }
  html:not(.no-chat) body:not(.pn-page) #bc-footer { display: none !important; }
  html:not(.no-chat) #shell { padding: 0 !important; }
  html:not(.no-chat) body:not(.pn-page) main { border-radius: 0 !important; border: 0 !important; }
  html:not(.no-chat) #thread-head {
    gap: 4px;
    padding: 6px 8px 6px 4px;
    padding-top: calc(6px + env(safe-area-inset-top, 0px));
    padding-left: max(4px, env(safe-area-inset-left, 0px));
    padding-right: max(8px, env(safe-area-inset-right, 0px));
    background: var(--card); position: relative; z-index: 3;
  }
  html:not(.no-chat) #chat-back, html:not(.no-chat) #chat-menu { display: inline-flex; }
  /* iphone-header: keep chat-bar controls ≥44px touch targets; burger was 48×44 and stole name room. */
  html:not(.no-chat) #chat-back,
  html:not(.no-chat) #search-btn,
  html:not(.no-chat) #thread-actions button.icon {
    width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  }
  html:not(.no-chat) #chat-menu.burger-btn {
    width: 44px; height: 44px; min-width: 44px; min-height: 44px; padding: 0 !important;
  }
  html:not(.no-chat) #thread-sub { font-size: 12px; }
  /* The global header folds away; only its menu stays usable (opened from the chat bar). */
  html:not(.no-chat) body:not(.pn-page) header {
    position: fixed !important; inset: 0 0 auto 0; height: 0; min-height: 0; padding: 0 !important;
    border: 0 !important; box-shadow: none !important; background: transparent !important; overflow: visible; z-index: 20;
  }
  html:not(.no-chat) body:not(.pn-page) header > :not(.header-actions) { display: none !important; }
  html:not(.no-chat) body:not(.pn-page) header .header-actions > :not(#app-menu) { display: none !important; }
  html:not(.no-chat) body:not(.pn-page) #app-menu { position: fixed; top: var(--menu-top, 56px); right: 8px; left: auto; }
  /* Home header: room for the brand without the old Chats button. */
  html.no-chat header { padding-top: calc(10px + env(safe-area-inset-top, 0px)); }
}
@media (min-width: 801px) {
  /* Wide: two panes. The list is wider, like Telegram Desktop. */
  #sidebar { width: min(320px, 34vw); }
  html.side-collapsed #sidebar { width: 64px; }
}

/* 0.21: home rows with last-message previews (Telegram style). */
.chat-row, #lobby-row.chat-row { display: flex !important; align-items: center; gap: 10px; text-align: left; }
.chat-row .row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.chat-row .row-top, .chat-row .row-bottom { display: flex; align-items: center; gap: 8px; min-width: 0; }
.chat-row .row-name { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#lobby-row.chat-row strong.row-name { font-size: 1.05em; grid-row: auto; }
.chat-row .row-time { flex: none; font-size: 12px; color: var(--muted); font-weight: 400; }
.chat-row .row-preview { flex: 1; min-width: 0; display: block; font-size: 13px; line-height: 1.35; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-row .row-preview .who { color: color-mix(in srgb, var(--accent) 55%, var(--text) 45%); }
.chat-row .row-bottom .unread { margin-left: auto; }
.chat-row .pfp, #lobby-row.chat-row #lobby-led { width: 42px; height: 42px; flex: none; }
html.side-collapsed .chat-row .row-main { display: none !important; }
/* Share chooser stays compact: smaller avatars and text, still one preview line. */
/* The lobby row shows its last-message preview (the old member-list line stays hidden). */
#lobby-row.chat-row #lobby-sub:not(.empty) { display: block !important; }

/* ===== 0.21.01: Telegram-style composer and emoji/GIF panel =====
   [+]  ( emoji/GIF | message ... | Send )
   The panel (#picker) sits under the bar in the space the keyboard used; app.js sets its
   height (element.style) to the keyboard's height, so swapping them moves nothing. */
#composer { border-top: 0; padding: 6px 8px calc(8px + env(safe-area-inset-bottom)); gap: 4px; }
#composer #attach-name, #composer #send-note { font-size: 13px; padding: 0 8px 0 60px; }
#composer-row { display: flex; align-items: flex-end; gap: 8px; }
#file-btn {
  flex: none; width: 46px; height: 46px; margin-bottom: 1px; padding: 0 !important;
  display: inline-grid; place-items: center; border-radius: 50% !important;
  border: 1.5px solid color-mix(in srgb, var(--text) 30%, transparent) !important;
  background: var(--card) !important; color: var(--text); box-shadow: none !important;
}
#file-btn:hover, #file-btn:focus-visible, #file-btn:active { background: color-mix(in srgb, var(--text) 10%, var(--card)) !important; }
#msg-bar {
  flex: 1; min-width: 0; display: flex; align-items: flex-end; gap: 2px;
  min-height: 48px; padding: 3px 4px;
  background: var(--card); border: 1px solid var(--line); border-radius: 24px;
}
#msg-bar:focus-within { border-color: color-mix(in srgb, var(--accent) 60%, var(--line)); }
#composer #text {
  flex: 1; min-width: 0; width: auto; height: 40px; min-height: 40px; max-height: none;
  margin: 0; padding: 9px 4px; line-height: 22px; resize: none; overflow-y: auto;
  border: 0 !important; border-radius: 0; background: transparent !important; box-shadow: none !important; outline: none;
}
#composer .bar-btn {
  flex: none; width: 40px; height: 40px; min-width: 0; min-height: 0; padding: 0 !important;
  display: inline-grid; place-items: center; border: 0 !important; border-radius: 50% !important;
  background: transparent !important; color: var(--muted); box-shadow: none !important;
}
#composer .bar-btn:hover, #composer .bar-btn:focus-visible, #composer .bar-btn:active { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent) !important; }
#emoji-btn > * { grid-area: 1 / 1; }
#emoji-btn .ico-gif {
  font-size: 11px; font-weight: 800; letter-spacing: .02em; line-height: 1;
  border: 2px solid currentColor; border-radius: 6px; padding: 3px 3px 2px;
}
#emoji-btn .ico-kb, #emoji-btn .ico-gif { display: none; }
#emoji-btn.show-gif .ico-smile { display: none; }
#emoji-btn.show-gif .ico-gif { display: block; }
#emoji-btn.show-kb .ico-smile, #emoji-btn.show-kb .ico-gif { display: none; }
#emoji-btn.show-kb .ico-kb { display: block; }
#composer #send {
  flex: none; width: 40px; height: 40px; min-width: 40px; min-height: 40px; align-self: flex-end;
  padding: 0 0 0 3px !important; display: inline-grid; place-items: center; font-size: inherit;
  border: 0; border-radius: 50% !important; background: var(--accent); color: var(--on-accent);
}
#composer #send:disabled, #composer button:disabled { opacity: .45; cursor: default; }

#picker[hidden] { display: none !important; }
#picker {
  flex: none; display: flex; flex-direction: column; overflow: hidden; min-height: 0;
  background: var(--card); border-top: 1px solid var(--line);
}
#picker-search-row { flex: none; padding: 8px 10px 6px; }
#picker-search { width: 100%; border-radius: 18px; padding: 7px 14px; }
#picker .picker-pane { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 2px 8px 6px; }
#picker #emoji-pop:not([hidden]) { display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); align-content: start; gap: 2px; }
#picker #emoji-pop .picker-empty { grid-column: 1 / -1; }
#picker #gif-pop:not([hidden]) { display: block; }
#picker #gif-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); grid-auto-rows: 110px; gap: 4px; }
#picker #gif-grid img { height: 110px; }
#picker #gif-note:empty { display: none; }
/* 26.10.4: the tabs (Emoji, GIF, and room for more, e.g. Stickers) are at the top of the panel, above the search box,
   centred. The open tab has brighter text and a bright Twigum-green underline (the wordmark's green: lighter on
   dark, deeper on light); the others are muted. Keyboard focus gets a clear ring. Any button with role="tab" in the
   row gets this look, so a third tab needs no extra styling. */
#picker-tabs {
  --tab-green: #7cc98c;
  flex: none; display: flex; justify-content: center; gap: 4px;
  padding: 6px 10px 0; border-bottom: 1px solid var(--line);
}
html[data-scheme="light"] #picker-tabs { --tab-green: #2e7d48; }
#picker-tabs [role="tab"] {
  position: relative; border: 0 !important; background: transparent !important; box-shadow: none !important;
  color: var(--muted); border-radius: 8px 8px 0 0 !important; padding: 7px 18px 9px; min-width: 76px;
  font-size: 14px; font-weight: 600; letter-spacing: .01em; transition: color .15s ease;
}
#picker-tabs [role="tab"]::after {
  content: ""; position: absolute; left: 14px; right: 14px; bottom: -1px; height: 3px; border-radius: 3px 3px 0 0;
  background: var(--tab-green); transform: scaleX(0); opacity: 0; transition: transform .18s ease, opacity .18s ease;
}
#picker-tabs [role="tab"]:hover { color: var(--text); }
#picker-tabs [role="tab"][aria-selected="true"] { color: var(--text); font-weight: 700; }
#picker-tabs [role="tab"][aria-selected="true"]::after { transform: scaleX(1); opacity: 1; box-shadow: 0 0 8px color-mix(in srgb, var(--tab-green) 55%, transparent); }
#picker-tabs [role="tab"]:focus-visible { outline: 2px solid var(--tab-green); outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) { #picker-tabs [role="tab"], #picker-tabs [role="tab"]::after { transition: none; } }
#picker-search-row { padding-top: 8px; }
#picker #gif-credit { margin: 6px 0 2px; text-align: center; font-size: 11px; opacity: .75; }
#picker .picker-pane { padding-bottom: calc(6px + env(safe-area-inset-bottom)); }
/* 26.10.3: "Frequently used" and "All emoji" headings span the whole row of the emoji grid / reaction list. */
.emoji-head {
  grid-column: 1 / -1; flex: 0 0 100%; width: 100%;
  font-size: 12px; font-weight: 600; color: var(--muted); padding: 6px 4px 2px; text-align: left;
}
#react-grid .emoji-head:first-child, #picker #emoji-pop .emoji-head:first-child { padding-top: 2px; }
/* 26.10.3: the GIF button beside the emoji button (same look as the old GIF badge). Slightly narrower so phones keep
   room to type; highlighted while the GIF tab is open. */
#composer #gif-btn { width: 36px; }
#gif-btn .ico-gif {
  font-size: 11px; font-weight: 800; letter-spacing: .02em; line-height: 1;
  border: 2px solid currentColor; border-radius: 6px; padding: 3px 3px 2px;
}
#composer #gif-btn.on { color: var(--accent); }
/* 26.10.3: quick reactions already on this message (yours) get a soft highlight. */
#react-quick button[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) 22%, transparent); }
#picker #emoji-pop button { background: transparent !important; border: 0 !important; box-shadow: none !important; }
#picker #emoji-pop button:hover, #picker #emoji-pop button:focus-visible { background: color-mix(in srgb, var(--accent) 16%, transparent) !important; }


/* snap polish (0.21.02): moved here from the <style> element app.js used to create at runtime,
   which the CSP (style-src 'self') blocked. Kept last so it overrides the snap rules above, as intended. */
.snap-gap{flex:0 0 auto!important;min-height:0}
.snap-spk{position:fixed;z-index:86;width:7px;height:7px;pointer-events:none;background:#fff3b8;
 clip-path:polygon(50% 0,62% 38%,100% 50%,62% 62%,50% 100%,38% 62%,0 50%,38% 38%);filter:drop-shadow(0 0 3px #ffd77a)}
.snap-figure svg path,.snap-figure svg rect{stroke-linejoin:round}
.snap-stage .snap-figure{animation:snap-spring 1.24s cubic-bezier(.34,1.56,.64,1) both!important;transform-origin:50% 100%}
.snap-stage .snap-figure.snap-pre{animation:snap-squash 0.275s ease-in-out both!important}
.snap-stage .snap-figure.snap-go .head{animation:snap-tilt 1.8s ease-in-out 0.4s both}
.snap-stage .snap-figure.snap-go .eyeR{animation:snap-wink 1s ease-in-out 0.7s both;transform-box:fill-box;transform-origin:center}
.snap-stage .snap-figure.snap-out{animation:snap-exit 1.1s cubic-bezier(.5,0,.75,0) forwards!important}
@keyframes snap-spring{from{opacity:0;transform:translateY(18px) scale(.7)}to{opacity:1;transform:none}}
@keyframes snap-squash{0%{transform:none}60%{transform:scale(1.05,.92)}100%{transform:scale(.98,1.03)}}
@keyframes snap-tilt{0%,100%{transform:rotate(0)}40%{transform:rotate(-7deg)}70%{transform:rotate(4deg)}}
@keyframes snap-wink{0%,100%{transform:scaleY(1)}50%{transform:scaleY(.1)}}
@keyframes snap-exit{to{opacity:0;transform:translateY(10px) scale(.85)}}
.snap-figure .fig{animation:sc-bob 1.8s ease-in-out infinite;transform-box:fill-box;transform-origin:50% 100%}
.snap-figure .eyes{animation:sc-blink 3.2s ease-in-out .5s infinite;transform-box:fill-box;transform-origin:50% 50%}
.snap-figure .earL{animation:sc-earL 2.4s ease-in-out .3s infinite}
.snap-figure .earR{animation:sc-earR 2.4s ease-in-out 1.1s infinite}
.snap-figure .tail{animation:sc-swish 1.5s ease-in-out infinite}
.snap-figure .canopy{animation:sc-sway 2.6s ease-in-out infinite}
.snap-figure .leafbit{transform-box:fill-box;transform-origin:50% 100%;animation:sc-flutter .9s ease-in-out infinite alternate}
.snap-figure .spark{transform-box:fill-box;transform-origin:center;animation:sc-twinkle 1.1s ease-in-out infinite}
.snap-figure .hand{transform-box:fill-box;transform-origin:20% 100%}
.snap-stage .snap-figure.snap-go .fig{animation:sc-giggle .18s ease-in-out 0.7s 12}
.snap-stage .snap-figure.snap-go .canopy{animation:sc-shake .16s ease-in-out 0.6s 14}
.snap-stage .snap-figure.snap-go .eyes{animation:sc-squeeze 2s ease-in-out 0.6s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .eyes{animation:sc-hide 2s steps(1) 0.6s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .shut{animation:sc-show 2s steps(1) 0.6s both}
.snap-stage .snap-figure.snap-go .eyeR{animation:none}
.snap-stage .snap-figure.snap-go .hand{animation:sc-snap 0.375s cubic-bezier(.3,1.6,.6,1) both}
.snap-stage .snap-figure.snap-go .leafbit{animation:sc-fall 2.8s ease-in 0.4s both}
.snap-stage .snap-figure.snap-out .hand{animation:sc-wave 1s ease-in-out both}
.snap-stage .snap-figure.snap-out .eyeR{animation:snap-wink 0.8s ease-in-out both}
.snap-stage .snap-figure.snap-out .eyes{animation:none}
.snap-stage .snap-figure.snap-out{animation:sc-exit 1.2s cubic-bezier(.5,0,.75,0) 0.3s forwards!important}
@keyframes sc-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-1.5px)}}
@keyframes sc-blink{0%,92%,100%{transform:scaleY(1)}96%{transform:scaleY(.1)}}
@keyframes sc-earL{0%,80%,100%{transform:rotate(0)}86%{transform:rotate(-14deg)}92%{transform:rotate(4deg)}}
@keyframes sc-earR{0%,80%,100%{transform:rotate(0)}86%{transform:rotate(14deg)}92%{transform:rotate(-4deg)}}
@keyframes sc-swish{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(6deg)}}
@keyframes sc-sway{0%,100%{transform:rotate(-1.5deg)}50%{transform:rotate(1.5deg)}}
@keyframes sc-flutter{from{transform:rotate(-12deg)}to{transform:rotate(12deg)}}
@keyframes sc-twinkle{0%,100%{transform:scale(.6) rotate(0);opacity:.6}50%{transform:scale(1.15) rotate(45deg);opacity:1}}
@keyframes sc-giggle{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.02,.98)}}
@keyframes sc-shake{0%,100%{transform:rotate(0)}25%{transform:rotate(-3deg)}75%{transform:rotate(3deg)}}
@keyframes sc-squeeze{0%,100%{transform:scaleY(1)}15%,85%{transform:scaleY(.15)}}
@keyframes sc-hide{0%{opacity:0}100%{opacity:1}}
@keyframes sc-show{0%{opacity:1}100%{opacity:0}}
@keyframes sc-snap{0%{transform:rotate(0)}40%{transform:rotate(-10deg) scale(1.08)}100%{transform:rotate(0)}}
@keyframes sc-fall{0%{transform:translate(0,0) rotate(0);opacity:1}100%{transform:translate(6px,26px) rotate(160deg);opacity:0}}
@keyframes sc-wave{0%,100%{transform:rotate(0)}30%{transform:rotate(-14deg)}65%{transform:rotate(10deg)}}
@keyframes sc-exit{0%{opacity:1;transform:none}100%{opacity:0;transform:translate(-18px,22px) scale(.85)}}
.snap-stage .snap-figure[data-char="fox"].snap-out .eyes,.snap-stage .snap-figure[data-char="fox"].snap-out .shut{animation:none}
@media (prefers-reduced-motion: reduce){.snap-figure .fig,.snap-figure .fig *{animation:none!important}}
@media (prefers-reduced-motion: reduce){.snap-stage .snap-figure,.snap-stage .snap-figure *{animation:none!important}.snap-spk{display:none}}
/* snap character parts: pivot points that were inline style="" attributes on the SVG groups (also CSP-blocked) */
.snap-figure svg .head { transform-box: fill-box; transform-origin: 50% 92%; }
.snap-figure svg .canopy { transform-box: fill-box; transform-origin: 50% 100%; }
.snap-figure svg .tail { transform-box: fill-box; transform-origin: 90% 90%; }
.snap-figure svg .earL { transform-box: fill-box; transform-origin: 70% 100%; }
.snap-figure svg .earR { transform-box: fill-box; transform-origin: 30% 100%; }
.snap-figure svg .eyeL, .snap-figure svg .eyeR { transform-box: fill-box; transform-origin: center; }

/* 0.21.02: CSP-safe replacements for inline style="" attributes */
#key-backup-ui[hidden] { display: none !important; }
.made-with-love .sounds-credit { font-size: 12px; opacity: .75; margin: 10px 0 4px; }
.made-with-love .emoji-credit { font-size: 12px; opacity: .75; margin: 10px 0 4px; line-height: 1.5; }   /* 26.10.4: emoji style credits (same small print as the sounds credit) */

/* 0.21.03: the version label is one unbreakable token ("v0.21.03"), small and muted, never split across lines. */
.ver { display: inline-block; white-space: nowrap; letter-spacing: .02em; font-variant-numeric: tabular-nums; vertical-align: baseline; }

/* treant (0.21.04): no gauntlet. Leafy shake, then roots (an SVG overlay drawn by app.js) wrap the message
   and pull it underground; a happy nod, then off. Transforms and opacity only. */
.snap-figure[data-char="treant"] svg .tr-canopy{transform-box:fill-box;transform-origin:50% 92%;animation:sc-sway 2.6s ease-in-out infinite}
.snap-figure[data-char="treant"] svg .tr-clA,.snap-figure[data-char="treant"] svg .tr-clB,
.snap-figure[data-char="treant"] svg .tr-clC,.snap-figure[data-char="treant"] svg .tr-clD,.snap-figure[data-char="treant"] svg .tr-clE{transform-box:fill-box;transform-origin:50% 80%}
.snap-figure[data-char="treant"] svg .tr-armL{transform-box:view-box;transform-origin:14px 33px;animation:tr-idleL 2.2s ease-in-out infinite}
.snap-figure[data-char="treant"] svg .tr-armR{transform-box:view-box;transform-origin:66px 33px;animation:tr-idleR 2.2s ease-in-out .4s infinite}
.snap-figure[data-char="treant"] svg .tr-edge{transform-box:fill-box;transform-origin:50% 90%}
.snap-figure[data-char="treant"] svg .tr-fall{opacity:0;transform-box:fill-box;transform-origin:50% 50%}
.snap-figure[data-char="treant"] svg .tr-shut,.snap-figure[data-char="treant"] svg .tr-mouthO{opacity:0}
.snap-stage .snap-figure.tr-shake .fig{animation:tr-hop .66s ease-in-out both 2}
.snap-stage .snap-figure.tr-shake .tr-canopy{animation:tr-rustle .66s cubic-bezier(.36,.07,.19,.97) both 2}
.snap-stage .snap-figure.tr-shake .tr-edge{animation:tr-rustle .66s cubic-bezier(.36,.07,.19,.97) 0.06s both 2}
.snap-stage .snap-figure.tr-shake .tr-clA{animation:tr-jitA .11s ease-in-out 12 alternate both}
.snap-stage .snap-figure.tr-shake .tr-clB{animation:tr-jitB .1s ease-in-out 0.06s 12 alternate both}
.snap-stage .snap-figure.tr-shake .tr-clC{animation:tr-jitC .12s ease-in-out 0.1s 10 alternate both}
.snap-stage .snap-figure.tr-shake .tr-clD{animation:tr-jitB .09s ease-in-out 0.04s 14 alternate both}
.snap-stage .snap-figure.tr-shake .tr-clE{animation:tr-jitC .1s ease-in-out 0.08s 12 alternate both}
.snap-stage .snap-figure.tr-shake .tr-head{animation:tr-headshake .66s ease-in-out both 2}
.snap-stage .snap-figure.tr-shake .tr-beard,.snap-stage .snap-figure.tr-shake .tr-mossL,.snap-stage .snap-figure.tr-shake .tr-mossR{animation:tr-swing .22s ease-in-out 6 alternate both}
.snap-stage .snap-figure.tr-shake .tr-armL{animation:tr-armL .66s ease-in-out both 2}
.snap-stage .snap-figure.tr-shake .tr-armR{animation:tr-armR .66s ease-in-out 0.04s both 2}
.snap-stage .snap-figure.tr-shake .eyes{animation:sc-squeeze 1.32s ease-in-out both}
.snap-stage .snap-figure.tr-shake .tr-mouth{animation:tr-off 1.32s steps(1) both}
.snap-stage .snap-figure.tr-shake .tr-mouthO{animation:tr-on 1.32s steps(1) both}
.snap-stage .snap-figure.tr-shake .tr-f1{animation:tr-fallA 2.5s ease-in 0.16s both}
.snap-stage .snap-figure.tr-shake .tr-f2{animation:tr-fallB 2.6s ease-in 0.36s both}
.snap-stage .snap-figure.tr-shake .tr-f3{animation:tr-fallA 2.3s ease-in 0.56s both}
.snap-stage .snap-figure.tr-shake .tr-f4{animation:tr-fallB 2.4s ease-in 0.24s both}
.snap-stage .snap-figure.tr-shake .tr-f5{animation:tr-fallC 2.6s ease-in 0.44s both}
.snap-stage .snap-figure.tr-shake .tr-f6{animation:tr-fallC 2.8s ease-in 0.04s both}
.snap-stage .snap-figure.tr-nod .fig{animation:tr-nod 1.2s ease-in-out both}
.snap-stage .snap-figure.tr-nod .tr-head{animation:tr-headnod 1.2s ease-in-out both}
.snap-stage .snap-figure.tr-nod .eyes{opacity:0;animation:none}
.snap-stage .snap-figure.tr-nod .tr-shut{opacity:1}
@keyframes tr-idleL{0%,100%{transform:rotate(0)}50%{transform:rotate(4deg)}}
@keyframes tr-idleR{0%,100%{transform:rotate(0)}50%{transform:rotate(-4deg)}}
@keyframes tr-hop{0%,100%{transform:none}15%{transform:translateY(.8px) scale(1.03,.96)}30%{transform:translateY(-1.4px) scale(.98,1.03)}45%{transform:translateY(.6px) scale(1.02,.97)}60%{transform:translateY(-1px)}80%{transform:translateY(.3px)}}
@keyframes tr-rustle{0%,100%{transform:none}10%{transform:rotate(-6deg) scale(1.05,.95)}20%{transform:rotate(6deg) scale(.96,1.05)}30%{transform:rotate(-7deg) scale(1.05,.95)}40%{transform:rotate(6deg) scale(.97,1.04)}50%{transform:rotate(-5deg)}60%{transform:rotate(4deg)}70%{transform:rotate(-3deg)}80%{transform:rotate(2deg)}90%{transform:rotate(-1deg)}}
@keyframes tr-jitA{from{transform:translate(0,0)}to{transform:translate(-.9px,-.6px) rotate(-4deg)}}
@keyframes tr-jitB{from{transform:translate(0,0)}to{transform:translate(.4px,-1px) scale(1.04)}}
@keyframes tr-jitC{from{transform:translate(0,0)}to{transform:translate(.9px,-.5px) rotate(4deg)}}
@keyframes tr-armL{0%,100%{transform:rotate(0)}12%{transform:rotate(20deg)}25%{transform:rotate(-14deg)}38%{transform:rotate(22deg)}50%{transform:rotate(-12deg)}62%{transform:rotate(15deg)}75%{transform:rotate(-7deg)}88%{transform:rotate(3deg)}}
@keyframes tr-armR{0%,100%{transform:rotate(0)}12%{transform:rotate(-20deg)}25%{transform:rotate(14deg)}38%{transform:rotate(-22deg)}50%{transform:rotate(12deg)}62%{transform:rotate(-15deg)}75%{transform:rotate(7deg)}88%{transform:rotate(-3deg)}}
@keyframes tr-off{0%{opacity:0}100%{opacity:1}}
@keyframes tr-on{0%{opacity:1}100%{opacity:0}}
@keyframes tr-fallA{0%{opacity:0;transform:translate(0,0) rotate(0)}8%{opacity:1}30%{transform:translate(-3px,5px) rotate(-50deg)}55%{transform:translate(2px,10px) rotate(25deg)}80%{opacity:.9;transform:translate(-2px,15px) rotate(-30deg)}100%{opacity:0;transform:translate(1px,20px) rotate(10deg)}}
@keyframes tr-fallB{0%{opacity:0;transform:translate(0,0) rotate(0)}8%{opacity:1}30%{transform:translate(3px,4px) rotate(45deg)}55%{transform:translate(-2px,9px) rotate(-20deg)}80%{opacity:.9;transform:translate(3px,14px) rotate(35deg)}100%{opacity:0;transform:translate(0,19px) rotate(-5deg)}}
@keyframes tr-fallC{0%{opacity:0;transform:translate(0,0) rotate(0)}8%{opacity:1}35%{transform:translate(4px,5px) rotate(70deg)}65%{transform:translate(7px,11px) rotate(20deg)}85%{opacity:.85;transform:translate(9px,16px) rotate(80deg)}100%{opacity:0;transform:translate(10px,21px) rotate(40deg)}}
@keyframes tr-nod{0%,100%{transform:none}25%{transform:translateY(1.4px) scale(1.03,.95)}50%{transform:translateY(-.8px) scale(.99,1.02)}72%{transform:translateY(1px) scale(1.02,.97)}}
.snap-stage .snap-figure svg{width:100%;height:100%}
.snap-figure[data-char="treant"] svg .tr-head{transform-box:fill-box;transform-origin:50% 100%}
.snap-figure[data-char="treant"] svg .tr-beard,.snap-figure[data-char="treant"] svg .tr-mossL,.snap-figure[data-char="treant"] svg .tr-mossR{transform-box:fill-box;transform-origin:50% 0;animation:tr-sway 2.4s ease-in-out infinite}
.snap-figure[data-char="treant"] svg .tr-glow{transform-box:fill-box;transform-origin:50% 50%;animation:tr-pulse 1.6s ease-in-out infinite}
.snap-figure[data-char="treant"] svg .tr-wisp{transform-box:fill-box;transform-origin:50% 50%;animation:tr-float 2.2s ease-in-out infinite}
.snap-figure[data-char="treant"] svg .tr-w2{animation-delay:-.7s;animation-duration:2.6s}
.snap-figure[data-char="treant"] svg .tr-w3{animation-delay:-1.4s;animation-duration:1.9s}
@keyframes tr-headshake{0%,100%{transform:none}20%{transform:rotate(-4deg)}40%{transform:rotate(4deg)}60%{transform:rotate(-3deg)}80%{transform:rotate(2deg)}}
@keyframes tr-headnod{0%,100%{transform:none}30%{transform:rotate(0) translateY(1px) scaleY(.94)}55%{transform:translateY(-.4px)}75%{transform:translateY(.8px) scaleY(.97)}}
@keyframes tr-swing{from{transform:rotate(-7deg)}to{transform:rotate(7deg)}}
@keyframes tr-sway{0%,100%{transform:rotate(-2deg)}50%{transform:rotate(2.5deg)}}
@keyframes tr-pulse{0%,100%{opacity:.75;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}
@keyframes tr-float{0%,100%{transform:translate(0,0);opacity:.7}50%{transform:translate(1.5px,-2.5px);opacity:1}}
svg.snap-roots{position:fixed;left:0;top:0;margin:0;z-index:84;pointer-events:none;overflow:visible;
  background:transparent!important;border:0!important;box-shadow:none!important;will-change:transform}
/* heroes (0.21.04): the gauntlet guy and the fox. Squash and stretch on the snap, an arcane flash and ring at the
   fingers, and follow-through on cape, hair, tail and ears. Transforms and opacity only. */
.snap-figure svg .aura,.snap-figure svg .ering{opacity:0;transform-box:fill-box;transform-origin:50% 50%}
.snap-figure[data-char="fox"] svg .hand{transform-box:view-box;transform-origin:48px 47px}
.snap-figure svg .cape{transform-box:view-box;transform-origin:36px 37px;animation:gx-cape 2.6s ease-in-out infinite}
.snap-figure svg .hair{transform-box:view-box;transform-origin:36px 16px}
.snap-figure[data-char="fox"] svg .tail{transform-box:view-box;transform-origin:26px 58px}
.snap-stage .snap-figure.snap-pre .hand{animation:gx-wind 0.275s ease-out both}
.snap-stage .snap-figure.snap-go .hand{animation:gx-snap 0.65s cubic-bezier(.2,1.5,.4,1) both}
.snap-stage .snap-figure.snap-go .aura{animation:gx-aura 1.44s ease-out 0.16s both}
.snap-stage .snap-figure.snap-go .ering{animation:gx-ring 1.24s cubic-bezier(.1,.7,.3,1) 0.2s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .fig{animation:gx-pop 0.625s cubic-bezier(.3,1.4,.5,1) both,sc-giggle .18s ease-in-out 1.1s 6}
.snap-stage .snap-figure.snap-go .cape{animation:gx-flap 1.7s ease-out 0.12s both}
.snap-stage .snap-figure.snap-go .hair{animation:gx-flop 1.2s ease-out 0.1s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .tail{animation:gx-whip 1.5s ease-out 0.08s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .earR{animation:gx-flick 0.84s ease-out 0.12s both}
.snap-stage .snap-figure[data-char="fox"].snap-go .earL{animation:gx-flickL 0.84s ease-out 0.2s both}
@keyframes gx-cape{0%,100%{transform:skewX(0) scaleX(1)}50%{transform:skewX(-2deg) scaleX(1.02)}}
@keyframes gx-wind{to{transform:rotate(9deg) scale(.94)}}
@keyframes gx-snap{0%{transform:rotate(9deg) scale(.94)}28%{transform:rotate(-16deg) scale(1.16,1.12)}55%{transform:rotate(4deg) scale(.98,1.02)}78%{transform:rotate(-2deg) scale(1.01)}100%{transform:none}}
@keyframes gx-aura{0%{opacity:0;transform:scale(.3)}22%{opacity:1;transform:scale(1.15)}100%{opacity:0;transform:scale(1.7)}}
@keyframes gx-ring{0%{opacity:1;transform:scale(.25)}100%{opacity:0;transform:scale(2.4)}}
@keyframes gx-pop{0%{transform:scale(1.05,.93)}35%{transform:translateY(-2.5px) scale(.96,1.06)}70%{transform:scale(1.01,.99)}100%{transform:none}}
@keyframes gx-flap{0%{transform:none}25%{transform:skewX(6deg) scaleY(.97)}55%{transform:skewX(-3.5deg)}80%{transform:skewX(1.2deg)}100%{transform:none}}
@keyframes gx-flop{0%{transform:none}30%{transform:rotate(-5deg)}65%{transform:rotate(3deg)}100%{transform:none}}
@keyframes gx-whip{0%{transform:none}25%{transform:rotate(-16deg) scale(1.04,.96)}55%{transform:rotate(9deg)}80%{transform:rotate(-3deg)}100%{transform:none}}
@keyframes gx-flick{0%,100%{transform:none}35%{transform:rotate(14deg)}}
@keyframes gx-flickL{0%,100%{transform:none}35%{transform:rotate(-10deg)}}
.snap-spk.v{background:#e7c2ff;filter:drop-shadow(0 0 3px #a65cff)}
.snap-spk.c{background:#c4f1ff;filter:drop-shadow(0 0 3px #4ab8ff)}
.snap-flash{position:fixed;z-index:85;pointer-events:none;border-radius:50%;
 background:radial-gradient(circle,rgba(255,255,255,.95) 0,rgba(222,186,255,.75) 28%,rgba(150,90,255,.25) 52%,rgba(120,60,255,0) 70%)}
.snap-ring{position:fixed;z-index:86;pointer-events:none;border-radius:50%;border:2px solid #eedcff;box-shadow:0 0 8px #a65cff,inset 0 0 6px #a65cff}
@media (prefers-reduced-motion: reduce){.snap-flash,.snap-ring{display:none}}
/* composer inset (0.21.04): on phones the composer row was edge to edge and rounded screen corners clipped the
   + button and Send. About 2.5% more inset each side (or the safe area, if larger) and ~7px more lift from the
   bottom. #picker is a sibling below the form, so keyboard and picker states get the same offset (no jump). */
@media (max-width: 800px) {
  #composer {
    padding-left: calc(8px + max(2.5vw, env(safe-area-inset-left, 0px)));
    padding-right: calc(8px + max(2.5vw, env(safe-area-inset-right, 0px)));
    padding-bottom: calc(15px + env(safe-area-inset-bottom, 0px));
  }
}
/* steady backdrop (0.21.04): the keyboard resizes the window, and a cover-sized, centred wallpaper used to rescale and
   jump with it. The image size, its vertical position and the zoom origin are now pinned to the tallest window height
   seen at this width (app.js sets --app-tall), so a shorter window only hides more of the bottom. All wallpapers are 16:9. */
html body::before, html[data-scheme] body::before {
  --wall-h: calc(var(--app-tall, 100lvh) + 80px);
  --wall-img-h: max(var(--wall-h), calc((100vw + 80px) * 0.5625));
  background-repeat: no-repeat;
  background-size: auto var(--wall-img-h);
  background-position: 50% calc((var(--wall-h) - var(--wall-img-h)) / 2);
  transform-origin: 50% calc(var(--wall-h) / 2);
}
html body::after, html[data-scheme] body::after {
  background-repeat: no-repeat; background-size: 100% var(--app-tall, 100lvh); background-position: 50% 0;
}
/* snap moment fix (0.21.04): removing snap-pre re-applied the spring-in, so the character faded out and back in
   right as it snapped. Once the snap starts the figure holds its pose; the exit animation still runs. */
.snap-stage .snap-figure.snap-go:not(.snap-out){animation:none!important;opacity:1}
.snap-stage .snap-figure svg{overflow:visible}

/* ===== 0.21.05: Telegram-style attach drawer (round + button) =====
   Phones and touch screens: a bottom sheet with a drag handle over a dimmed chat.
   Wide mouse screens: a popover just above the + (app.js sets left/bottom).
   Colours come from the palette variables, so light, dark and every palette work. */
#attach-scrim[hidden], #attach-sheet[hidden], #cam-view[hidden], #attach-sheet [hidden], #cam-view [hidden] { display: none !important; }
#attach-scrim {
  position: fixed; inset: 0; z-index: 94; background: rgba(0, 0, 0, .45);
  opacity: 0; transition: opacity .2s ease;
}
#attach-scrim.ad-in { opacity: 1; }
#attach-scrim.ad-pop { background: transparent; }
#attach-sheet {
  position: fixed; z-index: 95; left: 0; right: 0; bottom: 0; margin: 0 auto;
  width: 100%; max-width: 640px; height: min(64vh, 640px); height: min(64dvh, 640px);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--card); color: var(--text);
  border: 1px solid var(--line); border-bottom: 0; border-radius: 18px 18px 0 0;
  box-shadow: 0 -10px 34px rgba(0, 0, 0, .35);
  transform: translateY(105%); transition: transform .24s cubic-bezier(.2, .8, .2, 1);
  touch-action: pan-y;
}
#attach-sheet.ad-in { transform: none; }
#attach-sheet.is-drag { transition: none; }
#attach-sheet.ad-pop {
  right: auto; margin: 0; width: min(420px, calc(100vw - 16px)); height: min(520px, calc(100vh - 120px));
  border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 14px 40px rgba(0, 0, 0, .35);
  transform: translateY(12px) scale(.98); opacity: 0; transform-origin: bottom left;
  transition: transform .16s ease, opacity .16s ease;
}
#attach-sheet.ad-pop.ad-in { transform: none; opacity: 1; }
#ad-grab { flex: none; height: 22px; display: grid; place-items: center; cursor: grab; touch-action: none; }
#ad-grab span { width: 38px; height: 5px; border-radius: 3px; background: color-mix(in srgb, var(--text) 30%, transparent); }
#attach-sheet.ad-pop #ad-grab { height: 10px; cursor: default; }
#attach-sheet.ad-pop #ad-grab span { display: none; }
#ad-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 4px; }
.ad-pane { min-height: 100%; }
.ad-hint { color: var(--muted); font-size: 12.5px; line-height: 1.4; margin: 10px 10px 12px; text-align: center; }

/* Gallery grid: camera tile (2 rows tall), Choose tile, then your picks, 3 across */
.ad-grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: calc((min(100vw, 640px) - 16px) / 3); gap: 3px; }
#attach-sheet.ad-pop .ad-grid { grid-auto-rows: 132px; }
.ad-tile { position: relative; overflow: hidden; border-radius: 6px; background: color-mix(in srgb, var(--text) 8%, var(--card)); min-width: 0; }
#ad-cam-tile { grid-row: span 2; background: #0b0e12; color: #fff; }
#ad-cam-live { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#ad-cam-live.is-mirror, #cam-video.is-mirror { transform: scaleX(-1); }
#ad-cam-open {
  position: absolute; inset: 0; width: 100%; height: 100%; padding: 0; border: 0 !important; border-radius: 0 !important;
  background: transparent !important; color: #fff; box-shadow: none !important;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 600;
}
#ad-cam-tile.is-live #ad-cam-open { align-items: flex-end; justify-content: flex-start; padding: 8px; }
#ad-cam-tile.is-live #ad-cam-open svg { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .7)); }
#ad-cam-tile.is-live #ad-cam-label { display: none; }
#ad-cam-flip {
  position: absolute; left: 8px; bottom: 8px; width: 36px; height: 36px; min-width: 0; min-height: 0; padding: 0 !important;
  display: grid; place-items: center; border-radius: 50% !important; border: 0 !important;
  background: rgba(0, 0, 0, .45) !important; color: #fff; box-shadow: none !important;
}
.ad-choose {
  border: 1.5px dashed color-mix(in srgb, var(--text) 28%, transparent) !important; color: var(--text);
  background: color-mix(in srgb, var(--accent) 10%, var(--card)) !important; box-shadow: none !important;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 8px !important;
  font-size: 13px; font-weight: 600; text-align: center; line-height: 1.25;
}
.ad-choose svg { color: var(--accent); }
.ad-grid.is-empty #ad-gal-choose { grid-column: span 2; grid-row: span 2; font-size: 15px; }
.ad-item { cursor: pointer; }
.ad-item img, .ad-item video { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.ad-item.is-sel img, .ad-item.is-sel video { transform: scale(.88); border-radius: 6px; }
.ad-item img, .ad-item video { transition: transform .15s ease; }
.ad-item .ad-ext { position: absolute; inset: 0; display: grid; place-items: center; font-weight: 800; color: var(--muted); }
.ad-dur {
  position: absolute; left: 6px; bottom: 6px; padding: 1px 6px; border-radius: 9px; font-size: 11.5px; font-weight: 600;
  background: rgba(0, 0, 0, .55); color: #fff; pointer-events: none;
}
.ad-check {
  position: absolute; top: 6px; right: 6px; width: 26px; height: 26px; min-width: 0; min-height: 0; padding: 0 !important;
  border-radius: 50% !important; border: 2px solid #fff !important; background: rgba(0, 0, 0, .22) !important;
  color: var(--on-accent); font-size: 13px; font-weight: 800; line-height: 1; display: grid; place-items: center;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .18), 0 1px 3px rgba(0, 0, 0, .35) !important;
}
.ad-check[aria-pressed="true"] { background: var(--accent) !important; }

/* File list */
.ad-choose-row { width: calc(100% - 12px); margin: 4px 6px 6px; flex-direction: row; justify-content: flex-start; gap: 12px; padding: 14px 14px !important; border-radius: 12px !important; font-size: 15px; }
#ad-file-list { list-style: none; margin: 0; padding: 0 6px; }
.ad-file { position: relative; display: flex; align-items: center; gap: 12px; padding: 8px 44px 8px 6px; border-radius: 10px; cursor: pointer; }
.ad-file:hover { background: color-mix(in srgb, var(--text) 6%, transparent); }
.ad-file .ad-ext {
  flex: none; width: 46px; height: 46px; border-radius: 10px; display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent); font-size: 11.5px; font-weight: 800; letter-spacing: .02em;
}
.ad-file-text { min-width: 0; display: flex; flex-direction: column; }
.ad-file-text strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-file .ad-check { top: 50%; right: 10px; margin-top: -13px; border-color: color-mix(in srgb, var(--text) 45%, transparent) !important; background: transparent !important; }
.ad-file .ad-check[aria-pressed="true"] { background: var(--accent) !important; border-color: var(--accent) !important; }

/* Location */
.ad-loc { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 18px 18px 8px; gap: 6px; }
.ad-loc-pin { color: var(--accent); }
#ad-loc-text { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.45; max-width: 380px; }
#ad-loc-coords { margin: 6px 0 0; font-weight: 700; font-variant-numeric: tabular-nums; }
.ad-loc-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 8px; }
.ad-loc-actions button { border-radius: 999px; padding: 10px 18px; }
.loc-card { display: flex !important; align-items: center; gap: 10px; padding: 8px 10px; }
.loc-card .loc-pin { font-size: 26px; line-height: 1; }

/* Caption + Send (shows when something is selected) */
#ad-sendbar {
  flex: none; display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-top: 1px solid var(--line); background: var(--card);
}
#ad-sendbar-text { flex: 1; min-width: 0; color: var(--muted); font-size: 13.5px; }
#ad-send {
  position: relative; flex: none; width: 46px; height: 46px; min-width: 0; min-height: 0; padding: 0 !important;
  display: grid; place-items: center; border: 0; border-radius: 50% !important; background: var(--accent); color: var(--on-accent);
}
#ad-send-n {
  position: absolute; right: -3px; top: -3px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
  background: var(--text); color: var(--card); font-size: 12px; font-weight: 800; line-height: 20px; text-align: center;
  border: 2px solid var(--card);
}

/* Bottom tab bar */
#ad-tabs {
  flex: none; display: flex; justify-content: space-around; gap: 2px;
  padding: 6px 6px calc(6px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--text) 4%, var(--card));
}
#attach-sheet.ad-pop #ad-tabs { padding-bottom: 6px; }
#ad-tabs button {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 5px 2px 4px !important; border: 0 !important; border-radius: 14px !important; background: transparent !important;
  color: var(--muted); font-size: 12.5px; font-weight: 600; box-shadow: none !important;
}
#ad-tabs .ad-tab-ico { width: 52px; height: 30px; display: grid; place-items: center; border-radius: 15px; }
#ad-tabs button[aria-selected="true"] { color: var(--text); }
#ad-tabs button[aria-selected="true"] .ad-tab-ico { background: color-mix(in srgb, var(--accent) 26%, transparent); color: var(--accent); }
#ad-tabs button:hover .ad-tab-ico, #ad-tabs button:focus-visible .ad-tab-ico { background: color-mix(in srgb, var(--text) 10%, transparent); }

/* Full-screen camera */
#cam-view { position: fixed; inset: 0; z-index: 97; background: #000; color: #fff; display: block; }
#cam-video, #cam-shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000; }
#cam-shot { object-fit: contain; }
#cam-close {
  position: absolute; top: calc(10px + env(safe-area-inset-top)); left: 10px; width: 46px; height: 46px; min-width: 0; min-height: 0; padding: 0 !important;
  display: grid; place-items: center; border-radius: 50% !important; border: 0 !important; background: rgba(0, 0, 0, .4) !important; color: #fff;
}
#cam-note { position: absolute; left: 0; right: 0; top: 45%; margin: 0; text-align: center; font-size: 15px; color: #fff; text-shadow: 0 1px 3px #000; }
#cam-controls {
  position: absolute; left: 0; right: 0; bottom: 0; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: 18px 24px calc(26px + env(safe-area-inset-bottom)); background: linear-gradient(transparent, rgba(0, 0, 0, .5));
}
#cam-view.is-review #cam-controls { display: none; }
#cam-shutter {
  width: 74px; height: 74px; min-width: 0; min-height: 0; padding: 0 !important; border-radius: 50% !important;
  border: 5px solid #fff !important; background: rgba(255, 255, 255, .85) !important; box-shadow: 0 0 0 3px rgba(0, 0, 0, .25) !important;
}
#cam-shutter:active { background: #fff !important; transform: scale(.94); }
#cam-shutter:disabled { opacity: .5; }
#cam-flip {
  justify-self: end; width: 50px; height: 50px; min-width: 0; min-height: 0; padding: 0 !important;
  display: grid; place-items: center; border-radius: 50% !important; border: 0 !important; background: rgba(255, 255, 255, .18) !important; color: #fff;
}
#cam-review {
  position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: center; gap: 8px;
  padding: 12px 12px calc(14px + env(safe-area-inset-bottom)); background: rgba(0, 0, 0, .6);
}
#cam-retake { color: #fff; border-color: rgba(255, 255, 255, .5) !important; border-radius: 999px; padding: 10px 14px; }
#cam-review { justify-content: space-between; }
#cam-send {
  display: inline-flex; align-items: center; gap: 6px; padding: 10px 18px !important; border: 0; border-radius: 999px !important;
  background: var(--accent); color: var(--on-accent); font-weight: 700;
}
@media (prefers-reduced-motion: reduce) {
  #attach-sheet, #attach-sheet.ad-pop, #attach-scrim, .ad-item img, .ad-item video { transition: none !important; }
  #cam-shutter:active { transform: none; }
}

/* 0.21.05: attachment tray above the message bar (inside the composer, so its height just adds to it) */
#tray[hidden] { display: none !important; }
#tray {
  display: flex; gap: 8px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: thin;
  padding: 2px 4px 6px 54px; margin: 0;
}
.tray-item {
  position: relative; flex: none; width: 76px; height: 76px; border-radius: 12px; overflow: hidden;
  background: color-mix(in srgb, var(--text) 8%, var(--card)); border: 1px solid var(--line);
}
.tray-item img, .tray-item video { width: 100%; height: 100%; object-fit: cover; display: block; }
.tray-file { width: 196px; display: flex; align-items: center; gap: 10px; padding: 0 40px 0 10px; }
.tray-ext {
  flex: none; width: 42px; height: 42px; border-radius: 10px; display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent); font-size: 11px; font-weight: 800;
}
.tray-file-text { min-width: 0; display: flex; flex-direction: column; font-size: 12.5px; color: var(--muted); }
.tray-file-text strong { color: var(--text); font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tray-badge {
  position: absolute; left: 5px; bottom: 5px; padding: 1px 5px; border-radius: 8px; font-size: 10.5px; font-weight: 800;
  background: rgba(0, 0, 0, .6); color: #fff; pointer-events: none;
}
/* remove: a 44px tap target in the corner; the visible circle is smaller */
.tray-x {
  position: absolute; top: 0; right: 0; width: 44px; height: 44px; min-width: 0; min-height: 0; padding: 4px !important;
  display: flex; align-items: flex-start; justify-content: flex-end; border: 0 !important; border-radius: 0 !important;
  background: transparent !important; box-shadow: none !important; color: #fff; cursor: pointer;
}
.tray-x span {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 800; line-height: 1;
  background: rgba(0, 0, 0, .62); box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .85);
}
.tray-x:hover span, .tray-x:focus-visible span { background: var(--danger); }
.tray-x:disabled { display: none; }
/* 26.10.11: 720p / HD (original quality) chip on a video in the tray */
.tray-hq {
  position: absolute; left: 4px; top: 4px; min-height: 0; min-width: 0; padding: 1px 5px !important; border: 0 !important;
  border-radius: 8px !important; background: rgba(0, 0, 0, .6) !important; color: #fff; font-size: 10.5px; font-weight: 800; z-index: 2;
}
.tray-hq[aria-pressed="true"] { background: var(--accent) !important; color: var(--on-accent); }
.tray-item.is-uploading .tray-hq, .tray-item.is-failed .tray-hq:not(:focus) { opacity: .9; }
.tray-shade { position: absolute; inset: 0; display: none; place-items: center; background: rgba(0, 0, 0, .45); color: #fff; }
.tray-item.is-uploading .tray-shade { display: grid; }
.tray-ring { width: 40px; height: 40px; grid-area: 1 / 1; }
.tray-ring-bg { stroke: rgba(255, 255, 255, .3); }
.tray-ring-fg { stroke: #fff; stroke-linecap: round; transition: stroke-dashoffset .2s linear; }
.tray-pct { grid-area: 1 / 1; font-size: 10.5px; font-weight: 800; }
.tray-file .tray-shade { justify-items: start; padding-left: 11px; }
.tray-item.is-failed { border-color: var(--danger); }
.tray-retry {
  position: absolute; left: 4px; right: 4px; bottom: 4px; min-height: 0; padding: 4px 0 !important; border: 0 !important;
  border-radius: 8px !important; background: var(--danger) !important; color: #fff; font-size: 12px; font-weight: 700;
}
.tray-file .tray-retry { left: auto; right: 44px; top: 50%; bottom: auto; margin-top: -13px; padding: 4px 10px !important; }
@media (prefers-reduced-motion: reduce) { .tray-ring-fg { transition: none; } }

/* 0.21.07: camera controls (flash, brightness, zoom, tap to focus) and hold-to-record video */
#cam-stage { position: absolute; inset: 0; touch-action: none; }
#cam-note { pointer-events: none; padding: 0 16px; }
#cam-view.is-review #cam-note, #cam-view.is-rec #cam-note { top: calc(74px + env(safe-area-inset-top)); }
#cam-clip { position: absolute; left: 0; right: 0; top: 0; bottom: calc(72px + env(safe-area-inset-bottom)); width: 100%; height: calc(100% - 72px - env(safe-area-inset-bottom)); object-fit: contain; background: #000; }
#cam-view.is-review #cam-stage, #cam-view.is-review #cam-top, #cam-view.is-review #cam-ev, #cam-view.is-review #cam-timer, #cam-view.is-review #cam-focus { display: none !important; }

/* top right: flash and brightness */
#cam-top { position: absolute; top: calc(10px + env(safe-area-inset-top)); right: 10px; display: flex; gap: 8px; align-items: center; }
#cam-top button {
  height: 46px; min-width: 46px; min-height: 0; padding: 0 !important; display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  border-radius: 999px !important; border: 0 !important; background: rgba(0, 0, 0, .42) !important; color: #fff; box-shadow: none !important;
}
#cam-flash { padding: 0 14px 0 10px !important; font-size: 13.5px; font-weight: 700; }
#cam-flash[data-mode="on"], #cam-flash[data-mode="torch"] { color: #ffd54a; }
#cam-flash[data-mode="off"] { color: rgba(255, 255, 255, .82); }
#cam-ev-btn.is-set, #cam-ev-btn.is-on { color: #ffd54a; }
#cam-ev-btn.is-on { background: rgba(255, 213, 74, .22) !important; }

/* brightness slider */
#cam-ev {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: calc(168px + env(safe-area-inset-bottom)); width: min(380px, calc(100% - 32px));
  display: flex; align-items: center; gap: 10px; padding: 8px 10px 8px 14px; border-radius: 999px; background: rgba(0, 0, 0, .5); color: #ffd54a;
}
#cam-ev input[type="range"] { flex: 1; min-width: 0; height: 32px; margin: 0; accent-color: #ffd54a; background: transparent; }
#cam-ev-val {
  min-width: 52px; min-height: 0; height: 32px; padding: 0 8px !important; border: 0 !important; border-radius: 999px !important;
  background: rgba(255, 255, 255, .14) !important; color: #fff; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; box-shadow: none !important;
}

/* tap to focus */
#cam-focus {
  position: absolute; width: 74px; height: 74px; margin: -37px 0 0 -37px; border: 2px solid #ffd54a; border-radius: 14px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35); pointer-events: none;
}
#cam-focus.is-on { animation: cam-focus 1.4s ease-out forwards; }
@keyframes cam-focus { 0% { transform: scale(1.35); opacity: 0; } 15% { transform: scale(1); opacity: 1; } 75% { opacity: 1; } 100% { opacity: 0; } }

/* recording timer */
#cam-timer {
  position: absolute; top: calc(16px + env(safe-area-inset-top)); left: 50%; transform: translateX(-50%); display: none; align-items: center; gap: 7px;
  padding: 6px 12px; border-radius: 999px; background: rgba(0, 0, 0, .5); color: #fff; font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
}
#cam-timer-max { color: rgba(255, 255, 255, .7); font-weight: 600; }
.cam-dot { width: 10px; height: 10px; border-radius: 50%; background: #ff3b30; animation: cam-blink 1s steps(2, start) infinite; }
@keyframes cam-blink { to { visibility: hidden; } }
#cam-view.is-rec #cam-timer { display: flex; }

/* bottom row: zoom above the shutter, ring around it, hint under it */
#cam-controls { padding-top: 54px; }
#cam-zoom {
  position: absolute; left: 50%; top: 6px; transform: translateX(-50%); min-width: 44px; height: 38px; min-height: 0; padding: 0 10px !important;
  border: 0 !important; border-radius: 999px !important; background: rgba(0, 0, 0, .45) !important; color: #ffd54a; font-size: 13.5px; font-weight: 800;
  box-shadow: none !important; font-variant-numeric: tabular-nums;
}
#cam-shutter-wrap { position: relative; width: 96px; height: 96px; display: grid; place-items: center; }
#cam-ring { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0; transition: opacity .15s; }
.cam-ring-bg { stroke: rgba(255, 255, 255, .28); }
#cam-ring-fg { stroke: #ff3b30; stroke-linecap: round; transition: stroke-dashoffset .2s linear; }
#cam-shutter {
  position: relative; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  transition: transform .15s, background-color .15s;
}
#cam-shutter.is-down { transform: scale(.92); }
#cam-hint { grid-column: 1 / -1; margin: 6px 0 0; text-align: center; font-size: 13px; color: rgba(255, 255, 255, .85); text-shadow: 0 1px 2px #000; pointer-events: none; }
#cam-lock {
  position: absolute; left: 50%; bottom: calc(100% + 8px); display: none; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 7px 6px; border-radius: 999px; background: rgba(0, 0, 0, .45); color: #fff; pointer-events: none;
  transform: translate(-50%, calc(var(--cam-lock, 0) * -26px)); opacity: calc(.75 + var(--cam-lock, 0) * .25);
}
.cam-lock-up { animation: cam-up 1.2s ease-in-out infinite; }
@keyframes cam-up { 0%, 100% { transform: translateY(2px); opacity: .5; } 50% { transform: translateY(-3px); opacity: 1; } }

#cam-view.is-rec #cam-ring { opacity: 1; }
#cam-view.is-rec #cam-shutter { background: #ff3b30 !important; border-color: #fff !important; transform: scale(.9); }
#cam-view.is-rec:not(.is-locked) #cam-lock { display: flex; }
#cam-view.is-locked #cam-shutter { background: rgba(255, 255, 255, .9) !important; transform: none; }
#cam-view.is-locked #cam-shutter::after { content: ""; position: absolute; left: 50%; top: 50%; width: 24px; height: 24px; margin: -12px 0 0 -12px; border-radius: 5px; background: #ff3b30; }
#cam-view.is-rec #cam-top, #cam-view.is-rec #cam-flip, #cam-view.is-rec #cam-zoom, #cam-view.is-rec #cam-hint, #cam-view.is-rec #cam-ev { visibility: hidden; }
#cam-view.is-rec-starting #cam-shutter { animation: cam-pulse .6s ease-in-out infinite alternate; }
@keyframes cam-pulse { to { background-color: #ff8a80; } }

/* white screen flash for the front camera, and a quick blink when a photo is taken */
#cam-screen-flash { position: absolute; inset: 0; background: #fff; }
#cam-view.is-snap #cam-video { animation: cam-snap .3s ease-out; }
@keyframes cam-snap { 0% { opacity: .25; } 100% { opacity: 1; } }

#cam-lift {
  display: inline-flex; align-items: center; gap: 6px; color: #fff; border-color: rgba(255, 255, 255, .5) !important; border-radius: 999px; padding: 10px 14px;
}
#cam-lift[aria-pressed="true"] { color: #ffd54a; border-color: rgba(255, 213, 74, .7) !important; }

/* tray: photos and videos open in the viewer when tapped */
@media (prefers-reduced-motion: reduce) {
  #cam-focus.is-on, .cam-lock-up, #cam-view.is-snap #cam-video, #cam-view.is-rec-starting #cam-shutter, .cam-dot { animation: none !important; }
  #cam-shutter, #cam-ring, #cam-ring-fg { transition: none !important; }
}
/* 0.21.07: a full-size (invisible) button under the remove x opens the preview. It also gives a finger tap on the
   middle of the thumbnail a real target, so the browser's tap adjustment no longer snaps it to the remove x. */
.tray-open {
  position: absolute; inset: 0; width: 100%; height: 100%; min-width: 0; min-height: 0; margin: 0; padding: 0 !important;
  border: 0 !important; border-radius: 0 !important; background: transparent !important; box-shadow: none !important; cursor: zoom-in;
}
.tray-item.is-uploading .tray-open { pointer-events: none; }
/* the remove x keeps to its corner (34px target, above the 24px minimum) so the middle of the thumbnail is the preview */
.tray-x { width: 34px; height: 34px; padding: 3px !important; }

/* 0.21.07: change password: the rule is shown under New password, and the field with a problem is marked */
#pass-new-hint { margin: 4px 0 0; }
#password-fold input[aria-invalid="true"] { border-color: var(--danger); box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 35%, transparent); }

/* Chat-bar menu button: flat round like #search-btn / #chat-back (no resting ring).
   Phone media below keeps the ≥44px tap target; visibility is still decided by #chat-menu rules above. */
#chat-menu.burger-btn {
  width: 40px; height: 40px; min-width: 40px; min-height: 40px;
  padding: 0 !important; border-radius: 50% !important;
  background: transparent; border: 0; box-shadow: none !important;
  display: inline-grid; place-items: center;
}
#chat-menu.burger-btn:hover, #chat-menu.burger-btn:focus-visible, #chat-menu.burger-btn:active,
#chat-menu.burger-btn[aria-expanded="true"] {
  background: color-mix(in srgb, var(--text) 10%, transparent);
}

/* design/header-overflow-menu: ⋯ chat options (Telegram-style flat list).
   One flat list — no box/card per row; hover/focus highlight only.
   Line SVG icons (stroke); phone rows ≥44px; destructive rows use --danger. */
#chat-overflow[hidden] { display: none !important; }
#chat-overflow {
  position: fixed; z-index: 26;
  min-width: 220px; width: min(280px, calc(100vw - 16px));
  max-height: min(70dvh, 480px); overflow: auto;
  background: var(--card); color: var(--text);
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 6px 0;
  display: flex; flex-direction: column; gap: 0;
}
#chat-overflow .chat-ov-item {
  display: flex; align-items: center; gap: 14px;
  width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: 0 !important; border-radius: 0;
  padding: 11px 16px; color: var(--text);
  min-height: 44px; font: inherit;
  box-shadow: none !important;
  outline: none;
  -webkit-appearance: none; appearance: none;
}
#chat-overflow .chat-ov-item:hover,
#chat-overflow .chat-ov-item:focus-visible {
  background: color-mix(in srgb, var(--text) 8%, transparent);
  outline: none; border: 0 !important; box-shadow: none !important;
}
#chat-overflow .chat-ov-item.chat-ov-danger { color: var(--danger); }
#chat-overflow .chat-ov-item.chat-ov-danger:hover,
#chat-overflow .chat-ov-item.chat-ov-danger:focus-visible {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}
#chat-overflow .chat-ov-ico {
  flex: none; width: 22px; height: 22px; display: inline-grid; place-items: center;
  color: inherit; opacity: .92;
}
#chat-overflow .chat-ov-ico svg { width: 22px; height: 22px; display: block; }
#chat-overflow .chat-ov-label { flex: 1 1 auto; min-width: 0; line-height: 1.25; }
#chat-overflow .chat-ov-check {
  flex: none; font-size: 14px; opacity: .85; min-width: 1.1em; text-align: right;
}
/* Spacing only — no divider line (flat list in light and dark).
   Kill UA <hr> inset borders that otherwise show as boxed edges in light mode. */
#chat-overflow .chat-ov-sep {
  display: block; height: 8px; margin: 0; padding: 0; flex: none;
  background: transparent !important; background-color: transparent !important;
  border: 0 !important; border-width: 0 !important; border-style: none !important;
  outline: none; box-shadow: none; color: transparent; overflow: hidden;
}
#chat-overflow-hosts { position: absolute; width: 0; height: 0; overflow: hidden; clip: rect(0,0,0,0); }


/* 0.21.08: GIF infinite scroll: loading spinner, end note and Retry under the GIF grid */
#gif-more { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 40px; padding: 6px 0 4px; color: var(--muted); font-size: .85em; }
#gif-more[data-state=""] { min-height: 24px; padding: 0; }
#gif-more .gif-spin { display: none; flex: none; width: 18px; height: 18px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; animation: gif-spin .8s linear infinite; }
#gif-more[data-state="loading"] .gif-spin { display: inline-block; }
#gif-more .gif-retry { display: none; border-radius: 14px; padding: 4px 14px; font-size: inherit; color: var(--text); }
#gif-more[data-state="error"] { color: var(--danger); }
#gif-more[data-state="error"] .gif-retry { display: inline-block; }
@keyframes gif-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { #gif-more .gif-spin { animation-duration: 2.4s; } }
#gif-grid button.gif-broken { background: var(--line); }
#gif-grid button.gif-broken img { visibility: hidden; }

/* 0.21.08.1: composer jitter fix. Hidden copy of the message box that app.js measures instead of collapsing the real box.
   Fixed and off-screen, so it never takes part in the page layout and cannot move the messages. */
.grow-mirror {
  position: fixed !important; left: -10000px !important; top: 0 !important; z-index: -1; visibility: hidden; pointer-events: none;
  height: 0 !important; min-height: 0 !important; max-height: none !important; overflow: hidden !important; resize: none;
  margin: 0 !important; border-style: solid; border-color: transparent; background: none !important; box-shadow: none !important;
}
/* 0.21.08.1: profile pictures no longer carry a lock badge (one lock, next to the name). */
.pfp-lock { display: none !important; }
/* 0.21.08.1: emoji/GIF search with the keyboard up: the panel fills the space above the keyboard (many rows, still
   infinite scroll). The messages and the message bar are hidden only while this lasts; the chat header stays. */
html.picker-tall #log, html.picker-tall #composer { display: none !important; }
html.picker-tall #picker { flex: 1 1 auto !important; height: auto !important; min-height: 0; }
/* 0.21.08.2: more room between the profile picture and the lock + name in the chat header (was 6px, against the
   picture's glow ring). The Lobby picture on the home list also loses its lock badge, like every other picture (0.21.08.1). */
#thread-pic { margin-right: 8px; }
#lobby-led svg { display: none !important; }

/* 0.22.0 frosted-glass bubbles: the palette colour as a translucent tint over a blurred background, thin light edge,
   soft shadow. Higher opacity on light themes so the text stays readable. Not on jumbo emoji or removed messages. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
#log .msg:not(.removed) .bubble:not(.jumbo){-webkit-backdrop-filter:blur(12px) saturate(140%);backdrop-filter:blur(12px) saturate(140%);box-shadow:inset 0 0 0 1px rgba(255,255,255,.18),0 4px 14px rgba(0,0,0,.24)}
#log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--mine) 62%,transparent)}
#log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 64%,transparent)}
html[data-scheme="light"] #log .msg:not(.removed) .bubble:not(.jumbo){box-shadow:inset 0 0 0 1px rgba(255,255,255,.4),0 3px 12px rgba(0,0,0,.12)}
html[data-scheme="light"] #log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--mine) 78%,transparent)}
html[data-scheme="light"] #log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 74%,transparent)}
}
/* 0.22.0 jumbo emoji: 1-3 emoji only -> no bubble, emoji at 5x the message size; time stays small underneath */
#log .msg .bubble.jumbo{background:transparent!important;border:0!important;box-shadow:none!important;padding:0 2px 18px!important;min-width:0!important;font-size:500%;line-height:1.08;color:var(--text);white-space:pre;overflow-wrap:normal;letter-spacing:.02em}
#log .msg .bubble.jumbo .time{position:absolute;right:2px;bottom:0;font-size:11px;line-height:16px;letter-spacing:0;color:var(--muted);opacity:.95}
#log .msg .bubble.jumbo .edited{font-size:11px;line-height:1.2;letter-spacing:0;color:var(--muted)}
#log .msg.jumbo-row .reactions{margin-top:2px}

/* ===== 0.22.1: Copy / Forward in the message menu, "Copied" toast, forward picker, Forwarded label ===== */
#react-reply, #react-copy, #react-forward {
  display: block; width: 100%; margin-top: 6px; text-align: left; color: var(--text);
  background: transparent; border: 0; border-radius: 8px; padding: 8px;
}
#react-reply[hidden], #react-copy[hidden], #react-forward[hidden], #toast[hidden] { display: none; }
#toast {
  position: fixed; left: 50%; bottom: calc(88px + env(safe-area-inset-bottom, 0px)); z-index: 2147483000;
  transform: translate(-50%, 8px); opacity: 0; pointer-events: none;
  background: color-mix(in srgb, var(--text) 88%, transparent); color: var(--bg, #111);
  padding: 8px 16px; border-radius: 999px; font-size: .95rem; box-shadow: 0 4px 18px rgba(0,0,0,.28);
  transition: opacity .18s ease, transform .18s ease;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }
.copy-scratch { position: fixed; top: 0; left: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
#fwd-dialog { width: min(420px, calc(100vw - 32px)); }
#fwd-preview { margin: 0 0 10px; word-break: break-word; }
#fwd-list { max-height: min(50vh, 360px); overflow-y: auto; display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; }
.fwd-row { display: flex; align-items: center; gap: 10px; padding: 10px 8px; border-radius: 8px; cursor: pointer; }
.fwd-row:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.fwd-row input { width: 20px; height: 20px; margin: 0; flex: none; }
.bubble .fwd-label { font-size: .78em; font-style: italic; opacity: .72; margin-bottom: 2px; }
.bubble.jumbo .fwd-label { font-size: 15px; }
/* 0.22.1: clearer glass bubbles (feedback: not transparent enough). Lower tint alpha, lighter blur so the chat background
   shows through; same blue (own) / grey (others) tints; a faint text shadow keeps text readable over busy wallpaper. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
#log .msg:not(.removed) .bubble:not(.jumbo){-webkit-backdrop-filter:blur(7px) saturate(150%);backdrop-filter:blur(7px) saturate(150%);text-shadow:0 1px 2px rgba(0,0,0,.35)}
#log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--mine) 40%,transparent)}
#log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 42%,transparent)}
html[data-scheme="light"] #log .msg:not(.removed) .bubble:not(.jumbo){text-shadow:0 0 2px rgba(255,255,255,.45)}
html[data-scheme="light"] #log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,color-mix(in srgb,var(--mine) 55%,#0a2340) 64%,transparent);text-shadow:0 1px 2px rgba(0,0,0,.45)} /* deeper blue, so white text stays readable on the lighter light-theme background */
html[data-scheme="light"] #log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 52%,transparent)}
}
/* 0.22.1: shared mirror for delete characters on others' messages (see showFigure in app.js) */
.snap-stage.snap-mirror { transform: scaleX(-1); }
/* 0.22.1-beta.2: Aero glass bubbles (feedback: ~50% more see-through, "think Windows Vista Aero", subtle shine).
   Layers: the bubble keeps only the low-alpha tint (its background, which the burst pieces copy), the blur and the
   outer shadow. The gloss and the thin bright edge are a ::before at z-index -1 inside the bubble's own stacking
   context (isolation: isolate), so they always sit BELOW the text and never cover it. Overrides the rules above. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
#log .msg:not(.removed) .bubble:not(.jumbo){
  isolation:isolate;
  -webkit-backdrop-filter:blur(9px) saturate(160%);backdrop-filter:blur(9px) saturate(160%);
  box-shadow:0 0 0 1px rgba(0,0,0,.14),0 4px 14px rgba(0,0,0,.26);
  text-shadow:0 1px 2px rgba(0,0,0,.6),0 0 1px rgba(0,0,0,.45)}
#log .msg:not(.removed) .bubble:not(.jumbo)::before{
  content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none;
  background:linear-gradient(to bottom,rgba(255,255,255,.10),rgba(255,255,255,.035) 42%,rgba(255,255,255,0) 62%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.26),inset 0 1px 0 rgba(255,255,255,.3)}
#log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--mine) 20%,transparent)}
#log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 21%,transparent)}
html[data-scheme="light"] #log .msg:not(.removed) .bubble:not(.jumbo){box-shadow:0 0 0 1px rgba(0,0,0,.08),0 3px 12px rgba(0,0,0,.16)}
html[data-scheme="light"] #log .msg:not(.removed) .bubble:not(.jumbo)::before{background:linear-gradient(to bottom,rgba(255,255,255,.12),rgba(255,255,255,.04) 42%,rgba(255,255,255,0) 62%);box-shadow:inset 0 0 0 1px rgba(255,255,255,.32),inset 0 1px 0 rgba(255,255,255,.35)}
html[data-scheme="light"] #log .msg.other:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,var(--other) 26%,transparent);text-shadow:0 0 3px rgba(255,255,255,.85),0 0 1px rgba(255,255,255,.9)}
html[data-scheme="light"] #log .msg.mine:not(.removed) .bubble:not(.jumbo){background:color-mix(in srgb,color-mix(in srgb,var(--mine) 55%,#0a2340) 32%,transparent);text-shadow:0 1px 2px rgba(0,0,0,.7),0 0 4px rgba(0,0,0,.45)}
}
/* ===== Woodland delete characters (bunny, owl, badger, turtle). Vector art, transform-only motion, no frame swaps.
   On someone else's message the whole stage is mirrored by the shared .snap-stage.snap-mirror (0.22.1), so these
   left-facing motions (hop in from the left, hop off to the left) mirror with it. ===== */
.snap-stage .snap-figure.wd{--wd-dir:1}
.snap-stage .snap-figure.wd{animation:wd-hopin 1s cubic-bezier(.3,.7,.4,1) both!important}
.snap-stage .snap-figure.wd.snap-out{animation:wd-hopout 1.05s cubic-bezier(.5,0,.75,0) forwards!important}
@keyframes wd-hopin{0%{opacity:0;transform:translate(calc(var(--wd-dir) * -64px),0)}12%{opacity:1}25%{transform:translate(calc(var(--wd-dir) * -44px),-16px)}50%{transform:translate(calc(var(--wd-dir) * -22px),0)}75%{transform:translate(calc(var(--wd-dir) * -8px),-9px)}100%{opacity:1;transform:none}}
@keyframes wd-hopout{0%{transform:none}25%{transform:translate(calc(var(--wd-dir) * -14px),-10px)}50%{transform:translate(calc(var(--wd-dir) * -30px),0)}75%{transform:translate(calc(var(--wd-dir) * -50px),-14px)}100%{opacity:0;transform:translate(calc(var(--wd-dir) * -80px),0)}}
@media (prefers-reduced-motion: reduce){.snap-stage .snap-figure.wd,.snap-stage .snap-figure.wd *{animation:none!important}}
/* 0.22.2 fix (Oct 16): on glass bubbles your own text is always white (themes like the green one set dark
   --mine-text for a solid bright bubble, which turned black and unreadable on the see-through glass), and your own
   bubble is more see-through (dark 20% -> 12% tint, light 32% -> 26%). Shine stays on the ::before under the text. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
#log .msg.mine:not(.removed) .bubble:not(.jumbo){color:#fff;background:color-mix(in srgb,var(--mine) 12%,transparent)}
html[data-scheme="light"] #log .msg.mine:not(.removed) .bubble:not(.jumbo){color:#fff;background:color-mix(in srgb,color-mix(in srgb,var(--mine) 55%,#0a2340) 26%,transparent);text-shadow:0 1px 2px rgba(0,0,0,.8),0 0 5px rgba(0,0,0,.55)}
}

/* 0.22.3: eight more themes (feedback: "we need more variety in the themes"). Original palettes, light and dark. */
html[data-palette="forest"][data-scheme="dark"] {
  --bg: #0f1a14; --card: #17251d; --line: #2a3f31; --text: #eef5ef; --muted: #a9bfae;
  --mine: #2f7d4f; --mine-text: #fff; --other: #22332a; --other-text: #eef5ef;
  --accent: #8fd19e; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #1d2e24;
}
html[data-palette="forest"][data-scheme="light"] {
  --bg: #eef4ee; --card: #ffffff; --line: #cfdfd2; --text: #1b2a20; --muted: #56685b;
  --mine: #2f7d4f; --mine-text: #fff; --other: #e2ece3; --other-text: #1b2a20;
  --accent: #24683f; --on-accent: #fff; --danger: #b42318; --pill: #e2ece3;
}
html[data-palette="ocean"][data-scheme="dark"] {
  --bg: #0a1620; --card: #10212e; --line: #1f3a4d; --text: #e8f4fb; --muted: #9cb8c9;
  --mine: #137a9e; --mine-text: #fff; --other: #17303f; --other-text: #e8f4fb;
  --accent: #5fd0f0; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #15293a;
}
html[data-palette="ocean"][data-scheme="light"] {
  --bg: #e9f4f9; --card: #ffffff; --line: #c8e0ec; --text: #10283a; --muted: #4d6b7e;
  --mine: #137a9e; --mine-text: #fff; --other: #dcecf4; --other-text: #10283a;
  --accent: #0b5f80; --on-accent: #fff; --danger: #b42318; --pill: #dcecf4;
}
html[data-palette="sunset"][data-scheme="dark"] {
  --bg: #1a1016; --card: #251720; --line: #45293a; --text: #fbeff3; --muted: #d0aab9;
  --mine: #d4573b; --mine-text: #fff; --other: #35212d; --other-text: #fbeff3;
  --accent: #ffb36b; --on-accent: #0b0d12; --danger: #ff6b8a; --pill: #2e1c27;
}
html[data-palette="sunset"][data-scheme="light"] {
  --bg: #fdf1ea; --card: #ffffff; --line: #f1d6c8; --text: #3a1f1a; --muted: #7a5a50;
  --mine: #d4573b; --mine-text: #fff; --other: #f6e2d8; --other-text: #3a1f1a;
  --accent: #b5452a; --on-accent: #fff; --danger: #b42318; --pill: #f6e2d8;
}
html[data-palette="lavender"][data-scheme="dark"] {
  --bg: #14111d; --card: #1e1a2b; --line: #363050; --text: #f3f0fb; --muted: #b6aed0;
  --mine: #7b5cd6; --mine-text: #fff; --other: #2a2540; --other-text: #f3f0fb;
  --accent: #c4b1ff; --on-accent: #0b0d12; --danger: #ff6b8a; --pill: #241f37;
}
html[data-palette="lavender"][data-scheme="light"] {
  --bg: #f4f1fb; --card: #ffffff; --line: #ddd5f0; --text: #241d3a; --muted: #625a7c;
  --mine: #7b5cd6; --mine-text: #fff; --other: #e9e3f6; --other-text: #241d3a;
  --accent: #5a3fb8; --on-accent: #fff; --danger: #b42318; --pill: #e9e3f6;
}
html[data-palette="ember"][data-scheme="dark"] {
  --bg: #171210; --card: #221a16; --line: #3e2f27; --text: #f8efe9; --muted: #c8b3a5;
  --mine: #c2410c; --mine-text: #fff; --other: #2f2420; --other-text: #f8efe9;
  --accent: #ff9f43; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #2a201b;
}
html[data-palette="ember"][data-scheme="light"] {
  --bg: #faf3ee; --card: #ffffff; --line: #ead9cc; --text: #2e1f16; --muted: #6e5848;
  --mine: #c2410c; --mine-text: #fff; --other: #f2e5db; --other-text: #2e1f16;
  --accent: #9a3412; --on-accent: #fff; --danger: #b42318; --pill: #f2e5db;
}
html[data-palette="midnight"][data-scheme="dark"] {
  --bg: #07080f; --card: #0f1120; --line: #22263f; --text: #e9ebfa; --muted: #9da2c4;
  --mine: #3b4fd8; --mine-text: #fff; --other: #191c33; --other-text: #e9ebfa;
  --accent: #8a9bff; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #141730;
}
html[data-palette="midnight"][data-scheme="light"] {
  --bg: #eef0fa; --card: #ffffff; --line: #d3d7ef; --text: #151a3a; --muted: #545a80;
  --mine: #3b4fd8; --mine-text: #fff; --other: #e1e4f5; --other-text: #151a3a;
  --accent: #2c3ab0; --on-accent: #fff; --danger: #b42318; --pill: #e1e4f5;
}
html[data-palette="rose"][data-scheme="dark"] {
  --bg: #1a0f14; --card: #26161e; --line: #452836; --text: #fbeef3; --muted: #d2a9ba;
  --mine: #c2416c; --mine-text: #fff; --other: #36202b; --other-text: #fbeef3;
  --accent: #ff8fb3; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #2f1b25;
}
html[data-palette="rose"][data-scheme="light"] {
  --bg: #fcf0f4; --card: #ffffff; --line: #f0d3de; --text: #3a1726; --muted: #7a5263;
  --mine: #c2416c; --mine-text: #fff; --other: #f6e1e9; --other-text: #3a1726;
  --accent: #a3305a; --on-accent: #fff; --danger: #b42318; --pill: #f6e1e9;
}
html[data-palette="mint"][data-scheme="dark"] {
  --bg: #0c1716; --card: #132321; --line: #26403c; --text: #eaf8f5; --muted: #a1c4bd;
  --mine: #0f8f7a; --mine-text: #fff; --other: #1b302d; --other-text: #eaf8f5;
  --accent: #6ee7c8; --on-accent: #0b0d12; --danger: #ff6b6b; --pill: #172b28;
}
html[data-palette="mint"][data-scheme="light"] {
  --bg: #ecf8f5; --card: #ffffff; --line: #cbe8e0; --text: #12302a; --muted: #4c6e66;
  --mine: #0f8f7a; --mine-text: #fff; --other: #dcf0ea; --other-text: #12302a;
  --accent: #0b6e5e; --on-accent: #fff; --danger: #b42318; --pill: #dcf0ea;
}
html[data-scheme="dark"] [data-palette="forest"] .swatches i:nth-child(1) { background: #0f1a14; }
html[data-scheme="dark"] [data-palette="forest"] .swatches i:nth-child(2) { background: #2f7d4f; }
html[data-scheme="dark"] [data-palette="forest"] .swatches i:nth-child(3) { background: #8fd19e; }
html[data-scheme="light"] [data-palette="forest"] .swatches i:nth-child(1) { background: #eef4ee; }
html[data-scheme="light"] [data-palette="forest"] .swatches i:nth-child(2) { background: #2f7d4f; }
html[data-scheme="light"] [data-palette="forest"] .swatches i:nth-child(3) { background: #24683f; }
html[data-scheme="dark"] [data-palette="ocean"] .swatches i:nth-child(1) { background: #0a1620; }
html[data-scheme="dark"] [data-palette="ocean"] .swatches i:nth-child(2) { background: #137a9e; }
html[data-scheme="dark"] [data-palette="ocean"] .swatches i:nth-child(3) { background: #5fd0f0; }
html[data-scheme="light"] [data-palette="ocean"] .swatches i:nth-child(1) { background: #e9f4f9; }
html[data-scheme="light"] [data-palette="ocean"] .swatches i:nth-child(2) { background: #137a9e; }
html[data-scheme="light"] [data-palette="ocean"] .swatches i:nth-child(3) { background: #0b5f80; }
html[data-scheme="dark"] [data-palette="sunset"] .swatches i:nth-child(1) { background: #1a1016; }
html[data-scheme="dark"] [data-palette="sunset"] .swatches i:nth-child(2) { background: #d4573b; }
html[data-scheme="dark"] [data-palette="sunset"] .swatches i:nth-child(3) { background: #ffb36b; }
html[data-scheme="light"] [data-palette="sunset"] .swatches i:nth-child(1) { background: #fdf1ea; }
html[data-scheme="light"] [data-palette="sunset"] .swatches i:nth-child(2) { background: #d4573b; }
html[data-scheme="light"] [data-palette="sunset"] .swatches i:nth-child(3) { background: #b5452a; }
html[data-scheme="dark"] [data-palette="lavender"] .swatches i:nth-child(1) { background: #14111d; }
html[data-scheme="dark"] [data-palette="lavender"] .swatches i:nth-child(2) { background: #7b5cd6; }
html[data-scheme="dark"] [data-palette="lavender"] .swatches i:nth-child(3) { background: #c4b1ff; }
html[data-scheme="light"] [data-palette="lavender"] .swatches i:nth-child(1) { background: #f4f1fb; }
html[data-scheme="light"] [data-palette="lavender"] .swatches i:nth-child(2) { background: #7b5cd6; }
html[data-scheme="light"] [data-palette="lavender"] .swatches i:nth-child(3) { background: #5a3fb8; }
html[data-scheme="dark"] [data-palette="ember"] .swatches i:nth-child(1) { background: #171210; }
html[data-scheme="dark"] [data-palette="ember"] .swatches i:nth-child(2) { background: #c2410c; }
html[data-scheme="dark"] [data-palette="ember"] .swatches i:nth-child(3) { background: #ff9f43; }
html[data-scheme="light"] [data-palette="ember"] .swatches i:nth-child(1) { background: #faf3ee; }
html[data-scheme="light"] [data-palette="ember"] .swatches i:nth-child(2) { background: #c2410c; }
html[data-scheme="light"] [data-palette="ember"] .swatches i:nth-child(3) { background: #9a3412; }
html[data-scheme="dark"] [data-palette="midnight"] .swatches i:nth-child(1) { background: #07080f; }
html[data-scheme="dark"] [data-palette="midnight"] .swatches i:nth-child(2) { background: #3b4fd8; }
html[data-scheme="dark"] [data-palette="midnight"] .swatches i:nth-child(3) { background: #8a9bff; }
html[data-scheme="light"] [data-palette="midnight"] .swatches i:nth-child(1) { background: #eef0fa; }
html[data-scheme="light"] [data-palette="midnight"] .swatches i:nth-child(2) { background: #3b4fd8; }
html[data-scheme="light"] [data-palette="midnight"] .swatches i:nth-child(3) { background: #2c3ab0; }
html[data-scheme="dark"] [data-palette="rose"] .swatches i:nth-child(1) { background: #1a0f14; }
html[data-scheme="dark"] [data-palette="rose"] .swatches i:nth-child(2) { background: #c2416c; }
html[data-scheme="dark"] [data-palette="rose"] .swatches i:nth-child(3) { background: #ff8fb3; }
html[data-scheme="light"] [data-palette="rose"] .swatches i:nth-child(1) { background: #fcf0f4; }
html[data-scheme="light"] [data-palette="rose"] .swatches i:nth-child(2) { background: #c2416c; }
html[data-scheme="light"] [data-palette="rose"] .swatches i:nth-child(3) { background: #a3305a; }
html[data-scheme="dark"] [data-palette="mint"] .swatches i:nth-child(1) { background: #0c1716; }
html[data-scheme="dark"] [data-palette="mint"] .swatches i:nth-child(2) { background: #0f8f7a; }
html[data-scheme="dark"] [data-palette="mint"] .swatches i:nth-child(3) { background: #6ee7c8; }
html[data-scheme="light"] [data-palette="mint"] .swatches i:nth-child(1) { background: #ecf8f5; }
html[data-scheme="light"] [data-palette="mint"] .swatches i:nth-child(2) { background: #0f8f7a; }
html[data-scheme="light"] [data-palette="mint"] .swatches i:nth-child(3) { background: #0b6e5e; }
/* 0.22.3: per-chat theme note and "Use for all chats" */
.palette-scope{margin:6px 2px 4px;font-size:.82em;color:var(--muted);text-align:right}
.palette-all{display:block;margin:0 0 6px auto}
.palette-all[hidden]{display:none}

/* 0.22.3-beta.3 (Oct 16: "background so blurred out", bubbles not see-through on his phone). The blur was
   stacked three times (wallpaper 6px, chat panel 5px, each bubble 9px) under a tinted panel, so everything went to
   mush and the bubbles looked solid. The main cause was the page wallpaper itself: a small, pre-blurred 960x540
   copy stretched to phone height. Now: the sharp 1280x720 wallpaper, wallpaper only slightly soft, no blur or heavy tint on the chat panel,
   and a light 3px blur on bubbles, so the background stays clear through them. */
body::before, html[data-scheme="light"] body::before { background-image: url("/static/forest-bg.webp?v=26.11.1007-763b3d5b"); filter: none; opacity: 1; }
html[data-scheme="dark"] body::before { filter: brightness(.85); }
main, html[data-scheme="light"] main { background: color-mix(in srgb, var(--card) 14%, transparent); backdrop-filter: none; -webkit-backdrop-filter: none; }
#chat-bg { opacity: .75; }
#chat-bg::after { background: color-mix(in srgb, var(--bg) 22%, transparent); }
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
#log .msg:not(.removed) .bubble:not(.jumbo){-webkit-backdrop-filter:blur(3px) saturate(140%);backdrop-filter:blur(3px) saturate(140%)}
}
/* 0.22.3-beta.4 (feedback: on phones we can't see the tent or the campfire; "zoom out", extending the picture is OK as long
   as the original scene stays). Phones in portrait use forest-tall.webp: the original 1280x720 picture, untouched, with
   generated canopy above and stream/ferns below blended in. Being taller, it's shown smaller, so the whole camp fits.
   Keeps the keyboard-steady sizing from 0.21.04 (height pinned to --wall-h). */
@media (max-aspect-ratio: 1/1) {
  html body::before, html[data-scheme] body::before {
    background-image: url("/static/forest-tall.webp?v=26.11.1007-763b3d5b");
    background-size: auto max(var(--wall-h), calc((100vw + 80px) * 1.34375));
    background-position: 96% 0;
  }
}

/* 0.22.4: the "Edited" tag style (small, dimmed) was also landing on the whole message row, because the row gets
   class "edited" too, so edited messages looked different. Only the tag is styled now. */
.msg.edited { display: flex; margin-top: 0; font-size: inherit; opacity: 1; }
.bubble > span.edited { display: block; margin-top: 4px; font-size: 11px; opacity: .75; }
/* 0.22.4: video preview card (poster frame, play button, length); tap opens the player as before. */
.video-card { position: relative; display: block; padding: 0; margin: 0; border: 0; background: #000; border-radius: 12px; overflow: hidden; cursor: pointer; max-width: 100%; line-height: 0; }
.video-card .video-poster { display: block; width: auto; max-width: min(100%, 300px); max-height: 240px; min-width: 160px; min-height: 100px; object-fit: cover; border-radius: 12px; pointer-events: none; }
.video-card .video-wait { width: 220px; height: 124px; display: flex; align-items: center; justify-content: center; color: #ddd; font-size: 13px; line-height: 1.2; background: rgba(0,0,0,.45); }
.video-card .video-play { position: absolute; left: 50%; top: 50%; width: 48px; height: 48px; margin: -24px 0 0 -24px; border-radius: 50%; background: rgba(0,0,0,.55); box-shadow: 0 0 0 2px rgba(255,255,255,.85); }
.video-card .video-play::after { content: ""; position: absolute; left: 19px; top: 14px; border-style: solid; border-width: 10px 0 10px 16px; border-color: transparent transparent transparent #fff; }
.video-card .video-dur { position: absolute; right: 6px; bottom: 6px; padding: 2px 6px; border-radius: 6px; background: rgba(0,0,0,.6); color: #fff; font-size: 11px; line-height: 1.3; }
/* 0.22.4: picture viewer buttons. The close X was a small, faint glass circle that disappeared against the dark
   backdrop (and could sit under a phone's status bar), and Download was hidden for pictures. Both are now clear,
   solid round buttons in the top-right corner, below the phone's safe area. */
#lightbox.is-image > .x-close, #lightbox.is-image #light-download {
  position: fixed; z-index: 5; top: calc(env(safe-area-inset-top, 0px) + 14px); width: 44px; height: 44px;
  display: grid; place-items: center; border-radius: 50% !important; padding: 0 !important; opacity: 1;
  color: #fff !important; background: rgba(20,20,20,.72) !important; border: 2px solid rgba(255,255,255,.9) !important;
  box-shadow: 0 2px 10px rgba(0,0,0,.6) !important; backdrop-filter: none; -webkit-backdrop-filter: none;
}
#lightbox.is-image > .x-close { right: calc(env(safe-area-inset-right, 0px) + 14px); }
#lightbox.is-image > .x-close svg { width: 16px; height: 16px; }
#lightbox.is-image .actions { display: contents !important; }
#lightbox.is-image .actions > :not(#light-download) { display: none !important; }
#lightbox.is-image #light-download[hidden] { display: none !important; }
#lightbox.is-image #light-download { right: calc(env(safe-area-inset-right, 0px) + 68px); font-size: 0; text-decoration: none; }
#lightbox.is-image #light-download::before {
  content: ""; width: 20px; height: 20px; background: #fff;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3v12m0 0l-5-5m5 5l5-5M4 20h16' stroke='black' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3v12m0 0l-5-5m5 5l5-5M4 20h16' stroke='black' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* 0.22.4: Download in the message menu, styled like Edit. */
#react-download { display: block; width: 100%; margin-top: 6px; text-align: left; background: transparent; border: 0; border-radius: 8px; padding: 8px; color: var(--text); }
#react-download[hidden] { display: none !important; }

/* 0.22.6: real file inputs stay in the page (not display:none) so iPhone browsers open the picker from the label tap */
.pick-input { position: absolute !important; width: 1px; height: 1px; opacity: 0; overflow: hidden; clip: rect(0 0 0 0); pointer-events: none; left: 0; top: 0; }
label.ad-choose { cursor: pointer; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent; }
label.ad-choose:active { filter: brightness(.95); }
.ad-pick-note { margin: 6px 10px; color: var(--text); opacity: .85; font-size: 13px; }
/* ---- 0.23.0-beta.1: group chats ---- */
#new-group { display: flex; align-items: center; gap: 10px; width: auto; margin: 6px 0 2px; padding: 8px 10px; cursor: pointer;
  background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 38%, transparent);
  color: var(--text); font-weight: 600; text-align: left; }
#new-group:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
#new-group .ng-icon { width: 30px; height: 30px; flex: none; border-radius: 50%; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); }
html.side-collapsed #new-group { justify-content: center; padding: 8px 0; }
html.side-collapsed #new-group .ng-text { display: none; }
.pfp.gpic { display: inline-grid; place-items: center; font-weight: 700; font-size: 15px; letter-spacing: .02em; color: #fff;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 85%, #fff 0%), color-mix(in srgb, var(--accent) 55%, #1a2030));
  text-shadow: 0 1px 2px rgba(0,0,0,.45); user-select: none; }
.chat-row .pfp.gpic { font-size: 16px; }
#thread-pic .pfp.gpic { width: 36px; height: 36px; font-size: 14px; }
.gevent { align-self: center; max-width: 86%; text-align: center; margin: 4px 0; padding: 3px 12px; border-radius: 999px; font-size: 13px;
  background: var(--pill); color: var(--muted); box-shadow: 0 2px 8px rgba(0,0,0,.35); }
html[data-scheme="dark"] .gevent { color: color-mix(in srgb, var(--accent) 40%, #f2f5fa); text-shadow: 0 1px 3px rgba(0,0,0,.6); }
html[data-scheme="light"] .gevent { color: color-mix(in srgb, var(--accent) 50%, #1a2030); box-shadow: 0 2px 8px rgba(0,0,0,.18); }
#group-dialog, #ginfo-dialog { width: min(440px, calc(100vw - 32px)); }
#group-name { width: 100%; box-sizing: border-box; }
.group-lead { margin: 12px 0 6px; }
.group-list { max-height: min(42vh, 340px); overflow-y: auto; display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; }
.group-list .fwd-row .pfp { width: 28px; height: 28px; }
.ginfo-row { display: flex; align-items: center; gap: 10px; padding: 8px 6px; border-radius: 8px; }
.ginfo-row .pfp { width: 30px; height: 30px; }
.ginfo-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.role-chip { font-size: 12px; padding: 1px 8px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--text); }
.ginfo-remove { margin-left: auto; padding: 4px 10px; font-size: 13px; }
#ginfo-add-box[hidden] { display: none; }
#ginfo-add-go { margin-bottom: 6px; }
#thread-title:has(.gtitle-text) { display: flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap; }
.gtitle-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#group-dialog, #ginfo-dialog { background: color-mix(in srgb, var(--card) 97%, transparent); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); }

/* ---- 0.22.7 Add to Home Screen: START ---- */
#menu-a2hs[hidden], #a2hs-art[hidden], #a2hs-extra[hidden], #a2hs-extra .invite-linkbox[hidden] { display: none !important; }
#a2hs-dialog #a2hs-lead { color: var(--text); margin: 4px 0 10px; }
.a2hs-art {
  display: flex; align-items: center; justify-content: center; gap: 10px; margin: 6px 0 12px; padding: 14px 10px;
  border-radius: 14px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.a2hs-art svg, .a2hs-ic svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.a2hs-art circle, .a2hs-ic circle { fill: currentColor; stroke: none; }
.a2hs-art-share {
  display: grid; place-items: center; width: 52px; height: 52px; border-radius: 14px; flex: none;
  color: #0a84ff; background: var(--card); border: 1px solid var(--line); box-shadow: 0 2px 8px rgba(0,0,0,.18);
}
.a2hs-art-share svg { width: 30px; height: 30px; }
.a2hs-art-arrow { color: var(--muted); font-size: 22px; line-height: 1; }
.a2hs-art-row {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-radius: 12px; font-size: 15px; white-space: nowrap;
  background: var(--card); border: 1px solid var(--line); color: var(--text); box-shadow: 0 2px 8px rgba(0,0,0,.18);
}
.a2hs-art-row svg { width: 22px; height: 22px; flex: none; }
.a2hs-steps { margin: 0 0 10px; padding-left: 22px; color: var(--text); display: grid; gap: 8px; line-height: 1.45; }
.a2hs-steps b { font-weight: 650; }
.a2hs-ic {
  display: inline-grid; place-items: center; width: 22px; height: 22px; margin: 0 3px; vertical-align: -6px; border-radius: 6px;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.a2hs-ic svg { width: 16px; height: 16px; }
.a2hs-extra p { margin: 6px 0; }
.a2hs-extra #a2hs-note { color: var(--muted); font-size: 14px; }
@media (max-width: 380px) { .a2hs-art-row span { font-size: 13px; } .a2hs-art-share { width: 44px; height: 44px; } }
/* ---- 0.22.7 Add to Home Screen: END ---- */

/* ---- 0.22.8 Invite menu row: START ---- */
#app-menu #menu-invite.menu-row {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; margin: 2px 0 4px; padding: 8px 10px 8px 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line)); border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 10%, var(--card)); color: var(--invite-ink, var(--accent));
  font-weight: 600; text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease, border-color .15s ease;
}
#app-menu #menu-invite.menu-row:hover { background: color-mix(in srgb, var(--accent) 18%, var(--card)); border-color: color-mix(in srgb, var(--accent) 62%, var(--line)); }
#app-menu #menu-invite.menu-row:active { background: color-mix(in srgb, var(--accent) 26%, var(--card)); }
#app-menu #menu-invite.menu-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; background: color-mix(in srgb, var(--accent) 18%, var(--card)); }
#menu-invite .menu-row-ico {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent);
}
#menu-invite .menu-row-label { flex: 1 1 auto; min-width: 0; white-space: normal; overflow-wrap: anywhere; line-height: 1.3; }
#menu-invite .menu-row-chev { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--muted); transition: transform .15s ease, color .15s ease; }
#menu-invite svg { display: block; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
#menu-invite .menu-row-ico svg { width: 20px; height: 20px; stroke-width: 2; }
#menu-invite .menu-row-chev svg { width: 18px; height: 18px; stroke-width: 2.4; }
#app-menu #menu-invite.menu-row:is(:hover, :focus-visible) .menu-row-chev { color: var(--text); transform: translateX(2px); }
@media (prefers-reduced-motion: reduce) { #menu-invite, #menu-invite .menu-row-chev { transition: none !important; } }
/* Label uses the theme accent. Where a theme's accent is too faint on the menu (below 4.5:1), mix in some text color. */
#menu-invite { --invite-ink: var(--accent); }
html[data-palette="graphite"][data-scheme="light"] #menu-invite, html[data-palette="bubble"] #menu-invite, html[data-palette="lagoon"] #menu-invite { --invite-ink: color-mix(in srgb, var(--accent) 80%, var(--text)); }
html[data-palette="nebula"][data-scheme="light"] #menu-invite { --invite-ink: color-mix(in srgb, var(--accent) 70%, var(--text)); }
html[data-palette="nebula"][data-scheme="dark"] #menu-invite, html[data-palette="vinyl"][data-scheme="light"] #menu-invite, html[data-palette="glacier"][data-scheme="light"] #menu-invite { --invite-ink: color-mix(in srgb, var(--accent) 60%, var(--text)); }
#app-menu #menu-invite .menu-row-chev { color: var(--invite-ink, var(--accent)); opacity: .8; }
#app-menu #menu-invite.menu-row:is(:hover, :focus-visible) .menu-row-chev { color: var(--invite-ink, var(--accent)); opacity: 1; }
/* ---- 0.22.8 Invite menu row: END ---- */

/* ---- 0.23.0: menu, Profile settings and dialogs readable (were see-through when the blur isn't drawn) ---- */
#app-menu, #profile-pop, dialog { background: color-mix(in srgb, var(--card) 98%, transparent) !important;
  backdrop-filter: blur(8px) saturate(1.1); -webkit-backdrop-filter: blur(8px) saturate(1.1); }
html[data-scheme="light"] :is(#app-menu, #profile-pop, dialog) { background: color-mix(in srgb, var(--card) 96%, transparent) !important; }
@media (prefers-reduced-transparency: reduce) { #app-menu, #profile-pop, dialog, html[data-scheme="light"] :is(#app-menu, #profile-pop, dialog) { background: var(--card) !important; } }

/* ---- 0.23.1 invite pack: START ---- */
/* Invite buttons outside the menu share the 0.22.8 menu row look: person-plus icon, accent label, chevron. */
.invite-cta {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; margin: 8px 0 4px; padding: 8px 10px 8px 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line)); border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 10%, var(--card)); color: var(--invite-ink, var(--accent));
  font: inherit; font-weight: 600; text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease, border-color .15s ease;
}
.invite-cta:hover, .invite-cta:focus-visible { background: color-mix(in srgb, var(--accent) 18%, var(--card)); border-color: color-mix(in srgb, var(--accent) 62%, var(--line)); }
.invite-cta:active { background: color-mix(in srgb, var(--accent) 26%, var(--card)); }
.invite-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.invite-cta[hidden] { display: none; }
.invite-cta .cta-ico { flex: none; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 999px; background: var(--accent); color: var(--on-accent); }
.invite-cta .cta-label { flex: 1 1 auto; min-width: 0; line-height: 1.3; overflow-wrap: anywhere; }
.invite-cta .cta-chev { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--invite-ink, var(--accent)); opacity: .8; transition: transform .15s ease; }
.invite-cta svg { display: block; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.invite-cta .cta-ico svg { width: 20px; height: 20px; stroke-width: 2; }
.invite-cta .cta-chev svg { width: 18px; height: 18px; stroke-width: 2.4; }
.invite-cta:is(:hover, :focus-visible) .cta-chev { opacity: 1; transform: translateX(2px); }
/* Compact version for the group header (icon + "Invite", no chevron). */
.invite-cta.small { width: auto; min-height: 36px; margin: 0; padding: 3px 12px 3px 4px; gap: 8px; border-radius: 999px; }
.invite-cta.small .cta-ico { width: 28px; height: 28px; }
.invite-cta.small .cta-ico svg { width: 17px; height: 17px; }
.invite-cta.small .cta-chev { display: none; }
@media (prefers-reduced-motion: reduce) { .invite-cta, .invite-cta .cta-chev { transition: none !important; } }
/* ---- 26.10.4 tidy group header + gear menu: START ---- */
/* The group chat header shows icons only (bell, gear, and the menu on phones), so the name gets the room.
   Every header icon is the same 40px round button, with a little space between them. */
#thread-actions { gap: 0; }
/* Flat at rest like #search-btn: no ring/background; round hover/focus/active. */
#thread-actions button.icon {
  border-radius: 50%; padding: 9px;
  background: transparent; border: 0; box-shadow: none !important;
}
#thread-actions button.icon:hover,
#thread-actions button.icon:focus-visible,
#thread-actions button.icon:active {
  background: color-mix(in srgb, var(--text) 10%, transparent);
}
#thread-actions #group-info-btn svg { width: 22px; height: 22px; }
/* The name and member count may use all the space left over; long names end in "…". */
#thread-head .thread-text { flex: 1 1 auto; }
/* Gear menu (Group info): the "Invite people" row with a small plain line under the label. */
#ginfo-link { margin: 12px 0 6px; }
.invite-cta .cta-sub { display: block; font-weight: 400; font-size: 12.5px; color: var(--muted, var(--text)); opacity: .8; margin-top: 1px; }
/* Gear menu: "Members" section heading with a people icon and the head-count chip. */
.ginfo-section { display: flex; align-items: center; gap: 8px; margin: 14px 0 4px; font-size: 14px; font-weight: 700; letter-spacing: .01em; }
.ginfo-section-ico { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 22%, transparent); }
.ginfo-section-ico svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ginfo-count { font-size: 12px; font-weight: 600; padding: 1px 8px; border-radius: 999px; background: color-mix(in srgb, var(--text) 10%, transparent); }
.ginfo-count:empty { display: none; }
/* ---- 26.10.4 tidy group header + gear menu: END ---- */
.invite-cta { --invite-ink: var(--accent); }
html[data-palette="graphite"][data-scheme="light"] .invite-cta, html[data-palette="bubble"] .invite-cta, html[data-palette="lagoon"][data-scheme="light"] .invite-cta { --invite-ink: color-mix(in srgb, var(--accent) 80%, var(--text)); }
html[data-palette="glacier"][data-scheme="light"] .invite-cta { --invite-ink: color-mix(in srgb, var(--accent) 70%, var(--text)); }
html[data-palette="nebula"][data-scheme="dark"] .invite-cta, html[data-palette="vinyl"][data-scheme="light"] .invite-cta { --invite-ink: color-mix(in srgb, var(--accent) 60%, var(--text)); }

/* Empty chat list and quiet new group. */
.invite-empty { margin: 14px 10px; padding: 14px; border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--line)); border-radius: 14px; background: color-mix(in srgb, var(--accent) 5%, transparent); }
.invite-empty strong { display: block; font-size: 16px; margin-bottom: 4px; }
.invite-empty .sub { margin: 0 0 6px; }
.invite-empty.group-quiet { max-width: 420px; margin: 18px auto; text-align: left; }

/* Link box with Share/Copy and QR buttons: the link gets its own line. */
.invite-linkbox.has-qr { flex-wrap: wrap; }
.invite-linkbox.has-qr input { flex: 1 1 100%; }
.invite-linkbox.has-qr button { flex: 1 1 0; min-height: 40px; }

/* Group invite link dialog. */
.glink-make { border: 1px solid var(--line); border-radius: 12px; margin: 10px 0 4px; padding: 8px 12px 12px; }
.glink-make[hidden] { display: none; }
.glink-make legend { padding: 0 4px; font-weight: 600; font-size: 14px; }
.glink-field { display: flex; flex-direction: column; gap: 4px; margin: 6px 0 8px; font-size: 14px; }
.glink-field select { width: 100%; }
#glink-create { width: 100%; min-height: 40px; }
#glink-locked { padding: 8px 10px; border-radius: 10px; background: color-mix(in srgb, var(--accent) 8%, transparent); }
#glink-dialog .actions, #join-dialog .actions { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
#glink-off[hidden], #join-go[hidden], #glink-locked[hidden], #glink-active[hidden] { display: none; }

/* QR code: always black on white with a quiet zone, even in dark mode. */
.qr-dialog { text-align: center; }
/* It opens on top of another dialog: no see-through glass, so the text underneath does not show through. */
dialog#qr-dialog.qr-dialog { background: var(--card) !important; -webkit-backdrop-filter: none; backdrop-filter: none; }
.qr-card { display: inline-block; padding: 8px; margin: 6px auto; background: #fff; border-radius: 12px; box-shadow: 0 1px 4px rgba(0, 0, 0, .25); }
#qr-canvas { display: block; width: 264px; height: 264px; max-width: calc(100vw - 96px); max-height: calc(100vw - 96px); image-rendering: pixelated; background: #fff; }
.qr-hint { max-width: 320px; margin: 6px auto 0; }
/* ---- 0.23.1 invite pack: END ---- */

/* ---- 0.23.2 UX fixes + per-chat mute: START ---- */
/* UX-02: Add friend row, same look as New group */
#add-friend-row { display: flex; align-items: center; gap: 10px; width: auto; margin: 6px 0 2px; padding: 8px 10px; cursor: pointer;
  background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 38%, transparent);
  color: var(--text); font-weight: 600; text-align: left; }
#add-friend-row:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
#add-friend-row .ng-icon { width: 30px; height: 30px; flex: none; border-radius: 50%; display: grid; place-items: center; background: var(--accent); color: var(--on-accent); }
html.side-collapsed #add-friend-row { justify-content: center; padding: 8px 0; }
html.side-collapsed #add-friend-row .ng-text { display: none; }
/* UX-02: Add friend dialog */
#addfriend-dialog { width: min(420px, calc(100% - 24px)); }
#addfriend-dialog #add-friend { margin-top: 10px; }
#addfriend-dialog #friend-send:disabled { opacity: .55; cursor: default; }
#addfriend-dialog .actions:not(:has(button:not([hidden]))) { display: none; }
.af-notfound { margin: 12px 0 2px; padding: 12px; border-radius: 12px; border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--line)); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.af-notfound[hidden] { display: none; }
.af-notfound p { margin: 0 0 4px; }
.af-notfound .invite-cta { margin-bottom: 0; }
#friend-pick li .pick-tag { flex: none; }
/* Profile settings: one-line pointer instead of the old friend-request form */
.profile-moved { margin: 4px 0 0; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--line); font-size: 14px; line-height: 1.4; color: var(--text); }
#profile-addfriend { display: inline; margin: 0; padding: 0; border: 0; background: transparent; box-shadow: none; font: inherit; font-weight: 700; color: var(--text);
  text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 2px; text-underline-offset: 3px; cursor: pointer; }
#profile-addfriend:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
/* UX-01: quieter second button + privacy line in the empty card */
.invite-cta.ghost-cta { background: transparent; border-color: var(--line); color: var(--text); }
.invite-cta.ghost-cta .cta-ico { background: color-mix(in srgb, var(--accent) 24%, transparent); color: var(--text); }
.invite-cta.ghost-cta .cta-chev { color: var(--text); opacity: .6; }
.invite-cta.ghost-cta:hover, .invite-cta.ghost-cta:focus-visible { background: color-mix(in srgb, var(--text) 7%, transparent); }
.private-line { margin: 8px 2px 0; font-size: 13px; line-height: 1.35; color: var(--muted, color-mix(in srgb, var(--text) 65%, transparent)); display: flex; gap: 6px; align-items: flex-start; text-align: left; }
.private-line svg { flex: none; margin-top: 1px; }
#chats-empty.invite-empty { background: color-mix(in srgb, var(--card) 90%, transparent); }
/* UX-01 desktop: big "Start your first chat" card in the empty right pane; the small sidebar card hides so it isn't shown twice */
.first-chat, .welcome-sub-empty { display: none; }
@media (min-width: 801px) {
  html.no-chats .first-chat { display: block; }
  html.no-chats .welcome-sub-empty { display: block; margin: 0; color: var(--text); font-weight: 500; text-shadow: 0 1px 4px rgba(0,0,0,.55); }
  html[data-scheme="light"].no-chats .welcome-sub-empty { text-shadow: 0 0 6px rgba(255,255,255,.9), 0 1px 3px rgba(255,255,255,.8); }
  html.no-chats #welcome .welcome-sub { display: none; }
  html.no-chats #chats-empty { display: none; }
}
.first-chat { width: min(440px, 100%); margin-top: 14px; padding: 18px 18px 14px; text-align: left; border-radius: 16px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line)); background: color-mix(in srgb, var(--card) 94%, transparent);
  box-shadow: 0 8px 30px rgba(0,0,0,.28); color: var(--text); }
.first-chat strong { display: block; font-size: 17px; margin-bottom: 4px; }
.first-chat .sub { margin: 0 0 8px; }
/* Per-chat mute */
.muted-ico { flex: none; display: inline-grid; place-items: center; margin: 0 2px 0 4px; color: var(--text); }
.muted-ico svg { display: block; }
#thread-actions .mute-btn.is-muted { color: var(--text); background: transparent; }
#thread-actions .mute-btn.is-muted:hover,
#thread-actions .mute-btn.is-muted:focus-visible,
#thread-actions .mute-btn.is-muted:active {
  background: color-mix(in srgb, var(--text) 10%, transparent);
}
#mute-dialog { width: min(380px, calc(100% - 24px)); }
.mute-who { margin: 0 0 6px; font-weight: 700; font-size: 16px; overflow-wrap: anywhere; }
.mute-opts { display: flex; flex-direction: column; margin: 10px 0 4px; border-top: 1px solid var(--line); }
.mute-opt { display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 0 4px; border-bottom: 1px solid var(--line); font-size: 15px; cursor: pointer; }
.mute-opt input { width: 18px; height: 18px; margin: 0; flex: none; accent-color: var(--accent); }
.mute-status { margin: 8px 0 0; }
/* ---- 0.23.2: END ---- */
#sidebar .chat-row { -webkit-touch-callout: none; }

/* 0.23.4 group icon: members' bubbles in a tight cluster (groupPic in app.js). */
.pfp.gcl { background: none; box-shadow: none; text-shadow: none; display: inline-block; container-type: size; overflow: visible; }
.pfp.gcl.on { box-shadow: none; }
.pfp.gcl.gcl-empty { display: inline-grid; place-items: center; border-radius: 50%; color: var(--muted); border: 1.5px dashed color-mix(in srgb, var(--muted) 60%, transparent); box-sizing: border-box; font-size: 13px; }
.gc-face { position: absolute; box-sizing: border-box; border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  width: calc(var(--gc-d) * 100%); height: calc(var(--gc-d) * 100%);
  left: calc((var(--gc-x) - var(--gc-d) / 2) * 100%); top: calc((var(--gc-y) - var(--gc-d) / 2) * 100%);
  background: var(--gc-bg, #8b97a6); box-shadow: 0 0 0 var(--gc-ring-w, 1.5px) var(--gc-ring, var(--card)); }
.pfp.gcl .gc-face img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; background: transparent; }
.gc-ini { color: #1a2030; font-weight: 700; line-height: 1; letter-spacing: 0; font-size: 9px; font-size: calc(var(--gc-d) * 56cqw); user-select: none; }
.gc-more { background: color-mix(in srgb, var(--text) 22%, var(--card)); }
.gc-more .gc-ini { color: var(--text); font-size: 8px; font-size: calc(var(--gc-d) * 40cqw); letter-spacing: -.02em; }
.chat-row .pfp.gcl { width: 46px; height: 46px; margin: -2px; }
#thread-pic .pfp.gcl { width: 40px; height: 40px; margin: -2px; }
#ginfo-head { display: flex; align-items: center; gap: 14px; margin-bottom: 4px; padding-right: 34px; }  /* clear of the circled X */
#ginfo-head .ginfo-headtext { min-width: 0; flex: 1; }
#ginfo-head h2 { margin: 0; overflow-wrap: anywhere; }
#ginfo-head #ginfo-sub { margin: 2px 0 0; }
#ginfo-pic .pfp.gcl { width: 64px; height: 64px; --gc-ring-w: 2px; }
#ginfo-pic .pfp.gcl .gc-ini { font-size: calc(var(--gc-d) * 50cqw); }
.group-preview { display: flex; align-items: center; gap: 12px; margin: 10px 0 2px; min-height: 52px; }
#group-preview-pic .pfp.gcl { width: 52px; height: 52px; }

/* 0.23.4 group rename */
.gtitle-btn { all: unset; display: inline-flex; align-items: center; gap: 6px; min-width: 0; cursor: pointer; border-radius: 6px; padding: 1px 4px; margin: -1px -4px; }
.gtitle-btn:hover { background: rgba(127,127,127,.15); }
.gtitle-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.gtitle-btn .gtitle-text { min-width: 2.5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 560px) { .gtitle-btn svg.pencil { display: none; } }  /* phones: the header is full; tap the name (pencil stays in group settings) */
svg.pencil { width: 14px; height: 14px; flex: none; fill: currentColor; opacity: .7; }
.gtitle-btn:hover svg.pencil { opacity: 1; }
.ginfo-titlerow { display: flex; align-items: center; gap: 6px; min-width: 0; }
#ginfo-rename { padding: 4px 6px; line-height: 0; flex: none; }
#ginfo-rename[hidden], #ginfo-rename-box[hidden] { display: none; }
#ginfo-rename svg.pencil { width: 16px; height: 16px; }
#ginfo-rename-box { margin: 8px 0 4px; }
#ginfo-name { width: 100%; box-sizing: border-box; }
.ginfo-rename-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
/* version-link (Oct 17): the version label always looks like a link to the patch notes, not only on hover.
   Colour = 55% theme accent + 45% theme text, which stays at or above 4.5:1 on every palette, light and dark. */
a.ver { color: var(--accent); color: color-mix(in srgb, var(--accent) 55%, var(--text)); opacity: 1; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: color-mix(in srgb, currentColor 60%, transparent);
  text-underline-offset: .22em; border-radius: 3px; transition: text-decoration-color .15s, color .15s; }
a.ver:hover, a.ver:focus-visible { text-decoration: underline; text-decoration-color: currentColor; text-decoration-thickness: 2px;
  color: color-mix(in srgb, var(--accent) 40%, var(--text)); }
a.ver:focus { outline: none; }
a.ver:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 55%, var(--text)); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { a.ver { transition: none; } }
/* On the Patch notes page itself the label is plain text (you are already there): full strength, no fade. */
span.ver { opacity: 1; color: var(--muted); color: color-mix(in srgb, var(--muted) 65%, var(--text)); }

/* menu-reorg (0.23.3-beta.6) RANGE SLIDER FIX. Root cause: the generic `select, input, textarea { padding: 8px 10px; border: 1px solid; background; border-radius }`
   also hits <input type="range">. Chromium and WebKit paint the track across the padding box but keep the thumb inside the content box,
   so at max the thumb and fill stopped ~11px short with empty track after them, and at 0 a sliver of fill showed before the thumb.
   Range inputs get no box of their own; native track, fill (accent-color / ::-moz-range-progress) and thumb then share one width, so 100% fills fully. */
input[type="range"] { padding: 0; border: 0; border-radius: 0; background: transparent !important; box-shadow: none; }
#app-menu input[type="range"] { height: 24px; }
/* Robot Delete animation (key "robot"). Posed from JS every frame (rbShow), so the shared figure entrance and every
   inherited idle keyframe are switched off for it. */
.snap-stage .snap-figure[data-char="robot"],.snap-stage .snap-figure.wd[data-char="robot"],.snap-stage .snap-figure.wd[data-char="robot"].snap-out{animation:none!important;transform-origin:50% 100%;will-change:transform}
.snap-figure[data-char="robot"] svg,.snap-figure[data-char="robot"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="robot"] .rb-root{filter:drop-shadow(0 1.5px 2px rgba(0,0,0,.3))}

/* Turtle-dragon delete character. Its motion is posed from JS every frame (tdShow/tdPose), so the shared figure entrance
   and every inherited idle keyframe are switched off for it; nothing here animates. */
.snap-stage .snap-figure[data-char="turtle"],.snap-stage .snap-figure.wd[data-char="turtle"],.snap-stage .snap-figure.wd[data-char="turtle"].snap-out{animation:none!important;transform:none}
.snap-figure[data-char="turtle"] svg,.snap-figure[data-char="turtle"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="turtle"] .td-root{filter:drop-shadow(0 1.5px 2px rgba(0,0,0,.3))}
.td-ovhand{contain:layout style}
/* Owl Delete animation (key "owl", redone). Posed from JS every frame (owShow), so the shared figure entrance and the old
   owl keyframes are switched off for it. */
.snap-stage .snap-figure[data-char="owl"],.snap-stage .snap-figure.wd[data-char="owl"],.snap-stage .snap-figure.wd[data-char="owl"].snap-out{animation:none!important;transform-origin:50% 100%}
.snap-figure[data-char="owl"] svg,.snap-figure[data-char="owl"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="owl"] .o2-root{filter:drop-shadow(0 1.2px 1.6px rgba(0,0,0,.28))}
/* Bunny Delete animation (key "bunny", redone). Posed from JS every frame (bnShow), so the shared woodland entrance and
   the old bunny keyframes are switched off for it. */
.snap-stage .snap-figure[data-char="bunny"],.snap-stage .snap-figure.wd[data-char="bunny"],.snap-stage .snap-figure.wd[data-char="bunny"].snap-out{animation:none!important;transform-origin:50% 100%}
.snap-figure[data-char="bunny"] svg,.snap-figure[data-char="bunny"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="bunny"] .bn2-root{filter:drop-shadow(0 1.2px 1.6px rgba(0,0,0,.26))}
/* Badger Delete animation (key "badger", redone). Posed from JS every frame (bdShow), so the shared woodland entrance and
   the old badger keyframes are switched off for it. */
.snap-stage .snap-figure[data-char="badger"],.snap-stage .snap-figure.wd[data-char="badger"],.snap-stage .snap-figure.wd[data-char="badger"].snap-out{animation:none!important;transform-origin:50% 100%}
.snap-figure[data-char="badger"] svg,.snap-figure[data-char="badger"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="badger"] .bd2-root{filter:drop-shadow(0 1.2px 1.6px rgba(0,0,0,.28))}
/* Painter Delete animation (key "painter", redone). Posed from JS every frame (bnShow), so the shared woodland entrance and
   the old painter keyframes are switched off for it. */
.snap-stage .snap-figure[data-char="painter"],.snap-stage .snap-figure.wd[data-char="painter"],.snap-stage .snap-figure.wd[data-char="painter"].snap-out{animation:none!important;transform-origin:50% 100%}
.snap-figure[data-char="painter"] svg,.snap-figure[data-char="painter"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="painter"] .pt2-root{filter:drop-shadow(0 1.2px 1.6px rgba(0,0,0,.26))}

/* 0.23.3-beta.12: organisation banner (generic white-label). When BC_ORG_NAME / BC_ORG_ICON is set, the server swaps the Twigum
   wordmark in the top banner for the org's picture + name (header.has-org), with a small "on Twigum" credit and the version link
   underneath. The footer and About keep their Twigum trademark text. */
header.has-org > div:first-child { min-width: 0; flex: 1 1 0; }
header.has-org .brand strong { display: block; min-width: 0; }
.org-title { display: flex; align-items: center; gap: 9px; min-width: 0; }
header .brand img.org-pic { width: 38px; height: 38px; flex: none; object-fit: contain; border-radius: 0; background: none; box-shadow: none;
  -webkit-mask: none; mask: none; filter: drop-shadow(0 2px 4px rgba(0,0,0,.45)); }
html[data-scheme="light"] header .brand img.org-pic { filter: drop-shadow(0 2px 4px rgba(0,0,0,.18)); }
.org-title .org-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.org-title .org-name { font-family: "BC Outfit", "Segoe UI", "Noto Sans", sans-serif; font-size: 1.2em; font-weight: 650; letter-spacing: -.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.org-title .org-sub { display: flex; align-items: center; gap: .45em; min-width: 0; font-size: 11.5px; font-weight: 400; white-space: nowrap; }
.org-title .org-credit { color: var(--muted); text-shadow: none; flex: none; }
.org-title .org-sub .ver { flex: 0 1 auto; min-width: 2.2em; overflow: hidden; text-overflow: ellipsis; font-size: 11.5px; margin-left: 0; vertical-align: baseline; }
@media (max-width: 380px) { header .brand img.org-pic { width: 32px; height: 32px; } .org-title .org-name { font-size: 1.08em; } }
/* 0.23.3-beta.13: the org picture replaces the Twigum icon in the corner (header .bc-icon.org-icon). No credit bubble on it;
   the crest keeps its own shape (no rounded mask). On narrow phones the version link shortens (ellipsis) before the credit. */
header .bc-icon.org-icon { border-radius: 0; filter: none; }
header .bc-icon.org-icon::after { content: none; display: none; }

/* 26.10.2: group chats turned off on this server (BC_GROUPS=0). */
html[data-groups="off"] #new-group, html[data-groups="off"] #dm-group-btn, html[data-groups="off"] #chat-ov-start-group { display: none !important; }
/* 0.23.3-beta.14 (Oct 18 2:51 PM): the full footer (verse and memorial line) is on the About page only. Every other page
   keeps just the trademark line, in very small print at the bottom where the footer used to be. The pill keeps its
   existing readable background and colours; these rules only shrink the text and padding (!important so they win
   over the older footer size rules above). The trademark line inherits the 10px size instead of shrinking further. */
#bc-footer.bc-mini { padding: 2px 10px !important; margin-top: 0; margin-bottom: 4px; font-size: 10px !important; line-height: 1.3; }
#bc-footer.bc-mini .legal { font-size: inherit; margin: 0; }

/* 0.23.3-beta.15: ways into the Administrator page (owner only; #owner-tools is hidden for everyone else).
   One link at the top of Admin Tools, and one at the very bottom of the profile menu. */
.owner-admin-link, .profile-admin-link { display: block; color: var(--owner-accent); font-weight: 600; text-decoration: none; }
.owner-admin-link { margin: 0 0 10px; font-size: 14px; }
.profile-admin-link { margin-top: 14px; padding: 10px 12px; border: 1px solid var(--owner-accent); border-radius: 12px; text-align: center; }
/* Luke Oct 30: Log out sits at the bottom of Profile settings (same #menu-logout handler as before). */
#profile-pop #menu-logout {
  display: block; width: 100%; margin-top: 14px; margin-bottom: 4px; text-align: left;
  background: transparent; border: 0; border-radius: 10px; padding: 10px 12px; color: var(--text); font: inherit; cursor: pointer;
}
#profile-pop #menu-logout:hover, #profile-pop #menu-logout:focus-visible {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
#profile-pop #menu-logout:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.owner-admin-link:hover, .profile-admin-link:hover, .owner-admin-link:focus-visible, .profile-admin-link:focus-visible { text-decoration: underline; }

/* 26.10.2: "Pending invites" in the invite dialog: one row per invite, label wraps, buttons stay on the right. */
/* Invite without email: invite code first, QR beside it, optional email section below. */
.friend-primary-head { margin: 4px 0 4px; font-size: 1.05em; font-weight: 700; }
.friend-code-make { display: block; width: 100%; margin: 10px 0 4px; padding: 12px; font-size: 1.02em; }
.friend-code-box { margin-top: 8px; }
.friend-code-box input { width: 100%; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: max(16px, .85em); }
.friend-link-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.friend-link-actions button { flex: 1 1 auto; }
.friend-link-actions button[hidden] { display: none; }
.friend-qr-inline { display: block; width: 168px; height: 168px; margin: 12px auto 2px; border-radius: 8px; }
.friend-qr-inline[hidden] { display: none; }
.friend-email { margin-top: 14px; border-top: 1px solid var(--line, rgba(127,127,127,.25)); padding-top: 10px; font-size: .92em; }
.friend-email-head { margin: 0 0 6px; font-size: .95em; font-weight: 600; opacity: .8; }
.friend-email-row { display: flex; gap: 6px; }
#friend-dialog .friend-email-row input { flex: 1 1 auto; min-width: 0; width: auto; box-sizing: border-box; }
.friend-email-actions { margin-top: 0; }
.friend-email-actions:has(> [hidden]:only-child) { display: none; }
.friend-pending { margin-top: 14px; border-top: 1px solid var(--line, rgba(127,127,127,.25)); padding-top: 10px; }
.friend-pending-head { margin: 0 0 6px; font-size: 15px; }
.friend-pending-list { list-style: none; margin: 0; padding: 0; max-height: 220px; overflow-y: auto; }
.friend-pending-row { display: flex; align-items: center; gap: 6px; padding: 6px 0; flex-wrap: wrap; }
.friend-pending-label { flex: 1 1 160px; min-width: 0; overflow-wrap: anywhere; font-size: 14px; }

/* ---- Site-wide chat background (Oct 18 2026, 5:29 PM PT) ----
   The chat's chosen background (preset, seasonal or uploaded picture) now fills the whole window behind everything
   (header, chat list, chat pane), instead of only the message area. app.js moves #chat-bg to the top of <body> so it can
   be a fixed full-window layer. The chat pane turns nearly clear (the Transparency slider still sets how much of the
   card colour stays), with a soft scrim over the picture so messages and names stay readable in light and dark.
   With no chat open (the chat list home) the usual forest wallpaper shows. */

/* 3001 hotfix: chat background "None" is solid — never fall back to the default forest/Pines wallpaper. */
html[data-chatbg="none"]:not(.no-chat) body::before,
html[data-chatbg="none"]:not(.no-chat) body::after,
html[data-chatbg="none"]:not(.no-chat) #wall-anim { display: none !important; }
html[data-chatbg="none"]:not(.no-chat) main {
  background: var(--card) !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
/* 26.11 solid-bg-stutter: paint an opaque #log on solid "None". Transparent #log +
   contain/will-change promotes a scroll compositor layer that clears to near-black
   (html #0f1117) in the flex gaps between bubbles — worst when YouTube cards remount
   and live bubble backdrop-filter samples those cleared gaps. Picture themes hide it
   because #chat-bg keeps painting behind. Also drop live glass on solid (nothing to blur)
   and keep body/card paint consistent so Lite/transp holes cannot punch through to black. */
html[data-chatbg="none"]:not(.no-chat) body {
  background: var(--card);
}
html[data-chatbg="none"]:not(.no-chat) #log {
  background: var(--card) !important;
}
html[data-chatbg="none"]:not(.no-chat) #log .msg:not(.removed) .bubble:not(.jumbo) {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
html[data-chatbg="none"]:not(.no-chat) #log .msg.mine:not(.removed) .bubble:not(.jumbo) {
  background: color-mix(in srgb, var(--mine) 92%, transparent);
}
html[data-chatbg="none"]:not(.no-chat) #log .msg.other:not(.removed) .bubble:not(.jumbo) {
  background: color-mix(in srgb, var(--other) 92%, transparent);
}
html[data-scheme="light"][data-chatbg="none"]:not(.no-chat) #log .msg.mine:not(.removed) .bubble:not(.jumbo) {
  background: color-mix(in srgb, var(--mine) 94%, transparent);
}
html[data-scheme="light"][data-chatbg="none"]:not(.no-chat) #log .msg.other:not(.removed) .bubble:not(.jumbo) {
  background: color-mix(in srgb, var(--other) 94%, transparent);
}
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat)[data-bgsolid] body::before,
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat)[data-bgsolid] body::after { display: none; }   /* only once the picture is fully in */
/* each background is its own layer so a change can cross-fade (showBackground in app.js); the old ::before picture is unused */
body > #chat-bg::before { display: none; }
#chat-bg > .bgx { position: absolute; left: 0; right: 0; top: 0; bottom: 0; height: var(--bg-h, 100%); min-height: 100%; background-size: cover; background-position: center;
  opacity: 0; transition: opacity 1.75s var(--bc-ease-laminar, cubic-bezier(.37, 0, .63, 1)); }
#chat-bg > .bgx.in { opacity: 1; }
@media (prefers-reduced-motion: reduce) { #chat-bg > .bgx { transition: none; } }
body > #chat-bg {
  /* 26.11 bg-scale-gap: overscan past inset:0 so fractional devicePixelRatio / browser zoom
     cannot open a seam between the fixed layer and the viewport edge. */
  position: fixed; inset: -3px; z-index: -1; filter: saturate(.9); opacity: 1 !important;
}
body > #chat-bg::after { background: color-mix(in srgb, var(--bg) 26%, transparent); }
html[data-chatbg="upload"] body > #chat-bg::after { display: block; background: color-mix(in srgb, var(--bg) 18%, transparent); }
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) main { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
/* names, times and the day pills sit straight on the picture now: a soft shadow keeps them legible */
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log { text-shadow: 0 0 6px color-mix(in srgb, var(--bg) 85%, transparent); }
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log .bubble { text-shadow: none; }
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) .day { background: color-mix(in srgb, var(--card) 78%, transparent); }

/* ---- Animated backgrounds (Oct 2026; runtime in static/bganim/bg-anim.js, loaded only when switched on) ----
   One easing curve for every background move: a sine ease-in-out with no overshoot. The moving picture sits inside
   #chat-bg above its still picture and under its scrim, and fades in and out softly. */
:root { --bc-ease-laminar: cubic-bezier(.37, 0, .63, 1); --bc-dur-bg: 1500ms; }
@media (prefers-reduced-motion: reduce) { :root { --bc-dur-bg: 0ms; } }
#chat-bg .bga-layer { position: absolute; left: 0; right: 0; top: 0; bottom: 0; height: var(--bg-h, 100%); min-height: 100%; opacity: 0; transition: opacity 1.2s var(--bc-ease-laminar); }
#chat-bg .bga-layer.on { opacity: 1; }
.bga-host { overflow: hidden; }
.bga-stage { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.bga-stage > img { position: absolute; display: block; user-select: none; pointer-events: none; }
.bga-still { z-index: 10; transition: opacity var(--bc-dur-bg) var(--bc-ease-laminar); }
.bga-still.bga-hidden { opacity: 0; }
@media (prefers-reduced-motion: reduce) { #chat-bg .bga-layer { transition: none; } }
/* the switch, right under the background choices (same pill switch as Ambient sounds) */
.bganim-row { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.bganim-title { flex: 1 1 auto; font-weight: 600; }
:is(#bganim-toggle, #lite-toggle).bganim-switch {
  position: relative; width: 60px; height: 34px; padding: 0; margin: 0; flex: none; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--text) 16%, var(--line)) !important;
  background: color-mix(in srgb, var(--text) 14%, var(--card)) !important; box-shadow: none; cursor: pointer;
}
:is(#bganim-toggle, #lite-toggle).bganim-switch .sm-knob {
  position: absolute; top: 3px; left: 3px; width: 26px; height: 26px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.28); transform: translateX(0); transition: transform calc(.28s * var(--bc-anim-scale, 1)) cubic-bezier(.4,0,.2,1);
}
:is(#bganim-toggle, #lite-toggle).bganim-switch[aria-checked="true"] { background: var(--accent) !important; border-color: transparent !important; }
:is(#bganim-toggle, #lite-toggle).bganim-switch[aria-checked="true"] .sm-knob { transform: translateX(26px); }
:is(#bganim-toggle, #lite-toggle).bganim-switch:disabled { opacity: .5; cursor: default; }
:is(#bganim-toggle, #lite-toggle).bganim-switch:focus { outline: none; }
:is(#bganim-toggle, #lite-toggle).bganim-switch:focus-visible { outline: 3px solid var(--accent) !important; outline-offset: 3px; }
.bganim-help { margin: 4px 0 0; }
#bganim-note:empty { display: none; }
@media (prefers-reduced-motion: reduce) { :is(#bganim-toggle, #lite-toggle).bganim-switch .sm-knob { transition: none; } }
/* With the picture straight behind the messages (no pane tint any more), the glass bubbles get a little more of their
   own colour so text stays readable over bright or busy pictures, in light and dark. */
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log .msg.mine:not(.removed) .bubble:not(.jumbo) { background: color-mix(in srgb, var(--mine) 62%, transparent); }
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log .msg.other:not(.removed) .bubble:not(.jumbo) { background: color-mix(in srgb, var(--other) 64%, transparent); }
html[data-scheme="light"][data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log .msg.mine:not(.removed) .bubble:not(.jumbo) { background: color-mix(in srgb, color-mix(in srgb, var(--mine) 55%, #0a2340) 80%, transparent); }
html[data-scheme="light"][data-chatbg]:not([data-chatbg="none"]):not(.no-chat) #log .msg.other:not(.removed) .bubble:not(.jumbo) { background: color-mix(in srgb, var(--other) 72%, transparent); }

/* Character speech bubble (Painter, Badger delete animations). Positioned from JS (transform, --tail); the text is
   never mirrored. Cream bubble with dark text in both themes, like a comic, so it reads over any chat background. */
.char-say { position: fixed; left: 0; top: 0; margin: 0; z-index: 88; pointer-events: none; max-width: min(240px, 70vw);
  padding: 7px 12px 8px; border-radius: 16px; background: #fffaf0; color: #2a2118; border: 1.5px solid #3a2a1c;
  font: 600 15px/1.25 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; letter-spacing: .1px; text-align: center;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .28); transform-origin: var(--tail, 50%) 115%; will-change: transform, opacity; }
.char-say::after { content: ""; position: absolute; left: var(--tail, 50%); bottom: -8px; width: 13px; height: 13px; margin-left: -7px;
  background: #fffaf0; border-right: 1.5px solid #3a2a1c; border-bottom: 1.5px solid #3a2a1c; transform: rotate(45deg); border-bottom-right-radius: 3px; }
html[data-scheme="dark"] .char-say { box-shadow: 0 3px 12px rgba(0, 0, 0, .55); }

/* 26.10.2 perf: "baked glass" (see bakedGlass in app.js). While html[data-glass="baked"] is set, the bubbles show a
   pre-blurred copy of the window's background, pinned to the window like the real background, under their usual tint,
   instead of re-blurring it live on every frame. The tint colours are the bubbles' own, read from these same rules. */
html[data-glass="baked"] #log .msg:not(.removed) .bubble:not(.jumbo) {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  background-color: transparent !important;
  background-attachment: fixed, fixed !important; background-repeat: no-repeat, no-repeat !important;
  background-position: 0 0, 0 0 !important; background-size: var(--bc-glass-w) var(--bc-glass-h), var(--bc-glass-w) var(--bc-glass-h) !important;
}
html[data-glass="baked"] #log .msg.mine:not(.removed) .bubble:not(.jumbo) { background-image: linear-gradient(var(--bc-glass-mine), var(--bc-glass-mine)), var(--bc-glass-img) !important; }
html[data-glass="baked"] #log .msg.other:not(.removed) .bubble:not(.jumbo) { background-image: linear-gradient(var(--bc-glass-other), var(--bc-glass-other)), var(--bc-glass-img) !important; }

/* 26.10.2 perf: bubble shadow as one pre-drawn 9-slice picture (bubbleShadowImage in app.js) instead of a live blurred
   box-shadow per bubble. Only while html[data-bshadow="img"] is set. It is the bubble's own border-image pushed outwards
   (border-image-outset), which, like a box-shadow, is paint only: it never changes layout or the chat's scroll length.
   The border itself stays 0 wide; the picture's middle is cut out, so nothing is drawn over the bubble. */
html[data-bshadow="img"] #log .msg:not(.removed) .bubble:not(.jumbo) {
  box-shadow: none !important;
  border-style: solid; border-width: 0;
  border-image: var(--bc-bshadow-dark) var(--bc-bshadow-k) / var(--bc-bshadow-s) / var(--bc-bshadow-p) stretch;
}
html[data-bshadow="img"][data-scheme="light"] #log .msg:not(.removed) .bubble:not(.jumbo) { border-image-source: var(--bc-bshadow-light); }

/* 26.10.2 perf: the plain background picture under a running animated scene is fully covered by the scene's own opaque
   still, so it is not drawn while .bga-covered is set (see bgaSyncNow / bgaDropFrom in app.js). Looks identical. */
#chat-bg > .bgx.bga-covered { background-image: none !important; }

/* 26.10.2 perf: while the moving scene is drawn on one canvas with the colour filter already baked into its pictures,
   the full-window filter is off and the scrim uses the same baked colour (worked out in app.js, bgaBakeSetup). */
body > #chat-bg.bga-baked { filter: none; }
body > #chat-bg.bga-baked::after { background: var(--bga-scrim); }

/* 26.10.3 Twigum Helper bot: "Helper bot" label and suggestion buttons (only under its newest message). */
.bot-badge { display: inline-block; margin-left: 4px; padding: 1px 7px; border-radius: 999px; font-size: 11px; font-weight: 600;
  line-height: 16px; vertical-align: middle; color: #1f6b3a; background: rgba(46, 160, 90, .14); border: 1px solid rgba(46, 160, 90, .35); white-space: nowrap; }
.quick-replies { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 2px; max-width: 520px; }
.quick-reply { font: inherit; font-size: 14px; padding: 6px 12px; border-radius: 999px; cursor: pointer;
  border: 1px solid rgba(46, 160, 90, .55); background: rgba(255, 255, 255, .9); color: #1f6b3a; }
.quick-reply:hover, .quick-reply:focus-visible { background: #2ea05a; color: #fff; }
#log .msg.has-quick:not(:last-of-type) .quick-replies { display: none; }
html[data-scheme="dark"] .bot-badge { color: #8fe0aa; }
html[data-scheme="dark"] .quick-reply { background: rgba(20, 30, 24, .85); color: #8fe0aa; }
.bot-name { display: inline-flex; align-items: center; gap: 2px; min-width: 0; max-width: 100%; vertical-align: middle; }
.bot-name > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.bot-name > .bot-badge { flex-shrink: 0; }
/* ---- 26.10.2 sidebar layout: groups under the Lobby, a line before one-to-one chats, and the
   New group / Add friend buttons as a small two-button footer just above the account bar's line. ---- */
#group-list[hidden] { display: none; }
/* The line between the Lobby + groups section and the one-to-one chats: same thin line as under "Conversations"
   and above the account bar. */
.side-sep { flex: none; width: 100%; height: 0; margin: 0; border: 0; border-top: 1px solid var(--line); }
/* Footer row: two compact buttons side by side, each with its icon and name. */
#side-actions { flex: none; display: flex; gap: 8px; }
#side-actions .side-act { flex: 1 1 0; min-width: 0; width: auto; margin: 0; padding: 6px 8px; gap: 6px; justify-content: center;
  border-radius: 10px; font-size: 13px; font-weight: 600; line-height: 1.2; }
#side-actions .side-act .ng-icon { width: 22px; height: 22px; }
#side-actions .side-act .ng-icon svg { width: 15px; height: 15px; }
#side-actions .side-act .ng-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Collapsed desktop sidebar (64px): icons only, stacked. */
html.side-collapsed #side-actions { flex-direction: column; gap: 6px; width: 100%; }
html.side-collapsed #side-actions .side-act { padding: 6px 0; }
/* Both buttons hidden (groups off + share picking) -> no empty footer. */
#side-actions:not(:has(> .side-act:not([hidden]))) { display: none; }

/* 26.10.3 sound options under "Sound effects": same look as the Notification tone row and Tone volume slider. */
.sfx-opts { margin: 2px 0 4px; }
.sfx-opts[hidden] { display: none; }
.sfx-opts .menu-sub { display: block; margin-top: 6px; }
.vol-name { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.vol-ico { flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.sfx-opts .vol-range:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* ===== 26.10.4: stickers =====
   A sticker message has no bubble: just the picture, large, with the time in a small soft pill under its corner.
   Sender name, reactions, the message menu and the delete animations work as for any message. */
#log .msg .bubble.sticker-bubble {
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important; text-shadow: none !important;
  padding: 0 0 20px !important; min-width: 0 !important; position: relative;
}
.sticker-img { display: block; width: 168px; height: 168px; object-fit: contain; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
@media (max-width: 600px) { .sticker-img { width: 144px; height: 144px; } }
#log .msg .bubble.sticker-bubble .time {
  position: absolute; right: 4px; bottom: 0; font-size: 11px; line-height: 16px; padding: 0 7px; border-radius: 8px;
  color: var(--muted); background: color-mix(in srgb, var(--card) 82%, transparent);
}
#log .msg .bubble.sticker-bubble::before { display: none !important; }   /* no glass gloss/edge behind a sticker */
#log .msg .bubble.sticker-bubble .fwd-label { font-size: 12px; margin-bottom: 2px; }
#log .msg.sticker-row .reactions { margin-top: 2px; }
.sticker-alt { font-style: italic; opacity: .85; }
/* Gentle one-time movements for still stickers that have a "motion" hint (none when the device asks for less motion). */
.st-m-wave { transform-origin: 50% 90%; animation: st-wave 1.1s ease-in-out 2; }
.st-m-beat { animation: st-beat .9s ease-in-out 2; }
.st-m-bounce { transform-origin: 50% 100%; animation: st-bounce .8s cubic-bezier(.3, .7, .4, 1) 2; }
.st-m-float { animation: st-float 2.2s ease-in-out 1; }
.st-m-shake { animation: st-shake .7s ease-in-out 2; }
.st-m-wiggle { transform-origin: 50% 90%; animation: st-wiggle .9s ease-in-out 2; }
@keyframes st-wave { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-5deg); } 75% { transform: rotate(5deg); } }
@keyframes st-beat { 0%, 100% { transform: scale(1); } 30% { transform: scale(1.08); } 55% { transform: scale(.98); } }
@keyframes st-bounce { 0%, 100% { transform: translateY(0) scale(1, 1); } 35% { transform: translateY(-10px) scale(.98, 1.03); } 70% { transform: translateY(0) scale(1.03, .97); } }
@keyframes st-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes st-shake { 0%, 100% { transform: rotate(0); } 20% { transform: rotate(-4deg); } 40% { transform: rotate(4deg); } 60% { transform: rotate(-3deg); } 80% { transform: rotate(3deg); } }
@keyframes st-wiggle { 0%, 100% { transform: rotate(0); } 30% { transform: rotate(-3deg) translateY(-2px); } 65% { transform: rotate(3deg); } }
@media (prefers-reduced-motion: reduce) { [class*="st-m-"] { animation: none !important; } }

/* The Stickers tab: a sticky row of pack shortcuts, then "Recently used" and each pack as a grid of tiles. */
#picker #sticker-pop:not([hidden]) { display: block; padding-top: 0; }
#sticker-pop .sticker-packs {
  position: sticky; top: 0; z-index: 1; display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none;
  padding: 6px 2px; margin: 0 -8px; padding-left: 8px; padding-right: 8px;
  background: var(--card); border-bottom: 1px solid var(--line);
}
#sticker-pop .sticker-packs::-webkit-scrollbar { display: none; }
#sticker-pop .sticker-packs button {
  flex: none; width: 40px; height: 40px; padding: 3px; border: 0 !important; border-radius: 10px !important; background: transparent !important; box-shadow: none !important; cursor: pointer;
}
#sticker-pop .sticker-packs button:hover { background: color-mix(in srgb, var(--text) 9%, transparent) !important; }
#sticker-pop .sticker-packs img { width: 34px; height: 34px; object-fit: contain; display: block; }
#sticker-pop .sticker-head { font-size: 12px; font-weight: 600; color: var(--muted); padding: 10px 4px 4px; }
#sticker-pop .sticker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 4px; }
#sticker-pop .sticker-tile {
  aspect-ratio: 1; padding: 4px; border: 0 !important; border-radius: 12px !important; background: transparent !important; box-shadow: none !important; cursor: pointer;
  transition: background-color .12s ease, transform .12s ease;
}
#sticker-pop .sticker-tile:hover { background: color-mix(in srgb, var(--text) 8%, transparent) !important; transform: scale(1.04); }
#sticker-pop .sticker-tile:active { transform: scale(.96); }
#sticker-pop .sticker-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
#sticker-pop .sticker-tile:disabled { opacity: .5; }
#sticker-pop .sticker-tile img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }
#sticker-pop .sticker-credit { font-size: 11px; color: var(--muted); opacity: .8; margin: 4px 4px 2px; }
@media (prefers-reduced-motion: reduce) { #sticker-pop .sticker-tile { transition: none; } #sticker-pop .sticker-tile:hover { transform: none; } }
/* Tabs: a soft hover background on the unselected tabs, so they read as buttons (the green underline marks the open one). */
#picker-tabs [role="tab"][aria-selected="false"]:hover { background: color-mix(in srgb, var(--text) 7%, transparent) !important; }
/* 26.10.4: the MIT notice for the Classic Reactions stickers on the About page, folded away until opened. */
.made-with-love .license-text summary { cursor: pointer; }
.made-with-love .license-text pre { white-space: pre-wrap; text-align: left; font-size: 11px; max-width: 560px; margin: 6px auto; opacity: .9; }

/* 26.10.6: after backing out of a chat, the chat list keeps showing the background (that chat's own, or the main one
   after the Lobby) instead of hiding it; app.js sets data-bglist. The layer is already on screen, so nothing jumps. */
html.no-chat[data-bglist] body > #chat-bg { display: block !important; }
html.no-chat[data-bglist][data-chatbg]:not([data-chatbg="none"])[data-bgsolid] body::before,
html.no-chat[data-bglist][data-chatbg]:not([data-chatbg="none"])[data-bgsolid] body::after { display: none; }
/* ===== 26.10.5: friend profile card (UX-07 v2 look). Centered on every screen size. ===== */
#thread-title.profile-tap, #thread-pic.profile-tap, .msg .name.profile-tap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
#thread-title.profile-tap:focus-visible, #thread-pic.profile-tap:focus-visible, .msg .name.profile-tap:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
#thread-title.profile-tap:active, #thread-pic.profile-tap:active, .msg .name.profile-tap:active { opacity: .82; }
dialog#friend-card[open] { margin: auto; width: min(320px, calc(100vw - 48px)); padding: 22px 18px 16px; text-align: center;
  max-height: calc(100dvh - 48px); overflow-y: auto; overscroll-behavior: contain; box-sizing: border-box; outline: none; }
#friend-card .fc-photo { display: flex; justify-content: center; margin: 2px auto 10px; }
#friend-card .fc-photo .pfp { width: 112px; height: 112px; }
#friend-card .fc-photo .pfp img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
#friend-card h2.fc-name { margin: 0; padding: 0 !important; font-size: 21px; font-weight: 700; overflow-wrap: anywhere; }
#friend-card .fc-status { display: inline-flex; align-items: center; gap: 6px; margin: 2px 0 0; font-size: 14px; color: var(--muted); }
#friend-card .fc-status::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: color-mix(in srgb, var(--muted) 70%, transparent); }
#friend-card .fc-status.on::before { background: #3ecf6e; }
#friend-card .fc-contact { list-style: none; margin: 14px 0 2px; padding: 0; text-align: left; }
#friend-card .fc-contact li { display: flex; align-items: center; gap: 10px; padding: 10px 4px; border-top: 1px solid var(--line); font-size: 15px; min-width: 0; }
#friend-card .fc-contact li:last-child { border-bottom: 1px solid var(--line); }
#friend-card .fc-contact .k { width: 76px; flex: none; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
#friend-card .fc-contact .v { color: var(--text); text-decoration: none; overflow-wrap: anywhere; min-width: 0; }
#friend-card .fc-none { margin: 12px 0 2px; font-size: 13px; }
/* Gentle pop: fades and grows a little. Turned off for people who ask for less motion. */
#friend-card .fc-real { margin: 0; font-size: 13px; color: var(--muted); }
#friend-card .fc-nick { margin: 10px 0 0; text-align: left; }
#friend-card .fc-nick-view { all: unset; box-sizing: border-box; width: 100%; display: flex; align-items: center; gap: 10px; padding: 10px 4px; border-bottom: 1px solid var(--line); cursor: pointer; font-size: 15px; }
#friend-card .fc-nick-view:focus-visible { outline: 2px solid var(--accent); border-radius: 6px; }
#friend-card .fc-nick .k { width: 76px; flex: none; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
#friend-card .fc-nick-view .v { flex: 1; min-width: 0; overflow-wrap: anywhere; }
#friend-card .fc-nick-view .v.empty { color: var(--accent); }
#friend-card .fc-nick-view .chev { color: var(--muted); font-size: 18px; }
#friend-card .fc-nick-edit { padding: 8px 4px; }
#friend-card .fc-nick-edit .k { display: block; width: auto; margin-bottom: 4px; }
#friend-card .fc-nick-edit input { width: 100%; box-sizing: border-box; }
#friend-card .fc-nick-edit .sub { margin: 6px 0 0; font-size: 12px; }
#friend-card .fc-err { margin: 4px 0 0; font-size: 13px; color: #e5484d; }
#friend-card .fc-err:empty { display: none; }
#friend-card .fc-nick-edit .actions { margin-top: 8px; }
/* Remove friend: quiet red text link at the very bottom, not a big button. */
#friend-card .fc-remove { all: unset; display: block; margin: 16px auto 0; padding: 6px 10px; font-size: 14px; color: #e5484d; cursor: pointer; border-radius: 8px; }
#friend-card .fc-remove:hover, #friend-card .fc-remove:focus-visible { text-decoration: underline; outline: none; }
/* Desktop: placed under the friend's name (left/top are set by the script); a lighter dim behind it. */
dialog#friend-card.anchored[open] { position: fixed; margin: 0 !important; right: auto; bottom: auto; }
dialog#friend-card.anchored::backdrop { background: rgba(0, 0, 0, .18); }
/* The app gives every button a raised look; the nickname row and Remove friend link stay flat like the mock. */
#friend-card button.fc-nick-view, #friend-card button.fc-remove { background: none !important; box-shadow: none !important; border-top: 0 !important; border-left: 0 !important; border-right: 0 !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; min-height: 0; }
#friend-card button.fc-remove { border: 0 !important; }
@keyframes fc-in { from { opacity: 0; transform: scale(.94) translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes fc-fade { from { opacity: 0; } to { opacity: 1; } }
dialog#friend-card[open] { animation: fc-in .18s cubic-bezier(.2,.8,.3,1); }
dialog#friend-card[open]::backdrop { animation: fc-fade .18s ease-out; }
@media (prefers-reduced-motion: reduce) { dialog#friend-card[open], dialog#friend-card[open]::backdrop { animation: none; } }
/* 26.10.5: delete-message "Are you sure?" speech bubble.
   Grows out of the Delete button, then sits in the middle of the screen (both up/down and left/right). */
dialog#delete-msg-dialog[open] {
  position: fixed; inset: 0; margin: auto; height: fit-content;
  width: min(280px, calc(100% - 48px)); max-height: none; overflow: visible;
  padding: 18px 18px 16px; text-align: center; border-radius: 22px;
}
dialog#delete-msg-dialog::after {           /* the little speech-bubble tail */
  content: ""; position: absolute; left: 50%; bottom: -9px; width: 18px; height: 18px;
  background: inherit; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  transform: translateX(-50%) rotate(45deg); border-bottom-right-radius: 4px;
}
#delete-msg-dialog .bubble-q { margin: 0 0 4px; font-size: 20px; font-weight: 700; color: var(--text); }
#delete-msg-dialog .bubble-sub { margin: 0 0 14px; font-size: 13px; }
#delete-msg-dialog .bubble-actions { display: flex; justify-content: center; gap: 28px; }
#delete-msg-dialog .bubble-btn {
  width: 52px; height: 52px; padding: 0; border-radius: 50%; display: grid; place-items: center;
  cursor: pointer; transition: transform .12s ease;
}
#delete-msg-dialog .bubble-btn:active { transform: scale(.92); }
#delete-msg-dialog .bubble-no { background: transparent; color: var(--text); border: 2px solid var(--line); }
#delete-msg-dialog .bubble-yes { background: var(--danger); color: #fff; border: 2px solid var(--danger); }
#delete-msg-dialog .bubble-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
#delete-msg-dialog.rise { animation: bc-bubble-rise .26s cubic-bezier(.2,.9,.3,1.15) both; }
@keyframes bc-bubble-rise {
  from { transform: translate(var(--rise-x, 0px), var(--rise-y, 40px)) scale(.15); opacity: 0; }
  60% { opacity: 1; }
  to { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #delete-msg-dialog.rise { animation: bc-bubble-fade .12s ease-out both; }
  @keyframes bc-bubble-fade { from { opacity: 0; } to { opacity: 1; } }
}
/* 26.10.5: Report a bug. Change --bug-icon below to swap the icon (a/b/c from the icon sheet). */
:root {
  /* Luke's pick (a), the solid bug silhouette. To swap, replace this one line with (b) or (c) below. */
  --bug-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M9 4.2a1 1 0 0 1 1.4.2l.9 1.2a4 4 0 0 1 1.4 0l.9-1.2a1 1 0 1 1 1.6 1.2l-.7.9A4 4 0 0 1 16 8.4H8a4 4 0 0 1 1.5-1.9l-.7-.9A1 1 0 0 1 9 4.2zM7.5 10h9a1 1 0 0 1 .3 0l2.1-1.2a1 1 0 1 1 1 1.7l-2.4 1.4V13h2.5a1 1 0 1 1 0 2h-2.5v.3c0 .5-.1 1-.2 1.4l2.2 1.3a1 1 0 1 1-1 1.7l-2.1-1.2A5 5 0 0 1 13 20.9V12h-2v8.9a5 5 0 0 1-3.4-2.4l-2.1 1.2a1 1 0 1 1-1-1.7l2.2-1.3a5 5 0 0 1-.2-1.4V15H4a1 1 0 1 1 0-2h2.5v-1.1L4.1 10.5a1 1 0 1 1 1-1.7l2.1 1.2z'/%3E%3C/svg%3E");
  /* (b) bug in a circle:  --bug-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='black' stroke-width='2'/%3E%3Cpath d='M10.2 6.6a.8.8 0 0 1 1.1.1l.3.5h.8l.3-.5a.8.8 0 0 1 1.3 1l-.2.3c.6.3 1 .9 1.1 1.5H9.1c.1-.6.5-1.2 1.1-1.5l-.2-.3a.8.8 0 0 1 .2-1.1zM8.9 10.6h6.2l1.4-.8a.8.8 0 1 1 .8 1.4l-1.6.9v.8h1.6a.8.8 0 0 1 0 1.6h-1.6v.2l-.1.6 1.3.8a.8.8 0 1 1-.8 1.4l-1.2-.7a3.6 3.6 0 0 1-2.1 1.3v-6.2h-1.6v6.2a3.6 3.6 0 0 1-2.1-1.3l-1.2.7a.8.8 0 1 1-.8-1.4l1.3-.8-.1-.6v-.2H6.7a.8.8 0 0 1 0-1.6h1.6v-.8l-1.6-.9a.8.8 0 1 1 .8-1.4z'/%3E%3C/svg%3E");
     (c) line-art:        --bug-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8.5 9h7v5.5a3.5 3.5 0 0 1-7 0z'/%3E%3Cpath d='M9.5 9a2.5 2.5 0 0 1 5 0M10 5l1 1.5M14 5l-1 1.5M12 11v7M8.5 11.5 5 10M15.5 11.5 19 10M8.5 14H4.5M15.5 14h4M9 16.8 5.5 19M15 16.8l3.5 2.2'/%3E%3C/g%3E%3C/svg%3E"); */
}
/* The icon is a mask, so it is always drawn in the current text colour (light and dark mode). */
.bug-ico::before { content: ""; display: block; width: 20px; height: 20px; margin: auto; background: currentColor; -webkit-mask: var(--bug-icon) center / contain no-repeat; mask: var(--bug-icon) center / contain no-repeat; }
/* Small, faint, top right just under the header, clear of the notch; out of the way of the composer and keyboard. */
.bug-fab { position: fixed; z-index: 40; right: calc(8px + env(safe-area-inset-right, 0px)); top: calc(var(--header-h, 64px) + 8px + env(safe-area-inset-top, 0px));
  width: 32px; height: 32px; min-height: 0; padding: 0; border-radius: 50%; border: 1px solid var(--line); color: var(--text);
  background: color-mix(in srgb, var(--card) 70%, transparent); opacity: .55; display: grid; place-items: center; }
.bug-fab:hover, .bug-fab:focus-visible { opacity: 1; }
.bug-fab[hidden] { display: none; }
#menu-bug .menu-row-ico { display: inline-grid; place-items: center; }
#bug-dialog textarea { width: 100%; box-sizing: border-box; font: inherit; border-radius: 10px; border: 1px solid var(--line); background: var(--bg, transparent); color: var(--text); padding: 8px; resize: vertical; }
#bug-dialog .bug-lab { display: block; margin: 10px 0 4px; font-weight: 600; }
#bug-dialog .bug-shots { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
#bug-dialog .actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
#thread-actions .bug-head::before { width: 22px; height: 22px; }
/* Phones: the 1:1 header is already tight (the name truncates), so the floating button stands in for the header one there. */
@media (max-width: 800px) { #thread-actions .bug-head { display: none; } }
/* Moving default wallpaper (Oct 19 2026): #wall-anim holds the forest camp scene (bganim/forest.js). It copies the wallpaper's
   box exactly (body::before: 40 px bleed, the 1.02 zoom, the keyboard-steady height --wall-h and the phone/desktop picture
   sizes and positions above), so the moving picture lands pixel for pixel on the plain one. Hidden whenever the wallpaper is. */
#wall-anim { position: fixed; inset: -40px; z-index: -2; pointer-events: none; overflow: hidden;
  --wall-h: calc(var(--app-tall, 100lvh) + 80px);
  --wall-img-h: max(var(--wall-h), calc((100vw + 80px) * 0.5625));
  transform: translateZ(0) scale(1.02); transform-origin: 50% calc(var(--wall-h) / 2); }
#wall-anim > .wall-pic { position: absolute; height: var(--wall-img-h); width: calc(var(--wall-img-h) * 1280 / 720);
  left: calc((100% - var(--wall-img-h) * 1280 / 720) * 0.5); top: calc((var(--wall-h) - var(--wall-img-h)) / 2); }
@media (max-aspect-ratio: 1/1) {
  #wall-anim { --wall-img-h: max(var(--wall-h), calc((100vw + 80px) * 1.34375)); }
  #wall-anim > .wall-pic { width: calc(var(--wall-img-h) * 1280 / 1720); left: calc((100% - var(--wall-img-h) * 1280 / 1720) * 0.96); top: 0; }
}
#wall-anim .bga-layer { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s var(--bc-ease-laminar, ease); }
#wall-anim .bga-layer.on { opacity: 1; }
html[data-chatbg]:not([data-chatbg="none"]):not(.no-chat)[data-bgsolid] #wall-anim { display: none; }
@media (prefers-reduced-transparency: reduce) { #wall-anim { display: none; } }
@media (prefers-reduced-motion: reduce) { #wall-anim { display: none; } }

/* TEMPORARY TEST (26.10.5 hotfix): icon-only full-screen toggle at the bottom right of the hamburger menu. */
.fs-test { margin-left: auto; display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; padding: 0;
  border-radius: 10px; background: transparent; border: 1px solid transparent; color: inherit; opacity: .3; cursor: pointer; }
.fs-test:hover, .fs-test:focus-visible { opacity: .7; }  /* understated on purpose (a quiet easter egg) */
.fs-test svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.fs-test .fs-exit, .fs-test.on .fs-enter { display: none; }
.fs-test.on .fs-exit { display: block; }
.fs-hint { margin: 4px 12px 8px; font-size: 12px; opacity: .8; }
#app-menu .fs-test { background: transparent !important; border: 0 !important; box-shadow: none !important; }

/* 26.10.6: "Name is typing…" just above the message bar. Absolutely placed so showing it never moves the layout. */
#composer { position: relative; }
#typing-line {
  position: absolute; left: 14px; bottom: 100%; margin-bottom: 4px; max-width: calc(100% - 28px);
  display: flex; align-items: center; gap: 6px; padding: 3px 10px 3px 8px; border-radius: 999px;
  font-size: 12.5px; line-height: 1.3; color: var(--muted); pointer-events: none; z-index: 2;
  background: color-mix(in srgb, var(--panel, var(--bg, #fff)) 88%, transparent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 1; transition: opacity .18s ease;
}
#typing-line[hidden] { display: flex !important; opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility 0s .18s; }
#typing-text { overflow: hidden; text-overflow: ellipsis; }
.typing-dots { display: inline-flex; gap: 3px; flex-shrink: 0; }
.typing-dots i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; opacity: .35; animation: bc-typing 1.2s infinite ease-in-out; }
.typing-dots i:nth-child(2) { animation-delay: .15s; }
.typing-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes bc-typing { 0%, 60%, 100% { opacity: .3; transform: translateY(0); } 30% { opacity: .9; transform: translateY(-2px); } }
@media (prefers-reduced-motion: reduce) { .typing-dots i { animation: none; opacity: .6; } }
/* NEW-SNAPS CSS BEGIN */
/* new-snaps: Origami Crane. The stage holds the paper window; the rAF loop in crShow poses it, so no CSS animation. */
.snap-stage .snap-figure[data-char="crane"],.snap-stage .snap-figure.wd[data-char="crane"],.snap-stage .snap-figure.wd[data-char="crane"].snap-out{animation:none!important;transform:none}
.snap-figure[data-char="crane"] svg,.snap-figure[data-char="crane"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="crane"] .cr-win{filter:drop-shadow(0 1.2px 1.6px rgba(0,0,0,.28))}
.cr-fly svg{display:block;width:100%;height:100%;filter:drop-shadow(0 2px 2.5px rgba(0,0,0,.28))}
/* new-snaps: Snail Mail Carrier. snShow poses the SVG from one rAF loop, so no CSS animation on the figure. */
.snap-stage .snap-figure[data-char="snail"],.snap-stage .snap-figure.wd[data-char="snail"],.snap-stage .snap-figure.wd[data-char="snail"].snap-out{animation:none!important;transform:none}
.snap-figure[data-char="snail"] svg,.snap-figure[data-char="snail"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="snail"] svg{overflow:visible}
/* new-snaps: Otter Chef. otShow poses the SVG from one rAF loop, so no CSS animation on the figure. */
.snap-stage .snap-figure[data-char="otter"],.snap-stage .snap-figure.wd[data-char="otter"],.snap-stage .snap-figure.wd[data-char="otter"].snap-out{animation:none!important;transform:none}
.snap-figure[data-char="otter"] svg,.snap-figure[data-char="otter"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="otter"] svg{overflow:visible}
/* new-snaps: Beaver Builder. bvShow poses the SVG from one rAF loop, so no CSS animation on the figure. */
.snap-stage .snap-figure[data-char="beaver"],.snap-stage .snap-figure.wd[data-char="beaver"],.snap-stage .snap-figure.wd[data-char="beaver"].snap-out{animation:none!important;transform:none}
.snap-figure[data-char="beaver"] svg,.snap-figure[data-char="beaver"] svg *{animation:none!important;transition:none!important}
.snap-figure[data-char="beaver"] svg{overflow:visible}
/* NEW-SNAPS CSS END */

/* 26.10.4 emoji styles: emoji drawn as pictures (Twemoji, Noto or Fluent) sit in the text like the device's own emoji,
   about the same size as the letters around them; bigger in jumbo messages and the pickers because those use bigger
   text. Pictures never get stretched or blurred: they are vector SVGs drawn at the exact size. */
img.emo { width: 1.22em; height: 1.22em; vertical-align: -0.26em; margin: 0 .04em; display: inline-block; object-fit: contain; pointer-events: none; user-select: text; }
#emoji-pop button img.emo, #react-grid button img.emo, #react-quick button img.emo { width: 1.12em; height: 1.12em; margin: 0; vertical-align: middle; }
#react-quick button, #react-grid button, #emoji-pop button { line-height: 1; }
.react-chip img.emo { width: 1.15em; height: 1.15em; vertical-align: -0.22em; }
/* The style choice buttons: a small 😀 sample in each style before the name. */
#emoji-style-choices .es-btn { display: inline-flex; align-items: center; gap: 6px; }
#emoji-style-choices .es-sample { width: 20px; height: 20px; flex: none; display: inline-block; }
#emoji-style-choices .es-native { font-size: 18px; line-height: 20px; text-align: center; }

/* smooth-transitions (26.10.3): pre-filtered background pictures (bgxBake in app.js). While every layer has its baked
   copy, the full-window filter is off, the canvas shows instead of the plain picture, and the scrim uses the same colour
   change. Pixel for pixel the same look; the browser just no longer re-filters the whole window during a fade. */
#chat-bg > .bgx > canvas.bk { display: none; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
body > #chat-bg:is(.bgx-baked, .bga-baked) > .bgx.bk:not(.bga-covered) > canvas.bk { display: block; }
body > #chat-bg:is(.bgx-baked, .bga-baked) > .bgx.bk { background-image: none !important; }
body > #chat-bg.bgx-baked { filter: none; }
body > #chat-bg.bgx-baked::after { background: var(--bgx-scrim); }
body > #chat-bg.bgx-baked.bga-baked::after { background: var(--bga-scrim); }

/* 26.11 ipad-smooth: on Apple touch / WKWebView (html[data-ios] from scheme.js), never use live backdrop-filter on
   bubbles or scrolling panel layers — even if the user turns Lite off. Translucent solids match the Lite look closely;
   baked glass (data-glass=baked) still works when available because it is a picture, not a live filter.
   body::before drops its live filter:blur (static wallpaper + scrim instead). */
html[data-ios] body::before {
  filter: none; transform: none; inset: 0;
  background-image: url("/static/forest-bg-dark.webp?v=26.11.1007-763b3d5b"), url("/static/forest-bg.webp?v=26.11.1007-763b3d5b");
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
html[data-ios][data-scheme="light"] body::before {
  filter: none; opacity: 1;
  background-image: url("/static/forest-bg-light.webp?v=26.11.1007-763b3d5b"), url("/static/forest-bg.webp?v=26.11.1007-763b3d5b");
}
html[data-ios] #sidebar, html[data-ios] main, html[data-ios] dialog, html[data-ios] #profile-pop, html[data-ios] #app-menu,
html[data-ios] #bc-footer, html[data-ios] #side-expand {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  background: color-mix(in srgb, var(--card) 94%, transparent);
}
html[data-ios][data-scheme="light"] #sidebar, html[data-ios][data-scheme="light"] main,
html[data-ios][data-scheme="light"] #profile-pop, html[data-ios][data-scheme="light"] #app-menu {
  background: color-mix(in srgb, var(--card) 92%, transparent);
}
html[data-ios] main { background: color-mix(in srgb, var(--card) 88%, transparent); }
html[data-ios] #log .msg:not(.removed) .bubble:not(.jumbo) {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
html[data-ios] #composer, html[data-ios] #composer .dock, html[data-ios] #attach-tray,
html[data-ios] .inset-chrome, html[data-ios] #thread-head {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}

/* 26.10.8 Lite mode (html.lite, set by scheme.js; switch in the menu): no live backdrop blur anywhere (the GPU's most
   expensive effect on phones). Panels use the same near-solid glass as browsers without blur support; the pre-blurred
   "baked" bubble glass still works because it is a picture, not a live filter. */
html.lite *, html.lite *::before, html.lite *::after { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
html.lite #sidebar, html.lite main, html.lite dialog, html.lite #profile-pop, html.lite #app-menu { background: color-mix(in srgb, var(--card) 94%, transparent); }
html.lite[data-scheme="light"] #sidebar, html.lite[data-scheme="light"] main { background: color-mix(in srgb, var(--card) 92%, transparent); }

/* ===== 26.10.9 bug fix (Luke): bubble-less media =====
   A photo, GIF or video message has NO bubble: just the picture with rounded corners and a soft static shadow under it,
   so it looks like it's floating. Only plain text keeps a bubble. Cheap on purpose: one plain box-shadow on the picture,
   never filter:drop-shadow, never backdrop-filter, never animated (the glass blur, the baked glass and the 9-slice
   shadow picture are all switched off for these). The .bubble element stays as a clear wrapper, so the message menu,
   reactions and the delete animations (which take the .bubble) all still start from the picture.
   Time: a small chip over the picture's bottom corner. Reactions overlap the picture's bottom edge. Sender name stays
   a label above. A caption sits in its own small text bubble under the picture, and the time moves into it. */
#log .msg .bubble.media-bubble {
  background: transparent !important; background-image: none !important; border: 0 !important; border-image: none !important;
  box-shadow: none !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  text-shadow: none !important; padding: 0 !important; min-width: 0 !important; isolation: auto; white-space: normal;
  display: flex; flex-direction: column; gap: 4px;
}
.msg.mine .bubble.media-bubble { align-items: flex-end; }
.msg.other .bubble.media-bubble { align-items: flex-start; }
#log .msg .bubble.media-bubble::before { display: none !important; }
.media-bubble > .media-wrap { position: relative; max-width: 100%; line-height: 0; -webkit-touch-callout: none; }
.media-bubble .media-wrap > img.media, .media-bubble .media-wrap > .video-card {
  border-radius: 14px; box-shadow: 0 6px 14px -4px rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.22);
}
.media-bubble .media-wrap > .video-card .video-poster { border-radius: 14px; }
.media-bubble .media-wrap > img.media { min-width: 120px; min-height: 80px; }   /* a tiny picture still fits the time chip */
html[data-scheme="light"] .media-bubble .media-wrap > img.media,
html[data-scheme="light"] .media-bubble .media-wrap > .video-card { box-shadow: 0 6px 12px -4px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.14); }
/* Lite mode: one small, tight shadow only. */
html.lite .media-bubble .media-wrap > img.media, html.lite .media-bubble .media-wrap > .video-card { box-shadow: 0 2px 4px rgba(0,0,0,.3) !important; }
/* Time chip over the picture's bottom-right corner (video length moves to the bottom-left). */
#log .msg .bubble.media-bubble:not(.has-caption) > .time {
  position: absolute; right: 7px; bottom: 7px; z-index: 1; opacity: 1; line-height: 16px; padding: 1px 7px; border-radius: 9px;
  font-size: 11px; color: #fff; background: rgba(0,0,0,.5); cursor: pointer;
}
.media-bubble .video-card .video-dur { right: auto; left: 6px; }
#log .msg .bubble.media-bubble > .fwd-label { font-size: 12px; color: var(--muted); opacity: 1; line-height: 1.2; }
#log .msg .bubble.media-bubble:not(.has-caption) > span.edited { font-size: 11px; color: var(--muted); opacity: 1; margin: 0; line-height: 1.2; }
/* Caption: a small plain bubble under the picture (solid-ish tint, static shadow, no blur). */
.media-bubble > .caption-bubble {
  position: relative; max-width: 100%; border-radius: 14px; padding: 6px 10px 20px; min-width: 96px;
  white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.35; box-shadow: 0 3px 8px rgba(0,0,0,.22);
}
.msg.mine .media-bubble > .caption-bubble { background: color-mix(in srgb, var(--mine) 78%, transparent); color: #fff; }
.msg.other .media-bubble > .caption-bubble { background: color-mix(in srgb, var(--other) 82%, transparent); color: var(--other-text); }
html[data-scheme="light"] .media-bubble > .caption-bubble { box-shadow: 0 2px 6px rgba(0,0,0,.12); }
.media-bubble > .caption-bubble .time { right: 8px; bottom: 4px; }
/* Reactions overlap the picture's bottom edge (when there's no caption under it). */
#log .msg.media-row .bubble.media-bubble:not(.has-caption) + .reactions { margin-top: -12px; position: relative; z-index: 2; padding: 0 8px; }

/* 26.10.10d: Switch server (installed apps only) */
#menu-server[hidden], #switch-server-panel[hidden], #switch-server-add[hidden], #switch-server-manage[hidden] { display: none !important; }
#switch-server-panel { padding-bottom: 8px; }
#switch-server-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
#switch-server-list li { display: flex; gap: 6px; align-items: stretch; }
#switch-server-panel .switch-server-item { flex: 1; display: grid; grid-template-columns: 1fr auto; text-align: left; padding: 8px 10px; border-radius: 10px; border: 1px solid rgba(127,127,127,.35) !important; background: transparent; color: inherit; cursor: pointer; min-width: 0; }
#switch-server-panel .switch-server-item.current { border-color: #E0A458 !important; }
.switch-server-item .ss-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.switch-server-item .ss-host { grid-column: 1; font-size: .85em; opacity: .7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.switch-server-item .ss-badge { grid-column: 2; grid-row: 1 / span 2; align-self: center; font-size: .75em; padding: 2px 8px; border-radius: 999px; background: #E0A458; color: #1b1b1b; }
#switch-server-panel .ss-remove { padding: 0 10px; border-radius: 10px; border: 1px solid rgba(127,127,127,.35) !important; background: transparent; color: inherit; cursor: pointer; font-size: .85em; }
.switch-server-actions { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
#switch-server-panel .switch-server-actions button { flex: 1; padding: 6px 10px; border-radius: 10px; border: 1px solid rgba(127,127,127,.35) !important; background: transparent; color: inherit; cursor: pointer; }
.switch-server-empty { opacity: .7; font-size: .9em; }

/* 26.10.10e: one-time iPhone Home Screen banner to turn on alerts */
#ios-alert-banner { position: fixed; left: 12px; right: 12px; bottom: calc(env(safe-area-inset-bottom, 0px) + 84px); z-index: 60; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; padding: 12px 14px; border-radius: 14px; background: var(--panel, #1f2622); color: inherit; box-shadow: 0 6px 24px rgba(0,0,0,.35); border: 1px solid rgba(224,164,88,.6); }
#ios-alert-banner span { flex: 1 1 100%; }
#ios-alert-banner button { padding: 8px 14px; border-radius: 10px; border: 1px solid rgba(127,127,127,.4); background: transparent; color: inherit; font: inherit; }
#ios-alert-banner .iab-on { background: #E0A458; color: #1b1b1b; border-color: #E0A458; font-weight: 600; }

/* ===== 26.10.11: Reply to a message ===== */
.rq { display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0; text-align: left; font: inherit; color: inherit;
  background: color-mix(in srgb, currentColor 8%, transparent); border: 0; border-left: 3px solid var(--accent); border-radius: 8px;
  padding: 5px 8px; margin: 0; cursor: pointer; }
.rq-words { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.25; }
.rq-who { font-weight: 600; font-size: 13px; color: var(--accent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rq-text { font-size: 13px; opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rq-thumb { width: 36px; height: 36px; object-fit: cover; border-radius: 6px; flex: none; }
.bubble .reply-quote { margin: 0 0 4px; max-width: 100%; }
.msg.mine .bubble .reply-quote { border-left-color: currentColor; }
.bubble.media-bubble > .reply-quote, .bubble.sticker-bubble > .reply-quote { background: var(--card); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.15); }
.rq-gone .rq-text { font-style: italic; }
#reply-bar { display: flex; align-items: center; gap: 6px; margin: 0 8px 6px; padding: 4px; background: var(--card); border: 1px solid var(--line); border-radius: 10px; }
#reply-bar[hidden] { display: none; }
#reply-bar .rq { flex: 1; background: transparent; }
#reply-cancel { flex: none; width: 36px; height: 36px; border: 0; border-radius: 50%; background: transparent; color: var(--muted); font-size: 24px; line-height: 1; cursor: pointer; }
#reply-cancel:hover, #reply-cancel:focus-visible { background: var(--pill); color: var(--text); }
#log .msg.reply-flash > .bubble { animation: reply-flash 1.6s ease-out; }
@keyframes reply-flash { 0%, 35% { box-shadow: 0 0 0 3px var(--accent); filter: brightness(1.12); } 100% { box-shadow: 0 0 0 0 transparent; filter: none; } }
#log .msg.swipe-ready::before { content: "\21A9"; position: absolute; left: -28px; top: 50%; transform: translateY(-50%); font-size: 18px; color: var(--accent); }
#log .msg.swiping { position: relative; }
@media (prefers-reduced-motion: reduce) { #log .msg.reply-flash > .bubble { animation-duration: .01s; box-shadow: 0 0 0 3px var(--accent); } }

/* ===== 26.10.11: who reacted, in the message menu ===== */
#react-pop { max-height: calc(100dvh - 16px); overflow-y: auto; overscroll-behavior: contain; }
#react-who[hidden] { display: none !important; }
#react-who { display: flex; flex-direction: column; gap: 2px; margin: 4px 0 2px; padding: 4px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); max-height: min(30dvh, 200px); overflow-y: auto; }
.rw-row { display: flex; align-items: baseline; gap: 6px; padding: 3px 6px; border-radius: 8px; font-size: 14px; line-height: 1.3; }
.rw-row.mine { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.rw-emoji { font-size: 18px; flex: none; }
.rw-count { flex: none; font-weight: 600; color: var(--muted); min-width: 1ch; }
.rw-names { min-width: 0; overflow-wrap: anywhere; }

/* ===== 26.10.11: notifications-off reminder ===== */
#mute-bar[hidden] { display: none !important; }
#mute-bar { display: flex; align-items: center; gap: 8px; margin: 4px 8px 0; padding: 3px 4px 3px 10px; font-size: 13px; color: var(--muted);
  background: var(--card); border: 1px solid var(--line); border-radius: 999px; }
#mute-bar-text { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#mute-bar-on { flex: none; border: 0; border-radius: 999px; padding: 3px 10px; font: inherit; font-weight: 600; background: var(--accent); color: var(--on-accent); cursor: pointer; }
#mute-bar-x { flex: none; border: 0; background: transparent; color: var(--muted); font-size: 18px; line-height: 1; width: 26px; height: 26px; border-radius: 50%; cursor: pointer; }
#mute-bar-x:hover { background: var(--pill); }
@media (max-width: 800px) { #mute-bar { margin-right: 52px; } }   /* clear of the bug button in the chat corner */
/* 26.10.11.1 hotfix: long links with no spaces pushed the reply preview / quote off the screen on phones */
#reply-bar { min-width: 0; max-width: calc(100% - 16px); box-sizing: border-box; overflow: hidden; }
#reply-bar .rq, .bubble .reply-quote, .bubble .reply-quote .rq { min-width: 0; max-width: 100%; box-sizing: border-box; overflow: hidden; }
.rq-words, .rq-who, .rq-text { min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
.rq-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rq-text { white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; text-overflow: ellipsis; max-height: 2.6em; }
/* quote on top, a clear gap, the reply text underneath: never overlapping */
.bubble > .reply-quote { display: flex; position: static; float: none; margin: 0 0 8px; flex: none; }
.bubble:not(.media-bubble):not(.sticker-bubble) > .reply-quote + * { display: block; clear: both; }
.bubble:has(> .reply-quote) { min-width: 0; max-width: 100%; overflow-wrap: anywhere; }

/* 26.10.12: quality chip + edit button on tray photos/videos; zoomable viewer; photo/video editor */
.tray-hq[data-q="sd"] { background: rgba(60, 60, 60, .75) !important; }
.tray-edit {
  position: absolute; left: 4px; bottom: 4px; min-height: 0; min-width: 0; width: 24px; height: 24px; padding: 0 !important; border: 0 !important;
  border-radius: 50% !important; background: rgba(0, 0, 0, .6) !important; color: #fff; font-size: 13px; line-height: 24px; z-index: 2;
}
.tray-item.is-uploading .tray-edit { display: none; }
.tray-item.is-edited .tray-badge { background: var(--accent); color: var(--on-accent); }
#light-img { transform-origin: center center; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-user-drag: none; }
#light-img.is-zoomed { cursor: grab; transition: none; }
#lightbox.is-image { overflow: hidden; }
dialog.medit { width: min(940px, calc(100vw - 16px)); max-height: calc(100dvh - 16px); overflow: auto; padding: 14px; border-radius: 14px; border: 0; background: var(--panel, #fff); color: var(--text, #111); box-sizing: border-box; }
dialog.medit::backdrop { background: rgba(0, 0, 0, .6); }
dialog.medit h2 { margin: 0 0 10px; font-size: 1.1rem; }
.medit-stage { position: relative; display: flex; justify-content: center; align-items: center; min-height: 160px; background: #111; border-radius: 10px; overflow: hidden; }
.medit-canvas { display: block; max-width: 100%; }
.medit-crop { position: absolute; box-shadow: 0 0 0 9999px rgba(0, 0, 0, .5); outline: 2px solid #fff; cursor: move; touch-action: none; box-sizing: border-box; }
.medit-h { position: absolute; width: 22px; height: 22px; background: #fff; border-radius: 50%; border: 2px solid var(--accent, #2a7); box-sizing: border-box; }
.medit-nw { left: -11px; top: -11px; cursor: nwse-resize; } .medit-ne { right: -11px; top: -11px; cursor: nesw-resize; }
.medit-sw { left: -11px; bottom: -11px; cursor: nesw-resize; } .medit-se { right: -11px; bottom: -11px; cursor: nwse-resize; }
.medit-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; }
.medit-row .chip { padding: 4px 10px; border-radius: 999px; border: 1px solid currentColor; background: transparent; color: inherit; min-height: 32px; }
.medit-row .chip[aria-pressed="true"] { background: var(--accent, #2a7); color: var(--on-accent, #fff); border-color: transparent; }
.medit-adj { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 6px 14px; margin-top: 10px; }
.medit-slider, .medit-trim label { display: grid; grid-template-columns: 6.5em 1fr; align-items: center; gap: 8px; }
.medit-slider input, .medit-trim input { width: 100%; }
.medit-video { display: block; width: 100%; max-height: 50dvh; background: #000; border-radius: 10px; }
.medit-trim { display: grid; gap: 6px; margin-top: 10px; }
.medit-times { margin: 6px 0; font-variant-numeric: tabular-nums; opacity: .85; }
.medit-check { display: flex; gap: 8px; align-items: center; }
dialog.medit .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
#sendanim-speed-reset { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; text-decoration: underline dotted; }   /* 26.10.13 */
/* 26.10.13: photo/video editor labels sit above their own slider; groups spaced and divided (none after the last) */
.medit-slider, .medit-trim label { grid-template-columns: 1fr; gap: 4px; align-items: stretch; padding: 10px 0; }
.medit-slider + .medit-slider, .medit-trim label + label { border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); }
.medit-trim { gap: 0; }
.medit-adj { grid-template-columns: 1fr; gap: 0; }
.medit-vig { position: absolute; pointer-events: none; }   /* 26.10.13 */
.medit-head { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.medit-ico { display: inline-flex; opacity: .8; }
.medit-val { margin-left: auto; font-variant-numeric: tabular-nums; opacity: .85; min-width: 3ch; text-align: right; }
/* 26.10.13 (Luke): bigger attachment previews, every control a 44px tap target with readable labels */
#tray { padding-left: 12px; padding-right: 12px; }
.tray-item { width: 150px; height: 150px; }
.tray-file { width: min(280px, calc(100vw - 40px)); height: 88px; padding-right: 48px; }
.tray-file-text, .tray-file-text strong { font-size: 14px; }
.tray-x { width: 44px; height: 44px; padding: 4px !important; }
.tray-x span { width: 30px; height: 30px; font-size: 15px; }
.tray-hq { min-width: 44px; min-height: 44px; padding: 0 10px !important; font-size: 13px; border-radius: 10px !important; display: grid; place-items: center; }
.tray-edit { width: 44px; height: 44px; line-height: 44px; font-size: 18px; }
.tray-retry { min-height: 44px; font-size: 14px; }
.tray-file .tray-retry { margin-top: -22px; }
.tray-badge { left: auto; right: 6px; bottom: 6px; font-size: 12px; padding: 2px 6px; }
/* 26.10.13: pinned bar above the messages + its list */
#pin-bar { position: relative; display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-bottom: 1px solid var(--line); background: var(--card); }
#pin-bar[hidden] { display: none; }
.pin-jump { flex: 1; min-width: 0; min-height: 44px; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background: transparent !important; border: 0 !important; color: inherit; }
#pin-list-btn { min-height: 44px; flex: none; }
#pin-list { position: absolute; left: 0; right: 0; top: 100%; z-index: 20; background: var(--card); border: 1px solid var(--line); max-height: 50vh; overflow: auto; }
.pin-item { display: block; width: 100%; min-height: 44px; text-align: left; padding: 8px 12px !important; background: transparent !important; border: 0 !important; border-bottom: 1px solid var(--line) !important; color: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 26.10.13.2: a bubble with a link preview is only as wide as its preview card. A long unbroken URL
   (e.g. an Instagram reel link with a query string) used to set the bubble's width at its full
   one-line length, so the text ran past the card. min-content = the card's fixed width, because the
   text can break anywhere; min-width keeps short bubbles at their usual minimum. */
.bubble:has(.link-card) { width: min-content; max-width: 100%; }
/* Long URLs and words wrap in every bubble, so nothing ever overflows the bubble sideways. */
/* (.bubble already has overflow-wrap:anywhere and links break-all; this keeps any child from widening it.) */
.bubble > * { max-width: 100%; }

/* 26.10.13.3: My Stash treasure-chest icon (full color, never tinted). */
.stash-icon { flex: none; object-fit: contain; vertical-align: middle; }
.stash-pfp { background: transparent !important; display: inline-flex; align-items: center; justify-content: center; }
.stash-pfp .stash-icon { width: 100%; height: 100%; border-radius: 0; }
/* Pin and Save to My Stash get the same full-width rows as Forward (they showed as small inline buttons). */
#react-pin, #react-stash { display: flex; align-items: center; width: 100%; margin-top: 6px; text-align: left; color: var(--text);
  background: transparent; border: 0; border-radius: 8px; padding: 8px; }
#react-pin[hidden], #react-stash[hidden] { display: none; }
#react-stash .stash-icon { width: 20px; height: 20px; margin-right: 8px; }
.fwd-row .stash-icon { width: 24px; height: 24px; }

/* ===== 26.10.13.4: "A new version is available" pop-up (app.js updatePrompt). Same pill look as #toast, but it stays
   until the user picks Refresh or Later, and it sits above the composer so it never covers what they are typing. ===== */
#update-prompt {
  position: fixed; left: 50%; transform: translateX(-50%); z-index: 2147483001;
  bottom: calc(88px + env(safe-area-inset-bottom, 0px)); width: max-content; max-width: calc(100vw - 24px);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center;
  background: color-mix(in srgb, var(--text) 92%, transparent); color: var(--bg, #111);
  padding: 10px 12px; border-radius: 18px; font-size: .95rem; box-shadow: 0 4px 18px rgba(0,0,0,.28);
}
#update-prompt[hidden] { display: none; }
#update-prompt .up-text { flex: 1 1 100%; text-align: center; }   /* text on top, buttons side by side under it */
#update-prompt button { min-height: 44px; padding: 0 14px; border-radius: 999px; border: 0; font: inherit; cursor: pointer; }
#update-prompt .up-later { background: transparent; color: inherit; box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 45%, transparent); }
#update-prompt .up-refresh { background: #1a5fb4; color: #fff; font-weight: 600; } /* fixed dark blue: white text 6.4:1 (WCAG AA) in every theme */

/* Logout confirmation: same pill buttons as the update pop-up; destructive red with white text 5.9:1 in every theme */
#logout-dialog { width: min(360px, calc(100% - 24px)); text-align: center; }
#logout-dialog .lo-actions { display: flex; gap: 10px; justify-content: center; margin-top: 14px; }
#logout-dialog button { min-height: 44px; padding: 0 18px; border-radius: 999px; border: 0; font: inherit; cursor: pointer; }
#logout-dialog .lo-cancel { background: transparent; color: inherit; box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 45%, transparent); }
#logout-dialog .lo-go { background: #c01c28; color: #fff; font-weight: 600; }
#logout-dialog .lo-keys-note { margin: 16px 0 6px; font-size: 13px; opacity: .8; }
#logout-dialog .lo-remove { background: transparent; color: #c01c28; min-height: 40px; padding: 0 12px; text-decoration: underline; }
/* kofi-topbar: Ko-fi link under the composer. Soft rose text (Luke picked variant A).
   Kept to one ~16px line so the message area barely changes. */
#composer-support { margin: 2px 4px 0 0; padding: 0; text-align: right; line-height: 1; }
#composer-support a, #welcome-support a { --rose: #1a5fb4; /* 26.10.13.10: dark blue (Refresh button), was rose */ display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 500; letter-spacing: .02em;
  color: var(--rose); text-decoration: none; padding: 2px 4px; border-radius: 999px; opacity: .9; transition: opacity .15s, background-color .15s, color .15s; }
html[data-scheme="dark"] #composer-support a, html[data-scheme="dark"] #welcome-support a { --rose: #8ab4f8; }
html[data-scheme="light"] #composer-support a, html[data-scheme="light"] #welcome-support a { text-shadow: 0 0 6px rgba(255,255,255,.9), 0 0 2px rgba(255,255,255,.9); }
#composer-support a:hover, #welcome-support a:hover, #composer-support a:focus-visible, #welcome-support a:focus-visible { opacity: 1; text-decoration: underline; text-underline-offset: 2px; }
#composer-support a:active, #welcome-support a:active { opacity: .75; }
#composer-support .cs-heart, #welcome-support .cs-heart { display: inline-block; font-size: 11px; text-decoration: none; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  #composer-support a:hover .cs-heart, #welcome-support a:hover .cs-heart { animation: cs-pulse 1.1s ease-in-out infinite; }
}
@keyframes cs-pulse { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.22); } 60% { transform: scale(.96); } }
html.picker-tall #composer-support { display: none; }
#welcome-support { margin: 14px 0 0; padding: 0; text-align: center; line-height: 1; position: relative; z-index: 2; }  /* above #transcript */

/* ===== 26.10.13.13 (Luke): message menu. A floating reaction pill + a compact action card + a time/receipt footer,
   placed by app.js placeReactPop inside the visible chat (never under the header). Stacks above the header (z 10) and the bug button (z 40).
   Look: "Grove" (frosted glass, leaf unfurl), picked by Luke over the "canopy" alternative. ===== */
#react-pop {
  --rp-leaf: #3fae6a; --rp-w: 216px;
  z-index: 45;   /* above the header (10) and the floating bug button (40) */ position: fixed; display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  width: min(var(--rp-w), calc(100vw - 16px)); max-width: calc(100vw - 16px); max-height: none;
  padding: 0; background: transparent; border: 0; box-shadow: none; border-radius: 0;
  overflow-y: auto; overflow-x: visible; overscroll-behavior: contain; scrollbar-width: thin;
}
#react-pop:not([hidden]) { display: flex; }
#react-pop > * { flex: none; }
#react-pop[data-mine="1"] { align-items: flex-end; }
#react-pop[data-side="above"] > #react-card { order: 0; } #react-pop[data-side="above"] > #react-extra { order: 1; } #react-pop[data-side="above"] > #react-quick { order: 2; }

/* shared surfaces */
#react-quick, #react-card, #react-extra:not([hidden]) {
  background: color-mix(in srgb, var(--card) 55%, color-mix(in srgb, var(--bg, #141c18) 88%, transparent));
  -webkit-backdrop-filter: blur(16px) saturate(1.35); backdrop-filter: blur(16px) saturate(1.35);
  border: 1px solid color-mix(in srgb, var(--rp-leaf) 26%, var(--line));
  box-shadow: 0 8px 28px rgba(0,0,0,.32), 0 1px 0 rgba(255,255,255,.06) inset;
}
#react-quick { display: flex; flex-wrap: nowrap; align-items: center; gap: 0; width: max-content; max-width: 100%;
  border-radius: 999px; padding: 3px; }
#react-quick button.react-q { width: 32px; height: 32px; font-size: 20px; border-radius: 50%;
  transition: transform .12s ease, background-color .12s ease; }
#react-quick button.react-q:hover, #react-quick button.react-q:focus-visible { transform: scale(1.18); outline: none;
  background: color-mix(in srgb, var(--rp-leaf) 20%, transparent); }
#react-quick button.react-q[aria-pressed="true"] { background: color-mix(in srgb, var(--rp-leaf) 30%, transparent); box-shadow: 0 0 0 1.5px var(--rp-leaf) inset; }
#react-quick button.react-more { position: relative; width: 26px; height: 26px; margin: 0 2px 0 3px; border-radius: 50%;
  background: var(--pill); color: var(--muted); font-size: 0; }
#react-quick button.react-more::before { content: ""; position: absolute; left: 50%; top: 45%; width: 7px; height: 7px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: translate(-50%, -50%) rotate(45deg); transition: transform .15s; }
#react-quick button.react-more.open::before { transform: translate(-50%, -20%) rotate(225deg); }
#react-quick button.react-more:hover, #react-quick button.react-more:focus-visible { color: var(--text); outline: 2px solid color-mix(in srgb, var(--rp-leaf) 60%, transparent); }
#react-extra:not([hidden]) { margin: 0; padding: 6px; border-radius: 14px; width: 100%; box-sizing: border-box; }
#react-grid { max-height: min(34dvh, 240px); min-height: 0; }
#react-grid button { width: 34px; height: 34px; font-size: 21px; }

#react-card { display: flex; flex-direction: column; border-radius: 14px; padding: 4px; width: 100%; box-sizing: border-box; }
#react-card > button, #react-pop #react-reply, #react-pop #react-copy, #react-pop #react-forward, #react-pop #react-pin,
#react-pop #react-stash, #react-pop #react-edit, #react-pop #react-download, #react-pop #react-delete {
  display: flex; align-items: center; gap: 11px; width: 100%; min-height: 0; height: 34px; margin: 0; padding: 0 10px;
  border: 0; border-radius: 9px; background: transparent; color: var(--text); font: inherit; font-size: 14px; line-height: 1;
  text-align: left; cursor: pointer; white-space: nowrap; position: relative; }
#react-card > button[hidden] { display: none !important; }
#react-card .rp-ic, #react-pop #react-stash .stash-icon { width: 18px; height: 18px; flex: none; margin: 0; opacity: .82; }
#react-card > button:hover, #react-card > button:focus-visible { outline: none; background: color-mix(in srgb, var(--rp-leaf) 17%, transparent); }
#react-card > button:hover .rp-ic, #react-card > button:focus-visible .rp-ic { opacity: 1; color: var(--rp-leaf); }
#react-pop #react-delete { color: var(--danger); margin-top: 3px; }
#react-pop #react-delete::before { content: ""; position: absolute; left: 8px; right: 8px; top: -2px; height: 1px; background: var(--line); }
#react-pop #react-delete .rp-ic { color: var(--danger); opacity: 1; }
#react-pop #react-delete:hover, #react-pop #react-delete:focus-visible { background: color-mix(in srgb, var(--danger) 15%, transparent); }
#react-who:not([hidden]) { padding: 2px 4px 4px; margin-bottom: 2px; border-bottom: 1px solid var(--line); }
#react-note { margin: 2px 8px 4px; }
#react-foot { display: flex; align-items: center; gap: 6px; margin: 4px 6px 0; padding: 6px 4px 3px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#react-foot[hidden], #react-foot:empty { display: none; }
#react-foot .rp-ticks { position: static; display: inline; margin: 0; padding: 0; font-size: 12px; color: var(--rp-leaf); background: none; }
#react-foot .rp-ticks::after { content: " \00b7"; color: var(--muted); }
@media (pointer: coarse) {
  #react-card > button, #react-pop #react-reply, #react-pop #react-copy, #react-pop #react-forward, #react-pop #react-pin,
  #react-pop #react-stash, #react-pop #react-edit, #react-pop #react-download, #react-pop #react-delete { height: 38px; font-size: 15px; }
  #react-quick button.react-q { width: 36px; height: 36px; font-size: 22px; }
  #react-quick button.react-more { width: 30px; height: 30px; }
}

/* the message the menu is for: a soft leaf-green glow, the rest of the chat stays readable */
#log .msg.rp-target > .bubble { box-shadow: 0 0 0 2px color-mix(in srgb, var(--rp-leaf, #3fae6a) 70%, transparent), 0 0 18px color-mix(in srgb, #3fae6a 35%, transparent);
  transition: box-shadow .15s ease; }

/* open: the pill and card unfurl from the corner nearest the message, like a leaf opening (motion.css keyframes off here) */
#react-pop[data-bc-motion] { animation: none; }
#react-pop.rp-in > #react-quick { animation: rp-unfurl calc(190ms * var(--bc-anim-scale, 1)) cubic-bezier(.2, .9, .25, 1.15) both; transform-origin: inherit; }
#react-pop.rp-in > #react-card { animation: rp-unfurl calc(220ms * var(--bc-anim-scale, 1)) cubic-bezier(.2, .9, .25, 1.1) 40ms both; transform-origin: inherit; }
#react-pop.rp-in #react-quick .react-q { animation: rp-bud calc(260ms * var(--bc-anim-scale, 1)) cubic-bezier(.3, 1.4, .5, 1) both; }
#react-pop.rp-in #react-quick .react-q:nth-child(2) { animation-delay: 25ms; } #react-pop.rp-in #react-quick .react-q:nth-child(3) { animation-delay: 50ms; }
#react-pop.rp-in #react-quick .react-q:nth-child(4) { animation-delay: 75ms; } #react-pop.rp-in #react-quick .react-q:nth-child(5) { animation-delay: 100ms; }
#react-pop.rp-in #react-quick .react-q:nth-child(6) { animation-delay: 125ms; } #react-pop.rp-in #react-quick .react-q:nth-child(7) { animation-delay: 150ms; }
@keyframes rp-unfurl { from { opacity: 0; transform: translateY(var(--rp-from-y, -10px)) scale(.55) rotate(-5deg); } 60% { opacity: 1; } to { opacity: 1; transform: none; } }
@keyframes rp-bud { from { transform: scale(.2); opacity: 0; } to { transform: none; opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  #react-pop.rp-in > *, #react-pop.rp-in #react-quick .react-q { animation: none !important; }
  #react-quick button.react-q:hover { transform: none; }
}

/* ===== 26.10.13.13 (Luke): replies. The quoted message sits inside the top of the reply bubble as a compact inset:
   tinted block, 3px bar and name in the original sender's colour (Twigum accent if they have none), one line of
   the original (or a thumbnail + "Photo"); time and receipt stay bottom-right inside the bubble. ===== */
.bubble > .reply-quote { margin: 0 0 5px; padding: 4px 8px 4px 9px; gap: 8px; border-radius: 8px;
  border-left: 3px solid var(--rq-c, var(--accent)); background: color-mix(in srgb, var(--rq-c, var(--accent)) 14%, transparent); }
.msg.mine .bubble > .reply-quote { border-left-color: var(--rq-c, currentColor);
  background: color-mix(in srgb, var(--rq-c, #ffffff) 16%, rgba(0,0,0,.12)); }
.bubble > .reply-quote .rq-who { font-size: 13px; font-weight: 700; color: var(--rq-c, var(--accent)); line-height: 1.25; }
.msg.mine .bubble > .reply-quote .rq-who { color: var(--rq-c, currentColor); }
.bubble > .reply-quote .rq-text { display: block; -webkit-line-clamp: unset; line-clamp: none; max-height: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; line-height: 1.3; opacity: .82; }
.bubble > .reply-quote .rq-thumb { width: 34px; height: 34px; border-radius: 6px; order: -1; }
.bubble > .reply-quote:hover, .bubble > .reply-quote:focus-visible { outline: none; background: color-mix(in srgb, var(--rq-c, var(--accent)) 24%, transparent); }
.bubble:has(> .reply-quote) { min-width: min(220px, 100%); }

/* ===== embed-fullscreen-fix (Luke, roadmap 12 / 12a) =====
   Shared "inset" language for link previews (and the reply quote on msg-menu-position can reuse these tokens):
   frosted accent-tinted panel, rounded, with a small Twigum leaf mark instead of Telegram's plain left bar. */
:root {
  --bc-inset-bg: color-mix(in srgb, var(--accent) 12%, rgba(255,255,255,.06));
  --bc-inset-border: color-mix(in srgb, var(--accent) 28%, transparent);
  --bc-inset-radius: 12px;
  --bc-inset-blur: blur(8px) saturate(1.2);
}
html[data-scheme="light"] { --bc-inset-bg: color-mix(in srgb, var(--accent) 9%, rgba(255,255,255,.55)); }
@keyframes bc-fade { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* --- Link preview (non-YouTube): compact block inside the bubble --- */
.link-card.web-card.lp {
  position: relative; display: flex; align-items: flex-start; gap: 10px;
  box-sizing: border-box;
  width: min(320px, 70vw); height: 124px; min-height: 124px; max-height: 124px;
  margin: 6px 0 2px; padding: 8px 10px 8px 22px;
  border: 1px solid var(--bc-inset-border); border-left: 1px solid var(--bc-inset-border);
  border-radius: var(--bc-inset-radius); background: var(--bc-inset-bg);
  text-decoration: none; color: inherit; overflow: hidden;
  /* Locked box: title/image arrival must not change height. Off-screen cards keep that size. */
  content-visibility: auto;
  contain-intrinsic-size: 320px 124px;
  contain: layout style paint;
  animation: none;
}
.link-card.web-card.lp:hover { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.link-card.web-card.lp:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Leaf mark (picked by Luke) */
.link-card.web-card.lp::before {
  content: ""; position: absolute; left: 8px; top: 10px; width: 8px; height: 16px;
  border-radius: 0 100% 0 100%; background: var(--accent);
  box-shadow: 0 0 0 0 transparent; transform: rotate(-12deg);
}
.link-card.web-card.lp::after {   /* the stem */
  content: ""; position: absolute; left: 11px; top: 24px; bottom: 10px; width: 2px; border-radius: 2px;
  background: linear-gradient(var(--accent), transparent); opacity: .55;
}
.link-card.web-card.lp > .web-body { flex: 1; min-width: 0; padding: 0; gap: 2px; overflow: hidden; }
.link-card.web-card.lp > img {
  order: 2; flex: none; width: 56px; height: 56px; min-width: 56px; min-height: 56px;
  max-height: 56px; border-radius: 8px; object-fit: cover;
}
.lp .link-site { display: flex; align-items: center; gap: 5px; min-width: 0; font-size: 12px; font-weight: 650; opacity: 1; color: color-mix(in srgb, var(--accent) 75%, #fff); }
html[data-scheme="light"] .lp .link-site { color: color-mix(in srgb, var(--accent) 85%, #000); }
.lp .link-site-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp .link-fav { flex: none; display: inline-grid; place-items: center; width: 14px; height: 14px; border-radius: 4px; font-size: 9px; font-weight: 800; line-height: 1; color: #fff; background: var(--accent); }
.lp .web-title { font-size: 14px; line-height: 1.3; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.lp .web-desc { font-size: 13px; line-height: 1.35; opacity: .8; -webkit-line-clamp: 3; }
.msg.mine .lp .link-site { color: inherit; opacity: .92; }
.msg.mine .lp .link-fav { background: rgba(255,255,255,.9); color: var(--mine, #333); }

/* Pending and failed previews add no height. Width stays so the URL above keeps its
   wrap; display:none let the bubble shrink and the URL reflow into more lines. */
.link-card.web-card.lp-pending,
.link-card.web-card.lp-empty {
  display: block;
  box-sizing: border-box;
  width: min(320px, 70vw);
  height: 0; min-height: 0; max-height: 0;
  margin: 0; padding: 0; border: 0;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  content-visibility: hidden;
  contain-intrinsic-size: 320px 0px;
}

/* Android / coarse pointer: drop live bubble backdrop blur over animated Pine (GPU thrash while scrolling).
   Lite mode already kills all backdrop-filter; this covers Android that opted out of auto-lite. */
html[data-android] #log .msg:not(.removed) .bubble:not(.jumbo),
html[data-android] #log .msg:not(.removed) .bubble:not(.jumbo)::before {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
@media (pointer: coarse) {
  html:not(.lite):not([data-glass="baked"]) #log .msg:not(.removed) .bubble:not(.jumbo) {
    -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  }
}

/* --- YouTube: no bubble (12a). Player on the sender's side; link one line with "..." --- */
#log .msg .bubble.yt-bubble { background: transparent !important; box-shadow: none !important; padding: 0 !important; border: 0 !important; display: flex; flex-direction: column; gap: 4px; }
#log .msg .bubble.yt-bubble::before { display: none !important; }
.yt-bubble > .yt-card { margin: 0; border: 0; border-radius: 14px; background: color-mix(in srgb, var(--card) 70%, transparent);
  -webkit-backdrop-filter: var(--bc-inset-blur); backdrop-filter: var(--bc-inset-blur); box-shadow: 0 6px 14px -6px rgba(0,0,0,.45); }
/* Regular yt-card widths come from the tier media queries above; shorts stay compact. */
.link-card.yt-card.yt-short { width: min(240px, 58vw); max-width: 100%; }
.yt-short .yt-box, .yt-short .yt-frame { aspect-ratio: 9 / 16; }
.yt-card .link-foot { gap: 8px; padding: 0 10px; min-width: 0; height: 40px; box-sizing: border-box; flex: none; align-items: center; overflow: hidden; }
.yt-card .yt-url { flex: 1 1 auto; min-width: 0; display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 12px; line-height: 40px; height: 40px; color: var(--muted); text-decoration: none; }
.yt-card .yt-url:hover { text-decoration: underline; }
.yt-card .link-open { flex: none; font-size: 12px; line-height: 40px; height: 40px; display: inline-flex; align-items: center; }
.yt-play { width: 52px; height: 36px; border-radius: 10px; }
.yt-play::after { left: 21px; top: 10px; border-width: 8px 0 8px 13px; }
.yt-bubble > .caption-bubble.yt-text { order: -1; align-self: inherit; }
#log .msg .bubble.yt-bubble:not(.has-caption) > .time, #log .msg .bubble.yt-bubble:not(.has-caption) > span.edited {
  position: static !important; align-self: flex-end; margin: 0 4px; padding: 0 !important; background: none !important;
  font-size: 11px; color: var(--muted); opacity: .85; text-shadow: none; box-shadow: none !important; }
.msg.yt-row .name { opacity: .8; font-size: 12px; }
@media (pointer: coarse) { .yt-card .link-open, .yt-card .yt-url { /* height locked at 40px above — do not grow after mount */ } }
.yt-text a.msg-link { display: inline-block; max-width: 100%; vertical-align: bottom; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; word-break: normal; }

/* profile-crop: round profile-picture crop dialog (appended; no shared rules edited). Look: Canopy */
dialog.avc { width: min(560px, 94vw); max-height: 94vh; overflow: auto; box-sizing: border-box; padding: 16px; border: 0; border-radius: 18px; }
dialog.avc h2 { margin: 0 0 12px; font-size: 1.1rem; }
.avc-main { display: flex; gap: 16px; align-items: center; justify-content: center; flex-wrap: wrap; }
.avc-stage { position: relative; width: min(300px, 78vw); aspect-ratio: 1; border-radius: 14px; overflow: hidden; background: #0d120d; touch-action: none; user-select: none; -webkit-user-select: none; cursor: grab; outline: none; }
.avc-stage:active { cursor: grabbing; }
.avc-img { position: absolute; left: 50%; top: 50%; max-width: none; pointer-events: none; -webkit-user-drag: none; }
.avc-ring { position: absolute; inset: 0; pointer-events: none; border-radius: 50%; box-shadow: 0 0 0 999px rgba(6, 10, 6, .62); }
.avc-side { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.avc-preview { width: 96px; height: 96px; border-radius: 50%; background: #f5c518; }
.avc-preview-s { width: 36px; height: 36px; }
.avc-hint { font-size: .8rem; opacity: .75; }
.avc-zoom { display: flex; align-items: center; gap: 10px; margin: 14px auto 6px; max-width: 320px; font-weight: 600; }
.avc-zoom input { flex: 1; accent-color: var(--accent); }
.avc-tools { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 10px; }
@media (max-width: 480px) { .avc-side { flex-direction: row; } .avc-hint { display: none; } }
/* Canopy - soft leafy vignette, dashed leaf-green guide, rule-of-thirds while dragging */
.avc-canopy .avc-stage { background: radial-gradient(circle, #1d3a1f, #0a140b); }
.avc-canopy .avc-ring { box-shadow: 0 0 0 999px rgba(18, 40, 20, .78); border: 3px dashed rgba(127, 214, 120, .95); box-sizing: border-box; }
.avc-canopy .avc-ring::before { content: ""; position: absolute; inset: 0; border-radius: 50%; opacity: 0; transition: opacity .2s;
  background: linear-gradient(90deg, transparent 33%, rgba(255,255,255,.35) 33.3%, transparent 33.6%, transparent 66.4%, rgba(255,255,255,.35) 66.7%, transparent 67%),
              linear-gradient(0deg, transparent 33%, rgba(255,255,255,.35) 33.3%, transparent 33.6%, transparent 66.4%, rgba(255,255,255,.35) 66.7%, transparent 67%); }
.avc-canopy .avc-stage:active .avc-ring::before { opacity: 1; }
.avc-canopy .avc-preview { box-shadow: 0 0 0 3px #5fae5a; }

/* licensing: small License link in the trademark footer line (every server, links to /license) */
#bc-footer .bc-license-link, .fd-legal .bc-license-link { color: inherit; text-decoration: underline; text-underline-offset: 2px; opacity: .9; margin-left: .35em; }

/* Mobile menus open full screen (roadmap item 7). On phones the app menu and Profile Settings fill the screen, with a sticky
   bar (Back pill + title) that stays put while the panel scrolls. Back, Escape and the phone's own Back all close it. Desktop
   and tablets keep the pop-over. Draft: qwen3.5:9b (CT110), reviewed and completed by hand. */
.fs-bar { display: none; }
@media (max-width: 640px) {
  #app-menu:not([hidden]), #profile-pop:not([hidden]),
  html:not(.no-chat) body:not(.pn-page) #app-menu:not([hidden]) {
    position: fixed !important; inset: 0 !important; top: 0 !important; right: 0 !important; left: 0 !important; bottom: 0 !important;
    width: 100% !important; height: 100% !important; height: 100dvh !important; max-width: none !important; max-height: none !important;
    transform: none !important; margin: 0 !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important;
    z-index: 60 !important; padding: 0 12px calc(16px + env(safe-area-inset-bottom, 0px)) !important;
    overflow-y: auto !important; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    background: var(--card) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
  }
  /* Opaque, above everything: the light theme's see-through menu glass and the floating bug button stay out of the way. */
  html[data-scheme] #app-menu:not([hidden]), html[data-scheme] #profile-pop:not([hidden]) { background: var(--card) !important; }
  header:has(#app-menu:not([hidden])) { z-index: 61 !important; }
  html:has(#app-menu:not([hidden])) .bug-fab, html:has(#profile-pop:not([hidden])) .bug-fab { visibility: hidden; }
  #app-menu > .x-close, #profile-pop > .x-close, #profile-pop > #profile-head, #profile-pop > #profile-head + .profile-rule { display: none !important; }
  #app-menu > .fs-bar, #profile-pop > .fs-bar {
    display: flex; align-items: center; gap: 8px; position: sticky; top: 0; z-index: 3;
    min-height: calc(52px + env(safe-area-inset-top, 0px)); margin: 0 -12px 8px; padding: calc(6px + env(safe-area-inset-top, 0px)) 12px 6px;
    background: color-mix(in srgb, var(--card) 92%, transparent); border-bottom: 1px solid var(--line);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  }
  .fs-bar .fs-back, #app-menu .fs-bar .fs-back {
    display: inline-flex; align-items: center; gap: 2px; height: 40px; width: auto; padding: 0 14px 0 8px !important; margin: 0;
    border: 0 !important; border-radius: 999px !important; font: inherit; font-weight: 600; text-shadow: none;
    color: var(--accent) !important; background: color-mix(in srgb, var(--accent) 14%, transparent) !important; box-shadow: none !important;
  }
  .fs-bar .fs-back:active { background: color-mix(in srgb, var(--accent) 26%, transparent) !important; }
  .fs-bar .fs-title { flex: 1; min-width: 0; text-align: center; font-weight: 700; margin-right: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Reactions (roadmap item 11): emoji + count chips, a ring on yours, a pop when you add one, and a smiley-plus chip that
   opens the reaction menu. The add chip is always there on touch screens and shows on hover/focus with a mouse. */
.react-chip { display: inline-flex; align-items: center; gap: 4px; min-height: 26px; padding: 1px 8px 1px 6px; cursor: pointer;
  transition: transform .12s ease, background-color .15s ease, border-color .15s ease; }
.react-chip .rc-emoji { font-size: 16px; line-height: 1; display: inline-flex; align-items: center; }
.react-chip .rc-emoji img { width: 1.15em; height: 1.15em; }
.react-chip .rc-count { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--muted); min-width: .6em; text-align: center; }
.react-chip.mine { box-shadow: inset 0 0 0 1px var(--accent); }
.react-chip.mine .rc-count { color: color-mix(in srgb, var(--accent) 75%, var(--text)); }
.react-chip:active { transform: scale(.92); }
.react-chip.react-add { padding: 1px 7px; color: var(--muted); border-style: dashed; background: transparent; }
.react-chip.react-add:hover, .react-chip.react-add:focus-visible { color: var(--accent); border-color: var(--accent); border-style: solid; }
@media (hover: hover) and (pointer: fine) {
  .reactions .react-add { opacity: 0; transition: opacity .15s ease; }
  .msg:hover .reactions .react-add, .reactions:hover .react-add, .reactions .react-add:focus-visible { opacity: 1; }
}
@keyframes bc-react-pop { 0% { transform: scale(.6); } 55% { transform: scale(1.18); } 100% { transform: scale(1); } }
.react-chip.pop { animation: bc-react-pop .32s cubic-bezier(.3, 1.4, .5, 1); }
@media (prefers-reduced-motion: reduce) { .react-chip.pop { animation: none; } .react-chip { transition: none; } }

/* Display size (UI scale). Zoom interactive chrome (#shell + header + body-level pops), NOT body.
   Body zoom forced WebKit to rescale fixed wallpaper/#chat-bg with the UI and fought visualViewport.
   Leaving body>#chat-bg at 1× keeps the composer wallpaper seam closed at every scale (85–130%): .bgx
   height tracks the unzoomed layer clientHeight ≈ viewport. Shell/header use zoom so buttons and text still grow.
   Combined with the -3px overscan on #chat-bg / body::after, DPR and browser zoom also stay gap-free. */
html[data-ui-scale] body {
  height: var(--app-h, 100dvh);
  margin-top: var(--app-top, 0px);
}
html[data-ui-scale] body > header,
html[data-ui-scale] #shell {
  zoom: var(--ui-z, 1);
}
/* Pops / dialogs outside #shell: zoom with the chrome so Display size still applies.
   #react-pop and #lightbox stay at 1× — placeReactPop / lightbox set left/top from getBoundingClientRect
   (viewport px); inverse-zoom under the old body-zoom model kept them at 1× for the same reason. */
html[data-ui-scale] #profile-pop,
html[data-ui-scale] #members-pop,
html[data-ui-scale] #bc-footer,
html[data-ui-scale] dialog[open]:not(#lightbox) {
  zoom: var(--ui-z, 1);
}
#ui-scale-row .uis-ctl { align-items: center; gap: 6px; }
#ui-scale-row .uis-btn { width: 40px; height: 40px; padding: 0; font-size: 22px; font-weight: 600; line-height: 1; }
#ui-scale-row .uis-val { min-width: 3.4em; text-align: center; font-variant-numeric: tabular-nums; font-weight: 600; }
#ui-scale-row .uis-auto { height: 40px; padding: 0 12px; font-size: 14px; font-weight: 600; line-height: 1; }
#ui-scale-row .uis-auto[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
#ui-scale-row button:disabled { opacity: .4; }
/* Viewport units do not know about the zoom: menus that size from 100vw/100dvh get caps divided by --ui-z.
   #lightbox stays at the chrome zoom (no inverse): it is a body-level dialog, not measured against a zoomed body. */
html[data-ui-scale] #app-menu {
  width: min(360px, calc((100vw - 20px) / var(--ui-z, 1))); max-width: calc((100vw - 20px) / var(--ui-z, 1));
  max-height: min(calc(78dvh / var(--ui-z, 1)), 640px);
}
html[data-ui-scale] #profile-pop { max-width: calc((100vw - 16px) / var(--ui-z, 1)); max-height: calc((100dvh - 160px) / var(--ui-z, 1)); }
html[data-ui-scale] dialog[open] { max-width: calc((100vw - 16px) / var(--ui-z, 1)); max-height: calc((100dvh - 32px) / var(--ui-z, 1)); }

/* ===== chatlist-pin-reorder: one list, pins, drag order, archive, condensed rows, edge collapse toggle =====
   #people is the ONLY scroller in the panel: the Lobby, pinned chats, all chats, the "Archived Chats" row and the
   archived view's Back bar all live inside it and scroll together (no sticky parts, no nested scrollers).
   overscroll-behavior stops a fling at the end of the list from chaining to the page (Android pull/bounce). */
#sidebar { position: relative; overflow: visible; gap: 6px; }
#people { gap: 2px; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; touch-action: pan-y; scroll-padding: 8px; }
#friends { display: flex; flex-direction: column; gap: 2px; }
.chat-row, #lobby-row.chat-row { padding: 6px 8px; min-height: 52px; gap: 10px; border-radius: 10px; }
.chat-row .pfp, #lobby-row.chat-row .pfp { width: 38px; height: 38px; }
.chat-row .row-main { gap: 1px; }
.chat-row .row-preview { font-size: 12.5px; line-height: 1.3; }
/* The Lobby is an ordinary row now: same size and style as every chat, a small globe as its picture. */
#lobby-row, #lobby-row.chat-row { display: flex !important; box-shadow: none; background: transparent; }
#lobby-row strong, #lobby-row.chat-row strong.row-name { font-size: inherit; text-shadow: inherit; grid-row: auto; }
.pfp.lobby-pic, .pfp.arch-pic { display: inline-flex; align-items: center; justify-content: center; box-shadow: none;
  background: color-mix(in srgb, var(--accent) 22%, var(--card)); color: color-mix(in srgb, var(--accent) 70%, var(--text)); }
.pfp.arch-pic { background: color-mix(in srgb, var(--muted) 25%, var(--card)); color: var(--text); }
.row-pin { flex: none; color: var(--muted); opacity: .85; }
/* Drag grip: the only place a drag starts, so the rest of the row scrolls normally. 44px wide hit area. */
.chat-row { position: relative; }
.drag-handle { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; align-self: stretch;
  margin: -6px -8px -6px -4px; padding: 0 8px; color: var(--muted); opacity: .45; cursor: grab; touch-action: none; box-sizing: content-box; }
.chat-row:hover .drag-handle, .drag-handle:focus-visible { opacity: .9; }
#sidebar.arch-view .drag-handle, html.side-collapsed .drag-handle { display: none; }
.chat-row.dragging { z-index: 5; background: var(--card); box-shadow: 0 6px 18px rgba(0,0,0,.35); transition: none !important; opacity: .97; }
.chat-row.drag-shift { transition: transform .15s ease; }
html.chat-dragging, html.chat-dragging * { cursor: grabbing !important; user-select: none !important; -webkit-user-select: none !important; }
/* 26.11: grips mount only in edit mode; highlight the pressed row; cheap touch devices skip hover affordances. */
html:not(.chat-list-edit) .drag-handle { display: none; }
html.chat-list-edit .chat-row.edit-focus { outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent); outline-offset: -2px; }
html.chat-list-edit .drag-handle { opacity: .85; }
html[data-ios] .chat-row:hover .drag-handle, html[data-android] .chat-row:hover .drag-handle { opacity: .85; }

.list-label { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); padding: 6px 8px 2px; }
/* Archived view: the panel swaps in place; a big Back bar at the top (it scrolls with the list). */
#arch-head { display: flex; align-items: center; gap: 8px; padding: 2px 0 6px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
#arch-head[hidden] { display: none; }
#arch-back { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 14px 0 8px; border-radius: 22px;
  font-weight: 600; color: var(--text); background: color-mix(in srgb, var(--accent) 28%, var(--card)); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); cursor: pointer; }
#arch-back:hover { background: color-mix(in srgb, var(--accent) 40%, var(--card)); }
#arch-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#arch-head strong { font-size: 15px; }
#sidebar.arch-view #requests, #sidebar.arch-view #side-actions { display: none !important; }
.arch-empty { color: var(--muted); padding: 16px 8px; text-align: center; font-size: 13px; }
/* The long-press / right-click menu. */
dialog.chat-sheet { border: 1px solid var(--line); border-radius: 16px; padding: 10px; width: min(320px, 92vw); background: var(--card); color: var(--text); }
dialog.chat-sheet::backdrop { background: rgba(0,0,0,.45); }
.chat-sheet h3 { margin: 4px 8px 8px; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-sheet-acts { display: flex; flex-direction: column; gap: 2px; }
.chat-sheet-acts button, .chat-sheet-cancel { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; padding: 0 12px;
  border-radius: 10px; font: inherit; font-size: 15px; text-align: left; }
.chat-sheet-cancel { justify-content: center; margin-top: 6px; color: var(--muted); }
/* Collapse toggle: on the search row, to the right of the shortened search pill.
   It must not sit on its own empty header row or cover search, chips, chat rows,
   or messages. On the collapsed rail it stays at the top and points the other
   way. Phones (<=800px) hide it and the search pill goes full width. */
#side-collapse { position: relative; top: auto; right: auto; transform: none; z-index: 5;
  align-self: center; flex: none; margin: 0;
  width: 32px; height: 32px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%;
  background: var(--accent); color: var(--on-accent, #fff); border: 2px solid var(--card); box-shadow: 0 1px 6px rgba(0,0,0,.28); cursor: pointer; font-size: 0; }
#side-collapse svg { width: 18px; height: 18px; transition: transform .2s ease; }
#side-collapse:hover { filter: brightness(1.12); box-shadow: 0 2px 10px rgba(0,0,0,.35); }
#side-collapse:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 55%, #fff); outline-offset: 2px; }
@media (min-width: 801px) {
  html.side-collapsed #side-collapse { align-self: center; margin: 6px auto 4px; transform: none; }
  html.side-collapsed #side-collapse svg { transform: rotate(180deg); }
  html.side-collapsed #sidebar { display: flex !important; }
  html.side-collapsed #side-expand { display: none !important; }
  html.side-collapsed #arch-head strong, html.side-collapsed #arch-back span { display: none; }
}
@media (max-width: 800px) { #side-collapse { display: none !important; } }
/* Share chooser: one list now (#group-list is gone). */

/* ===== chatlist-pin-reorder: compact panel footer (Variant B, html.foot-b, see FOOTER_VARIANT in app.js).
   Slim profile pill + a separate, subtle ghost "+" beside it. ===== */
html.foot-b #me-dock { position: relative; border-top: 0; padding-top: 4px; display: flex; align-items: center; gap: 6px; }
html.foot-b #me-bar { display: flex; align-items: center; gap: 4px; padding: 4px 6px; min-height: 0; border-radius: 999px; flex: 1 1 auto; min-width: 0; }
html.foot-b #me-open { flex: 1 1 auto; min-width: 0; min-height: 40px; padding: 0 6px 0 0; gap: 8px; display: flex; align-items: center; }
html.foot-b #me-photo { width: 32px; height: 32px; flex: none; }
html.foot-b #me-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; }
html.foot-b #foot-plus, html.foot-b #me-gear {
  flex: none; width: 40px !important; height: 40px !important; min-width: 40px; min-height: 40px; padding: 0 !important; margin: 0 !important;
  display: inline-flex; align-items: center; justify-content: center; border-radius: 50% !important; box-shadow: none; }
html.foot-b #side-actions { display: none !important; }
/* Ghost "+": no fill (no accent), icon + outline clearly visible at rest, with a colour per theme.
   Hover / keyboard focus / open: firmer outline + soft tint. */
html.foot-b #foot-plus { background: transparent; cursor: pointer; transition: background .15s, color .15s, border-color .15s;
  color: #1c2430; border: 1.5px solid rgba(28, 36, 48, .55); }
html.foot-b #foot-plus:hover, html.foot-b #foot-plus:focus-visible, html.foot-b #foot-plus[aria-expanded="true"] {
  color: #0f1620; border-color: rgba(28, 36, 48, .8); background: rgba(28, 36, 48, .12); }
html[data-scheme="dark"].foot-b #foot-plus { color: #e8eef5; border-color: rgba(232, 238, 245, .55); background: rgba(14, 22, 33, .25); }
html[data-scheme="dark"].foot-b #foot-plus:hover, html[data-scheme="dark"].foot-b #foot-plus:focus-visible, html[data-scheme="dark"].foot-b #foot-plus[aria-expanded="true"] {
  color: #ffffff; border-color: rgba(232, 238, 245, .85); background: rgba(232, 238, 245, .14); }
html.foot-b #foot-plus:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
html.foot-b #foot-plus[aria-expanded="true"] svg { transform: rotate(45deg); }
html.foot-b #foot-plus svg { transition: transform .15s ease; }
html.foot-b #foot-menu { position: absolute; bottom: calc(100% + 6px); right: 8px; z-index: 30; display: flex; flex-direction: column; gap: 2px;
  min-width: 190px; padding: 6px; background: var(--card); color: var(--text); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 8px 24px rgba(0,0,0,.35); }
html.foot-b #foot-menu[hidden] { display: none; }
html.foot-b #foot-menu .side-act { display: flex; width: 100%; min-height: 44px; margin: 0; padding: 0 10px; gap: 10px; justify-content: flex-start; border-radius: 10px; }
html.foot-b #foot-menu .side-act[hidden] { display: none; }
/* Collapsed desktop rail (64px): stack pill buttons and the +, hide the name. */
@media (min-width: 801px) {
  html.side-collapsed.foot-b #me-dock { flex-direction: column; }
  html.side-collapsed.foot-b #me-bar { flex-direction: column; padding: 4px 0; border-radius: 22px; flex: none; }
  html.side-collapsed.foot-b #me-name { display: none; }
  html.side-collapsed.foot-b #me-open { flex: none; padding: 0; justify-content: center; }
  html.side-collapsed.foot-b #foot-menu { left: 8px; right: auto; }
}
/* chatlist-pin-reorder (Luke): bug button centred under the hamburger (#menu-open: 48px wide, 14px from the right edge,
   so its centre is 38px in; the 32px bug button needs right: 22px) and ~18px lower than before (gap under the menu
   button ~0px -> ~17px). */
.bug-fab { right: calc(22px + env(safe-area-inset-right, 0px)); top: calc(var(--header-h, 64px) + 26px + env(safe-area-inset-top, 0px)); }
/* chatlist-pin-reorder (Luke): bug button more solid so it reads where it overlaps the chat-list edge.
   Was: opacity .55 on a 70% card background. Now: fully opaque button on a 94% card background, icon at full text colour. */
.bug-fab { opacity: .92; background: color-mix(in srgb, var(--card) 94%, transparent); color: var(--text); border-color: color-mix(in srgb, var(--text) 22%, var(--line)); box-shadow: 0 2px 8px rgba(0,0,0,.18); }
.bug-fab:hover, .bug-fab:focus-visible { opacity: 1; }
/* bugbtn-phone-fix (Luke, 26.10.13.13): on phones the floating bug button covered the top-right of the chat, so tapping
   your own top message opened Report a bug. Phones now use the "Report a bug" row in the hamburger menu (#menu-bug,
   same dialog). Luke, 26.10.13.13 follow-up: the floating button is removed on every width, desktop included; the
   menu row is the one way in everywhere. */
.bug-fab { display: none !important; }
@media (max-width: 800px) { #mute-bar { margin-right: 0; } }
/* uiscale-fullscreen-menus (Luke, 26.10.25; 26.11 bg-scale-gap): with Display size ≠ 100% the phone full-screen
   menus live under header/shell zoom, so 100dvh layout is multiplied by --ui-z visually. Divide it back, like the
   other caps above; the menu's content still follows the chosen size. (Desktop pop-over position is in menu.css.) */
@media (max-width: 640px) {
  html[data-ui-scale] #app-menu:not([hidden]), html[data-ui-scale] #profile-pop:not([hidden]),
  html[data-ui-scale]:not(.no-chat) body:not(.pn-page) #app-menu:not([hidden]) {
    width: calc(100vw / var(--ui-z, 1)) !important; height: calc(100dvh / var(--ui-z, 1)) !important;
  }
}

/* group-online-list: members pop-over (wide screens, placed by app.js placeMembers) / full-screen sheet (phones). */
#thread-head .members-tap { cursor: pointer; }
#members-pop {
  position: fixed; z-index: 45; width: min(340px, calc((100vw - 24px) / var(--ui-z, 1))); overflow-y: auto; overscroll-behavior: contain;
  background: var(--card); color: var(--text); border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 10px 32px rgba(0,0,0,.3);
  padding: 0 8px 8px;
}
#members-pop[hidden] { display: none; }
#members-pop .mp-bar { display: flex; align-items: center; gap: 8px; position: sticky; top: 0; z-index: 2; padding: 10px 4px 6px; background: var(--card); }
#members-pop .mp-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
#members-pop .mp-back { display: none; }
#members-pop .mp-x { width: 36px; height: 36px; border: 0; border-radius: 999px; background: transparent; color: inherit; font-size: 22px; line-height: 1; cursor: pointer; }
#members-pop .mp-count { margin: 0 4px 6px; }
#members-pop .mp-head { margin: 8px 6px 4px; font-size: .78rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
#members-pop .mp-row { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 52px; padding: 6px; border: 0; border-radius: 12px; background: transparent; color: inherit; font: inherit; text-align: left; }
#members-pop button.mp-row { cursor: pointer; }
#members-pop button.mp-row:hover, #members-pop button.mp-row:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
#members-pop .mp-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
#members-pop .mp-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
#members-pop .mp-row.on .mp-status { color: #2ec27e; font-weight: 600; }
html[data-scheme="light"] #members-pop .mp-row.on .mp-status { color: #1c7c4b; }
@media (max-width: 640px) {
  #members-pop.mp-sheet {
    inset: 0; width: calc(100vw / var(--ui-z, 1)); height: calc(100dvh / var(--ui-z, 1)); max-height: none; border: 0; border-radius: 0; box-shadow: none;
    z-index: 60; padding: 0 12px calc(16px + env(safe-area-inset-bottom, 0px));
  }
  #members-pop.mp-sheet .mp-bar {
    min-height: calc(52px + env(safe-area-inset-top, 0px)); margin: 0 -12px 8px; padding: calc(6px + env(safe-area-inset-top, 0px)) 12px 6px;
    border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--card) 92%, transparent); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  }
  #members-pop.mp-sheet .mp-back {
    display: inline-flex; align-items: center; gap: 2px; height: 40px; padding: 0 14px 0 8px; border: 0; border-radius: 999px; font: inherit; font-weight: 600;
    color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); cursor: pointer;
  }
  #members-pop.mp-sheet .mp-x { display: none; }
  #members-pop.mp-sheet .mp-title { text-align: center; margin-right: 64px; }
  html:has(#members-pop.mp-sheet:not([hidden])) .bug-fab { visibility: hidden; }
}

/* ===== resizable-sidebar: drag the Conversations panel's right edge to resize it (wide two-pane layouts only).
   Width lives in --side-w (CSS px, set by app.js, saved per device as "bc-side-w"). Phones (<=800px) and the
   collapsed 64px rail ignore it and never show the handle. The collapse button (z 20) stays above the handle (z 15). */
#side-resize { display: none; }
@media (min-width: 801px) {
  html:not(.side-collapsed) #sidebar { width: var(--side-w, min(320px, 34vw)); }
  html:not(.side-collapsed) #side-resize {
    display: block; position: absolute; top: 12px; bottom: 12px; right: -10px; width: 8px; z-index: 15;
    cursor: col-resize; touch-action: none; border-radius: 4px; background: transparent; outline: none;
    transition: background-color .15s ease;
  }
  #side-resize::after { content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 2px; border-radius: 1px;
    background: var(--accent); opacity: 0; transition: opacity .15s ease; }
  #side-resize:hover::after, #side-resize:focus-visible::after, html.side-resizing #side-resize::after { opacity: .7; }
  #side-resize:hover, #side-resize:focus-visible, html.side-resizing #side-resize { background: color-mix(in srgb, var(--accent) 16%, transparent); }
  #side-resize:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent); }
  html.side-resizing, html.side-resizing * { cursor: col-resize !important; user-select: none !important; -webkit-user-select: none !important; }
}

/* lobby-header-fix: Join/Leave shows its words on wide screens, an icon on phones, so the "Lobby" title is never covered. */
#thread-actions .lobby-join { display: inline-flex; align-items: center; gap: 6px; }
#thread-actions .lobby-join svg { display: none; }
@media (max-width: 800px) {
  #thread-actions .lobby-join { padding: 9px !important; border-radius: 50% !important; min-width: 0; }
  #thread-actions .lobby-join svg { display: block; }
  #thread-actions .lobby-join .lobby-join-label { display: none; }
  /* iphone-header: keep ~120px for the name before actions crush it (was 4.2em ≈ 67px). */
  #thread-head .thread-text { min-width: min(120px, 32vw); overflow: hidden; }
  #thread-title { overflow: hidden; }
  #thread-head > #search-btn, #thread-head > #chat-menu { flex: none; }
}
/* lobby-header-fix: the Lobby's own picture (lobby-icon.webp) is back in the chat list; it was swapped for a plain globe in 607b101. */
.pfp.lobby-pic { background: url("/static/lobby-icon.webp?v=26.11.1007-763b3d5b") center / cover no-repeat; }
.pfp.lobby-pic svg { display: none; }
#members-pop .mp-pic { flex: none; display: inline-flex; }
#members-pop .mp-pic:empty { display: none; }
#members-pop .mp-pic > * { width: 32px; height: 32px; }
#members-pop.mp-sheet .mp-pic { margin-left: auto; }
/* iphone-header: fit ladder. Touch targets stay ≥44px. Report/Block and start-group live in ⋯ now. */
#thread-head.fit-1 {
  gap: 2px !important;
  padding-left: max(0px, env(safe-area-inset-left, 0px)) !important;
  padding-right: max(4px, env(safe-area-inset-right, 0px)) !important;
}
#thread-head.fit-1 #thread-actions button.icon,
#thread-head.fit-1 #thread-actions .lobby-join,
#thread-head.fit-1 #thread-actions .mute-btn { padding: 6px !important; }
#thread-head.fit-1 #search-btn,
#thread-head.fit-1 #chat-menu {
  width: 44px !important; height: 44px !important; min-width: 44px !important; min-height: 44px !important; padding: 0 !important;
}
#thread-head.fit-2 #thread-pic > * { width: 26px !important; height: 26px !important; font-size: .7em; }
#thread-head.fit-2 #thread-pic .lobby-pic, #thread-head.fit-2 #thread-pic .pfp { box-shadow: none; }
/* fit-3: fold mute into the ⋯ menu (paintChatOverflow mirrors it). Search / ⋯ / back stay. */
#thread-head.fit-3 #mute-btn,
#thread-head.fit-3 .mute-btn { display: none !important; }
#thread-head.fit-4 #thread-pic { display: none !important; }


/* device-approval: persistent high-contrast pill in the chat list until Approve/Deny */
.device-approval-pill {
  display: flex; flex-direction: column; gap: 8px; align-items: stretch;
  border: 2px solid #1a7f37; border-radius: 12px; padding: 10px 12px;
  background: color-mix(in srgb, #1a7f37 12%, transparent);
  margin: 6px 0;
}
.device-approval-pill .device-approval-label strong { font-size: 1rem; }
.device-approval-pill .device-approval-match { display: flex; align-items: center; gap: 8px; font-size: 0.92rem; }
.device-approval-pill .device-approval-actions { display: flex; gap: 8px; justify-content: flex-end; }
.device-approval-pill .device-approval-actions .solid:disabled { opacity: 0.45; cursor: not-allowed; }

/* device-cap: boot screen when POST /api/devices returns 409 (account at DEVICE_MAX) */
#bc-device-cap {
  position: fixed; inset: 0; z-index: 10000;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  background: color-mix(in srgb, var(--bg, #111) 88%, transparent);
  box-sizing: border-box;
}
#bc-device-cap .bc-device-cap-card {
  width: min(420px, 100%);
  max-height: min(90vh, 640px);
  overflow: auto;
  padding: 18px 16px;
  border-radius: 14px;
  background: var(--panel, #1c1c1e);
  color: var(--text, #fff);
  box-shadow: 0 8px 28px rgba(0,0,0,.4);
  box-sizing: border-box;
}
#bc-device-cap .bc-device-cap-card h2 { margin: 0 0 8px; font-size: 1.25em; }
#bc-device-cap .bc-device-cap-card > p { margin: 0 0 12px; line-height: 1.45; }
#bc-device-cap .sessions-list { margin-bottom: 10px; }
#bc-device-cap .sessions-list li button { min-height: 44px; padding: 0 14px; }

/* Above #twigum-share (100001) and #update-prompt (2147483001). The SW-update
   bar still exists; requestBcSwReload waits until this page is gone before reloading. */
#bc-signing-unlock {
  position: fixed; inset: 0; z-index: 2147483646;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  background: color-mix(in srgb, var(--bg, #111) 88%, transparent);
  box-sizing: border-box;
}
#bc-signing-unlock .bc-signing-unlock-card {
  width: min(420px, 100%);
  padding: 18px 16px;
  border-radius: 14px;
  background: var(--panel, var(--card, #1c1c1e));
  color: var(--text, #fff);
  box-shadow: 0 8px 28px rgba(0,0,0,.4);
  box-sizing: border-box;
}
#bc-signing-unlock .bc-signing-unlock-card h2 { margin: 0 0 8px; font-size: 1.25em; }
#bc-signing-unlock .bc-signing-unlock-card > p { margin: 0 0 12px; line-height: 1.45; }
#bc-signing-unlock label { display: block; margin: 10px 0 4px; }
#bc-signing-unlock input {
  width: 100%; box-sizing: border-box; min-height: 44px; padding: 8px 10px;
  border-radius: 8px; border: 1px solid var(--hair, #444); background: var(--input, #111); color: inherit;
}
#bc-signing-unlock .actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
#bc-signing-unlock .actions button { min-height: 44px; padding: 0 14px; }

/* Signing / device-notice banner: theme tokens that exist in every palette
   (--panel is undefined, so the old inline fallback painted dark text on #222). */
.bc-trust-banner {
  position: fixed;
  left: 50%;
  top: 8px;
  transform: translateX(-50%);
  z-index: 9999;
  max-width: min(640px, 94vw);
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--line);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .35);
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}
.bc-trust-banner > button:not(.ghost) {
  background: var(--accent);
  color: var(--on-accent);
  border: 0;
  border-radius: 10px;
  padding: 8px 12px;
}
.bc-trust-banner > button.ghost {
  color: inherit;
  background: transparent;
  border: 1px solid var(--line);
}

/* Cap / reauth dialogs: keep password + TOTP fields usable at 390px */
.bc-trust-dialog {
  width: min(360px, calc(100vw - 24px));
  max-width: calc(100vw - 24px);
  box-sizing: border-box;
  padding: 14px;
}
.bc-trust-dialog input {
  width: 100%;
  box-sizing: border-box;
  min-height: 40px;
}
.bc-trust-dialog label { display: block; margin: 8px 0 4px; }
.bc-trust-dialog .actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* Delta Jet Neon color-pair swatches (Send animations menu) */
.deltajet-pairs {
  display: flex; gap: 8px; align-items: center; margin: 6px 0 2px 4px; flex-wrap: wrap;
}
.deltajet-pairs[hidden] { display: none !important; }
.deltajet-swatch {
  width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent;
  background: linear-gradient(135deg, var(--dj-l) 50%, var(--dj-r) 50%);
  cursor: pointer; padding: 0; box-shadow: 0 0 0 1px rgba(0,0,0,.18);
}
.deltajet-swatch[aria-pressed="true"] {
  border-color: var(--accent, #5ccdbf);
  box-shadow: 0 0 0 2px var(--accent, #5ccdbf);
}
.deltajet-swatch:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
/* Delta Jet canvas: never inherit CSS filters / backdrop filters */
canvas.send-deltajet { filter: none !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }


/* cold-open: chat-list skeleton while first sync is in flight.
   Cached name rows (.chat-cached) look like normal chat rows — no greyed/disabled styling. */
.chat-skel { pointer-events: none; opacity: 0.6; }
.skel-block, .skel-line {
  background: color-mix(in srgb, var(--muted) 28%, transparent);
  animation: skel-pulse 1.2s ease-in-out infinite;
}
.skel-block { width: 42px; height: 42px; border-radius: 50%; flex: none; display: inline-block; }
.skel-line { display: block; height: 12px; width: 52%; margin-top: 10px; border-radius: 6px; }
@keyframes skel-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 0.9; } }

/* ---- Twigum wordmark + brand header gradients (dev/twigum-leaf) ---- */
:root {
  /* Default: logo-inspired BLUE→TEAL (no violet). A=blue→white via ?brandGrad=a; B=old violet-teal via ?brandGrad=b */
  --brand-grad-logo: linear-gradient(135deg, #1E5BD8 0%, #2489C4 48%, #2EBCB5 100%);
  --brand-grad-a: linear-gradient(90deg, #1a5fb4 0%, #4a90d9 38%, #d6e8f8 78%, #ffffff 100%);
  --brand-grad-b: linear-gradient(90deg, #4632a0 0%, #5a50c8 35%, #3ca0b4 70%, #28b4aa 100%);
  --brand-grad: var(--brand-grad-logo);
}
html[data-brand-grad="a"] { --brand-grad: var(--brand-grad-a); }
html[data-brand-grad="b"] { --brand-grad: var(--brand-grad-b); }

/* App header follows the selected color theme (light/dark and accent palettes)
   so it blends with the rest of the page. Login brand cards still use --brand-grad. */
header {
  background: color-mix(in srgb, var(--accent) 10%, var(--card)) !important;
  border-bottom-color: color-mix(in srgb, var(--accent) 22%, var(--line));
  color: var(--text);
}

/* Login / gate brand card top accent */
.brand {
  position: relative;
}
form .brand,
.gate-brand,
#login .brand,
#factor .brand,
#reset .brand,
#signup .brand {
  padding: 10px 12px;
  margin: -4px -4px 8px;
  border-radius: 14px;
  background: var(--brand-grad);
  box-shadow: 0 2px 10px rgba(0,0,0,.18);
}

img.bc-wordmark {
  display: inline-block;
  height: 28px;
  width: auto;
  max-width: min(220px, 55vw);
  vertical-align: -6px;
  object-fit: contain;
  background: transparent !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  -webkit-mask: none !important;
  mask: none !important;
  /* Approved AFTER treatment (Luke): crisp dark outline + soft shadow — same on light & dark */
  filter:
    drop-shadow(0 0 1px rgba(0,0,0,.9))
    drop-shadow(0 1px 0 rgba(0,0,0,.55))
    drop-shadow(0 -1px 0 rgba(0,0,0,.35))
    drop-shadow(1px 0 0 rgba(0,0,0,.35))
    drop-shadow(-1px 0 0 rgba(0,0,0,.35))
    drop-shadow(0 2px 3px rgba(0,0,0,.4));
}
header img.bc-wordmark { height: 26px; }
form .brand img.bc-wordmark,
#login .brand img.bc-wordmark { height: 40px; max-width: min(280px, 70vw); }
.welcome-title img.bc-wordmark { height: 32px; vertical-align: -8px; }
/* wordmark filter: one treatment everywhere (dark+light) */
/* Hide legacy text logo if any remain */
span.bc-logo:has(+ nothing) { }

/* ---- Header/brand legibility outlines (Luke: A/B gradients) ---- */
:root {
  --brand-outline:
    0 0 1px rgba(0,0,0,.85),
    0 1px 0 rgba(0,0,0,.75),
    0 -1px 0 rgba(0,0,0,.55),
    1px 0 0 rgba(0,0,0,.55),
    -1px 0 0 rgba(0,0,0,.55),
    1px 1px 0 rgba(0,0,0,.55),
    -1px 1px 0 rgba(0,0,0,.55),
    1px -1px 0 rgba(0,0,0,.45),
    -1px -1px 0 rgba(0,0,0,.45),
    0 2px 4px rgba(0,0,0,.35);
  --brand-icon-outline:
    drop-shadow(0 0 1px rgba(0,0,0,.9))
    drop-shadow(0 1px 1px rgba(0,0,0,.65))
    drop-shadow(0 -1px 0 rgba(0,0,0,.4))
    drop-shadow(1px 0 0 rgba(0,0,0,.4))
    drop-shadow(-1px 0 0 rgba(0,0,0,.4));
}

/* Login brand cards sit on the gradient, so their words keep a dark outline.
   The app header uses theme text colors instead. */
form .brand h1,
form .brand .ver,
form .brand a.ver,
#login .brand h1,
#signup .brand h1,
#factor .brand h1,
#reset .brand h1 {
  text-shadow: var(--brand-outline) !important;
  -webkit-text-stroke: 0.35px rgba(0,0,0,.35);
  paint-order: stroke fill;
}

/* Keep version link readable on the login brand card */
header a.ver,
form .brand a.ver {
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
header a.ver { color: var(--muted); }
form .brand a.ver { color: #f5fbff; }
html[data-scheme="light"] form .brand a.ver { color: #0b1a2e; }
html[data-scheme="light"] form .brand h1 { color: #0b1a2e; }

/* Light theme: crisp white outline on the login brand card */
html[data-scheme="light"] form .brand h1,
html[data-scheme="light"] form .brand .ver,
html[data-scheme="light"] form .brand a.ver,
html[data-scheme="light"] #login .brand h1,
html[data-scheme="light"] #signup .brand h1,
html[data-scheme="light"] #factor .brand h1,
html[data-scheme="light"] #reset .brand h1 {
  text-shadow:
    0 1px 0 #fff,
    0 -1px 0 #fff,
    1px 0 0 #fff,
    -1px 0 0 #fff !important;
  -webkit-text-stroke: 1px #fff;
  paint-order: stroke fill;
}

/* Login brand icons: dark halo so they read on the gradient */
form .brand .bc-icon,
form .brand .bc-icon img {
  filter: var(--brand-icon-outline);
}
form .brand .bc-icon img {
  filter:
    drop-shadow(0 0 1px rgba(0,0,0,.9))
    drop-shadow(0 1px 1px rgba(0,0,0,.55))
    drop-shadow(0 2px 4px rgba(0,0,0,.35));
}
img.bc-wordmark {
  filter:
    drop-shadow(0 0 1px rgba(0,0,0,.9))
    drop-shadow(0 1px 0 rgba(0,0,0,.55))
    drop-shadow(0 -1px 0 rgba(0,0,0,.35))
    drop-shadow(1px 0 0 rgba(0,0,0,.35))
    drop-shadow(-1px 0 0 rgba(0,0,0,.35))
    drop-shadow(0 2px 3px rgba(0,0,0,.4)) !important;
}



/* 26.11 ipad-freeze: theme swatches only paint when Colors and Themes is open (rules scoped to #themes-panel).
   Parked panel bodies live under #bc-menu-park — never decode swatches or run menu chrome work there.
   Host-only content-visibility: applying it to descendants (#bc-menu-park *) left WebKit (iPadOS)
   with unpainted palette buttons / snap icons after remount (blank Color theme list gap).
   display:none on the park host already skips work; descendant CV is unsafe for remount paint. */
#bc-menu-park { content-visibility: hidden; }
#themes-panel[hidden] .bg-swatch { background-image: none !important; }

/* Lighter hamburger on iPad / Android: no shadow stack, cheaper transitions while the menu is open. */
html[data-ios] #app-menu,
html[data-android] #app-menu {
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink) 18%, transparent);
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
html[data-ios] #app-menu .notify-acc,
html[data-android] #app-menu .notify-acc {
  transition: none;
}

/* Twigum share picker. The list scrolls because the sheet has a definite height and the
   list is a flex child with min-height: 0. Text uses em so the Large text setting
   (body font-size) scales it. Rows stay at least 56px and tap targets at least 48px. */
#twigum-share {
  display: none;
  position: fixed;
  z-index: 100001;
  left: 0;
  right: 0;
  top: 0;
  height: 100dvh;
  max-height: 100dvh;
  box-sizing: border-box;
  flex-direction: column;
  min-height: 0;
  background: var(--card, #17212b);
  color: var(--text, #f5f5f5);
  font-size: 1em;
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}
html.share-pending #twigum-share { display: flex !important; }
.twigum-share-top {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.45em 0.7em 0.2em;
}
.twigum-share-heading { flex: 1; min-width: 0; }
.twigum-share-heading strong { display: block; font-size: 1.06em; line-height: 1.3; }
#twigum-share-cancel {
  flex: none;
  min-height: max(48px, 2.8em);
  min-width: 4.5em;
  padding: 0 1em;
  font-size: 1em;
}
#twigum-share-search {
  flex: none;
  width: calc(100% - 1.5em);
  margin: 0.35em 0.75em 0.2em;
  box-sizing: border-box;
  min-height: max(48px, 2.8em);
  padding: 0 0.8em;
  font: inherit;
  font-size: max(16px, 1em);
  color: var(--text);
  background: color-mix(in srgb, var(--text) 6%, var(--card));
  border: 1px solid var(--line);
  border-radius: 12px;
}
#twigum-share-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  padding: 0.2em 0.45em 0.45em;
}
.twigum-share-section {
  margin: 0.6em 0.5em 0.2em;
  font-size: 0.76em;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.twigum-share-row {
  display: flex;
  align-items: center;
  gap: 0.7em;
  min-height: max(56px, 3.3em);
  padding: 0.45em 0.6em;
  border-radius: 12px;
  cursor: pointer;
  touch-action: manipulation;
}
.twigum-share-row:active, .twigum-share-row:focus-within {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.twigum-share-check {
  width: 1.4em;
  height: 1.4em;
  min-width: 22px;
  min-height: 22px;
  flex: none;
  margin: 0;
}
.twigum-share-avatar {
  flex: none;
  width: 2.6em;
  height: 2.6em;
  min-width: 44px;
  min-height: 44px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.06em;
  font-weight: 700;
  background: color-mix(in srgb, var(--accent) 28%, var(--card));
  color: var(--text);
}
.twigum-share-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1em; }
.twigum-share-line { display: flex; align-items: baseline; gap: 0.45em; min-width: 0; }
.twigum-share-name {
  flex: 1;
  min-width: 0;
  font-size: 1em;
  font-weight: 650;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.twigum-share-time { flex: none; font-size: 0.76em; color: var(--muted); }
.twigum-share-preview {
  font-size: 0.88em;
  line-height: 1.3;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.twigum-share-empty { margin: 1.4em 0.7em; font-size: 0.94em; color: var(--muted); text-align: center; }
.twigum-share-foot {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  padding: 0.25em 0 calc(0.6em + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line);
  background: var(--card);
}
#twigum-share-preview {
  margin: 0.3em 0.75em 0;
  font-size: 0.88em;
  line-height: 1.35;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#twigum-share-note {
  flex: none;
  width: calc(100% - 1.5em);
  margin: 0.15em 0.75em 0;
  box-sizing: border-box;
  min-height: max(48px, 2.8em);
  padding: 0 0.8em;
  font: inherit;
  font-size: max(16px, 1em);
  color: var(--text);
  background: color-mix(in srgb, var(--text) 6%, var(--card));
  border: 1px solid var(--line);
  border-radius: 12px;
}
#twigum-share-search::placeholder,
#twigum-share-note::placeholder {
  color: color-mix(in srgb, var(--text) 15%, var(--muted));
  opacity: 1;
}
#twigum-share-send.solid {
  min-height: max(48px, 2.8em);
  margin: 0.25em 0.75em 0;
  font-size: 1em;
  font-weight: 700;
  background: var(--accent);
  color: var(--on-accent);
  opacity: 1;
}
/* White on these blues is under 4.5:1. Keep the accent fill; use the dark ink. */
html[data-palette="glacier"][data-scheme="light"] #twigum-share-send.solid,
html[data-palette="bubble"] #twigum-share-send.solid {
  color: #0b0d12;
}
#twigum-share-status {
  min-height: 0;
  margin: 0 0.75em;
  font-size: 0.82em;
  white-space: pre-line;
  color: var(--danger);
}
#twigum-share-status:empty { display: none; }

/* ===== chat-list layouts
   Roomy (default) and Quiet add their own rules. Compact keeps the rules above.
   No per-row blur or backdrop-filter: a flat plate and a text shadow stay cheap while scrolling. */
#chat-layout-row { padding: 2px 12px 8px; }
#chat-layout-row > .menu-label { display: block; padding: 8px 0 4px; }
#chat-layout-choices .layout-btn { min-height: 40px; padding: 6px 12px; font-size: 14px; font-weight: 650; }
#chat-list-tools { display: none; }
#chat-list-tools[hidden] { display: none !important; }
.chat-list-skip { display: none !important; }
#chat-list-empty { padding: 16px 12px; text-align: center; }

/* Text size is the body size (small 14 / medium 17 / large 22) and does not touch Display size.
   Fixed preview, time, and message sizes follow it. Medium keeps the sizes already set above. */
html[data-text="small"] .chat-row .row-preview { font-size: calc(12.5px * 14 / 17); }
html[data-text="large"] .chat-row .row-preview { font-size: calc(12.5px * 22 / 17); }
html[data-text="small"] .chat-row .row-time { font-size: calc(12px * 14 / 17); }
html[data-text="large"] .chat-row .row-time { font-size: calc(12px * 22 / 17); }
html[data-text="small"] .msg .name { font-size: calc(13px * 14 / 17); }
html[data-text="large"] .msg .name { font-size: calc(13px * 22 / 17); }
html[data-text="small"] .msg .time { font-size: calc(11px * 14 / 17); }
html[data-text="large"] .msg .time { font-size: calc(11px * 22 / 17); }
html[data-text="small"] .msg .bubble { font-size: 14px; }
html[data-text="large"] .msg .bubble { font-size: 22px; }

/* Same letter color on every name. A chosen color is a glow, with the outline kept so it stays readable. */
.dname, .msg .name.dname, .row-name.dname, #thread-title .dname { color: var(--text); }
.dname[style*="--name-glow"] {
  color: var(--text);
  text-shadow:
    -1px 0 0 rgba(0,0,0,.85), 1px 0 0 rgba(0,0,0,.85),
    0 -1px 0 rgba(0,0,0,.85), 0 1px 0 rgba(0,0,0,.85),
    0 0 6px var(--name-glow), 0 0 14px color-mix(in srgb, var(--name-glow) 75%, transparent);
}

/* Readable on the forest wallpaper and every other theme: a cheap shadow, brighter preview. */
.chat-row .row-name,
.chat-row .row-preview,
.chat-row .row-time,
.chat-row .row-sender {
  text-shadow: 0 0 2px rgba(0,0,0,.9), 0 1px 2px rgba(0,0,0,.75);
}
html[data-scheme="light"] .chat-row .row-name,
html[data-scheme="light"] .chat-row .row-preview,
html[data-scheme="light"] .chat-row .row-time,
html[data-scheme="light"] .chat-row .row-sender {
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 1px 1px rgba(255,255,255,.9), 0 0 1px rgba(0,0,0,.35);
}
.chat-row .row-preview { color: color-mix(in srgb, var(--text) 82%, var(--muted)); }

html[data-chat-layout="roomy"] #chat-list-tools,
html[data-chat-layout="quiet"] #chat-list-tools {
  display: flex; flex-direction: column; gap: 8px; padding: 8px 12px 6px; flex: none;
}
html.side-collapsed #chat-list-tools { display: flex !important; flex-direction: column; align-items: center; padding: 0; gap: 0; }
html.side-collapsed .chat-list-search,
html.side-collapsed #chat-list-filters { display: none !important; }
html.side-collapsed .chat-list-search-row { display: flex; justify-content: center; width: 100%; }
html[data-chat-layout="roomy"] #chat-list-search,
html[data-chat-layout="quiet"] #chat-list-search {
  width: 100%; min-height: 40px; border-radius: 12px; padding: 8px 12px;
  background: color-mix(in srgb, var(--card) 90%, transparent);
}
html[data-chat-layout="roomy"] #chat-list-filters { display: flex; gap: 6px; flex-wrap: wrap; }
html[data-chat-layout="roomy"] #chat-list-filters button {
  min-height: 32px; padding: 4px 14px; border-radius: 999px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--card) 80%, transparent); font-weight: 650; color: var(--text);
}
html[data-chat-layout="roomy"] #chat-list-filters button[aria-selected="true"] {
  background: var(--accent); color: var(--on-accent); border-color: transparent;
}
html[data-chat-layout="quiet"] #chat-list-filters { display: none; }

html[data-chat-layout="roomy"] #sidebar,
html[data-chat-layout="quiet"] #sidebar { padding-left: 0; padding-right: 0; padding-bottom: 0; }
html[data-chat-layout="roomy"] #people { gap: 0; padding-bottom: 0; margin-bottom: 0; }
html[data-chat-layout="roomy"] #friends { gap: 0; margin-bottom: 0; padding-bottom: 0; }
html[data-chat-layout="roomy"] #me-dock { margin-top: auto; padding: 6px 10px 8px; }
html[data-chat-layout="roomy"] #requests { padding: 0 12px; }
html[data-chat-layout="roomy"] .chat-row,
html[data-chat-layout="roomy"] #lobby-row.chat-row {
  min-height: 74px; padding: 10px; gap: 12px; border-radius: 14px;
  background: color-mix(in srgb, var(--card) 84%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 65%, transparent);
}
html[data-chat-layout="roomy"] .chat-row .pfp,
html[data-chat-layout="roomy"] #lobby-row.chat-row .pfp { width: 54px; height: 54px; }
html[data-chat-layout="roomy"] .chat-row .row-name { font-size: 1.05em; }
html[data-chat-layout="roomy"] .chat-row .row-preview { font-size: 0.92em; }
html[data-chat-layout="roomy"] .chat-row .row-time { font-size: 0.78em; }
html[data-chat-layout="roomy"] .row-sender {
  display: block; font-size: 0.82em; font-weight: 700; line-height: 1.3;
  color: color-mix(in srgb, var(--text) 90%, var(--accent));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html[data-chat-layout="roomy"] .row-pin { width: 18px; height: 18px; color: var(--accent); opacity: 1; }
/* Checkmark stays inline at the start of the preview (WhatsApp): "✓ You: text…".
   Ellipsis cuts the text, not the mark. Not a flex sibling of the preview. */
.chat-row .row-preview .who,
.chat-row .row-preview .row-ticks { display: inline; }
.chat-row .row-preview .row-ticks {
  display: inline-flex; vertical-align: -0.2em; width: auto; height: 1em; margin-right: 0.15em;
  color: var(--muted); flex: none;
}
.chat-row .row-preview .row-ticks svg { width: 1.15em; height: 1em; display: block; }
.chat-row .row-preview .row-ticks[data-state="read"] { color: var(--accent); }
html[data-chat-layout="roomy"] .row-ticks[data-state="read"] { color: var(--accent); }
html[data-chat-layout="roomy"] .chat-row.is-unread .row-name,
html[data-chat-layout="roomy"] .chat-row.is-unread .row-sender,
html[data-chat-layout="roomy"] .chat-row.is-unread .row-preview { font-weight: 750; }
html[data-chat-layout="roomy"] .chat-row.is-unread .row-time { color: var(--accent); font-weight: 700; }
html[data-chat-layout="roomy"] .chat-row .unread {
  min-width: 22px; height: 22px; line-height: 22px; padding: 0 7px; font-size: 13px; font-weight: 800;
}
html[data-chat-layout="roomy"] .drag-handle { margin: -10px -14px -10px 0; }

html[data-chat-layout="quiet"] #people { gap: 0; padding-bottom: 0; margin-bottom: 0; }
html[data-chat-layout="quiet"] #friends { gap: 0; margin-bottom: 0; padding-bottom: 0; }
html[data-chat-layout="quiet"] #me-dock { margin-top: auto; padding: 6px 10px 8px; }
html[data-chat-layout="quiet"] .chat-row,
html[data-chat-layout="quiet"] #lobby-row.chat-row {
  min-height: 84px; padding: 12px 14px 12px 28px; gap: 12px; border-radius: 0; position: relative;
  background: color-mix(in srgb, var(--card) 84%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 65%, transparent);
}
html[data-chat-layout="quiet"] .chat-row .row-main { order: 1; }
html[data-chat-layout="quiet"] .chat-row .pfp { order: 2; width: 48px; height: 48px; margin-left: 8px; }
html[data-chat-layout="quiet"] .chat-row .row-preview {
  white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  font-size: 0.95em; line-height: 1.35;
}
html[data-chat-layout="quiet"] .chat-row .unread {
  position: absolute; left: 10px; top: 50%; margin: 0; transform: translateY(-50%);
  width: 11px; min-width: 11px; height: 11px; padding: 0; font-size: 0; line-height: 0;
  border-radius: 50%; box-shadow: none;
}
html[data-chat-layout="quiet"] .chat-row.is-unread .row-name { font-weight: 750; }
html.side-collapsed[data-chat-layout="quiet"] .chat-row .pfp { order: 0; margin-left: 0; }

@media (max-width: 800px) {
  html[data-chat-layout="roomy"].no-chat #shell,
  html[data-chat-layout="quiet"].no-chat #shell { padding: 0 !important; gap: 0 !important; }
  html[data-chat-layout="roomy"].no-chat #sidebar,
  html[data-chat-layout="quiet"].no-chat #sidebar {
    width: 100% !important; max-width: none !important; border-radius: 0; border-left: 0; border-right: 0;
  }
}
@media (min-width: 801px) {
  html[data-chat-layout="roomy"] #shell,
  html[data-chat-layout="compact"] #shell { padding-left: 0; gap: 0; }
  html[data-chat-layout="roomy"] #sidebar,
  html[data-chat-layout="compact"] #sidebar { border-radius: 0; }
}

/* Approved list: dark row tint (no per-row blur), white names, preview #d7e2ef.
   Text size moves list and message letters only; chrome stays at 17px. */
html[data-text="small"] body,
html[data-text="large"] body,
html[data-text="medium"] body { font-size: 17px; }
.chat-row .row-preview { color: #d7e2ef; }
.chat-row .row-name,
.chat-row .dname { color: #f5f8fc; }
.chat-row,
#lobby-row.chat-row {
  background: rgba(8, 12, 18, 0.42);
  border: 1px solid rgba(255,255,255,.06);
}
.chat-row.is-unread { background: rgba(8, 12, 18, 0.55); }
html[data-scheme="light"] .chat-row,
html[data-scheme="light"] #lobby-row.chat-row { background: rgba(8, 12, 18, 0.62); }
.chat-row .row-name,
.chat-row .row-preview,
.chat-row .row-time,
.chat-row .row-sender,
.chat-row .you-text {
  text-shadow: 0 1px 3px rgba(0,0,0,.65), 0 0 1px rgba(0,0,0,.45);
}
.dname[style*="--name-glow"] {
  color: #f5f8fc;
  text-shadow:
    0 0 6px var(--name-glow),
    0 0 14px color-mix(in srgb, var(--name-glow) 70%, transparent),
    0 1px 3px rgba(0,0,0,.65);
}
.msg .bubble { font-size: var(--bc-list-text, 17px); }
.msg .name { font-size: calc(var(--bc-list-text, 17px) * 13 / 17); }
.msg .time { font-size: calc(var(--bc-list-text, 17px) * 11 / 17); }

html[data-chat-layout="roomy"] #chat-list-tools,
html[data-chat-layout="compact"] #chat-list-tools {
  display: flex; flex-direction: column; gap: 8px; padding: 0 12px 8px; flex: none;
}
.chat-list-search {
  display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 12px;
  border-radius: 14px; border: 1px solid rgba(255,255,255,.12);
  background: color-mix(in srgb, var(--card) 55%, transparent); color: #d7e2ef;
}
.chat-list-search input {
  flex: 1; min-width: 0; border: 0; background: transparent; padding: 0; outline: none;
  font-size: calc(var(--bc-list-text, 17px) * 15 / 17); color: inherit;
}
#chat-list-filters { display: flex; gap: 8px; flex-wrap: wrap; }
#chat-list-filters button {
  height: 30px; padding: 0 14px; border-radius: 999px; border: 1px solid rgba(255,255,255,.1);
  background: color-mix(in srgb, var(--card) 40%, transparent); color: #f5f8fc;
  font-size: 13px; font-weight: 650;
}
#chat-list-filters button[aria-selected="true"] {
  background: var(--accent); color: var(--on-accent); border-color: transparent;
}

html[data-chat-layout="roomy"] #friends { gap: 4px; margin-bottom: 0; padding: 4px 6px 8px; }
html[data-chat-layout="roomy"] .chat-row,
html[data-chat-layout="roomy"] #lobby-row.chat-row {
  min-height: 74px; padding: 10px; gap: 12px; border-radius: 14px;
}
html[data-chat-layout="roomy"] .chat-row .pfp,
html[data-chat-layout="roomy"] #lobby-row.chat-row .pfp { width: 54px; height: 54px; }
html[data-chat-layout="roomy"] .chat-row .row-name { font-size: calc(var(--bc-list-text, 17px) * 16.5 / 17); font-weight: 650; }
html[data-chat-layout="roomy"] .chat-row .row-preview,
html[data-chat-layout="roomy"] .chat-row .you-text { font-size: calc(var(--bc-list-text, 17px) * 14 / 17); color: #d7e2ef; }
html[data-chat-layout="roomy"] .chat-row .row-time { font-size: calc(var(--bc-list-text, 17px) * 12.5 / 17); }
html[data-chat-layout="roomy"] .row-sender { font-size: calc(var(--bc-list-text, 17px) * 13 / 17); }
html[data-chat-layout="roomy"] .chat-row .unread { min-width: 26px; height: 26px; line-height: 26px; border-radius: 13px; }
html[data-chat-layout="roomy"] .row-pin { width: 18px; height: 18px; }

html[data-chat-layout="compact"] .chat-row .row-name { font-size: calc(var(--bc-list-text, 17px) * 14.5 / 17); }
html[data-chat-layout="compact"] .chat-row .row-preview,
html[data-chat-layout="compact"] .chat-row .you-text { font-size: calc(var(--bc-list-text, 17px) * 12.5 / 17); color: #d7e2ef; }
html[data-chat-layout="compact"] .chat-row .row-preview .who { font-weight: 650; }

.chat-row .row-preview.you-line {
  display: flex; align-items: center; gap: 4px; min-width: 0;
  overflow: hidden; white-space: nowrap;
}
.chat-row .row-preview.you-line .you-text {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-row .row-preview.you-line .who { display: inline; }
.chat-row .row-preview.you-line .row-ticks {
  flex: none; display: inline-flex; width: auto; height: 1em; margin: 0; color: var(--accent);
}
.chat-row .row-preview.you-line .row-ticks[data-state="sent"] { color: #d7e2ef; }
.chat-row .row-preview.you-line .row-ticks svg { width: 1.15em; height: 1em; display: block; }

#chat-layout-row, #text-size-row { padding: 4px 12px 10px; }
.layout-picks { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.layout-pick {
  display: flex; flex-direction: column; align-items: flex-start; text-align: left;
  border-radius: 14px; padding: 12px; border: 1.5px solid rgba(255,255,255,.12);
  background: color-mix(in srgb, var(--bg) 55%, transparent); color: var(--text); min-height: 0;
}
.layout-pick[aria-pressed="true"] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.layout-pick .pick-title { font-size: 14px; font-weight: 700; }
.layout-pick .pick-sub { font-size: 11.5px; color: var(--muted); margin: 2px 0 8px; }
.layout-pick .mini { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.layout-pick .mini i {
  display: block; height: 7px; border-radius: 4px;
  background: color-mix(in srgb, var(--text) 22%, transparent);
}
.layout-pick.roomy .mini i { height: 12px; }
.layout-pick.roomy .mini i:nth-child(2) { width: 88%; }
.layout-pick.roomy .mini i:nth-child(3) { width: 76%; }
.layout-pick .tag {
  margin-top: 8px; font-size: 10.5px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--on-accent); background: var(--accent);
  padding: 2px 7px; border-radius: 999px;
}
.layout-hint { margin: 8px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.35; }
.text-size-slider { display: flex; align-items: center; gap: 8px; }
.text-size-slider .a-small { font-size: 12px; opacity: .8; }
.text-size-slider .a-large { font-size: 18px; opacity: .9; }
#text-size-range { flex: 1; min-width: 0; accent-color: var(--accent); }
#text-size-val { min-width: 4.2em; text-align: right; font-weight: 650; }

@media (max-width: 800px) {
  html.no-chat[data-chat-layout="roomy"] #shell,
  html.no-chat[data-chat-layout="compact"] #shell { padding: 0 !important; gap: 0 !important; }
  html.no-chat[data-chat-layout="roomy"] #sidebar,
  html.no-chat[data-chat-layout="compact"] #sidebar {
    width: 100% !important; max-width: none !important; border-radius: 0;
  }
}

/* ===== chatlist-polish: thin overlay scrollbars + selected-row outline =====
   Scrollbars: Telegram / Discord / Slack desktop — thin rounded thumb, no
   arrow buttons, transparent track. Shown clearly on hover or while scrolling.
   Selected chat: a full accent outline on all four sides plus a soft glow,
   not clipped by the next row or by overflow. */
#people, #log {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--text) 35%, transparent) transparent;
}
#people:hover, #people:focus-within, #people.is-scrolling,
#log:hover, #log:focus-within, #log.is-scrolling {
  scrollbar-color: color-mix(in srgb, var(--text) 55%, transparent) transparent;
}
#people::-webkit-scrollbar,
#log::-webkit-scrollbar { width: 6px; height: 6px; }
#people::-webkit-scrollbar-button,
#log::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
#people::-webkit-scrollbar-track,
#log::-webkit-scrollbar-track,
#people::-webkit-scrollbar-corner,
#log::-webkit-scrollbar-corner { background: transparent; }
#people::-webkit-scrollbar-thumb,
#log::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text) 32%, transparent);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
#people:hover::-webkit-scrollbar-thumb,
#people:focus-within::-webkit-scrollbar-thumb,
#people.is-scrolling::-webkit-scrollbar-thumb,
#log:hover::-webkit-scrollbar-thumb,
#log:focus-within::-webkit-scrollbar-thumb,
#log.is-scrolling::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text) 52%, transparent);
  background-clip: padding-box;
}
@media (hover: hover) and (pointer: fine) {
  #people::-webkit-scrollbar-thumb,
  #log::-webkit-scrollbar-thumb { background: transparent; }
  #people:hover::-webkit-scrollbar-thumb,
  #people:focus-within::-webkit-scrollbar-thumb,
  #people.is-scrolling::-webkit-scrollbar-thumb,
  #log:hover::-webkit-scrollbar-thumb,
  #log:focus-within::-webkit-scrollbar-thumb,
  #log.is-scrolling::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--text) 48%, transparent);
    background-clip: padding-box;
  }
}

html[data-chat-layout] .chat-row.active,
html[data-chat-layout] #lobby-row.chat-row.active,
html[data-chat-layout] #lobby-row.active,
.row.active, .person.active {
  position: relative;
  z-index: 2;
  border: 1px solid var(--accent);
  border-bottom-color: var(--accent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 70%, transparent),
    0 0 12px color-mix(in srgb, var(--accent) 38%, transparent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
/* When the rail is 64px, clip rows so the selected outline cannot spill into the chat pane.
   Overflow stays visible on the expanded panel so the resize handle (right: -10px) still works. */
html.side-collapsed #sidebar { overflow: hidden; }
html.side-collapsed #people,
html.side-collapsed #friends,
html.side-collapsed .chat-row {
  min-width: 0;
  max-width: 100%;
}
html.side-collapsed .chat-row { overflow: hidden; }

html[data-scheme="light"][data-chat-layout] .chat-row.active,
html[data-scheme="light"][data-chat-layout] #lobby-row.chat-row.active,
html[data-scheme="light"] .row.active,
html[data-scheme="light"] .person.active {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 80%, transparent),
    0 0 10px color-mix(in srgb, var(--accent) 32%, transparent);
}

/* ===== chatlist-polish-0905: search-row collapse, search pill, collapsed rail ===== */
.chat-list-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.chat-list-search-row .chat-list-search {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
}
@media (max-width: 800px) {
  .chat-list-search-row .chat-list-search { width: 100%; }
}

/* Search: one soft filled pill. The earlier roomy rule styled the INPUT as a
   second rounded box, which made a harsh doubled border beside the magnifier. */
html[data-chat-layout] .chat-list-search,
.chat-list-search {
  display: flex;
  align-items: center;
  gap: 8px;
  box-sizing: border-box;
  width: 100%;
  height: 40px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
  background: color-mix(in srgb, var(--text) 8%, var(--card));
  color: var(--muted);
  box-shadow: none;
}
html[data-scheme="light"] .chat-list-search {
  border-color: color-mix(in srgb, var(--text) 14%, transparent);
  background: color-mix(in srgb, var(--text) 6%, var(--card));
}
.chat-list-search svg { flex: none; opacity: .65; }
html[data-chat-layout] .chat-list-search > input,
html[data-chat-layout="roomy"] #chat-list-search,
html[data-chat-layout="quiet"] #chat-list-search,
html[data-chat-layout="compact"] #chat-list-search,
.chat-list-search input,
#chat-list-search {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0 !important;
  height: auto !important;
  margin: 0;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  outline: none;
  color: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.chat-list-search input::-webkit-search-decoration,
.chat-list-search input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}
html[data-chat-layout] .chat-list-search:focus-within,
.chat-list-search:focus-within {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}

/* Collapsed rail: wide enough for a 48px avatar plus its ring/glow, like
   Discord's server rail. Overlay scrollbar sits in the side padding, not
   on the pictures. Expanded layout and phones (<=800px) are unchanged. */
@media (min-width: 801px) {
  html.side-collapsed #sidebar {
    width: 88px;
    padding: 10px 8px;
    align-items: center;
    overflow: hidden;
  }
  html.side-collapsed #people {
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-gutter: auto;
    padding-inline: 0;
  }
  html.side-collapsed[data-chat-layout] #friends,
  html.side-collapsed #friends {
    padding: 4px 0 8px;
    gap: 8px;
  }
  html.side-collapsed[data-chat-layout] .chat-row,
  html.side-collapsed[data-chat-layout] #lobby-row.chat-row,
  html.side-collapsed .chat-row {
    justify-content: center;
    align-items: center;
    min-height: 56px;
    padding: 4px 0;
    gap: 0;
    overflow: visible;
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    max-width: 100%;
  }
  html.side-collapsed[data-chat-layout] .chat-row.active,
  html.side-collapsed[data-chat-layout] #lobby-row.chat-row.active,
  html.side-collapsed .row.active,
  html.side-collapsed .person.active {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
  }
  html.side-collapsed .chat-row .pfp,
  html.side-collapsed #lobby-row.chat-row .pfp {
    width: 48px;
    height: 48px;
    margin: 0;
    flex: none;
  }
  html.side-collapsed .chat-row .pfp.gcl {
    width: 48px;
    height: 48px;
    margin: 0;
  }
  html.side-collapsed .chat-row.active .pfp,
  html.side-collapsed .chat-row.active .pfp.gcl {
    box-shadow:
      0 0 0 2px var(--accent),
      0 0 10px color-mix(in srgb, var(--accent) 40%, transparent);
  }
  html.side-collapsed #side-actions,
  html.side-collapsed #me-dock,
  html.side-collapsed #me-bar {
    max-width: 100%;
    justify-content: center;
    overflow: visible;
  }
}

/* Window-wide file drop highlight. pointer-events: none so the overlay does
   not steal dragleave; document listeners in app.js handle the drop. */
#file-drop-overlay {
  position: fixed; inset: 10px; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  border: 2px dashed color-mix(in srgb, var(--accent) 80%, transparent);
  border-radius: 16px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--text);
  font-size: 20px; font-weight: 600;
  text-shadow: 0 1px 4px color-mix(in srgb, var(--bg) 70%, transparent);
}
#file-drop-overlay[hidden] { display: none !important; }
html.bc-file-drop #file-drop-overlay:not([hidden]) { display: flex; }
html.no-chat #file-drop-overlay .file-drop-msg { display: none; }
html:not(.no-chat) #file-drop-overlay .file-drop-nochat { display: none; }
