:root, html[data-theme="grey"] {
  --bg: #303030; --ink: #E8E4DC; --grey: #8A8A86; --line: rgba(232,228,220,.22);
  --cap: #4A4A48; --edge: #2E2E2C; --cap-ink: #A6A6A1; --dot-back: #1c1c1a; --soft: rgba(232,228,220,.08);
  --font: 'IBM Plex Sans', system-ui, -apple-system, 'Helvetica Neue', sans-serif;
  color-scheme: dark;
}
html[data-theme="white"]  { --bg: #F2EFE8; --ink: #2A2A28; --grey: #8A8A86; --line: rgba(42,42,40,.22); --cap: #E4E0D6; --edge: #C9C4B7; --cap-ink: #6A6864; --dot-back: #C9C4B7; --soft: rgba(42,42,40,.07); color-scheme: light; }
html[data-theme="pure"]   { --bg: #FFFFFF; --ink: #1E1E1C; --grey: #8A8A86; --line: rgba(30,30,28,.2); --cap: #EFEFEE; --edge: #CFCFCC; --cap-ink: #6A6A66; --dot-back: #CFCFCC; --soft: rgba(30,30,28,.07); color-scheme: light; }
html[data-theme="salmon"] { --bg: #FAD0BB; --ink: #3A2A22; --grey: #8F6E60; --line: rgba(58,42,34,.25); --cap: #F0BFA6; --edge: #C9987F; --cap-ink: #6A4A3C; --dot-back: #C9987F; --soft: rgba(58,42,34,.08); color-scheme: light; }
html[data-theme="pink"]   { --bg: #F2D8DA; --ink: #3A2628; --grey: #8B6E70; --line: rgba(58,38,40,.25); --cap: #E8C6C9; --edge: #C49EA2; --cap-ink: #5E4245; --dot-back: #C49EA2; --soft: rgba(58,38,40,.08); color-scheme: light; }
html[data-theme="silver"] { --bg: #DADADA; --ink: #222220; --grey: #6F6F6C; --line: rgba(34,34,32,.22); --cap: #CBCBCB; --edge: #A8A8A8; --cap-ink: #5A5A58; --dot-back: #A8A8A8; --soft: rgba(34,34,32,.07); color-scheme: light; }
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { min-height: 100%; background: var(--bg); color: var(--ink); font-family: var(--font); font-weight: 300; }
a { color: inherit; }
button, input { font: inherit; color: inherit; }
button:focus-visible, input:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

/* The scrollbar's space is held open whether or not one is showing. Root scrolls and
   the chat and deck pages don't, so without this the page would jump sideways as you
   move between them. */
html { scrollbar-gutter: stable; }

/* One width everywhere. On a phone the app fills the screen; on a desktop it takes
   55% of it, but stops growing past a comfortable line length. */
.app { width: 100%; max-width: 480px; margin: 0 auto; min-height: 100vh; display: flex; flex-direction: column; }
/* Desktop is handled by the desk (desk.php): every page at a wide window is sent there
   and shown inside a panel. Inside a panel the page marks itself html.framed, and these
   rules apply — the scroll moves onto main so the panel's rounded corners clip the
   scrollbar cleanly, inset a little from the edge, in the site's own line colour. */
html.framed body { margin: 0; height: 100vh; overflow: hidden; }
html.framed .app:not(.deck):not(.chat) { height: 100vh; min-height: 0; overflow: hidden; }
html.framed .app:not(.deck):not(.chat) main { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding-bottom: 40px; margin: 0 0 8px; }

/* One scrollbar treatment for every scrolling surface inside a panel — main, the chat
   log, the report and book overlays. The thumb is inset from the edge by a transparent
   border rather than by moving the element, so an overlay can still reach the edge and
   nothing beneath it shows through. Thin and in the line colour, on a clear track. */
/* Every scrollbar inside a panel, whichever element happens to own it — naming three
   elements meant any other scrolling surface kept the browser's white track, which is
   the strip that showed beside the bar. */
html.framed, html.framed body { background: var(--bg); }
html.framed * { scrollbar-width: thin; scrollbar-color: var(--line) var(--bg); }
html.framed *::-webkit-scrollbar { width: 12px; height: 12px; background: var(--bg); }
html.framed *::-webkit-scrollbar-track { background: var(--bg); }
html.framed *::-webkit-scrollbar-corner { background: var(--bg); }
html.framed *::-webkit-scrollbar-thumb { background: var(--line); background-clip: padding-box; border: 3px solid transparent; border-right-width: 6px; border-radius: 6px; }
html.framed main, html.framed .log, html.framed .report-over { overflow-x: hidden; }
/* A full-height overlay would run its scrollbar into the panel's rounded corners. A
   border in the page colour keeps the bar inside it — the element still reaches the
   edge, so nothing shows through, but the bar stops short of the corners. The book
   and report carry their own header, so the border sits below it. */
html.framed .log, html.framed .report-over { border-top: 62px solid var(--bg); border-bottom: 8px solid var(--bg); box-sizing: border-box; }
html.framed .report-over .report-close { top: calc(23px + env(safe-area-inset-top, 0px)); }
header { padding: calc(18px + env(safe-area-inset-top, 0px)) 24px 0; height: 44px; box-sizing: content-box; font-size: 12px; letter-spacing: .04em; color: var(--grey); display: flex; align-items: center; justify-content: space-between; gap: 14px; }
header .home { color: var(--grey); text-decoration: none; display: inline-flex; align-items: center; }
header .home:hover { color: var(--ink); }
header .right { color: var(--grey); text-decoration: none; font-size: 12px; letter-spacing: 0; }
header .right:hover { color: var(--ink); }
/* Room under the header before anything starts — tabs, the cube, settings alike. */
main { flex: 1; padding: 40px 24px calc(40px + env(safe-area-inset-bottom, 0px)); }

h1 { font-size: 26px; font-weight: 300; line-height: 1.35; margin-bottom: 28px; }
p { font-size: 14px; line-height: 1.6; color: var(--grey); margin-bottom: 18px; }
p.ink { color: var(--ink); }

.field { margin-bottom: 26px; }
.field label { display: block; font-size: 11px; color: var(--grey); margin-bottom: 6px; }
.field input {
  width: 100%; background: none; border: 0; border-bottom: 1px solid var(--line);
  padding: 8px 0; font-size: 16px; color: var(--ink);
}
.field input:focus { border-bottom-color: var(--ink); outline: none; }

.btn {
  display: inline-block; background: none; border: 1px solid var(--line);
  border-radius: 3px; padding: 8px 14px; font-size: 13px; cursor: pointer;
}
.btn:active { background: rgba(232,228,220,.1); }
.row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 8px; }
.small { font-size: 12px; color: var(--grey); text-decoration: none; }
.small:hover { color: var(--ink); }
.err { font-size: 13px; color: var(--ink); border-left: 1px solid var(--ink); padding-left: 12px; margin-bottom: 24px; }
.ok  { font-size: 14px; color: var(--ink); }
.codebox {
  font-size: 13px; color: var(--ink); background: var(--soft);
  padding: 12px 14px; border-radius: 3px; word-break: break-all; margin: 14px 0;
}

.chatlist { list-style: none; margin-bottom: 36px; }
.chatlist li a, .chatlist li .linkbtn {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 14px 0; border-bottom: 1px solid var(--soft);
  font-size: 15px; color: var(--ink); text-decoration: none; background: none; border-top: 0; border-left: 0; border-right: 0; cursor: pointer;
}
.chatlist .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink); opacity: 0; }
.chatlist .dot.on { opacity: 1; }
header .home svg circle { transition: fill .35s ease, stroke .35s ease; }
header .home.lit svg circle { fill: var(--ink) !important; stroke: var(--ink) !important; }
/* !important because .app.chat header .home and .app.deck header .home are more
   specific and set the grey — without it the mark could never light on those pages,
   and only the circles (which carry their own !important) would change. */
header .home.lit { color: var(--ink) !important; opacity: 1; }
.chatlist .tag { font-size: 11px; color: var(--grey); }
.check { font-size: 13px; color: var(--grey); display: flex; align-items: center; gap: 8px; }
.check input { accent-color: var(--ink); }
.linkbtn { background: none; border: 0; cursor: pointer; }


.search { margin-bottom: 18px; display: flex; align-items: center; gap: 10px; }
.search input { flex: 1; min-width: 0; }
.search input { font-size: 14px; }
.search input::placeholder { color: var(--grey); }
/* Every chat row is the same height: name with people beneath on the left, "public" and the icons centred on the right. */
.chatlist li a { flex-wrap: nowrap; height: 48px; padding: 0; }
.chatlist .stack { display: flex; flex-direction: column; justify-content: center; gap: 2px; flex: 1 1 auto; min-width: 0; }
/* .nm is itself a flex: its gap is what separates the favicon from the name. 18px to
   match the sources rows, whose gap does the same job. */
.chatlist .nm { display: inline-flex; align-items: center; gap: 18px; flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chatlist .people { font-size: 12px; color: var(--grey); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chatlist .tag { flex: 0 0 auto; margin-left: auto; }
.nomatch { font-size: 13px; }

.tabs { display: flex; gap: 18px; margin: 0; padding-bottom: 6px; font-size: 13px; }
.controls-block { margin-bottom: 24px; }
.tabs a { color: var(--grey); text-decoration: none; padding-bottom: 4px; border-bottom: 1px solid transparent; }
.tabs a.on { color: var(--ink); border-bottom-color: var(--ink); }
.crumb { font-size: 12px; }
.crumb a { color: var(--grey); text-decoration: none; }

.controls-block { position: relative; padding-bottom: 0; }
.controls-row { display: flex; align-items: center; gap: 12px; margin: -10px 0 28px; }
.grid-btn { position: absolute; right: -3px; bottom: -3px; display: inline-flex; align-items: flex-end; justify-content: flex-end; width: 58px; height: 58px; color: var(--grey); text-decoration: none; }
.grid-btn:hover { color: var(--ink); }
.swatches { display: inline-flex; gap: 12px; margin: 0; vertical-align: middle; }

.swatches .swatch { transition: transform .18s ease, opacity .18s ease; }
.swatches.open .swatch { animation: swatch-in .18s ease both; }
@keyframes swatch-in { from { opacity: 0; transform: scale(.6) } to { opacity: 1; transform: scale(1) } }
@media (prefers-reduced-motion: reduce) { .swatches.open .swatch { animation: none; } }
.mute { display: inline-flex; align-items: center; gap: 12px; margin: 0; vertical-align: middle; }
.mute-btn { width: 20px; height: 20px; padding: 0; background: none; border: 0; color: var(--grey); cursor: pointer; display: inline-flex; }
.mute-btn:hover { color: var(--ink); }
.mute-btn .slash { display: none; }
.mute-btn.off .slash { display: block; }
.mute-btn.off .core { display: none; }
.swatch { width: 20px; height: 20px; box-sizing: border-box; border-radius: 50%; border: 1px solid var(--line); cursor: pointer; padding: 0; box-shadow: inset 0 0 0 1px rgba(0,0,0,.18); }
.swatch.on { outline: none; }

.chatlist li:not(.chat) { display: flex; align-items: center; gap: 10px; }
.chatlist li:not(.chat) > a, .chatlist li:not(.chat) > .linkbtn { flex: 1; min-width: 0; }
.chatlist li.chat { display: block; }
.chatlist li.chat > .row { display: flex; align-items: center; gap: 10px; padding-left: calc(var(--depth, 0) * 18px); }
.chatlist li.chat > .row > a { flex: 1; min-width: 0; }
.chatlist .disc { flex: 0 0 auto; background: none; border: 0; color: var(--grey); padding: 8px 6px; cursor: pointer; display: inline-flex; transition: transform .2s ease; }
.chatlist li.chat.open > .row > .disc { transform: rotate(90deg); }
/* Sub-chats: hidden until the triangle is turned. These rules were destroyed by a
   careless regex that matched ".subs" meaning the followed-subjects list — hence the
   triangle rotating while nothing appeared. */
.chatlist li.chat > .subs { display: none; }
.chatlist li.chat.open > .subs,
.chatlist li.chat.search-open > .subs { display: block; }
.chatlist .chatlist .row a { font-size: 15px; }
.chatlist .newsub { padding-left: calc((var(--depth, 0) + 1) * 18px); }
.chatlist .newsub form { flex: 1; min-width: 0; }
.chatlist .newsub input { width: 100%; background: none; border: 0; border-bottom: 1px solid transparent; padding: 10px 0; font: inherit; font-size: 13px; color: var(--ink); }
.chatlist .newsub input::placeholder { color: var(--grey); }
.chatlist .newsub input:focus { outline: none; border-bottom-color: var(--line); }
.chatlist .leave { flex: 0 0 auto; }
.chatlist .leave button { background: none; border: 0; color: var(--grey); font-size: 18px; line-height: 1; padding: 6px 0 6px 6px; cursor: pointer; opacity: .55; }
.chatlist .leave button:hover { color: var(--ink); opacity: 1; }

.mute-label { font-size: 11px; color: var(--grey); margin-left: 8px; align-self: center; }


/* Dropped from the tabs, so it needs air above as well as below. */
.searchrow { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.searchrow .field { flex: 1; }
.pfilter { width: 20px; height: 20px; padding: 0; margin-bottom: 26px; background: none; border: 0; color: var(--grey); cursor: pointer; display: inline-flex; opacity: .45; }
.pfilter .slash { display: none; }
.pfilter[data-state="public"] { color: var(--ink); opacity: 1; }
.pfilter[data-state="private"] { color: var(--ink); opacity: 1; }
.pfilter[data-state="private"] .slash { display: block; }

.chatlist .spanner { flex: 0 0 auto; background: none; border: 0; color: var(--grey); padding: 8px 6px; cursor: pointer; display: inline-flex; opacity: .55; }
.chatlist .spanner:hover { color: var(--ink); opacity: 1; }
.chatlist .spanner svg { transition: transform .3s ease; }
.chatlist .spanner.open svg { transform: rotate(30deg); }
.chatlist .spanner.open { color: var(--ink); opacity: 1; }
@media (prefers-reduced-motion: reduce) { .chatlist .spanner svg { transition: none; } }
.chatlist .tools { padding: 4px 0 10px calc(var(--depth, 0) * 18px + 12px); font-size: 12px; color: var(--grey); }
.tool-row { display: flex; align-items: center; gap: 14px; padding: 6px 0; border-bottom: 1px solid var(--soft); }
.tool-row span { flex: 1; color: var(--ink); }
.tool-row button { background: none; border: 0; color: var(--grey); font: inherit; font-size: 11px; cursor: pointer; padding: 2px 0; }
.tool-row button:hover { color: var(--ink); }

.tool-feed { padding-top: 8px; }
.tool-feed input { width: 100%; background: none; border: 0; border-bottom: 1px solid transparent; padding: 6px 0; font: inherit; font-size: 12px; color: var(--ink); }
.tool-feed input::placeholder { color: var(--grey); }
.tool-feed input:focus { outline: none; border-bottom-color: var(--line); }

.suggest { display: flex; flex-direction: column; margin: -18px 0 22px; max-height: 320px; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.suggest::-webkit-scrollbar { width: 8px; }
.suggest::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
.suggest button { touch-action: pan-y; }
.suggest:empty { margin: 0; }
.suggest button { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--soft); padding: 9px 0; font: inherit; font-size: 14px; color: var(--ink); cursor: pointer; }
.suggest button small { font-size: 11px; color: var(--grey); }
.suggest button:hover span { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line); }
.tool-feed .suggest { margin: 0; }
.tool-feed .suggest button { font-size: 12px; padding: 7px 0; }

.tool-feedset { display: flex; flex-direction: column; gap: 8px; padding: 10px 0 6px; border-bottom: 1px solid var(--soft); }
.tool-feedset label { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 11px; color: var(--grey); }
.tool-feedset input[type="text"] { flex: 1; background: none; border: 0; border-bottom: 1px solid var(--line); padding: 4px 0; font: inherit; font-size: 12px; color: var(--ink); text-align: right; }
.tool-feedset input[type="number"] { width: 52px; background: none; border: 0; border-bottom: 1px solid var(--line); padding: 4px 0; font: inherit; font-size: 12px; color: var(--ink); text-align: right; }
.tool-feedset input[type="checkbox"] { accent-color: var(--ink); }
.tool-feedset input:focus { outline: none; border-bottom-color: var(--ink); }
.tool-feedset button { align-self: flex-end; background: none; border: 0; color: var(--grey); font: inherit; font-size: 11px; cursor: pointer; padding: 2px 0; }
.tool-feedset button:hover { color: var(--ink); }
.tool-status { font-size: 10px; color: var(--grey); }




[hidden] { display: none !important; }

/* Wherever the page runs under a system bar, keep the bottom clear of it. */
main { padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px)); }

.notify { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pill { background: none; border: 1px solid var(--line); border-radius: 999px; padding: 4px 11px; font: inherit; font-size: 12px; color: var(--grey); cursor: pointer; }
.pill.on { color: var(--ink); border-color: var(--ink); }
.pill.off { opacity: .4; cursor: default; }
.pill:not(.off):hover { color: var(--ink); }

.notify-opts { display: inline-flex; gap: 8px; }

/* ---- keyboard ---- */
.keyboard { padding: 6px 10px calc(10px + env(safe-area-inset-bottom, 0px)); user-select: none; }
.keyboard .row { display: flex; justify-content: center; gap: 4px; margin-bottom: 6px; }
.key {
  flex: 1 1 0; max-width: 34px; height: 34px; border: 0; border-radius: 4px;
  background: var(--cap); color: var(--cap-ink); box-shadow: 0 2px 0 var(--edge);
  font: inherit; font-size: 13px; font-weight: 400; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.key.down { transform: translateY(1px); box-shadow: 0 1px 0 var(--edge); color: var(--ink); }
.key.fn { max-width: 46px; font-size: 11px; }
.key.space { max-width: none; flex-grow: 4; }
.key.punct { max-width: 28px; }
.key.send { max-width: 52px; background: none; color: var(--cap-ink); box-shadow: none; border: 1px solid var(--cap); }
.key.send.down { transform: none; border-color: var(--cap-ink); }
.key.shift.on { background: var(--cap-ink); color: var(--cap); box-shadow: 0 2px 0 var(--edge); }

.keyboard.floating { position: fixed; left: 0; right: 0; bottom: 0; width: 100%; max-width: 480px; margin: 0 auto; background: var(--bg); padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); z-index: 40; border-top: 1px solid var(--soft); }
body.xkb-open main { padding-bottom: 220px; }
@media (min-width: 900px) { .keyboard { display: none !important; } body.xkb-open main { padding-bottom: 40px; } }

.name-btn { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: text; text-align: left; }
.name-form, .pin-form { margin: -12px 0 28px; }

.codebox.copyable { display: flex; align-items: center; gap: 12px; }
.codebox.copyable span { flex: 1; min-width: 0; word-break: break-all; }
.copy { flex: 0 0 auto; background: none; border: 0; padding: 4px; color: var(--grey); cursor: pointer; display: inline-flex; }
.copy:hover, .copy.done { color: var(--ink); }
.copy.done svg { transform: scale(1.15); }

.tool-move { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 11px; color: var(--grey); padding: 8px 0; border-bottom: 1px solid var(--soft); }
.tool-move select { font: inherit; font-size: 12px; color: var(--ink); background: var(--bg); border: 0; border-bottom: 1px solid var(--line); padding: 4px 0; max-width: 70%; }


.archived .chatlist li a { color: var(--grey); font-size: 14px; height: 40px; }

.tool-list { padding: 8px 0; border-bottom: 1px solid var(--soft); }
.tool-list label { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--grey); cursor: pointer; }
.tool-list input { accent-color: var(--ink); }

/* No margin: .nm's own gap spaces it. A margin here was adding to that gap, which is
   why the feed rows sat wider than the sources rows however the gap was set. */
.favicon { width: 16px; height: 16px; flex-shrink: 0; border-radius: 2px; vertical-align: -3px; opacity: .9; }
/* (a duplicate of the rule above; it sets no gap, so spacing comes from there) */

.head-actions { display: inline-flex; align-items: center; gap: 14px; margin-left: auto; line-height: 1; }
.head-actions .invite { display: inline-flex; align-items: center; height: 20px; }
.head-actions .invite { text-decoration: none; font-size: 18px; font-weight: 300; color: var(--grey); line-height: 1; }
.head-actions .invite:hover { color: var(--ink); }
.settings-btn { background: none; border: 0; padding: 0; color: var(--grey); cursor: pointer; display: inline-flex; align-items: center; opacity: .55; }
.settings-btn:hover, .settings-btn.open { opacity: 1; }
.settings-btn:hover { color: var(--ink); }
.settings-btn svg { transition: transform .2s ease; }
.settings-btn.open svg { transform: rotate(180deg); }
.settings { margin: 0 0 18px; }
.controls-row { margin: 0 0 6px; }

.feed-head { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink); padding-bottom: 6px; }
.feed-head .favicon { margin-right: 0; }
.feed-head span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-remove { background: none; border: 0; color: var(--grey); font: inherit; font-size: 11px; cursor: pointer; padding: 0; }
.feed-remove:hover { color: var(--ink); }
.tool-feedset + .tool-feedset { margin-top: 6px; }

.chat-mark { display: inline-flex; align-items: center; flex-shrink: 0; }   /* spaced by .nm's gap */
.chat-mark svg { width: 15px; height: 13px; }
.tool-colour { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 11px; color: var(--grey); padding: 8px 0; border-bottom: 1px solid var(--soft); }
.chat-swatch { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--line); cursor: pointer; padding: 0; }
.chat-swatch.none { background: none; }
.chat-swatch.on { box-shadow: 0 0 0 1px var(--bg), 0 0 0 2px var(--ink); }


.qr { margin: 26px 0 10px; }
.qr svg { display: block; }
.qr p { margin-top: 10px; color: var(--grey); }

.field select, .bulk { width: 100%; background: none; border: 0; border-bottom: 1px solid var(--line); color: var(--ink); font: inherit; font-size: 15px; padding: 8px 0; border-radius: 0; }
.bulk { border: 1px solid var(--line); padding: 10px; line-height: 1.5; }
.field select:focus, .bulk:focus { outline: none; border-bottom-color: var(--ink); }

/* Reading, as squares: one per thing opened, in the order they were read. */
.reading { margin: 0 0 22px; }
.read-grid { display: flex; flex-wrap: wrap; gap: 3px; margin-bottom: 12px; }
.read-sq { width: 11px; height: 11px; border-radius: 1px; opacity: .9; }
.read-sq:hover { opacity: 1; outline: 1px solid var(--ink); outline-offset: 1px; }
#cubeBtn svg { transition: transform .2s ease; }
#cubeBtn.open svg { transform: rotate(45deg); }

/* + sits in the list like any other row, and the line unfolds beneath it. */
/* Last in the list now, so the border belongs above it rather than below. */
.chatlist li.create-row { display: block; border-bottom: 0; border-top: 1px solid var(--soft); }
.create-open { display: flex; align-items: center; width: 100%; height: 48px; background: none; border: 0; padding: 0; font: inherit; font-size: 16px; color: var(--grey); cursor: pointer; text-align: left; }
.create-open:hover, .create-open.open { color: var(--ink); }
.create-open .chat-mark { margin-right: 18px; }   /* its own margin, matching the rows gap below */
.create-open .plus { font-size: 18px; font-weight: 300; line-height: 1; }
.create-row .newchat { padding: 0 0 18px; }

.create-row .newchat .row { margin-top: 12px; }


/* An invite as a card: its mark, the code, the link and the QR together. */
.invite-card { border: 1px solid var(--line); border-radius: 10px; padding: 24px 20px 10px; margin: 0 0 18px; }
.invite-mark { display: flex; justify-content: center; margin-bottom: 18px; color: var(--ink); }
.invite-card .qr { margin-top: 22px; text-align: center; }
.invite-card .qr svg { margin: 0 auto; }

/* The codes you've made, each with its own mark. */
/* Every row the same height, whatever it says. */
.invites .invite-row { display: flex; align-items: center; gap: 12px; height: 44px; padding: 0; border-bottom: 1px solid var(--soft); }
.invite-glyph { display: inline-flex; align-items: center; flex-shrink: 0; color: var(--ink); }
.invite-what { flex: 1; min-width: 0; font-size: 13px; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-when { color: var(--grey); font-size: 11px; line-height: 1.2; flex-shrink: 0; }
.invite-row.spent { opacity: .5; }
.invite-off { margin: 0; }

/* Earlier codes, folded away — they name people, so they stay shut until asked for. */
.past-invites { margin-top: 26px; }
.past-toggle { background: none; border: 0; padding: 8px 0; font: inherit; font-size: 13px; color: var(--grey); cursor: pointer; display: inline-flex; align-items: center; gap: 8px; }
.past-toggle:hover, .past-toggle.open { color: var(--ink); }
.past-toggle::before { content: '+'; font-size: 14px; line-height: 1; }
.past-toggle.open::before { content: '–'; }

/* A close in the header, where a page is a thing you finish with. */
.close-x { margin-left: auto; color: var(--grey); text-decoration: none; font-size: 22px; line-height: 1; display: inline-flex; align-items: center; height: 20px; }
.close-x:hover { color: var(--ink); }

@media (min-width: 900px) { .keyboard.floating { width: 55%; max-width: 720px; } }

.tool-danger { background: none; border: 0; padding: 8px 0; font: inherit; font-size: 13px; color: #B4483A; cursor: pointer; }
.tool-danger:hover { text-decoration: underline; }

/* Passkeys: the devices that can sign you in. These rows sit in a chatlist, so the
   button has to shed what that gives it — 16px type and a border of its own, which
   doubled up with the row's own line. */
.passkeys { margin: 0 0 18px; }
.passkeys #passkeyBody { padding-top: 4px; }
/* Name on one line, when it was added beneath it, forget kept level with the name at
   the top of the row rather than floating in the middle of the two lines. */
.passkey-row { display: flex; align-items: flex-start; gap: 12px; height: auto; min-height: 0; padding: 10px 0; border-bottom: 1px solid var(--soft); }
.passkey-row:last-of-type { border-bottom: 0; }
.passkey-what { flex: 1; min-width: 0; font-size: 13px; display: block; overflow: hidden; line-height: 1.3; }
.passkey-what .invite-when { display: block; margin-top: 3px; }
.chatlist li.passkey-row .passkey-forget {
  width: auto; padding: 0; border: 0; font-size: 12px; color: var(--grey);
  flex: 0 0 auto; align-self: flex-start; line-height: 1.3; background: none; height: auto;
}
.chatlist li.passkey-row .passkey-forget:hover { color: var(--ink); }
.passkey-in { margin-top: 26px; text-align: center; }
.passkey-in .small { color: var(--grey); }
.passkey-in .btn { margin: 8px 0; }

/* Someone's posts, on their page. */
.posts-list .post-row { display: block; padding: 14px 0; border-bottom: 1px solid var(--soft); }
.post-body { font-size: 15px; line-height: 1.5; }
.post-link { display: block; margin-top: 6px; font-size: 12px; color: var(--grey); }
.post-link:hover { color: var(--ink); }
.post-meta { margin-top: 6px; font-size: 11px; color: var(--grey); }

/* A page of prose, for the one place xyp has any. */
.prose { max-width: 34em; }
.prose h2 { font-size: 14px; font-weight: 400; letter-spacing: .04em; color: var(--grey); margin: 30px 0 8px; }
.prose p { font-size: 14px; line-height: 1.65; margin: 0 0 12px; }
.prose ul { margin: 0 0 12px; padding-left: 18px; }
.prose li { font-size: 14px; line-height: 1.65; margin-bottom: 6px; }
.prose b { font-weight: 500; }

.settings-terms { margin: 16px 0 0; font-size: 12px; }
.settings-terms a { color: var(--grey); text-decoration: none; }
.settings-terms a:hover { color: var(--ink); }

/* A subject as the graph knows it. */
/* No heading: the search box above already holds the word. */
.rep-meta { margin: 0 0 18px; }
.rep-pulse { display: flex; align-items: flex-end; gap: 4px; height: 30px; margin: 0 0 34px; }
.rep-pulse i { width: 16px; background: var(--line); display: block; }
.rep-pulse i.on { background: var(--ink); }
.rep-pulse-note { align-self: flex-end; margin-left: 10px; font-size: 10px; letter-spacing: .06em; color: var(--grey); }
/* More air between sections, so the page reads as parts rather than a run. */
/* Exactly a row's title: 15px, ink, weight 300 inherited from body, no letter-spacing
   and no transform. A row sets none of these, so neither does a heading — that way the
   text is identical moving between feed, sources and filters. */
.rep-h { font-size: 15px; font-weight: 300; letter-spacing: 0; text-transform: none; color: var(--ink); margin: 34px 0 10px; }
/* The count sits away from the word. Outside .chatlist it had no spacing at all, so
   "mute a topic" and its 0 ran together as one word. */
.rep-h .tag { font-size: 11px; color: var(--grey); margin-left: 8px; font-weight: 300; }
main > .rep-h:first-child, .directory .rep-h:first-child, .mute-block:first-child .rep-h { margin-top: 4px; }
.rep-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; line-height: 1.4; align-items: flex-start; }
.rep-chips a, .rep-chips span { display: inline-block; flex: 0 0 auto; width: auto; font-size: 12px; line-height: 1.3; padding: 4px 10px; border: 1px solid var(--line); text-decoration: none; color: var(--ink); }
.rep-chips a:hover { border-color: var(--ink); }
.rep-chips.far a { border-style: dashed; color: var(--grey); }
.rep-chips.plain span { border: 0; padding: 4px 0; color: var(--grey); }
.rep-chips.plain b { font-weight: 400; color: var(--ink); margin-left: 6px; }
/* These rows sit in a chatlist, so the link inside inherits its flex layout, padding
   and border. All of that has to be undone or the parts sit on top of each other. */
.rep-list .rep-row { display: flex; align-items: flex-start; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--soft); }
.chatlist.rep-list li a.rep-piece,
.rep-piece {
  /* A flex item has to be block-level to shrink and wrap — inline ignores the sizing,
     which is why long titles ran into the column beside them. Clamped to two lines. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  flex: 1 1 0; min-width: 0; width: auto; max-width: 100%;
  overflow: hidden; overflow-wrap: anywhere;
  padding: 0; border: 0; text-align: left;
  font-size: 14px; line-height: 20px; color: var(--ink); text-decoration: none;
  /* An exact box, or a third line shows through as a sliver where the clamp cuts. */
  max-height: 40px;
}
.rep-piece:hover { text-decoration: underline; text-underline-offset: 3px; }
/* Source above date in their own column, right-aligned, so a long publication name
   can't collide with the piece's title. */
.rep-meta-col { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; width: 92px; overflow: hidden; }
.rep-src { font-size: 11px; line-height: 1.35; color: var(--grey); text-align: right; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rep-when { font-size: 10px; line-height: 1.35; color: var(--grey); }
.rep-foot { margin-top: 48px; padding-top: 16px; border-top: 1px solid var(--soft); font-size: 11px; color: var(--grey); line-height: 1.7; }

/* A report over the deck. Closing it leaves the card exactly where it was. */
.report-over { position: fixed; inset: 0; z-index: 45; background: var(--bg); overflow-y: auto; -webkit-overflow-scrolling: touch; }
.report-over[hidden] { display: none; }
.report-inner { max-width: 40em; margin: 0 auto; padding: 56px 26px 70px; }
/* Where the book was, at the book's tone: centred on the header's line, 24px from the
   right, held back to the same half opacity — so the × sits exactly where the mark you
   tapped had been. */
.report-close { position: fixed; top: calc(23px + env(safe-area-inset-top, 0px)); right: 18px; z-index: 46; background: var(--bg); border: 0; font-size: 26px; font-weight: 300; line-height: 1; color: var(--grey); opacity: .5; cursor: pointer; padding: 4px 6px; }
.report-close:hover { color: var(--ink); opacity: 1; }
.rep-wait { color: var(--grey); font-size: 13px; }
body.reporting { overflow: hidden; }

/* When a piece arrived by more than one route, how many — not three identical rows. */
.rep-also { font-weight: 400; font-size: 9px; margin-left: 4px; opacity: .65; }

/* Asking the graph: the same query the gesture makes, typed. */
/* The pulse sits inside the field at its right edge — as a separate box beside it, it
   crowded the close button in the corner above. */
.rep-search { position: relative; margin: 0 0 30px; max-width: 18em; }
.rep-search input { width: 100%; box-sizing: border-box; font: inherit; font-size: 15px; padding: 9px 44px 9px 12px; border: 1px solid var(--line); background: none; color: var(--ink); border-radius: 0; -webkit-appearance: none; }
.rep-search input:focus { outline: none; border-color: var(--ink); }
.rep-search button { position: absolute; right: 1px; top: 1px; bottom: 1px; width: 40px; font: inherit; padding: 0; border: 0; background: none; color: var(--grey); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.rep-search button svg { display: block; }
.rep-search button:hover { color: var(--ink); }

.rep-w { font-weight: 400; font-size: 9px; opacity: .5; margin-left: 5px; }
.rep-note { color: var(--grey); margin: 8px 0 0; }

.suggest-row.busy { opacity: .5; }
.suggest-row.taken .suggest-no { display: none; }
.suggest-row.taken .suggest-add { color: var(--ink); }


/* What the cube's colours mean. Without it the grid is a pattern, not a picture. */
.read-key { list-style: none; padding: 0; margin: 18px 0 0; display: flex; flex-direction: column; gap: 7px; }
.read-key li { display: flex; align-items: center; gap: 9px; font-size: 12px; }
.read-key i { width: 9px; height: 9px; flex: 0 0 auto; }
.read-key b { font-weight: 400; flex: 0 0 auto; max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.read-bar { flex: 1; min-width: 0; height: 3px; background: var(--soft); }
.read-bar em { display: block; height: 100%; min-width: 2px; }
.read-key u { text-decoration: none; color: var(--grey); font-size: 11px; flex: 0 0 auto; min-width: 22px; text-align: right; }
.read-more { margin-top: 10px; color: var(--grey); }

/* While the cube is open, your reading is the page — the tabs, the lists and the
   suggestions all wait. */
/* While the cube is open, your reading is the page. Named precisely for the same
   reason — the key beneath the grid is a .chatlist too. */
body.reading-open .tabs,
body.reading-open .searchrow,
body.reading-open #chatlist,
body.reading-open .folder,
body.reading-open .settings,
body.reading-open .grid,
body.reading-open .empty,
body.reading-open .nomatch { display: none; }

/* And the same while settings is open — but named precisely, because the devices list
   inside the panel is itself a .chatlist and a class-wide rule hid it. */
body.settings-open .tabs,
body.settings-open .searchrow,
body.settings-open #chatlist,
body.settings-open .folder,
body.settings-open .grid,
body.settings-open .empty,
body.settings-open .nomatch { display: none; }

.rep-follow { background: none; border: 1px solid var(--line); padding: 5px 12px; font: inherit; font-size: 12px; color: var(--grey); cursor: pointer; margin: 0 0 22px; }
.rep-follow:hover { border-color: var(--ink); color: var(--ink); }
.rep-follow.on { border-color: var(--ink); color: var(--ink); }

/* Subjects, suggestions and archived: three lists that fold the same way. Each is a
   quiet line with a count, and the rows beneath share one shape. */
.folder { margin: 22px 0 0; }
.folder .past-toggle { width: 100%; text-align: left; }

/* The marks on a subject or a suggestion sit exactly where a feed's favicon does,
   because these rows are a feed row — same markup, same rules. */
.chat-mark.brain { color: #E29AB0; }
.chat-mark.cite { color: var(--grey); }

/* The controls at the right of a subject or suggestion row. The name takes the slack,
   the buttons keep their width — without this they sat on top of each other. */
.chatlist li.chat > .row > .row-x,
.chatlist li.chat > .row > .suggest-add {
  flex: 0 0 auto; width: auto; padding: 8px 4px; border: 0; background: none;
  font-size: 12px; line-height: 1; color: var(--grey); cursor: pointer;
}
/* The same weight and tone as the × on a feed row: 18px, grey, and held back to 55%. */
.chatlist li.chat > .row > .row-x { font-size: 18px; padding: 6px 0 6px 6px; opacity: .55; }
.chatlist li.chat > .row > .row-x:hover { color: var(--ink); opacity: 1; }
.chatlist li.chat > .row > .suggest-add:hover { color: var(--ink); }
.chatlist li.chat.suggest-row > .row > a,
.chatlist li.chat > .row > a { flex: 1 1 0; min-width: 0; }
.suggest-row.taken .row-x { display: none; }

/* The magnifier sits at the right of the tabs; the field folds away beneath them. */
.tabs .tab-search { margin-left: auto; background: none; border: 0; padding: 0 0 0 14px; color: var(--grey); cursor: pointer; display: inline-flex; align-items: center; align-self: center; }
.tabs .tab-search:hover, .tabs .tab-search.on { color: var(--ink); }
.tabs .tab-search svg { display: block; }
.searchrow[hidden] { display: none; }

/* Settings as a short list: name, devices, colour, sound — each on its own line with
   the same label at the left, so they read as one set rather than a scatter. */
.settings h1 { font-size: 15px; font-weight: 400; margin: 0 0 4px; padding: 11px 0; border-bottom: 1px solid var(--soft); }
.settings .name-btn { font: inherit; font-size: 15px; }
.set-row { display: flex; align-items: center; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--soft); }
.set-label { flex: 0 0 auto; min-width: 84px; font-size: 13px; color: var(--grey); }
.set-row form { margin: 0; }
.settings .passkeys .past-toggle { min-width: 0; }

/* Devices lines up with the others: label at the left, its control starting in the
   same column as the swatches and the sound icon. The list it unfolds sits under that
   column rather than under the label. */
.set-row-block { display: flex; align-items: flex-start; }
/* The label lines up with the first line of whatever sits beside it, matching the
   row's own top padding rather than sitting above it. */
.set-row-block .set-label { padding-top: 10px; }
.set-row-block .passkeys { flex: 1; min-width: 0; margin: 0; }
.set-row-block .past-toggle { padding: 0; width: auto; text-align: left; }
.set-row-block #passkeyBody { padding-top: 0; }
.set-row-block #passkeyList { margin: 0; }


/* A person's page. */
.person-head { display: flex; align-items: center; gap: 16px; margin: 0 0 8px; }
.person-mark { flex: 0 0 auto; display: inline-flex; }
.person-mark svg { display: block; }
.person-who { flex: 1; min-width: 0; }
.person-name { font-size: 20px; font-weight: 300; margin: 0 0 2px; }



/* Coverage: the retention number, and the misses as a list to act on. */
.cov-h1 { font-size: 22px; font-weight: 300; margin: 0 0 4px; }
.cov { margin: 30px 0 0; padding-top: 18px; border-top: 1px solid var(--soft); }
.cov-top { display: flex; justify-content: space-between; align-items: baseline; font-size: 12px; color: var(--grey); }
.cov-src { color: var(--ink); }
.cov-num { display: flex; align-items: baseline; gap: 12px; margin: 8px 0 12px; }
.cov-num b { font-size: 34px; font-weight: 200; line-height: 1; letter-spacing: -.02em; }
.cov-num span { font-size: 12px; color: var(--grey); }
.cov-line { display: flex; align-items: flex-end; gap: 3px; height: 40px; margin: 0 0 14px; }
.cov-line i { display: block; flex: 1; max-width: 14px; background: var(--ink); opacity: .35; }
.cov-h2 { font-size: 10px; font-weight: 400; letter-spacing: .1em; text-transform: uppercase; color: var(--grey); margin: 14px 0 6px; display: flex; align-items: center; gap: 8px; }
.cov-list .row a { flex: 1; min-width: 0; }
.cov-note { flex: 0 0 auto; font-size: 10px; color: var(--grey); }
.cov-add { flex: 0 0 auto; margin: 0; }
.cov-foot { margin-top: 26px; color: var(--grey); line-height: 1.6; }

.subj-binned { margin: -18px 0 30px; color: var(--grey); }
.subj-binned a { color: var(--ink); }

/* Subjects as rows, like every other list here. The mark is the channel's colour; the
   line beneath says how much sits behind the subject. */
.subj-list { margin: 0 0 30px; }
/* Two lines, so the row is taller than the 48px every other chatlist link is fixed at —
   without this the meta line drew over the bottom of the name. */
.chatlist.subj-list li.chat > .row > a { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 3px; height: auto; min-height: 56px; padding: 9px 0; }
.chatlist.subj-list li.chat > .row { min-height: 56px; }
.subj-list .nm { display: flex; align-items: center; gap: 8px; }
.subj-mark svg { display: block; }
.subj-meta { font-size: 10px; letter-spacing: .03em; color: var(--grey); padding-left: 24px; }
.subj-list li.chat.on .nm { color: var(--ink); }
.subj-list .subj-bin { opacity: .35; }
.subj-binned { margin: -18px 0 30px; color: var(--grey); }
.subj-binned a { color: var(--ink); }

/* The browser's own decorations, brought into line. type=search grows a blue × in
   Chrome, and Android colours the cursor handle with the page accent, which was never
   set. Both now follow the site's ink. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
input, textarea { caret-color: var(--ink); accent-color: var(--grey); }
::selection { background: var(--soft); color: var(--ink); }
:root { accent-color: var(--grey); }

/* The report: most of the numbers fold behind "more"; the sources are buttons that
   narrow the list to one publication. */
.rep-more { margin: 24px 0 0; }
.rep-more .past-toggle { width: 100%; text-align: left; }
.rep-more #repMore { padding-top: 8px; }
.rep-more .rep-meta { margin-top: 0; }
.rep-h-note { font-size: 10px; letter-spacing: .04em; text-transform: none; color: var(--grey); font-weight: 300; }
.rep-chips.sources .rep-src-btn { font: inherit; font-size: 12px; padding: 4px 10px; border: 1px solid var(--line); background: none; color: var(--ink); cursor: pointer; display: inline-block; }
.rep-chips.sources .rep-src-btn b { font-weight: 400; color: var(--grey); margin-left: 6px; }
.rep-chips.sources .rep-src-btn.on { border-color: var(--ink); background: var(--soft); }
.rep-list .rep-row[hidden] { display: none; }

/* The book: what you've opened. */
.chatlist.opened-list li.chat > .row > a { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; height: auto; min-height: 58px; padding: 8px 0; }
.opened-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
/* Lighter than the deck's own text: what you've already read sits back. */
.opened-title { font-size: 14px; line-height: 20px; max-height: 40px; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow-wrap: anywhere; color: var(--grey); }
.chatlist.opened-list li.chat > .row > a:hover .opened-title { color: var(--ink); }
.opened-meta { font-size: 10px; letter-spacing: .03em; color: var(--grey); opacity: .6; }

/* The channel picker: a switch per row rather than the usual ×, since this is on/off
   for a channel that keeps existing, not a removal. */
.chan-list .row { align-items: center; }
.chan-count { margin-left: 8px; padding-left: 0; }
.chan-toggle { flex: 0 0 auto; width: 34px; height: 20px; border-radius: 10px; background: var(--soft); border: 1px solid var(--line); position: relative; cursor: pointer; padding: 0; }
.chan-toggle::after { content: ''; position: absolute; top: 1px; left: 1px; width: 16px; height: 16px; border-radius: 50%; background: var(--paper, #fff); transition: transform .15s ease; }
.chatlist.chan-list li.chat.on .chan-toggle { background: var(--ink); border-color: var(--ink); }
.chatlist.chan-list li.chat.on .chan-toggle::after { transform: translateX(14px); background: var(--bg); }
.chatlist.chan-list li.chat:not(.on) .nm { color: var(--grey); }
.chan-done { margin-top: 24px; }

/* The channel list: always visible, not folded — it's the primary lever over the
   deck, not a secondary discovery list like the two folds either side of it. */
.folder.channels { margin: 24px 0; }
.folder.channels .chatlist li.chat.off .nm { color: var(--grey); }
.folder.channels .chan-drop { font-size: 15px; }

/* The comments tab's badge, matching the deck's own. */
.tabs a { position: relative; }
.tab-badge { display: inline-block; min-width: 15px; height: 15px; padding: 0 3px; margin-left: 5px; border-radius: 8px; background: color-mix(in srgb, var(--grey) 55%, var(--bg) 45%); color: var(--bg); font-size: 10px; line-height: 15px; text-align: center; font-variant-numeric: tabular-nums; vertical-align: middle; }

/* The thread page: the card as context, the messages, the reply line. */
.thread-card { padding-bottom: 16px; margin-bottom: 20px; border-bottom: 1px solid var(--soft); }
.thread-title { font-size: 16px; font-weight: 400; margin: 0 0 6px; line-height: 1.4; }
.thread-list { margin-bottom: 20px; }
.thread-msg { padding: 12px 0; border-bottom: 1px solid var(--soft); }
.thread-msg.mine .thread-meta { color: var(--ink); }
.thread-meta { font-size: 11px; color: var(--grey); margin: 0 0 4px; }
.thread-body { font-size: 15px; line-height: 1.5; margin: 0; white-space: pre-wrap; word-break: break-word; }
.thread-reply .field { margin: 0; border-bottom: 1px solid var(--line); }
.thread-reply input { width: 100%; background: none; border: 0; padding: 8px 0; font: inherit; font-size: 15px; color: var(--ink); }
.thread-preview { display: block; margin-top: 3px; font-style: italic; }

.thread-report { position: absolute; top: 12px; right: 0; font-size: 11px; opacity: .4; }
.thread-msg { position: relative; }
.thread-report:hover { opacity: 1; }

.report-row { padding: 14px 0; border-bottom: 1px solid var(--soft); }
.report-row.resolved { opacity: .5; }

/* The page foot: small print on the left, Log out held to the right of the same line. */
.foot-line { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-top: 48px; }
.foot-line .settings-terms { margin: 0; }
.foot-line form { margin: 0; flex: 0 0 auto; }

/* And the people tab goes bold while someone new is waiting there. */
/* Something waiting: the tab is underlined, in ink — the same mark the current tab
   carries, so it reads as "there is something here" without shouting. */
.tabs a.has-new { color: var(--ink); text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }

/* The four sections, and the talk links held apart at the row's end. */
.tab-gap { flex: 1; }
.tabs a.tab-talk { opacity: .55; }
.tabs a.tab-talk.on { opacity: 1; }
.section-list .sec-note { margin: 2px 0 0; font-size: 12px; color: var(--grey); line-height: 1.45; }
.section-list li { padding-bottom: 8px; }
/* The directory: favicon, name and a line beneath, follow at the right. Its own
   structure, not the chat list's — that one's flex rules swallowed the name. */
.dir-row { display: flex; align-items: center; gap: 18px; padding: 10px 0; border-bottom: 1px solid var(--soft); }
.dir-ico { width: 16px; height: 16px; border-radius: 2px; flex: 0 0 auto; object-fit: contain; }
.dir-ico-none { display: inline-block; background: var(--soft); }
.dir-txt { flex: 1; min-width: 0; }
.dir-name { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dir-meta { font-size: 11px; color: var(--grey); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dir-act { flex: 0 0 auto; background: none; border: 1px solid var(--line); border-radius: 12px; padding: 3px 10px; font: inherit; font-size: 12px; color: var(--grey); cursor: pointer; }
.dir-act:hover { color: var(--ink); border-color: var(--ink); }
.dir-act:disabled { color: var(--grey); border-color: transparent; cursor: default; }

/* Graph tab numbers — the same grid the stats page uses. */
.stats-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 18px; margin: 0 0 24px; }
/* Nearer the rows on the other tabs: a number, not a headline. */
.stat b { display: block; font-size: 17px; font-weight: 300; line-height: 1.2; font-variant-numeric: tabular-nums; }
.stat span { display: block; font-size: 12px; margin-top: 5px; color: var(--grey); }
@media (min-width: 560px) { .stats-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Filters: each block opens with the same + row the feed tab uses to add a feed, so
   the two tabs read as one design. */
.mute-block .create-open { height: 44px; }
.mute-block .create-open.open .plus { transform: rotate(45deg); display: inline-block; }
.mute-form { margin: 4px 0 8px; }
.mute-none { margin: 4px 0 0; }
.mute-block .chatlist li { padding: 0; }
.mute-block .chatlist li .linkbtn { height: 44px; font-size: 15px; }

/* Feed rows and source rows share one measure: a 20px favicon with 4px corners, 12px
   gap, 15px name, the same vertical padding. Two lists that look like one product. */
/* The link inside a row already draws the divider; the row itself must not, or every
   feed gets two lines. */
.chatlist li.chat > .row a { height: auto; padding: 10px 0; }
.chatlist li.chat .nm { font-size: 15px; }
.chatlist li.chat .tag { font-size: 11px; }

/* Filters and graph read at the same size and rhythm as feed and sources: rows at
   15px, headings small and lettered, notes at 12px grey with the same spacing. */
.mute-block .chatlist li .linkbtn { height: auto; padding: 14px 0; font-size: 15px; font-weight: 300; color: var(--ink); }
/* The + row and the forms start at the same left edge as the rows — no indent. */
.mute-block .create-open, .mute-block .mute-form, .mute-block .row { padding-left: 0; }
.mute-block .rep-h { margin: 0 0 10px; }
/* Each filter is a block with a line under it, as the rows in feed and sources have —
   so the three read as a list rather than three loose groups. */
.mute-block { padding: 22px 0; border-bottom: 1px solid var(--soft); margin: 0; }
.mute-block:last-of-type { border-bottom: 0; }
/* Inside a block the list sits closer, and its last row drops its own line so it does
   not double with the block's. */
.mute-block .chatlist { margin-bottom: 0; }
.mute-block .chatlist li:last-child .linkbtn { border-bottom: 0; padding-bottom: 0; }
.mute-none, .directory .small, .mute-block .small { font-size: 12px; line-height: 1.5; color: var(--grey); }
.mute-form { margin: 10px 0 6px; }
.mute-form input, .mute-form select { font-size: 15px; }
/* Graph: the numbers and the line beneath them sit on the same rhythm. */
.stats-grid { margin: 22px 0 18px; gap: 18px 18px; }
.stat span { font-size: 12px; margin-top: 2px; }

/* The mark that crosses between the two halves: a speech bubble on xyp, the root mark
   on chat. Same weight as its neighbours in the header. */
.head-actions .talk-link svg { display: block; }

/* A source opened out: what it is delivering right now, indented under its row. */
.dir-wrap { border-bottom: 1px solid var(--soft); }
.dir-wrap .dir-row { border-bottom: 0; }
.dir-peek { padding: 0 0 12px 34px; }
.dir-item { display: block; font-size: 13px; line-height: 1.45; color: var(--grey); text-decoration: none; padding: 5px 0; }
.dir-item:hover { color: var(--ink); }

/* A people row: the line belongs to the row, not to the link inside it, so it runs the
   whole width — and the × is held at the far right by margin-left:auto, the way the
   chat rows hold their own trailing controls. */
.chatlist li.person { border-bottom: 1px solid var(--soft); }
.chatlist li.person .row { display: flex; align-items: center; gap: 10px; margin: 0; }
.chatlist li.person .row > a { flex: 1 1 auto; min-width: 0; border-bottom: 0; }
.chatlist li.person .row > form { margin: 0 0 0 auto; flex: 0 0 auto; }
.person-x { background: none; border: 0; font-size: 18px; line-height: 1; color: var(--grey); opacity: .5; cursor: pointer; padding: 4px 6px; }
.person-x:hover { opacity: 1; color: var(--ink); }
