:root, [data-theme="light"] {
  color-scheme: light;
  --bg: #f4f3ef;
  --panel: #ffffff;
  --side: #e9e7e0;
  --fg: #1c1c1a;
  --dim: #71716c;
  --border: #d8d6cf;
  --accent: #3468a8;
  --accent-fg: #ffffff;
  --danger: #b03030;
  --mine: #e8f0fa;
  /* phone drawer glass (light theme: light + translucent) */
  --drawer-bg: rgba(247, 246, 242, .3);
  --drawer-fg: #1c1c1a;
  --drawer-dim: #6d6d66;
  --drawer-hilite: rgba(0, 0, 0, .07);
}
/* dark palette, shared by system-dark and the explicit dark toggle. The
   data-theme blocks come last so they win over the media query (equal
   specificity → source order). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #191a1c; --panel: #222327; --side: #131416; --fg: #e6e5e1;
    --dim: #8f8f89; --border: #35363b; --accent: #6fa3dd; --accent-fg: #10151c; --mine: #253243;
    --drawer-bg: rgba(19, 20, 22, .45); --drawer-fg: #e2e1dd; --drawer-dim: #9a9a93;
    --drawer-hilite: rgba(255, 255, 255, .09);
  }
}
[data-theme="dark"] {
  color-scheme: dark;
  --bg: #191a1c; --panel: #222327; --side: #131416; --fg: #e6e5e1;
  --dim: #8f8f89; --border: #35363b; --accent: #6fa3dd; --accent-fg: #10151c; --mine: #253243;
  --drawer-bg: rgba(19, 20, 22, .45); --drawer-fg: #e2e1dd; --drawer-dim: #9a9a93;
  --drawer-hilite: rgba(255, 255, 255, .09);
}
/* accent choice (per device), overrides the theme's accent. Placed after the
   theme blocks so it wins on --accent/--accent-fg. */
/* :root[...] so these out-specify the dark-mode theme rule (which is
   :root:not([data-theme="light"]) — higher specificity than a bare attribute) */
:root[data-accent="blue"]   { --accent: #3468a8; --accent-fg: #ffffff; }
:root[data-accent="purple"] { --accent: #7c5cd6; --accent-fg: #ffffff; }
:root[data-accent="green"]  { --accent: #2f9e57; --accent-fg: #ffffff; }
:root[data-accent="orange"] { --accent: #d98032; --accent-fg: #17110a; }

* { box-sizing: border-box; }
html { touch-action: manipulation; } /* no double-tap zoom anywhere */
html, body { height: 100%; }
body {
  margin: 0;
  font: 15px/1.5 -apple-system, system-ui, sans-serif;
  background: var(--bg); color: var(--fg);
  overflow-x: hidden; /* nothing should ever pan sideways */
}

.shell { display: flex; min-height: 100vh; }

/* sidebar is always dark, whatever the system theme */
aside {
  --sb-fg: #d6d6d0;
  --sb-dim: #85857f;
  width: 205px; flex-shrink: 0;
  background: #141518; color: var(--sb-fg);
  padding: 1rem .9rem;
  display: flex; flex-direction: column; gap: 1.1rem;
}
.brand {
  font-weight: 900; font-size: 1.15rem; letter-spacing: -.02em; font-style: italic;
  color: #fff; text-decoration: none; padding: 0 .4rem .2rem;
  display: flex; align-items: center; gap: .45rem; min-width: 0;
}
.brandname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* the brand ellipsis doubles as the connection light (accent = healthy);
   it lives OUTSIDE the ellipsizing name span so truncation can't eat it */
#conndots { transition: color .3s ease; margin-left: -.3rem; flex: none; }
#conndots.ok { color: var(--accent); }
/* identity row rides directly under the brand */
.merow-wrap {
  display: flex; align-items: center; gap: .4rem;
  margin: -0.6rem 0 -0.55rem;
  padding: .5rem .1rem;
  border-top: 1px solid rgba(255, 255, 255, .13);
  border-bottom: 1px solid rgba(255, 255, 255, .13);
}
.merow-wrap .merow { flex: 1; min-width: 0; }
.merow-wrap .logout {
  width: 2.2rem; height: 2.2rem; flex: none; padding: 0;
  border-radius: 999px;
}
aside nav { display: flex; flex-direction: column; gap: 1px; }
.navrow {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 .4rem .3rem;
}
.navhead {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--sb-dim);
}
a.plus, button.plus {
  display: flex; align-items: center; justify-content: center;
  width: 1.35rem; height: 1.35rem; border-radius: 6px;
  background: rgba(255,255,255,.09); color: var(--sb-fg);
  text-decoration: none; font-size: 1rem; line-height: 1;
  border: 0; cursor: pointer; padding: 0; font-family: inherit;
}
a.plus:hover, button.plus:hover, a.plus[data-active] { background: var(--accent); color: var(--accent-fg); }
aside nav a:not(.plus) {
  color: var(--sb-fg); text-decoration: none;
  padding: .3rem .45rem; border-radius: 6px;
  display: flex; align-items: center; gap: .4rem;
}
.navlabel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dot {
  width: .5rem; height: .5rem; border-radius: 50%; flex-shrink: 0;
  background: #e8a33d; margin-left: auto;
}
/* a dot carrying an unread count grows into a badge */
.dot:not(:empty) {
  width: auto; min-width: 1.15rem; height: 1.15rem; border-radius: .6rem;
  padding: 0 .3rem; display: flex; align-items: center; justify-content: center;
  font-size: .7rem; font-weight: 700; color: #241a05;
}
.dot.inline { display: inline-block; margin-left: .3rem; vertical-align: middle; }
.dot.inline:not(:empty) { display: inline-flex; }
/* composer: 📎 on the left, pill textarea with the ➤ nested inside its
   right end (bottom-anchored, so it stays put as the textarea grows) */
.composer { position: relative; display: flex; align-items: flex-end; gap: .45rem; }
.composer textarea {
  flex: 1; resize: none; display: block; min-height: 2.9rem;
  border-radius: 1.45rem; padding: .68rem 3rem .68rem 1rem;
}
.composer .attach {
  order: -1; width: 2.9rem; height: 2.9rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; cursor: pointer;
  font-size: 1.15rem; line-height: 1; padding: 0;
  align-self: flex-end; /* the global button align-self would pin it top */
  background: transparent; border: 2px solid var(--accent);
}
.composer .attach:hover { background: var(--border); }
.composer .sendbtn {
  position: absolute; right: .3rem; bottom: .3rem;
  width: 2.3rem; height: 2.3rem;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 999px; cursor: pointer;
  font-size: 1rem; line-height: 1; padding: 0;
  background: var(--accent); color: var(--accent-fg);
}
.attachname:not(:empty) { font-size: .85rem; }
.msgimg {
  display: block; max-width: min(100%, 420px); max-height: 420px;
  border-radius: 8px; margin: .35rem 0; cursor: zoom-in;
}
.msgimg.full { max-width: 100%; max-height: none; cursor: zoom-out; }

/* --- ovals: oval-shaped, 30-second video messages --- */
/* the mask is display-only; underneath it's a plain square MP4 */
/* just off-circle on purpose: round at a glance, not quite when you look */
.oval {
  width: 200px; height: 210px; display: block; object-fit: cover;
  background: #000; margin-top: .25rem;
  clip-path: ellipse(50% 50% at 50% 50%);
}
button.ovalplay {
  border: 0; cursor: pointer; font-size: 2.2rem; position: relative;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 32%, var(--panel));
  color: var(--fg); padding: 0;
}
button.ovalplay:disabled { cursor: wait; }
/* first-frame preview under the ▶ glyph */
.ovalplay img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ovalplay span { position: relative; color: #fff; text-shadow: 0 0 10px rgba(0, 0, 0, .85); }
/* selfie mirror: flipped for display everywhere (preview, poster, playback);
   the recorded bytes stay unflipped */
video.oval, .ovalplay img { transform: scaleX(-1); }
/* playing oval + its scrub bar */
.ovalcol { width: 200px; }
/* scrub bar: generous touch target around a thin track */
.ovalbar { margin-top: .5rem; height: 16px; display: flex; align-items: center; cursor: pointer; touch-action: none; }
.ovalbar .track {
  position: relative; width: 100%; height: 5px; border-radius: 999px;
  background: var(--border); overflow: hidden;
}
.ovalbar .fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--accent); border-radius: 999px; }
/* review overlay carries the same bar, sized to the preview */
.ovaloverlay .ovalbar { width: min(70vw, 300px); margin-top: 0; }
/* voice msg player: ▶ + inline track + length */
.voicemic { font-size: 3.2rem; }
.voicemsg { display: flex; align-items: center; gap: .55rem; margin-top: .3rem; width: min(280px, 100%); }
.voicemsg .voiceplay {
  flex: none; width: 2.2rem; height: 2.2rem; border-radius: 50%; border: 0;
  cursor: pointer; background: var(--accent); color: var(--accent-fg); font-size: .95rem;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.voicemsg .voiceplay svg { display: block; }
.voicemsg .track {
  position: relative; flex: 1; height: 5px; border-radius: 999px;
  background: var(--border); cursor: pointer; touch-action: none;
}
.voicemsg .fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--accent); border-radius: 999px; }
.voicetime { flex: none; font-size: .75rem; }
/* profile pictures: the picture (or a tinted initial) in the house near-circle */
.avatar {
  --sz: 1.3rem;
  width: var(--sz); height: var(--sz); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; clip-path: ellipse(47% 50% at 50% 50%);
  font-size: calc(var(--sz) * .58); font-weight: 700; color: #fff;
  vertical-align: -0.32em; margin-right: .3rem;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar.big { --sz: 1.9rem; vertical-align: -0.45em; }
ul.plain .avatar { --sz: 1.6rem; margin-right: .45rem; }
.mbtitle .avatar { margin-right: .35rem; }
/* the poodle-post brand mark; the brand is a flex row so it lines up */
.brandlogo { height: 1.6em; flex: none; }
/* your picture + name at the top of settings; click = change picture */
.merow {
  display: flex; align-items: center; gap: .5rem; width: 100%;
  padding: .3rem .4rem; border: 0; border-radius: 8px;
  background: transparent; color: inherit; cursor: pointer; text-align: left;
  font-size: .95rem; font-weight: 600;
}
.merow:hover { background: rgba(255, 255, 255, .08); }
.merow .avatar { margin-right: 0; }
/* chat headers: avatar centred against the name block */
body[data-page="dm"] main > h1 { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
body[data-page="dm"] main > h1 .avatar { margin-right: 0; }
/* desktop chats wear the same black locked bar as the phone */
@media (min-width: 701px) {
  body[data-page="dm"] main > h1, body.grouplayout main > h1 {
    /* floating glass pill; sticky pins below the scroller's padding, so
       -0.9rem leaves a .5rem float gap at the top */
    position: sticky; top: -0.9rem; z-index: 20;
    background: transparent; color: var(--fg);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
    border: 2px solid var(--accent); border-radius: 999px;
    box-shadow: 0 4px 18px rgba(0, 0, 0, .2);
    margin: -.9rem -1rem .6rem; padding: .45rem 1.2rem;
  }
  /* the phone's round gear, on desktop too */
  body[data-page="dm"] main > h1 .chatmenu summary, body.grouplayout main > h1 .chatmenu summary {
    width: 2.2rem; height: 2.2rem; padding: 0; font-size: 1.2rem;
    border: 2px solid var(--accent); border-radius: 999px;
    display: flex; align-items: center; justify-content: center;
    margin-left: auto;
  }
}
.mbtitle .mbid { display: flex; align-items: baseline; gap: .4rem; min-width: 0; }
/* attach menu: a floating pill column of icon buttons above the 📎 */
.attachmenu {
  /* centred over the 📎 (2.9rem wide, so its middle is 1.45rem in) */
  position: absolute; left: 1.45rem; transform: translateX(-50%);
  bottom: 3.3rem; z-index: 30; width: max-content;
  display: flex; flex-direction: column; gap: .25rem; padding: .3rem;
  background: var(--panel); border: 2px solid var(--accent); border-radius: 999px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .3);
}
.attachmenu button {
  display: flex; align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; flex: none;
  border: 0; border-radius: 999px; background: transparent; cursor: pointer;
  color: var(--fg); padding: 0;
}
.attachmenu button:hover { background: var(--border); }
.attachmenu button svg { display: block; }
/* full-screen recording / review overlay */
.ovaloverlay {
  position: fixed; inset: 0; z-index: 100; background: rgba(0, 0, 0, .88);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.1rem;
}
.ovaloverlay .oval { width: min(70vw, 300px); height: min(73.5vw, 315px); margin: 0; }
.ovalcount {
  color: #fff; font-size: 1.4rem; min-height: 1.8rem;
  font-variant-numeric: tabular-nums;
}
.ovalrow { display: flex; gap: .8rem; }
.ovalrow button {
  padding: .55rem 1.4rem; border-radius: 999px; border: 0; cursor: pointer;
  background: #333; color: #eee; font-size: 1rem;
}
.ovalrow button.primary { background: var(--accent); color: var(--accent-fg); }
aside nav a:not(.plus):hover { background: rgba(255,255,255,.08); }
aside nav a:not(.plus).active { background: var(--accent); color: var(--accent-fg); }
/* buttons living in the sidebar nav, styled like its links */
aside nav .navbtn {
  background: none; border: 0; font: inherit; cursor: pointer;
  color: var(--sb-fg); text-align: left;
  padding: .3rem .45rem; border-radius: 6px;
  display: flex; align-items: center; gap: .4rem;
}
aside nav .navbtn:hover { background: rgba(255,255,255,.08); }
aside nav .navbtn.danger { color: #e08585; }
.reqrow { display: flex; align-items: center; gap: .3rem; padding: .25rem .45rem; color: var(--sb-fg); }
.reqrow .navlabel { flex: 1; }
.reqrow button { background: rgba(255,255,255,.1); color: var(--sb-fg); border: 0; border-radius: 5px; cursor: pointer; width: 1.5rem; height: 1.5rem; }
.reqrow .reqyes:hover { background: #3aa655; color: #fff; }
.reqrow .reqno:hover { background: var(--danger); color: #fff; }
#chatgate { margin-top: 1rem; }
#chatgate button:not(.linkish) { margin-top: .5rem; }
.accentrow { display: flex; gap: .4rem; margin-bottom: .5rem; }
.accentrow button {
  flex: 1; height: 1.15rem; border: 0; border-radius: 6px; cursor: pointer;
  outline: 2px solid transparent; outline-offset: 1px;
}
.accentrow button[aria-pressed="true"] { outline: 2px solid rgba(255,255,255,.35); outline-offset: -4px; }
/* swatch colours live here (inline styles are blocked by our CSP) */
.accentrow button[data-accent="blue"]   { background: #3468a8; }
.accentrow button[data-accent="purple"] { background: #7c5cd6; }
.accentrow button[data-accent="green"]  { background: #2f9e57; }
.accentrow button[data-accent="orange"] { background: #d98032; }
.themerow { display: flex; gap: .35rem; margin-bottom: .55rem; }
.themerow button {
  flex: 1; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.07); color: var(--sb-fg);
  border: 0; border-radius: 6px; padding: .28rem 0; cursor: pointer; font-size: 1.05rem; line-height: 1;
}
.themerow button[aria-pressed="true"] { background: var(--accent); color: var(--accent-fg); }
.logout-ic { margin-right: .35rem; }
.sidefoot {
  margin-top: auto; padding-top: .8rem; border-top: 1px solid rgba(255,255,255,.1);
  display: flex; flex-direction: column; gap: .55rem;
}
/* settings dropdown lives in the sidebar footer and opens upward */
details.menu { position: relative; }
details.menu summary {
  cursor: pointer; list-style: none; user-select: none;
  color: var(--sb-dim); padding: 0 .4rem; font-size: .88rem;
}
details.menu summary::-webkit-details-marker { display: none; }
details.menu summary::after { content: " ▾"; font-size: .75em; }
details.menu[open] summary { color: var(--sb-fg); }
.menupanel {
  position: absolute; left: 0; bottom: calc(100% + .5rem); z-index: 10;
  width: max-content;
  background: var(--panel); border: 1px solid var(--border); border-radius: 9px;
  box-shadow: 0 6px 24px rgba(0,0,0,.25);
  display: flex; flex-direction: column; padding: .35rem;
}
.menupanel a, .menupanel button {
  text-align: left; padding: .4rem .6rem; border-radius: 6px; white-space: nowrap;
  color: var(--fg); text-decoration: none; background: none; border: none;
  font: inherit; cursor: pointer;
}
.menupanel a:hover, .menupanel button:hover {
  background: color-mix(in srgb, var(--fg) 8%, transparent);
}
.menupanel button.danger { color: var(--danger); font-size: inherit; }
button.logout {
  width: 100%; display: flex; align-items: center; justify-content: center;
  background: transparent; color: var(--sb-fg);
  border: 1px solid var(--accent);
  border-radius: 6px; padding: .3rem .6rem;
}
button.logout:hover { background: rgba(255,255,255,.12); }
/* quoted original inside a reply; tapping jumps to the message */
.quote {
  display: flex; flex-direction: column; overflow: hidden;
  border-left: 3px solid var(--accent); border-radius: 6px;
  background: color-mix(in srgb, var(--fg) 7%, transparent);
  padding: .25rem .5rem; margin: .3rem 0 .05rem;
  font-size: .82rem; color: var(--dim); cursor: pointer;
}
.quote .quotewho { color: var(--accent); font-weight: 600; }
.quote span:last-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
article.flash { background: color-mix(in srgb, var(--accent) 24%, var(--panel)) !important; transition: background .5s; }
.replybar[hidden] { display: none; } /* the flex below would defeat [hidden] */
.replybar {
  display: flex; align-items: center; gap: .5rem;
  font-size: .82rem; color: var(--dim);
  padding: .3rem .5rem; border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--fg) 7%, transparent); border-radius: 6px;
}
.replybar span { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ticks { margin-left: .35rem; color: var(--dim); font-size: .95em; letter-spacing: -.12em; }
.ticks.read { color: #3aa655; }
#peername.online { color: #3aa655; }
#peerstatus { font-weight: 400; font-size: .8rem; }
#peerstatus.onlinetxt { color: #3aa655; }
/* gear menu in the chat header: same panel, opens downward */
.chatmenu { display: inline-block; margin-left: .35rem; vertical-align: middle; }
.chatmenu summary { color: var(--dim); font-size: 1.05rem; padding: 0 .2rem; }
details.chatmenu summary::after { content: none; } /* must out-specify details.menu */
details.chatmenu summary { font-size: 1.15rem; } /* readable on desktop; phone bar overrides */
.chatmenu[open] summary, .chatmenu summary:hover { color: var(--fg); }
.chatmenu .menupanel { bottom: auto; top: calc(100% + .4rem); left: 50%; right: auto; transform: translateX(-50%); }

main { flex: 1; padding: 1.4rem 2rem 3rem; max-width: 46rem; min-width: 0; }
main.solo { margin: 6vh auto 0; flex: initial; width: min(24rem, 92vw); padding: 0 1rem; }

h1 { font-size: 1.25rem; margin: 0 0 1rem; }
h2 { font-size: 1rem; margin: 1.8rem 0 .6rem; }
a { color: var(--accent); }
p { margin: .4rem 0; }

ul.plain { list-style: none; padding: 0; margin: 0; }
ul.plain li { padding: .45rem 0; border-bottom: 1px solid var(--border); }

.stack { display: flex; flex-direction: column; gap: .6rem; max-width: 24rem; }
.stack label { display: flex; flex-direction: column; gap: .2rem; font-size: .85rem; color: var(--dim); }
label.check { flex-direction: row; align-items: center; gap: .45rem; color: var(--fg); }
input:not([type=checkbox]), textarea {
  font: inherit; color: var(--fg); background: var(--panel);
  padding: .45rem .55rem; border: 1px solid var(--border); border-radius: 7px;
  width: 100%;
}
input:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent; }
button {
  font: inherit; padding: .42rem 1rem; border: none; border-radius: 7px;
  background: var(--accent); color: var(--accent-fg); cursor: pointer;
  align-self: flex-start;
}
button:disabled { opacity: .5; }
button.linkish {
  background: none; color: var(--accent); padding: 0; border-radius: 0;
  text-decoration: underline; cursor: pointer; font-size: .85rem;
}
button.linkish.danger { color: var(--danger); }
form.inline { display: inline; margin-left: .5rem; }
.topnav form.inline { margin-left: 0; }

/* flat admin-style rows: divider lines, no card chrome */
article {
  position: relative;
  padding: .6rem 0 .65rem;
  border-bottom: 1px solid var(--border);
}
article .meta { font-size: .78rem; color: var(--dim); }
article.mine .meta { color: var(--accent); }
article p { margin: .15rem 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
/* actions appear when the message is tapped: reactions left, edit/delete right */
article.actionable { cursor: pointer; }
article .actions {
  display: none; justify-content: space-between; align-items: center;
  gap: 1rem; margin-top: .3rem;
  scroll-margin-bottom: 12px; /* the auto-scroll should overshoot a touch */
}
article .textactions { display: flex; align-items: center; gap: .45rem; }
article .reactbtns { display: flex; gap: .35rem; }
/* in chats the action row mirrors the bubble: your messages read
   reply·edit·delete·emojis; the other person's are the mirror image */
#msgs article:not(.mine) .actions,
#msgs article:not(.mine) .textactions,
body.grouplayout #posts article:not(.mine) .actions,
body.grouplayout #posts article:not(.mine) .textactions {
  flex-direction: row-reverse;
}
article .reactbtns button {
  background: none; border: none; cursor: pointer; padding: 0 .15rem;
  font-size: 1.05rem; line-height: 1;
}
.reactions { display: flex; flex-wrap: wrap; gap: .3rem; }
.reactions:not(:empty) { margin-top: .3rem; }
.reactchip {
  font-size: .8rem; padding: .05rem .4rem; border-radius: .8rem;
  background: color-mix(in srgb, var(--fg) 8%, transparent);
}
.reactchip.minechip { outline: 1px solid var(--accent); }
article.sel .actions { display: flex; }
article .actions button {
  background: none; border: none; cursor: pointer;
  font: inherit; font-size: .8rem; padding: 0;
}
/* reply / edit / save as pills. Use a neutral tint (not accent) so they stay
   visible on your own accent-tinted bubbles as well as the other person's */
article .actions .editbtn {
  color: var(--accent); font-size: .72rem; font-weight: 600; line-height: 1;
  padding: .2rem .55rem; border-radius: 999px;
  background: color-mix(in srgb, var(--fg) 12%, transparent);
}
article .actions .editbtn:hover { background: color-mix(in srgb, var(--fg) 20%, transparent); }
/* delete: a small pinkish pill in the bubble's top-right, shown on tap so it
   reads clearly instead of an icon floating over the message text */
article .cornerdel {
  position: absolute; top: .3rem; right: .4rem; z-index: 2;
  display: none; cursor: pointer; border: 0;
  color: var(--danger); font-size: .72rem; font-weight: 600; line-height: 1;
  padding: .2rem .5rem; border-radius: 999px;
  background: color-mix(in srgb, var(--danger) 18%, var(--panel));
}
article .cornerdel:hover { background: color-mix(in srgb, var(--danger) 30%, var(--panel)); }
article.sel .cornerdel { display: block; }
.editwrap { display: flex; flex-direction: column; gap: .45rem; margin-top: .45rem; max-width: 100%; }
.editrow { display: flex; gap: .6rem; scroll-margin-bottom: 12px; }
.editrow .cancelbtn {
  background: none; border: 1px solid var(--danger); color: var(--danger);
  padding: .35rem .9rem; border-radius: 7px;
}
textarea { min-height: 4.2rem; resize: vertical; overflow: hidden; }

#msgs {
  max-height: 60vh; overflow-y: auto; margin-bottom: .3rem; padding-right: .2rem;
  overscroll-behavior: contain; /* chat scroll must not spill into the page */
}
/* chats are bubbles: theirs left, yours right */
#msgs article {
  max-width: 82%; width: fit-content;
  margin: 0 auto .55rem 0;
  padding: .45rem .7rem .5rem;
  background: var(--panel);
  border: 1px solid var(--border); border-bottom: 1px solid var(--border);
  border-radius: 12px 12px 12px 4px;
}
#msgs article.mine {
  margin: 0 0 .55rem auto;
  border-radius: 12px 12px 4px 12px;
  background: color-mix(in srgb, var(--accent) 14%, var(--panel));
}
/* tapped-open bubbles may grow (to fit the action row) but only as much as
   needed. Reserve space for the corner delete on the meta line alone, so the
   box widens just enough and the action row still reaches the right edge. */
#msgs article.sel, body.grouplayout #posts article.sel { max-width: 94%; }
#msgs article.sel .meta, body.grouplayout #posts article.sel .meta { padding-right: 3.4rem; }
/* peer-is-typing dots: an in-flow phantom bubble under the last message
   (moved to the end of the thread by JS whenever they light up) */
#typing {
  display: none; gap: .28rem; align-items: center; width: fit-content;
  padding: .55rem .65rem; margin: 0 auto .55rem 0; pointer-events: none;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px 12px 12px 4px;
}
#typing.on { display: flex; }
#dmmain #msgs { padding-bottom: .4rem; scroll-padding-bottom: .4rem; }
/* short chats grow upward from the composer, not down from empty space:
   the first bubble's auto top-margin soaks up any spare height */
#dmmain #msgs { display: flex; flex-direction: column; }
#dmmain #msgs > :first-child { margin-top: auto; }
#typing span {
  width: .42rem; height: .42rem; border-radius: 50%;
  background: var(--dim); animation: typingblink 1.2s infinite;
}
#typing span:nth-child(2) { animation-delay: .2s; }
#typing span:nth-child(3) { animation-delay: .4s; }
@keyframes typingblink { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }
.msgswrap { position: relative; }
/* floating "where am I" date pill, shown near the scrollbar while scrolling
   chat history and faded out shortly after the scrolling stops */
.scrolldate {
  position: absolute; top: .5rem; right: 1.3rem; z-index: 6;
  background: var(--accent);
  border: 1px solid transparent; color: var(--accent-fg);
  font-size: .78rem; padding: .16rem .65rem; border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0,0,0,.28);
  opacity: 0; transition: opacity .18s; pointer-events: none;
  white-space: nowrap;
}
.scrolldate.on { opacity: 1; }
#jumpdown[hidden] { display: none; } /* display:flex below would defeat [hidden] */
#jumpdown {
  position: absolute; right: .9rem; bottom: 1.4rem;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; padding: 0;
  border: 0; cursor: pointer; font-size: 1.25rem; line-height: 1;
  background: var(--accent); color: var(--accent-fg);
  box-shadow: 0 2px 10px rgba(0,0,0,.35);
}
/* amber dot: new messages arrived below while scrolled up */
#jumpdown.unseen::after {
  content: ''; position: absolute; top: -1px; right: -1px;
  width: .75rem; height: .75rem; border-radius: 50%; background: #e8a33d;
}

.publicnote { color: #b8860b; font-size: .82rem; margin: 0 0 .6rem; }
.memberspanel { border: 1px solid var(--border); border-radius: 9px; padding: .6rem .8rem; margin: 0 0 1rem; }
.memberrow { display: flex; justify-content: space-between; align-items: center; padding: .25rem 0; }
.memberadd { display: flex; gap: .5rem; margin-top: .5rem; }
.memberadd select { flex: 1; }
.memberpick { display: flex; flex-direction: column; gap: .25rem; max-height: 40vh; overflow-y: auto; }
.err { color: var(--danger); }
.dim { color: var(--dim); font-size: .88rem; }
.pager { display: flex; gap: 1.5rem; margin-top: 1rem; }
code {
  background: color-mix(in srgb, var(--fg) 9%, transparent);
  padding: .1rem .35rem; border-radius: 5px; overflow-wrap: anywhere; font-size: .85em;
}
details:not(.menu) { margin-top: .4rem; }
details:not(.menu) summary { cursor: pointer; color: var(--accent); font-size: .85rem; }
details .stack { margin: .6rem 0 .4rem; }

/* mobile top bar: separate floating glass pills — ☰ | title | gear */
.mobilebar {
  display: none; align-items: center; gap: .5rem;
  height: 2.9rem; flex: none; padding: 0;
  margin: .45rem .55rem .15rem;
  background: transparent;
  position: relative; z-index: 50;
}
.mobilebar .mbtitle {
  flex: 1; text-align: center; font-weight: 700; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  height: 100%; display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--accent); border-radius: 999px;
  background: transparent;
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .2);
}
#menubtn, #mbsettings {
  width: 2.9rem; height: 2.9rem; padding: 0; border-radius: 999px;
  border: 2px solid var(--accent);
  display: flex; align-items: center; justify-content: center;
  background: transparent; color: var(--fg); font-size: 1.15rem;
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .2);
  flex: none;
}
.mobilebar .mbtitle { font-style: normal; }
.mobilebar .mblogout {
  background: rgba(255,255,255,.09); color: #d6d6d0;
  padding: .35rem .7rem; border-radius: 7px; font-size: .85rem;
}
.mobilebar form { margin: 0; }
/* the global button align-self:flex-start pins them to the bar top otherwise */
.mobilebar button { align-self: center; }

@media (max-width: 700px) {
  /* the app is rigid: the page never scrolls, only main / the chat do */
  html, body { height: 100dvh; overflow: hidden; overscroll-behavior: none; }
  /* position:fixed kills iOS rubber-band bounce that overflow:hidden misses */
  body { display: flex; flex-direction: column; position: fixed; inset: 0; width: 100%; }
  /* inputs under 16px make iOS zoom in on focus — never below 16 on phones */
  input:not([type=checkbox]), textarea, select { font-size: 16px; }
  .mobilebar { display: flex; }
  .shell { flex: 1; min-height: 0; }
  /* sidebar becomes a drawer under the bar; ☰ toggles it */
  /* backdrop scrim: dims the page behind the open drawer and eats the
     closing tap so it never reaches the chat underneath */
  #scrim {
    position: fixed; inset: 0; z-index: 35;
    background: rgba(0, 0, 0, .28);
    -webkit-backdrop-filter: blur(2.5px);
    backdrop-filter: blur(2.5px);
    opacity: 0; pointer-events: none; transition: opacity .18s ease-out;
  }
  body.menuopen #scrim { opacity: 1; pointer-events: auto; }
  aside {
    position: fixed; top: 3.9rem; bottom: 0; left: 0; z-index: 40;
    width: min(68vw, 16.5rem);
    transform: translateX(-100%); transition: transform .18s ease-out;
    overflow-y: auto; overscroll-behavior: contain;
    /* only the edges facing the app get dressed: the free corner rounds,
       the top and right sides wear the accent */
    border-top-right-radius: 16px;
    border-top: 2px solid var(--accent);
    border-right: 2px solid var(--accent);
    /* glass, following the theme (the always-dark rule is desktop-only) */
    background: var(--drawer-bg);
    -webkit-backdrop-filter: blur(9px) saturate(1.35);
    backdrop-filter: blur(9px) saturate(1.35);
    --sb-fg: var(--drawer-fg);
    --sb-dim: var(--drawer-dim);
  }
  aside .brand { color: var(--drawer-fg); }
  aside .merow-wrap { border-color: color-mix(in srgb, var(--drawer-fg) 18%, transparent); }
  aside a.plus, aside button.plus,
  aside .themerow button:not([aria-pressed="true"]) { background: var(--drawer-hilite); }
  aside nav a:not(.plus):hover, aside .merow:hover { background: var(--drawer-hilite); }
  body.menuopen aside { transform: translateX(0); box-shadow: 0 0 34px rgba(0,0,0,.55); }
  main { padding: .8rem .9rem 1rem; overflow-y: auto; height: 100%; }
  main.solo { margin: 6vh auto 0; height: auto; }
  /* chat header is hoisted into the top bar on phones; hide the empty h1 */
  body[data-page="dm"] main > h1 { display: none; }
  body.grouplayout main > h1 { display: none; } /* the pill already names it */
  .mobilebar .mbtitle { display: flex; align-items: center; gap: .45rem; min-width: 0; }
  .mobilebar .mbtitle #peername { font-weight: 700; }
  .mobilebar .mbtitle #peerstatus {
    font-size: .68rem; font-weight: 400;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  }
  .mobilebar .mbtitle .avatar { margin-right: 0; }
  .mobilebar .chatmenu { flex: none; }
  .mobilebar .chatmenu summary {
    color: var(--fg); font-size: 1.25rem; padding: 0;
    width: 2.9rem; height: 2.9rem; border-radius: 999px;
    border: 2px solid var(--accent); background: transparent;
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
    display: flex; align-items: center; justify-content: center;
  }
  .mobilebar .chatmenu .menupanel { left: 50%; right: auto; transform: translateX(-50%); }
}

/* chat fills the viewport at every size; composer pinned at the bottom */
body[data-page="dm"] { height: 100dvh; overflow: hidden; }
body[data-page="dm"] .shell { height: 100%; min-height: 0; }
body[data-page="dm"] main { display: flex; flex-direction: column; overflow-y: auto; height: 100%; max-width: none; }
body[data-page="dm"] h1 { margin-bottom: .5rem; }
#dmmain:not([hidden]) { flex: 1; display: flex; flex-direction: column; min-height: 0; }
#dmmain .msgswrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#dmmain #msgs { flex: 1; max-height: none; min-height: 0; }
#dmmain form { max-width: none; }

/* the board gear menu is only for group-chats */
#boardmenu { display: none; }
body.grouplayout #boardmenu { display: inline-block; }
body.grouplayout #membersbtn,
body.grouplayout #reportbtn,
body.grouplayout #lockbtn,
body.grouplayout #delboard { display: none; }

/* group-chats: a board rendered like a DM (bubbles, composer pinned) */
body.grouplayout { height: 100dvh; overflow: hidden; }
body.grouplayout .shell { height: 100%; min-height: 0; }
body.grouplayout main { display: flex; flex-direction: column; height: 100%; max-width: none; min-height: 0; overflow: hidden; }
body.grouplayout #boardmain:not([hidden]) { flex: 1; display: flex; flex-direction: column; min-height: 0; position: relative; /* anchors the scroll-date pill */ }
body.grouplayout #posts {
  flex: 1; order: 1; overflow-y: auto; min-height: 0; overscroll-behavior: contain;
  display: flex; flex-direction: column; padding-right: .2rem;
}
body.grouplayout #postform { order: 2; max-width: none; margin-top: .3rem; }
body.grouplayout .pager { display: none; }
/* bubbles, same as chat: theirs left, yours right */
body.grouplayout #posts article {
  max-width: 82%; width: fit-content; margin: 0 auto .55rem 0;
  padding: .45rem .7rem .5rem; background: var(--panel);
  border: 1px solid var(--border); border-radius: 12px 12px 12px 4px;
}
body.grouplayout #posts article.mine {
  margin: 0 0 .55rem auto; border-radius: 12px 12px 4px 12px;
  background: color-mix(in srgb, var(--accent) 14%, var(--panel));
}
/* short groups grow upward too (specificity must beat the .mine margins) */
body.grouplayout #posts > article:first-child,
body.grouplayout #posts > article.mine:first-child { margin-top: auto; }

/* sidebar sections collapse on tap of their heading */
aside nav .navhead { cursor: pointer; user-select: none; }
aside nav .navhead::after { content: ' ▾'; opacity: .55; font-size: .85em; }
aside nav.collapsed .navhead::after { content: ' ▸'; }
aside nav.collapsed > a, aside nav.collapsed > .navbtn { display: none; }

/* drawn glyphs sit dead-centre in their circles (inline svg has a baseline gap) */
.chatmenu summary svg, #mbsettings svg, #menubtn svg, .composer .attach svg, .themerow svg, button.logout svg { display: block; }
.chatmenu summary svg { transform: translate(1px, 1px); } /* optical nudge, per the boss */
/* gear menu as a vertical icon pill, same language as the attach menu */
.menupanel.iconpanel {
  border: 2px solid var(--accent); border-radius: 999px;
  padding: .3rem; gap: .25rem; min-width: 0; width: max-content;
}
.menupanel.iconpanel button {
  display: flex; align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; padding: 0; border-radius: 999px;
  color: var(--fg);
}
.menupanel.iconpanel button svg { display: block; }
.menupanel.iconpanel button.danger { color: var(--danger); }
/* glasses ride inline with the last-seen time */
#peerstatus svg { display: inline-block; vertical-align: -0.28em; margin-right: .15rem; }

/* generated-password panels (register + change password) */
.pwbox { display: flex; gap: .4rem; align-items: stretch; }
.pwbox input { flex: 1; font-family: ui-monospace, SFMono-Regular, monospace; letter-spacing: .04em; }
.pwbox .pwcopy { flex: none; padding: 0 .9rem; }
.pwregen { align-self: flex-start; font-size: .85rem; }
