/* ===========================================================================
   Tayfa — chat app layer
   The four-column shell: server rail · channel sidebar · message column ·
   member list. Values come from tokens.css; the only literals here are
   sub-pixel detail (hairlines, 2px row gaps, status-dot geometry), which is
   the same convention components.css already follows.

   Nothing in this file reads the theme. The surfaces are named tokens
   (--rail-bg, --channels-bg, --chat-bg, --input-bg) so the dark → light step
   across the four columns survives all three themes.
   =========================================================================== */

html, body { height: 100%; }
body { overflow: hidden; }

/* The hidden attribute is only display:none in the UA stylesheet, so any
   author display rule outranks it — and popovers, the emoji picker and the
   reply strip all set their own display. Without this they all render open
   on page load. */
[hidden] { display: none !important; }

/* ===========================================================================
   SHELL
   One viewport-tall flex row. Every column scrolls inside itself — the page
   itself never scrolls, so the composer and the user bar stay put while a
   thousand messages move behind them.
   =========================================================================== */
.shell {
  /* Konumlandırılmış ebeveyn: dar ekranda arama paneli üstüne bindiğinde
     sayfaya göre değil kabuğa göre yerleşmesi gerekiyor. */
  position: relative;
  display: flex;
  height: 100vh;
  height: 100dvh;   /* mobile: discount the browser chrome, not the layout */
  overflow: hidden;
  background: var(--chat-bg);
}

/* Scroll containers that should not advertise themselves. The rail and the
   sidebar are chrome; a visible track inside 72px of chrome is noise. */
.hidescroll { scrollbar-width: none; }
.hidescroll::-webkit-scrollbar { width: 0; height: 0; }

/* The rail and the channel list are one unit: on desktop they are two
   columns of the row, and below 760px the same pair slides in as a drawer.
   Grouping them here means the mobile layout is a transform on one element
   rather than a different markup tree. */
.drawer { display: flex; flex: none; min-height: 0; }
.drawer__scrim { display: none; }

/* ===========================================================================
   SERVER RAIL
   =========================================================================== */
.rail {
  width: var(--rail-w);
  flex: none;
  background: var(--rail-bg);
  padding: var(--space-3) 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

/* The item is the hit area, the pill lives outside it. Both are on one
   element so a server never shows a pill without the icon under it. */
.guild {
  position: relative;
  width: var(--guild-size);
  height: var(--guild-size);
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--bg-elevated);
  color: var(--fg-muted);
  font-size: var(--fs-body);
  font-weight: 600;
  overflow: visible;
  /* The circle → squircle morph is the whole gesture of the rail, so radius
     is transitioned explicitly. transition-all would also animate the
     pill's height from the parent and double the motion. */
  transition:
    border-radius var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-micro) var(--ease-out);
}
.guild__art {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  border-radius: inherit;
  overflow: hidden;
  background: var(--guild-tint, var(--bg-elevated));
  color: var(--fg);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: -.02em;
}
.guild__art img { width: 100%; height: 100%; object-fit: cover; }

.guild:hover,
.guild[aria-current="page"] { border-radius: var(--guild-radius); color: var(--fg); }
.guild:hover .guild__art,
.guild[aria-current="page"] .guild__art { border-radius: var(--guild-radius); }
.guild:active { transform: translateY(1px); }

/* Unread and mention state. The pill is the only unread signal on the rail,
   so it has to be legible at 4px: it grows rather than changing colour. */
.guild::before {
  content: "";
  position: absolute;
  /* Sits flush against the rail's left edge. Derived from the rail and icon
     widths rather than a literal, because the rail centres its items: a fixed
     offset puts the pill outside the rail, where it is clipped away. */
  left: calc((var(--rail-w) - var(--guild-size)) / -2);
  top: 50%;
  width: 4px;
  height: 0;
  background: var(--fg);
  border-radius: 0 4px 4px 0;
  transform: translateY(-50%);
  transition: height var(--dur-fast) var(--ease-out);
}
.guild--unread::before { height: 8px; }
.guild:hover::before { height: 20px; }
.guild[aria-current="page"]::before { height: 40px; }

.guild__count {
  position: absolute;
  right: -2px; bottom: -2px;
  min-width: 20px; height: 20px;
  display: grid; place-items: center;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--live);
  color: #fff;   /* on --live, which is a red dark enough for white at 4.9:1 */
  box-shadow: 0 0 0 3px var(--rail-bg);
  font-size: var(--fs-micro);
  line-height: 1;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Action tiles: home, add a server, discover. Dashed outline for "add" is the
   one affordance that reads as "there is nothing here yet, put something". */
.guild--action { background: var(--bg-elevated); color: var(--success); }
.guild--action:hover { background: var(--success); color: var(--bg-base); }
.guild--home { background: var(--accent-soft); color: var(--accent); }
.guild--home:hover,
.guild--home[aria-current="page"] { background: var(--accent); color: var(--accent-fg); }
.guild--home svg { width: 28px; height: 28px; }
.guild--action svg { width: var(--icon-md); height: var(--icon-md); }

.rail__sep { width: 32px; height: 2px; background: var(--border); border-radius: 1px; flex: none; }

/* Rail tooltip. The rail has no labels — the tooltip is the only place a
   server's name appears, so it is part of the component, not a nicety. */
.guild__tip {
  position: absolute;
  left: calc(100% + var(--space-3));
  top: 50%;
  transform: translateY(-50%) scale(.94);
  transform-origin: left center;
  z-index: var(--z-tooltip);
  opacity: 0;
  pointer-events: none;
  font-weight: 600;
  transition: opacity var(--dur-micro) var(--ease-out), transform var(--dur-micro) var(--ease-out);
}
.guild__tip::before {
  content: "";
  position: absolute;
  left: -4px; top: 50%;
  width: 8px; height: 8px;
  background: var(--bg-elevated);
  border-left: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  transform: translateY(-50%) rotate(45deg);
}
.guild:hover .guild__tip,
.guild:focus-visible .guild__tip { opacity: 1; transform: translateY(-50%) scale(1); }

/* ===========================================================================
   CHANNEL SIDEBAR
   =========================================================================== */
.chans {
  width: var(--channels-w);
  flex: none;
  min-width: 0;
  background: var(--channels-bg);
  display: flex;
  flex-direction: column;
  --sdot-ring: var(--channels-bg);
}

/* Boosted servers get a banner above the header. Fixed ratio so the channel
   list does not shift as it loads, and absent entirely when unset — an empty
   strip reads as a failure, no strip reads as a choice. */
.chans__banner {
  aspect-ratio: 16 / 6;
  overflow: hidden;
  flex: none;
  /* Yüklenmiş bir afiş aşağıdaki yedek deseni kaplıyor. cover ve merkez:
     hangi oranda yüklenirse yüklensin şeridi dolduruyor ve ortasından
     kırpılıyor. */
  background-size: cover;
  background-position: center;
  /* Stand-in art. A flat panel where a banner goes reads as a broken image;
     this reads as a banner nobody has uploaded yet. A real <img> inside
     simply covers it. */
  background:
    radial-gradient(70% 90% at 26% 20%, color-mix(in oklab, var(--accent) 16%, transparent) 0%, transparent 62%),
    radial-gradient(60% 80% at 86% 84%, color-mix(in oklab, var(--role-boost) 14%, transparent) 0%, transparent 60%),
    linear-gradient(150deg, var(--bg-elevated), var(--bg-base));
}
.chans__banner img { width: 100%; height: 100%; object-fit: cover; }

.chans__head {
  height: var(--chead-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--fg);
  /* A shadow, not a border: it has to sit over the scrolling list below so
     the first category heading slides under it. */
  box-shadow: 0 1px 0 var(--border), 0 1px 4px var(--bg-scrim);
  position: relative;
  z-index: 1;
  transition: background-color var(--dur-fast) var(--ease-out);
}
.chans__head:hover { background: var(--row-hover); }
.chans__head .chans__name { flex: 1; min-width: 0; }
.chans__head svg { width: 14px; height: 14px; color: var(--fg-muted); flex: none; transform: rotate(90deg); }
.chans__head[aria-expanded="true"] svg { transform: rotate(-90deg); }

.chans__list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 var(--space-2) var(--space-5);
}

/* ---- category ----------------------------------------------------------- */
.cat { display: flex; flex-direction: column; }
.cat__head {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 24px;
  margin-top: var(--space-4);
  padding-right: var(--space-1);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  transition: color var(--dur-fast) var(--ease-out);
}
.cat__head:hover { color: var(--fg); }
.cat__head > svg {
  width: 12px; height: 12px; flex: none;
  transform: rotate(90deg);
  transition: transform var(--dur-fast) var(--ease-out);
}
.cat__head[aria-expanded="false"] > svg { transform: rotate(0deg); }
.cat__name { flex: 1; min-width: 0; }
.cat__add {
  width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  color: var(--fg-subtle);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.cat:hover .cat__add { opacity: 1; }
.cat__add:hover { color: var(--fg); background: var(--row-hover); }
.cat__add:focus-visible { opacity: 1; }
.cat__add svg { width: 12px; height: 12px; }

/* A collapsed category still shows its unread and active channels — that is
   the point of collapsing it, not hiding what matters. */
.cat__body { display: flex; flex-direction: column; }
.cat__head[aria-expanded="false"] + .cat__body > .chan:not(.chan--unread):not([aria-current="page"]) { display: none; }

/* ---- channel row -------------------------------------------------------- */
.chan {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--chan-h);
  flex: none;
  padding: 0 var(--space-2);
  margin-top: 2px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-msg);
  font-weight: 500;
  color: var(--fg-muted);
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.chan:hover { background: var(--row-hover); color: var(--fg); }
.chan[aria-current="page"] { background: var(--row-active); color: var(--fg); }
.chan__icon { width: var(--icon-md); height: var(--icon-md); flex: none; color: var(--fg-subtle); }
.chan:hover .chan__icon,
.chan[aria-current="page"] .chan__icon { color: var(--fg-muted); }
.chan__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Unread: the name goes solid and a pill appears in the gutter. Both, not
   one — bold alone is invisible when scanning thirty rows. */
.chan--unread { color: var(--fg); font-weight: 600; }
.chan--unread::before {
  content: "";
  position: absolute;
  left: calc(var(--space-2) * -1);
  top: 50%;
  width: 4px; height: 8px;
  background: var(--fg);
  border-radius: 0 4px 4px 0;
  transform: translateY(-50%);
}
.chan__count {
  min-width: 16px; height: 16px;
  display: grid; place-items: center;
  padding: 0 var(--space-1);
  border-radius: var(--radius-full);
  background: var(--live);
  color: #fff;
  font-size: var(--fs-micro);
  line-height: 1;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  flex: none;
}
/* Row actions appear on hover and take the name's space rather than
   overlaying it, so a long channel name never ends up under a button. */
.chan__act {
  width: 16px; height: 16px;
  display: none;
  place-items: center;
  color: var(--fg-muted);
  flex: none;
}
.chan:hover .chan__act { display: grid; }
.chan__act:hover { color: var(--fg); }
.chan__act:focus-visible { display: grid; }
.chan__act svg { width: 14px; height: 14px; }
.chan__lock { width: 10px; height: 10px; color: var(--fg-subtle); flex: none; }

/* Reordering by drag: a line where the channel will land, and the row being
   carried dimmed. A line, not a gap — moving the rows while the pointer is
   over them would move the target out from under it. */
.chan.is-dragging { opacity: .4; }
.chan--dropbefore { box-shadow: inset 0 2px 0 var(--accent); }
.cat__head--drop { color: var(--fg); box-shadow: inset 0 -2px 0 var(--accent); }

/* ---- members inside a voice channel ------------------------------------- */
.vclist { display: flex; flex-direction: column; padding-left: var(--space-5); }
.vcuser {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 28px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--fg-muted);
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.vcuser:hover { background: var(--row-hover); color: var(--fg); }
.vcuser .avatar { width: var(--avatar-xs); height: var(--avatar-xs); }
.vcuser__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vcuser__flag { width: 14px; height: 14px; flex: none; color: var(--danger); }
.vcuser__flag--live { color: var(--accent); }
/* Speaking is a ring on the avatar, matching the voice tiles: one visual
   language for "this person is talking" in both places. */
.vcuser--speaking .avatar { box-shadow: 0 0 0 2px var(--status-online); }

/* ---- connected-voice panel, docked over the user bar -------------------- */
.vconn {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2);
  background: var(--userbar-bg);
  border-top: 1px solid var(--border);
}
.vconn__top { display: flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-1); }
.vconn__sig { width: var(--icon-sm); height: var(--icon-sm); color: var(--success); flex: none; }
.vconn__text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.vconn__name { font-size: var(--fs-small); font-weight: 700; color: var(--success); }
.vconn__where { font-size: var(--fs-caption); color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vconn__acts { display: flex; gap: var(--space-1); }
.vconn__acts .btn { flex: 1; }

/* ---- user bar ----------------------------------------------------------- */
.userbar {
  height: var(--userbar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
  background: var(--userbar-bg);
  --sdot-ring: var(--userbar-bg);
}
.userbar__me {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1;
  min-width: 0;
  padding: var(--space-1);
  border-radius: var(--radius-md);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.userbar__me:hover { background: var(--row-hover); }
.userbar__text { display: flex; flex-direction: column; min-width: 0; }
/* The name and status line are the button that opens the status choice. */
.userbar__status {
  flex: 1; align-items: flex-start; text-align: left;
  padding: 0; border: 0; background: none; color: inherit; font: inherit; cursor: pointer;
  border-radius: var(--radius-sm);
}
.userbar__status:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The 2FA key, grouped in fours so it can be typed without losing place,
   and the recovery codes in two columns. Monospace, selectable as a unit. */
.secretkey {
  display: block;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  letter-spacing: .08em;
  user-select: all;
  word-break: break-all;
}
.recovery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2) var(--space-5);
  margin: 0;
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-6);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  user-select: all;
}

/* A role's colour: a dot in lists, a pickable swatch in the editor. The
   colour is the role's own data, so it arrives as a custom property. */
.rolechip { width: 12px; height: 12px; border-radius: var(--radius-full); background: var(--chip); flex: none; }
.swatch {
  width: 28px; height: 28px; border-radius: var(--radius-full); background: var(--chip);
  cursor: pointer; box-shadow: inset 0 0 0 2px var(--border);
  transition: transform var(--dur-micro) var(--ease-out), box-shadow var(--dur-micro) var(--ease-out);
}
.swatch:hover { transform: scale(1.08); }
.swatch:has(input:checked) { box-shadow: 0 0 0 2px var(--bg-elevated), 0 0 0 4px var(--fg); }
.swatch:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
/* Member rows became buttons (they open the member's card); they keep the
   row's look rather than a button's. */
button.member { width: 100%; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
button.member:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* One row per status in the picker; the chosen one is marked. */
.statuspick {
  width: 100%; border: 0; background: none; color: inherit; font: inherit; text-align: left;
  cursor: pointer; border-radius: var(--radius-md); padding-inline: var(--space-2);
  transition: background-color var(--dur-fast) var(--ease-out);
  --sdot-ring: var(--bg-elevated);
}
.statuspick:hover { background: var(--row-hover); }
.statuspick:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.statuspick[aria-checked="true"] { background: var(--row-active); }
.statuspick__dot { width: 20px; height: 20px; }
.statuspick__dot .sdot { position: static; }
.userbar__name { font-size: var(--fs-small); font-weight: 600; color: var(--fg); }
/* The second line swaps from the handle to the status on hover, the way the
   client does it. Both are the same height so the row never shifts. */
.userbar__sub { font-size: var(--fs-caption); color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userbar__me .userbar__sub--hover { display: none; }
.userbar__me:hover .userbar__sub--idle { display: none; }
.userbar__me:hover .userbar__sub--hover { display: block; }

.iconbtn {
  width: 32px; height: 32px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  color: var(--fg-muted);
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.iconbtn:hover { background: var(--row-hover); color: var(--fg); }
.iconbtn:active { transform: scale(.94); }
.iconbtn:disabled { opacity: .45; cursor: not-allowed; }
.iconbtn svg { width: var(--icon-md); height: var(--icon-md); }
.iconbtn--sm { width: var(--control-h-sm); height: var(--control-h-sm); }
.iconbtn--sm svg { width: var(--icon-sm); height: var(--icon-sm); }
/* Self-muted is a state on the control, and it has to be readable without
   comparing it to its neighbour — hence colour plus the struck-through icon. */
.iconbtn--off { color: var(--danger); }
.iconbtn--off:hover { background: var(--danger-soft); color: var(--danger); }
.iconbtn--on { color: var(--accent); }

/* ===========================================================================
   STATUS DOT
   Shape, not just colour: at 8px a red circle and a green circle are the same
   mark to anyone who cannot separate the hues. Online is a disc, idle a
   crescent, dnd a barred disc, offline a ring.
   The ring around it is painted in the surface it sits on, which each context
   sets through --sdot-ring.
   =========================================================================== */
.withdot { position: relative; display: inline-flex; flex: none; }
.sdot {
  position: absolute;
  right: -2px; bottom: -2px;
  width: 14px; height: 14px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--sdot-ring, var(--channels-bg));
}
.sdot::before, .sdot::after { content: ""; grid-area: 1 / 1; border-radius: var(--radius-full); }
.sdot::before { width: 8px; height: 8px; background: var(--status-offline); }
.sdot::after { width: 0; height: 0; }

.sdot--online::before { background: var(--status-online); }

.sdot--idle::before { background: var(--status-idle); }
.sdot--idle::after {
  width: 7px; height: 7px;
  background: var(--sdot-ring, var(--channels-bg));
  transform: translate(-2.5px, -2.5px);
}

.sdot--dnd::before { background: var(--status-dnd); }
.sdot--dnd::after {
  width: 6px; height: 2px;
  border-radius: 1px;
  background: var(--sdot-ring, var(--channels-bg));
}

.sdot--offline::before { background: transparent; box-shadow: inset 0 0 0 2px var(--status-offline); }

.sdot--sm { width: 11px; height: 11px; right: -1px; bottom: -1px; }
.sdot--sm::before { width: 7px; height: 7px; }
.sdot--lg { width: 20px; height: 20px; right: 0; bottom: 0; }
.sdot--lg::before { width: 12px; height: 12px; }
.sdot--lg.sdot--idle::after { width: 10px; height: 10px; transform: translate(-3.5px, -3.5px); }
.sdot--lg.sdot--dnd::after { width: 9px; height: 3px; border-radius: 2px; }

/* ===========================================================================
   MESSAGE COLUMN
   =========================================================================== */
.chatcol {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--chat-bg);
  --sdot-ring: var(--chat-bg);
}

.chead {
  height: var(--chead-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) 0 var(--space-4);
  box-shadow: 0 1px 0 var(--border);
  position: relative;
  z-index: 1;
}
.chead__icon { width: var(--icon-lg); height: var(--icon-lg); color: var(--fg-subtle); flex: none; }
.chead__name { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -.01em; color: var(--fg); flex: none; }
.chead__sep { width: 1px; height: 24px; background: var(--border); flex: none; margin: 0 var(--space-2); }
/* The topic takes the slack and truncates. It is the only thing on this row
   allowed to shrink — every icon to its right is a target. */
.chead__topic {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-small);
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chead__acts { display: flex; align-items: center; gap: var(--space-1); flex: none; }
.chead__search { width: 144px; flex: none; }
.chead__search .input { height: var(--control-h-sm); font-size: var(--fs-caption); background: var(--rail-bg); border-color: transparent; }
.chead__search .search__icon { left: var(--space-2); }
.chead__search .input { padding-left: var(--space-8); }

/* ---- message scroller --------------------------------------------------- */
.msgs {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  padding-bottom: var(--space-5);
}
/* Load-bearing. Flex items shrink by default, and the pad below grows to push
   the conversation to the bottom — so in this column container every message
   gets squeezed under its own content height and the lines overlap. Nothing
   in the list may shrink. */
.msgs > * { flex: none; }

/* Pushes a short conversation to the bottom of the viewport, where chat is
   read from. Without it a channel with four messages renders them at the top
   with a void underneath. Declared after the rule above so it keeps its grow. */
.msgs__pad { flex: 1 0 auto; min-height: var(--space-4); }

/* ---- channel intro ------------------------------------------------------ */
.intro {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-4) var(--space-4);
}
.intro__icon {
  width: 68px; height: 68px;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--bg-overlay);
  color: var(--fg);
  margin-bottom: var(--space-2);
}
.intro__icon svg { width: 42px; height: 42px; }
.intro__title { font-size: var(--fs-display); line-height: var(--lh-display); font-weight: 800; letter-spacing: -.02em; }
.intro__text { font-size: var(--fs-msg); line-height: var(--lh-msg); color: var(--fg-muted); max-width: 60ch; }
.intro__acts { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-3); }

/* ---- dividers ----------------------------------------------------------- */
.daydiv {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-6) var(--space-4) var(--space-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--fg-subtle);
}
.daydiv::before, .daydiv::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* The unread marker. Red line plus a label, pinned to where reading stopped. */
.newdiv {
  position: relative;
  margin: var(--space-4) var(--space-4) var(--space-2);
  border-top: 1px solid var(--live);
}
.newdiv__tag {
  position: absolute;
  right: 0; top: 0;
  transform: translateY(-50%);
  padding: 1px var(--space-1);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--live);
  color: #fff;
  font-size: var(--fs-micro);
  line-height: var(--lh-micro);
  font-weight: 700;
  letter-spacing: .06em;
}

/* ===========================================================================
   MESSAGE
   The left gutter is 72px: 16 padding + 40 avatar + 16 gap. A follow-up
   message from the same person keeps that gutter and drops the avatar, which
   is what makes a run of messages read as one turn in a conversation.
   =========================================================================== */
.m {
  position: relative;
  padding: 2px var(--space-12) 2px 72px;
  min-height: 22px;
}
.m:hover { background: var(--msg-hover); }
.m--first { margin-top: var(--space-4); }

.m__av { position: absolute; left: var(--space-4); top: 2px; }
.m__head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.m__name {
  font-size: var(--fs-msg);
  line-height: var(--lh-msg);
  font-weight: 600;
  color: var(--role-color, var(--fg));
}
.m__name:hover { text-decoration: underline; }
.m__time { font-size: var(--fs-caption); font-weight: 500; color: var(--fg-subtle); }
.m__text {
  font-size: var(--fs-msg);
  line-height: var(--lh-msg);
  color: var(--fg);
  overflow-wrap: break-word;
  white-space: pre-wrap;
}
.m__edited { font-size: 10px; color: var(--fg-subtle); margin-left: var(--space-1); }

/* Continuation rows show their timestamp in the avatar gutter, on hover only.
   It is absolutely positioned so revealing it cannot reflow the message. */
.m--cont .m__time--gutter {
  position: absolute;
  left: var(--space-4);
  top: 3px;
  width: var(--space-10);
  text-align: right;
  font-size: 10px;
  opacity: 0;
  transition: opacity var(--dur-micro) var(--ease-out);
}
.m--cont:hover .m__time--gutter { opacity: 1; }

.m--mention { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
.m--mention:hover { background: color-mix(in oklab, var(--accent) 18%, var(--chat-bg)); }
.m--sending { opacity: .55; }
.m--failed { background: var(--danger-soft); box-shadow: inset 2px 0 0 var(--danger); }
.m__failnote { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-caption); color: var(--danger); }
.m__failnote button { font-weight: 600; text-decoration: underline; color: var(--danger); }

/* ---- reply reference ---------------------------------------------------- */
/* The spine is drawn with two borders on a pseudo-element rather than an SVG:
   it has to start at the avatar's centre and elbow into the quoted row, and
   those are both layout positions, not a fixed shape. */
.m__ref {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: 2px;
  font-size: var(--fs-small);
  color: var(--fg-muted);
  overflow: hidden;
  white-space: nowrap;
}
.m__ref::before {
  content: "";
  position: absolute;
  left: 36px;
  top: 12px;
  width: 28px;
  height: 10px;
  border-left: 2px solid var(--border-strong);
  border-top: 2px solid var(--border-strong);
  border-top-left-radius: var(--space-2);
}
.m__ref .avatar { width: var(--avatar-xs); height: var(--avatar-xs); }
.m__ref-name { font-weight: 600; color: var(--role-color, var(--fg)); }
.m__ref-text { overflow: hidden; text-overflow: ellipsis; color: var(--fg-muted); }
.m__ref:hover .m__ref-text { color: var(--fg); }
.m__ref-icon { width: 14px; height: 14px; color: var(--fg-subtle); flex: none; }

/* ---- hover toolbar ------------------------------------------------------ */
/* Pulled up over the row above so it does not cover the message it acts on.
   Hidden from the accessibility tree is wrong here — these are the only way
   to reply or react, so they stay focusable and appear on focus. */
/* Fareyle üzerine gelince beliriyor ama klavye için **her zaman** orada.
   display:none bir öğeyi odaklanamaz yapıyor, yani araç çubuğuna yalnız
   fareyle ulaşılabiliyordu — mesaja tepki vermenin, yanıtlamanın ve
   silmenin klavyeden hiçbir yolu yoktu. Görünürlük opaklıkla, tıklanabilirlik
   pointer-events ile; ikisi de odağı engellemiyor, ve odak gelince
   :focus-within onu görünür yapıyor. */
.m__tools {
  position: absolute;
  right: var(--space-4);
  top: -16px;
  z-index: 2;
  display: flex;
  opacity: 0;
  pointer-events: none;
  align-items: center;
  gap: 2px;
  padding: 2px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}
.m:hover .m__tools,
.m:focus-within .m__tools,
.m__tools:focus-within { opacity: 1; pointer-events: auto; }
.m__tools .iconbtn { width: var(--control-h-sm); height: var(--control-h-sm); }
.m__tools .iconbtn svg { width: var(--icon-sm); height: var(--icon-sm); }

/* ---- inline markdown --------------------------------------------------- */
.mention {
  padding: 0 2px;
  border-radius: 3px;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
a.mention:hover { background: var(--accent); color: var(--accent-fg); }
.mention--chan { background: var(--bg-overlay); color: var(--info); }
a.mention--chan:hover { background: var(--info); color: var(--bg-base); }

.m__text a { color: var(--info); }
.m__text a:hover { color: var(--info); text-decoration: underline; }
.m__text strong { font-weight: 700; }
.m__text code {
  padding: 1px 3px;
  border-radius: var(--radius-sm);
  background: var(--rail-bg);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 13px;
}
.m__text pre {
  margin: var(--space-2) 0;
  padding: var(--space-2) var(--space-3);
  max-width: 560px;
  overflow-x: auto;
  background: var(--rail-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.4;
  white-space: pre;
}
.m__text pre code { padding: 0; background: none; border: 0; font-size: inherit; }
.m__text blockquote {
  margin: var(--space-1) 0;
  padding-left: var(--space-3);
  border-left: 4px solid var(--border-strong);
  color: var(--fg-muted);
}
.spoiler {
  border-radius: 3px;
  background: var(--border-strong);
  color: transparent;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.spoiler.is-open { background: var(--bg-overlay); color: var(--fg); cursor: auto; }

/* Emoji sized to the line box. A standalone emoji message goes large, which
   is the one piece of message markdown that changes layout. */
.emo { font-size: 20px; line-height: 1; vertical-align: -3px; }
.m__text--jumbo { font-size: 44px; line-height: 1.2; }

/* ---- reactions ---------------------------------------------------------- */
.reacts { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-1); }
.react {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  flex: none;          /* same reason as .msgs > *: a wrapped row must not squash */
  height: 24px;
  padding: 0 var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
  background: var(--bg-overlay);
  color: var(--fg-muted);
  font-size: var(--fs-caption);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: background-color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.react:hover { border-color: var(--border-strong); color: var(--fg); }
.react[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.react__add { color: var(--fg-subtle); opacity: 0; }
.m:hover .react__add { opacity: 1; }
.react__add:focus-visible { opacity: 1; }
.react__add svg { width: var(--icon-sm); height: var(--icon-sm); }

/* ---- emoji picker ------------------------------------------------------- */
/* Fixed, and appended to <body> rather than to the message. The message list
   scrolls; a popover positioned inside it would scroll away from the button
   it belongs to, and `overflow` on the list would clip it. */
.epick {
  position: fixed;
  z-index: var(--z-dropdown);
  width: 340px;
  max-width: calc(100vw - var(--space-4));
  max-height: 380px;
  display: flex;
  flex-direction: column;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: epick-in var(--dur-fast) var(--ease-out);
}
@keyframes epick-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.epick__head {
  flex: none;
  padding: var(--space-2);
  border-bottom: 1px solid var(--border);
}
.epick__body { overflow-y: auto; padding: var(--space-2); }
.epick__sect + .epick__sect { margin-top: var(--space-3); }
.epick__label { padding: 0 var(--space-1) var(--space-1); }

/* A wrapping row rather than a fixed grid: the cells are a fixed size and
   the popover width is not, so letting them wrap keeps the last row honest
   at every width instead of leaving a column-shaped gap. */
.epick__grid { display: flex; flex-wrap: wrap; gap: 2px; }

.epick__cell {
  width: 36px;
  height: 36px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease-out), transform var(--dur-micro) var(--ease-out);
}
.epick__cell:hover { background: var(--row-hover); }
.epick__cell:active { transform: scale(.92); }
.epick__cell:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  background: var(--row-hover);
}

.epick__empty { padding: var(--space-6) var(--space-4); text-align: center; }
.epick__empty-icon { display: inline-flex; color: var(--fg-subtle); margin-bottom: var(--space-2); }

/* The add button has to be reachable by keyboard, not only by hover: it is
   the only way to put the first reaction on a message. */
.react:focus-visible,
.react__add:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; opacity: 1; }
.react:active { transform: scale(.96); }
.react:disabled { opacity: .5; cursor: not-allowed; }
.react { cursor: pointer; }
.react .emo { font-size: 13px; line-height: 1; }

@media (prefers-reduced-motion: reduce) {
  .epick { animation: none; }
  .epick__cell:active, .react:active { transform: none; }
}

/* ---- attachments -------------------------------------------------------- */
.att { margin-top: var(--space-2); max-width: 400px; }
.att img { border-radius: var(--radius-lg); border: 1px solid var(--border); }
.att__ph {
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background:
    radial-gradient(80% 90% at 26% 20%, color-mix(in oklab, var(--accent) 10%, transparent) 0%, transparent 60%),
    linear-gradient(150deg, var(--bg-elevated), var(--bg-base));
}
.filecard {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
  max-width: 440px;
  padding: var(--space-3);
  background: var(--bg-overlay);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.filecard__icon { width: var(--icon-lg); height: var(--icon-lg); color: var(--fg-muted); flex: none; }
.filecard__text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.filecard__name { font-size: var(--fs-small); font-weight: 600; color: var(--info); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filecard__size { font-size: var(--fs-caption); color: var(--fg-subtle); }

/* ---- embed -------------------------------------------------------------- */
.embed {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-3);
  margin-top: var(--space-2);
  max-width: 440px;
  padding: var(--space-3) var(--space-4) var(--space-3) var(--space-3);
  border-left: 4px solid var(--embed-tint, var(--accent));
  border-radius: var(--radius-sm);
  background: var(--bg-overlay);
}
.embed__body { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.embed__author { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-caption); font-weight: 600; color: var(--fg); }
.embed__author .avatar { width: var(--avatar-xs); height: var(--avatar-xs); }
.embed__title { font-size: var(--fs-small); font-weight: 700; color: var(--info); }
.embed__desc { font-size: var(--fs-small); line-height: 1.45; color: var(--fg-muted); }
.embed__fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-top: var(--space-1); }
.embed__fname { font-size: var(--fs-caption); font-weight: 700; color: var(--fg); }
.embed__fval { font-size: var(--fs-caption); color: var(--fg-muted); }
/* A video link: the card goes one column and the thumbnail sits under the
   text at 16:9, the shape of what it opens. */
.embed--video { grid-template-columns: 1fr; }
.embed__media { display: block; margin-top: var(--space-2); border-radius: var(--radius-md); overflow: hidden; }
.embed__media img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.embed__thumb {
  width: 72px; height: 72px;
  flex: none;
  border-radius: var(--radius-md);
  background: linear-gradient(150deg, var(--bg-elevated), var(--bg-base));
  border: 1px solid var(--border);
}
.embed__foot { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-1); font-size: var(--fs-micro); letter-spacing: 0; font-weight: 500; color: var(--fg-subtle); }

/* ---- system message ----------------------------------------------------- */
.m--sys { color: var(--fg-muted); }
.m--sys .m__sysicon {
  position: absolute;
  left: var(--space-5);
  top: 4px;
  width: var(--icon-md); height: var(--icon-md);
  color: var(--success);
}
.m--sys .m__text { font-size: var(--fs-small); color: var(--fg-muted); }
.m--sys .m__text strong { color: var(--fg); font-weight: 600; }

/* ---- thread chip under a message --------------------------------------- */
.threadchip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  background: var(--bg-overlay);
  font-size: var(--fs-caption);
  color: var(--fg-muted);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.threadchip:hover { background: var(--bg-elevated); color: var(--fg); }
.threadchip strong { color: var(--info); font-weight: 600; }
.threadchip svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--fg-subtle); }

/* ===========================================================================
   TYPING + COMPOSER
   =========================================================================== */
.composer { flex: none; padding: 0 var(--space-4) var(--space-6); }

.typing {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 24px;
  padding: 0 var(--space-1);
  font-size: var(--fs-caption);
  color: var(--fg-muted);
}
.typing strong { color: var(--fg); font-weight: 600; }
.typing__dots { display: inline-flex; gap: 3px; }
.typing__dots i {
  width: 5px; height: 5px;
  border-radius: var(--radius-full);
  background: var(--fg-muted);
  animation: typing 1.3s var(--ease-out) infinite;
}
.typing__dots i:nth-child(2) { animation-delay: .18s; }
.typing__dots i:nth-child(3) { animation-delay: .36s; }
@keyframes typing {
  0%, 60%, 100% { transform: translateY(0); opacity: .45; }
  30%           { transform: translateY(-3px); opacity: 1; }
}

.composer__box {
  display: flex;
  align-items: flex-end;
  background: var(--input-bg);
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.composer__box:focus-within { border-color: var(--accent-ring); }
.composer__add {
  width: 44px; height: 44px;
  flex: none;
  display: grid; place-items: center;
  color: var(--fg-muted);
  transition: color var(--dur-fast) var(--ease-out);
}
.composer__add:hover { color: var(--fg); }
.composer__add svg { width: 22px; height: 22px; }
.composer__field {
  flex: 1;
  min-width: 0;
  /* 11px top and bottom lands a one-line field on 44px, the same height as
     the + button next to it, so an empty composer is a single clean bar. */
  padding: 11px 0;
  max-height: 144px;
  background: none;
  border: 0;
  resize: none;
  overflow-y: auto;
  color: var(--fg);
  font-size: var(--fs-msg);
  line-height: var(--lh-msg);
}
.composer__field::placeholder { color: var(--fg-subtle); }
.composer__field:focus { outline: none; }
.composer__tools { display: flex; align-items: center; height: 44px; padding-right: var(--space-2); flex: none; }
.composer__tools .iconbtn { width: 36px; height: 36px; }
.composer__tools .iconbtn svg { width: 22px; height: 22px; }

.composer__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) var(--space-1) 0;
  font-size: var(--fs-caption);
  color: var(--fg-subtle);
}
.composer__count { margin-left: auto; font-variant-numeric: tabular-nums; }
.composer__count--over { color: var(--danger); font-weight: 600; }

/* The reply/edit strip that sits on top of the composer. */
.composer__ctx {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-elevated);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  font-size: var(--fs-caption);
  color: var(--fg-muted);
}
.composer__ctx + .composer__box { border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.composer__ctx strong { color: var(--fg); font-weight: 600; }

/* No permission to post: the composer is replaced, not disabled. A greyed
   input invites a click that will never work. */
.composer__locked {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  background: var(--input-bg);
  border-radius: var(--radius-lg);
  font-size: var(--fs-small);
  color: var(--fg-muted);
}
.composer__locked svg { width: var(--icon-md); height: var(--icon-md); color: var(--fg-subtle); flex: none; }

/* ===========================================================================
   MEMBER LIST
   =========================================================================== */
.members {
  width: var(--members-w);
  flex: none;
  background: var(--channels-bg);
  overflow-y: auto;
  padding: 0 var(--space-2) var(--space-5);
  --sdot-ring: var(--channels-bg);
}
.members__head {
  padding: var(--space-6) var(--space-2) var(--space-1);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}
.member {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--member-h);
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  transition: background-color var(--dur-micro) var(--ease-out);
}
.member:hover { background: var(--row-hover); }
.member__text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.member__name {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--role-color, var(--fg-muted));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.member:hover .member__name { color: var(--role-color, var(--fg)); }
.member__act { font-size: var(--fs-caption); color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.member__crown { width: 12px; height: 12px; color: var(--role-owner); flex: none; }
.member--offline { opacity: .42; }
.member--offline:hover { opacity: .75; }

.tag {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 0 var(--space-1);
  height: 15px;
  border-radius: 3px;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 10px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: .02em;
  flex: none;
}
.tag--bot { background: var(--role-bot); color: var(--bg-base); }

/* ===========================================================================
   RIGHT-HAND PANEL — threads, pinned, search results
   =========================================================================== */
.rpanel {
  width: 340px;
  flex: none;
  display: flex;
  flex-direction: column;
  background: var(--channels-bg);
  border-left: 1px solid var(--border);
  --sdot-ring: var(--channels-bg);
}
.rpanel__head {
  height: var(--chead-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) 0 var(--space-4);
  box-shadow: 0 1px 0 var(--border);
  font-size: var(--fs-h3);
  font-weight: 700;
}
.rpanel__body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }

.tcard {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.tcard:hover { border-color: var(--border-strong); }
.tcard__title { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-small); font-weight: 700; color: var(--fg); }
.tcard__title svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--fg-subtle); flex: none; }
.tcard__last { font-size: var(--fs-caption); color: var(--fg-muted); }
.tcard__meta { display: flex; align-items: center; gap: var(--space-3); font-size: var(--fs-caption); color: var(--fg-subtle); }

/* ===========================================================================
   VOICE / STAGE
   =========================================================================== */
.voice {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--voice-bg);
  --sdot-ring: var(--voice-bg);
}
.voice__head {
  height: var(--chead-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) 0 var(--space-4);
  box-shadow: 0 1px 0 var(--border);
}

.vgrid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  align-content: center;
  justify-content: center;
}
/* Few participants should not stretch into letterboxes the width of the
   window — the grid centres and the tiles keep a sane maximum. */
.vgrid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 1120px; margin: 0 auto; width: 100%; }
.vgrid--1 { grid-template-columns: minmax(0, 1fr); max-width: 760px; margin: 0 auto; width: 100%; }

/* Yalnız yüzler varken kareler daha dar. Yukarıdaki ölçüler bir **ekran
   paylaşımı** karesi için: bakılacak bir görüntü olduğunda 760 piksel
   doğru. Tek bir avatar için aynı kutu, ortasında küçük bir daire olan
   büyük boş bir dikdörtgen demek.

   Video geldiğinde bu sınıf kalkıyor ve kutular yine büyüyor. */
.vgrid--faces.vgrid--1 { max-width: 380px; }
.vgrid--faces.vgrid--2 { max-width: 740px; }
.vgrid--faces { max-width: 1080px; margin: 0 auto; width: 100%; }

.vtile {
  position: relative;
  aspect-ratio: 16 / 9;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 2px solid transparent;
  background: var(--bg-surface);
  transition: border-color var(--dur-fast) var(--ease-out);
}
/* Green, and only on the tile border — the same mark as the avatar ring in
   the sidebar, so "speaking" is one idea with one colour. */
.vtile--speaking { border-color: var(--status-online); }
.vtile--screen {
  grid-column: 1 / -1;
  aspect-ratio: 16 / 9;
  background:
    radial-gradient(70% 80% at 30% 24%, color-mix(in oklab, var(--accent) 10%, transparent) 0%, transparent 62%),
    linear-gradient(150deg, var(--bg-elevated), var(--bg-base));
}
/* The shared screen fills the tile without cropping: a screen is text and
   interface, and cutting its edges off loses exactly what is being shown. */
.vtile__video { position: absolute; inset: 0; display: grid; }
.vtile__video video { width: 100%; height: 100%; object-fit: contain; background: var(--bg-base); }
.vtile--screen:fullscreen { aspect-ratio: auto; border: 0; border-radius: 0; }
.vtile__av { width: 80px; height: 80px; }
.vtile__av .avatar { width: 80px; height: 80px; }
.vtile__name {
  position: absolute;
  left: var(--space-2); bottom: var(--space-2);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: calc(100% - var(--space-8));
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  background: var(--bg-scrim);
  backdrop-filter: blur(4px);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: #fff;   /* on a blurred scrim, which is dark in every theme */
}
.vtile__name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vtile__flags { position: absolute; right: var(--space-2); top: var(--space-2); display: flex; gap: var(--space-1); }
.vtile__flag {
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--bg-scrim);
  backdrop-filter: blur(4px);
  color: #fff;
}
.vtile__flag svg { width: 14px; height: 14px; }
.vtile__flag--off { background: var(--danger); }
.vtile__tag {
  position: absolute;
  left: var(--space-2); top: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--fs-micro);
  line-height: var(--lh-micro);
  font-weight: 700;
  letter-spacing: .06em;
}

/* ---- voice control bar -------------------------------------------------- */
.vbar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4);
}

/* Boş kanal ve perde notu. Izgara kutusunun içinde değil onun yerinde
   duruyorlar: boş bir ızgara, kutu yüksekliği kadar boşluk bırakıp altına
   yazı koymak olurdu. */
.voice__empty {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  text-align: center;
}
.voice__note {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  color: var(--fg-muted);
  font-size: var(--fs-caption);
}
.vbtn {
  width: 48px; height: 48px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--bg-overlay);
  color: var(--fg);
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), transform var(--dur-micro) var(--ease-out);
}
.vbtn:hover { background: var(--bg-elevated); }
.vbtn:active { transform: scale(.94); }
.vbtn svg { width: 22px; height: 22px; }
/* "Off" is a filled white pill with the struck icon, the way the client marks
   a muted mic: the state is the loudest thing on the bar. */
.vbtn--off { background: var(--fg); color: var(--bg-base); }
.vbtn--off:hover { background: var(--fg-muted); }
.vbtn--on { background: var(--accent); color: var(--accent-fg); }
.vbtn--on:hover { background: var(--accent-hover); }
.vbtn--hangup { background: var(--danger); color: #fff; }
.vbtn--hangup:hover { background: var(--danger-hover); }
.vbar__sep { width: 1px; height: 32px; background: var(--border); margin: 0 var(--space-2); }

/* ---- stage ------------------------------------------------------------- */
.stage { flex: 1; min-height: 0; overflow-y: auto; padding: var(--space-6) var(--space-4); display: flex; flex-direction: column; gap: var(--space-8); }
.stage__head { display: flex; flex-direction: column; gap: var(--space-2); align-items: center; text-align: center; }
.stage__title { font-size: var(--fs-h1); line-height: var(--lh-h1); font-weight: 800; letter-spacing: -.02em; }
.stage__speakers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 240px));
  gap: var(--space-4);
  justify-content: center;
}
.speaker {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4);
  background: var(--bg-surface);
  border: 2px solid transparent;
  border-radius: var(--radius-xl);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.speaker--speaking { border-color: var(--status-online); }
.speaker__name { font-size: var(--fs-body); font-weight: 700; }
.speaker__role { font-size: var(--fs-caption); color: var(--fg-muted); }
/* The audience is a dense grid of faces with names under them — at a hundred
   people the name is what you scan, not the picture. */
.audience {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: var(--space-4) var(--space-2);
}
.listener { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-align: center; }
.listener__name {
  width: 100%;
  font-size: var(--fs-caption);
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.listener--hand .avatar { box-shadow: 0 0 0 2px var(--accent); }
.listener__hand {
  position: absolute;
  right: -4px; top: -4px;
  width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-fg);
}
.listener__hand svg { width: 11px; height: 11px; }

/* ===========================================================================
   3D ROOM
   The WebGL canvas and the CSS3D layer are stacked in the same box. The CSS
   layer is on top so the embedded player stays clickable — which means the
   screen is never occluded by anything in front of it. It hangs on the back
   wall above head height, so in practice nothing is.
   =========================================================================== */
.room {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: var(--voice-bg);
  /* The scene is dragged to orbit, so the browser's own pan must not fight it. */
  touch-action: none;
}
.room__canvas { position: absolute; inset: 0; cursor: grab; }
.room__canvas:active { cursor: grabbing; }
.room__gl { position: absolute; inset: 0; display: block; }
.room__css {
  position: absolute;
  top: 0; left: 0;
  pointer-events: none;   /* only the embed itself takes clicks */
}
.room__css iframe, .room__embed { pointer-events: auto; }
.room__embed {
  border-radius: 2px;
  overflow: hidden;
  background: #000;
}
.room__embed iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---- floating name tags ------------------------------------------------
   Positioned every frame from the projected head position. transform only —
   writing left/top would relayout the whole list sixty times a second. */
.room__tags { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.ntag {
  position: absolute;
  top: 0; left: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 3px var(--space-2) 3px var(--space-1);
  border-radius: var(--radius-full);
  background: var(--bg-scrim);
  backdrop-filter: blur(6px);
  border: 1px solid var(--border);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 600;
  color: #fff;          /* on a dark blurred scrim in every theme */
  white-space: nowrap;
  will-change: transform;
}
.ntag__dot {
  width: 16px; height: 16px;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--accent);
}
.ntag__icon { width: 12px; height: 12px; color: var(--danger); flex: none; }
.ntag--me { border-color: var(--accent); }
.ntag--speaking { border-color: var(--status-online); }
.ntag--speaking .ntag__dot { box-shadow: 0 0 0 2px var(--status-online); }

/* Table labels, projected the same way the name tags are. */
.ttag {
  position: absolute;
  top: 0; left: 0;
  padding: 3px var(--space-2);
  border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--success) 88%, #000);
  color: #fff;
  font-size: var(--fs-micro);
  line-height: var(--lh-micro);
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
  will-change: transform;
}

/* ---- walk mode ---------------------------------------------------------
   The control hint, and the overlays that get out of the way once the room
   is being walked rather than inspected. */
.room__hint {
  position: absolute;
  left: 50%; bottom: var(--space-6);
  transform: translateX(-50%);
  z-index: 3;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  background: var(--bg-scrim);
  backdrop-filter: blur(6px);
  border: 1px solid var(--border);
  font-size: var(--fs-small);
  color: #fff;
  white-space: nowrap;
  pointer-events: none;
}
.room__hint b {
  display: inline-block;
  padding: 1px 6px;
  margin: 0 2px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .16);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 700;
}

/* Walking is a full-screen activity: the room takes the window and the chat
   chrome steps aside. The cinema panel goes too — you pick what is on the
   screen before you walk in, not while steering. */
body.is-walking .drawer,
body.is-walking .members,
body.is-walking .mbar,
body.is-walking .protoribbon,
body.is-walking .voice__head,
body.is-walking .vbar,
body.is-walking .room__cinema,
body.is-walking .room__tl { display: none; }
body.is-walking .room__br { top: var(--space-4); bottom: auto; }

/* ---- seat hint --------------------------------------------------------- */
.room__seatlabel {
  position: absolute;
  z-index: 3;
  transform: translate(14px, -140%);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  background: var(--success);
  color: var(--bg-base);
  font-size: var(--fs-caption);
  font-weight: 700;
  pointer-events: none;
  white-space: nowrap;
}

/* ---- overlays ---------------------------------------------------------- */
.room__tl {
  position: absolute;
  left: var(--space-4); top: var(--space-4);
  z-index: 2;
  display: flex;
  gap: var(--space-2);
}
.room__br {
  position: absolute;
  right: var(--space-4); bottom: var(--space-4);
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  align-items: flex-end;
}
.room__br .select { height: var(--control-h-sm); font-size: var(--fs-caption); }

.room__cinema {
  position: absolute;
  left: var(--space-4); bottom: var(--space-4);
  z-index: 2;
  width: min(480px, calc(100% - var(--space-12)));
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.room__cinema-head { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-small); }
.room__cinema-head svg { color: var(--accent); flex: none; }
.room__cinema-head strong { font-weight: 700; }
.room__playstatus { font-size: var(--fs-caption); color: var(--fg-muted); }
/* The status line is where the two paths become visible: which one ran is
   the whole point of the demonstration. */
.room__playstatus[data-kind="yt"]::before,
.room__playstatus[data-kind="file"]::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  margin-right: var(--space-2);
  border-radius: var(--radius-full);
  background: var(--success);
  vertical-align: 1px;
}
.room__playstatus[data-kind="error"] { color: var(--danger); }

@media (max-width: 760px) {
  .room__cinema { width: calc(100% - var(--space-8)); }
  .room__br { bottom: auto; top: var(--space-4); }
  .room__tl { display: none; }
}

/* ===========================================================================
   WARDROBE — "Oda kıyafeti"
   The preview is a real character from the same builder the room uses, so
   what you pick here is literally what walks into the room.
   =========================================================================== */
.ward { display: flex; height: 100vh; height: 100dvh; overflow: hidden; background: var(--chat-bg); }
.ward__left {
  width: 320px;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--channels-bg);
  overflow-y: auto;
}
.ward__stage {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background:
    radial-gradient(60% 50% at 50% 18%, color-mix(in oklab, var(--accent) 22%, transparent) 0%, transparent 70%),
    linear-gradient(170deg, var(--bg-elevated), var(--bg-base));
  border: 1px solid var(--border);
}
.ward__stage canvas { display: block; width: 100%; height: 100%; }
.ward__label {
  position: absolute;
  left: var(--space-3); top: var(--space-3);
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--fg-muted);
}
.ward__presets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.ward__preset {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-lg);
  border: 2px solid var(--border);
  background: linear-gradient(170deg, var(--bg-elevated), var(--bg-base));
  display: grid;
  place-items: center;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.ward__preset:hover { border-color: var(--border-strong); }
.ward__preset[aria-pressed="true"] { border-color: var(--accent); }
/* A two-tone silhouette: enough to tell two outfits apart at thumbnail size
   without rendering nine more canvases. */
.ward__preset i {
  width: 46%; height: 56%;
  border-radius: 40% 40% 18% 18%;
  background: linear-gradient(180deg, var(--w-top, var(--accent)) 0 52%, var(--w-bottom, var(--bg-overlay)) 52% 100%);
}

.ward__right { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
.ward__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6) var(--space-3);
}
.ward__tabs { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 0 var(--space-6) var(--space-4); }
.ward__grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--space-3);
  padding: 0 var(--space-6) var(--space-6);
  align-content: start;
}
.ward__item {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--radius-lg);
  border: 2px solid var(--border);
  background: var(--bg-surface);
  display: grid;
  place-items: center;
  transition: border-color var(--dur-fast) var(--ease-out), transform var(--dur-micro) var(--ease-out);
}
.ward__item:hover { border-color: var(--border-strong); }
.ward__item:active { transform: scale(.97); }
.ward__item[aria-pressed="true"] { border-color: var(--accent); }
.ward__swatch { width: 54%; height: 54%; border-radius: var(--radius-md); background: var(--w-color, var(--bg-overlay)); }
.ward__item--none .ward__swatch {
  background: none;
  border: 2px dashed var(--border-strong);
  display: grid;
  place-items: center;
}
.ward__lock {
  position: absolute;
  right: var(--space-1); top: var(--space-1);
  width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--bg-scrim);
  color: var(--fg-muted);
}
.ward__lock svg { width: 11px; height: 11px; }
.ward__check {
  position: absolute;
  right: -6px; bottom: -6px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-fg);
  opacity: 0;
}
.ward__item[aria-pressed="true"] .ward__check { opacity: 1; }
.ward__check svg { width: 12px; height: 12px; }
.ward__foot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--border);
  background: var(--channels-bg);
}

@media (max-width: 860px) {
  .ward { flex-direction: column; }
  .ward__left { width: auto; flex-direction: row; align-items: flex-start; }
  .ward__stage { width: 160px; flex: none; }
  .ward__presets { grid-template-columns: repeat(4, 56px); }
}

/* ===========================================================================
   AUTH FRAME
   Used by the chromeless pages (data-shell="bare"), which the shell does not
   wrap.
   =========================================================================== */
.authwrap {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--space-12) var(--space-5);
  overflow-y: auto;
  background:
    radial-gradient(70% 60% at 50% 0%, color-mix(in oklab, var(--accent) 10%, transparent) 0%, transparent 60%),
    var(--bg-base);
}

/* ===========================================================================
   LIVE APP
   The overlay host and the toast stack. Both sit outside the shell so they
   are not clipped by its overflow.
   =========================================================================== */
#overlay { display: none; }
#overlay.is-open { display: block; }

.livedialog {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--space-5);
  pointer-events: none;
}
.livedialog .dialog {
  pointer-events: auto;
  max-height: calc(100vh - var(--space-12));
  display: flex;
  flex-direction: column;
}
.livedialog .dialog__body { overflow-y: auto; }

.livetoasts {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
}
.livetoasts .toast { pointer-events: auto; }

/* ===========================================================================
   ROUTER
   =========================================================================== */
/* Only appears once a fetch has been slow enough to notice — a bar that
   flashes on every instant navigation reads slower than no bar at all. */
html.is-loading::before {
  content: "";
  position: fixed;
  left: 0; top: 0;
  height: 2px;
  width: 100%;
  z-index: var(--z-toast);
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 40% 100%;
  background-repeat: no-repeat;
  animation: routerbar 900ms var(--ease-out) infinite;
}
@keyframes routerbar {
  from { background-position: -40% 0; }
  to   { background-position: 140% 0; }
}

.routertoast {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-12);
  z-index: var(--z-toast);
}

/* The crossfade between two pages. Short on purpose: long enough to read as
   a transition, short enough that nobody waits for it. */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 160ms; }

/* ===========================================================================
   SETTINGS — full-window takeover
   Nav column is right-aligned against the content, which is what keeps the
   two reading as one centred block instead of two panes.
   =========================================================================== */
.set { display: flex; height: 100vh; height: 100dvh; overflow: hidden; background: var(--chat-bg); }
.set__nav {
  width: 268px;
  flex: none;
  background: var(--channels-bg);
  overflow-y: auto;
  display: flex;
  justify-content: flex-end;
  padding: var(--space-16) var(--space-2) var(--space-16) var(--space-5);
}
.set__navinner { width: 192px; display: flex; flex-direction: column; gap: 2px; }
.set__brand { display: flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-2) var(--space-5); }
.set__navhead {
  padding: var(--space-4) var(--space-2) var(--space-1);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}
.set__link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--chan-h);
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-msg);
  font-weight: 500;
  color: var(--fg-muted);
  text-align: left;
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.set__link:hover { background: var(--row-hover); color: var(--fg); }
.set__link[aria-selected="true"] { background: var(--row-active); color: var(--fg); }
.set__link svg { width: var(--icon-sm); height: var(--icon-sm); flex: none; color: var(--fg-subtle); }
.set__link[aria-selected="true"] svg { color: var(--fg-muted); }
.set__link--danger { color: var(--danger); }
.set__link--danger:hover { background: var(--danger-soft); color: var(--danger); }
.set__sep { height: 1px; background: var(--border); margin: var(--space-2) var(--space-2); }

.set__main { flex: 1; min-width: 0; overflow-y: auto; position: relative; }
.set__inner { max-width: 740px; padding: var(--space-16) var(--space-10) var(--space-16) var(--space-10); display: flex; flex-direction: column; gap: var(--space-8); }
.set__close { position: absolute; top: var(--space-16); right: var(--space-10); display: flex; flex-direction: column; align-items: center; gap: var(--space-1); color: var(--fg-muted); }
.set__close:hover { color: var(--fg); }
.set__closebtn {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  border: 2px solid var(--border-strong);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.set__close:hover .set__closebtn { border-color: var(--fg-muted); }
.set__closebtn svg { width: var(--icon-md); height: var(--icon-md); }
.set__esc { font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 700; letter-spacing: .08em; }

.set__sec { display: flex; flex-direction: column; gap: var(--space-4); }
.set__sectitle { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: 700; letter-spacing: -.012em; }
.set__label {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.set__hr { height: 1px; background: var(--border); }

/* A labelled row with a control on the right — the shape most settings take. */
.setrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-3) 0;
}
.setrow__text { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.setrow__title { font-size: var(--fs-body); font-weight: 600; color: var(--fg); }
.setrow__hint { font-size: var(--fs-small); color: var(--fg-muted); }
.setrow + .setrow { border-top: 1px solid var(--border); }

/* A list inside a dialog — permissions, people to pick: the dialog stays
   on screen and the list scrolls, rather than the save button scrolling
   out of reach. */
.dlglist { max-height: 40vh; overflow-y: auto; margin: calc(var(--space-2) * -1) 0; }
.dlglist .setrow__title { font-size: var(--fs-small); }
.dlglist .setrow__hint { font-size: var(--fs-caption); }
.segmented__opt:disabled { opacity: .5; cursor: not-allowed; }

/* The account card: banner, avatar, then the fields as read-only rows with
   their own edit buttons, which is how a profile avoids being one big form. */
.acctcard { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-xl); overflow: hidden; }
.acctcard__banner { height: 100px; background: var(--acct-tint, var(--accent)); }
.acctcard__head { display: flex; align-items: flex-end; gap: var(--space-4); padding: 0 var(--space-4) var(--space-4); margin-top: -40px; flex-wrap: wrap; }
.acctcard__av { border: 6px solid var(--bg-surface); border-radius: var(--radius-full); }
.acctcard__id { display: flex; flex-direction: column; flex: 1; min-width: 160px; padding-bottom: var(--space-2); }
.acctcard__rows { padding: 0 var(--space-4) var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.acctrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-overlay);
  border-radius: var(--radius-lg);
}
.acctrow__text { display: flex; flex-direction: column; min-width: 0; }

/* Theme picker: the swatch *is* the preview, so each option paints a real
   mini layout rather than a coloured square. */
.themepick { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-3); }
.themeopt {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 2px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  transition: border-color var(--dur-fast) var(--ease-out);
  text-align: left;
}
.themeopt:hover { border-color: var(--border-strong); }
.themeopt[aria-pressed="true"] { border-color: var(--accent); }
.themeopt__name { display: flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-1) var(--space-1); font-size: var(--fs-small); font-weight: 600; }
.themeopt__check { width: var(--icon-sm); height: var(--icon-sm); margin-left: auto; color: var(--accent); opacity: 0; }
.themeopt[aria-pressed="true"] .themeopt__check { opacity: 1; }
/* The preview is built from literal values on purpose: it has to show the
   theme you are *choosing*, not the one currently applied. This is the same
   exemption the guide's dark/light specimens take. */
.themeprev { display: flex; height: 64px; border-radius: var(--radius-md); overflow: hidden; }
.themeprev__rail { width: 12px; }
.themeprev__side { width: 28px; }
.themeprev__main { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 4px; padding: 0 6px; }
.themeprev__line { height: 5px; border-radius: 99px; }
.themeprev--dark  .themeprev__rail { background: #07090b; }
.themeprev--dark  .themeprev__side { background: #0f1114; }
.themeprev--dark  .themeprev__main { background: #16191d; }
.themeprev--dark  .themeprev__line { background: #32373e; }
.themeprev--light .themeprev__rail { background: #e1e3e8; }
.themeprev--light .themeprev__side { background: #f1f2f5; }
.themeprev--light .themeprev__main { background: #ffffff; }
.themeprev--light .themeprev__line { background: #cdd2d8; }
.themeprev--night .themeprev__rail { background: #000000; }
.themeprev--night .themeprev__side { background: #050607; }
.themeprev--night .themeprev__main { background: #0b0d0f; }
.themeprev--night .themeprev__line { background: #2e343b; }
.themeprev__line--accent { background: var(--accent) !important; width: 40%; }

/* Range input, used by the font scale and the volume sliders. */
.range { -webkit-appearance: none; appearance: none; width: 100%; height: 20px; background: none; }
.range::-webkit-slider-runnable-track { height: 8px; border-radius: var(--radius-full); background: var(--bg-overlay); }
.range::-moz-range-track { height: 8px; border-radius: var(--radius-full); background: var(--bg-overlay); }
.range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 20px; height: 20px; margin-top: -6px;
  border-radius: var(--radius-full);
  background: var(--fg);
  border: 2px solid var(--bg-base);
  box-shadow: var(--shadow-sm);
}
.range::-moz-range-thumb {
  width: 20px; height: 20px;
  border-radius: var(--radius-full);
  background: var(--fg);
  border: 2px solid var(--bg-base);
}
.range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }
.range--accent::-webkit-slider-thumb { background: var(--accent); }
.range--accent::-moz-range-thumb { background: var(--accent); }

/* Mic test meter: segmented so a level reads without a number next to it. */
.levels { display: flex; gap: 2px; height: 10px; }
.levels i { flex: 1; border-radius: 1px; background: var(--bg-overlay); }
.levels i.on { background: var(--success); }
.levels i.hot { background: var(--warning); }

/* Role list + permission editor */
.rolelist { display: flex; flex-direction: column; }
.rolerow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.rolerow:hover { background: var(--row-hover); }
.rolerow[aria-selected="true"] { background: var(--row-active); }
.rolerow__swatch { width: 12px; height: 12px; border-radius: var(--radius-full); background: var(--role-tint, var(--fg-subtle)); flex: none; }
.rolerow__name { flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: 600; color: var(--role-tint, var(--fg)); }
.rolerow__n { font-size: var(--fs-caption); color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.rolerow__grip { color: var(--fg-subtle); cursor: grab; }

/* Audit log entries read as a timeline, not a table: what matters is the
   order and the actor, and both live in the left rail of the row. */
.audit { display: flex; flex-direction: column; }
.auditrow { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.auditrow:last-child { border-bottom: 0; }
.auditrow__icon {
  width: 32px; height: 32px;
  flex: none;
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--bg-overlay);
  color: var(--fg-muted);
}
.auditrow__icon svg { width: var(--icon-sm); height: var(--icon-sm); }
.auditrow__body { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; flex: 1; }
.auditrow__text { font-size: var(--fs-small); color: var(--fg-muted); }
.auditrow__text strong { color: var(--fg); font-weight: 600; }
.auditrow__time { font-size: var(--fs-caption); color: var(--fg-subtle); }

/* ===========================================================================
   DISCOVERY
   =========================================================================== */
.disc { flex: 1; min-width: 0; overflow-y: auto; background: var(--chat-bg); }
.disc__hero {
  padding: var(--space-12) var(--space-8);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-align: center;
  background:
    radial-gradient(70% 90% at 50% 0%, color-mix(in oklab, var(--accent) 14%, transparent) 0%, transparent 66%),
    var(--chat-bg);
}
.disc__title { font-size: var(--fs-display); line-height: var(--lh-display); font-weight: 800; letter-spacing: -.025em; }
.disc__sub { font-size: var(--fs-msg); line-height: var(--lh-msg); color: var(--fg-muted); max-width: 56ch; }
.disc__body { padding: 0 var(--space-8) var(--space-12); display: flex; flex-direction: column; gap: var(--space-8); }
.disc__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--space-4); }

.scard {
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  transition: border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.scard:hover { border-color: var(--accent-ring); transform: translateY(-2px); }
.scard__banner {
  aspect-ratio: 16 / 6;
  background:
    radial-gradient(70% 90% at 28% 22%, color-mix(in oklab, var(--accent) 12%, transparent) 0%, transparent 60%),
    linear-gradient(150deg, var(--bg-elevated), var(--bg-base));
}
.scard__body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.scard__top { display: flex; align-items: center; gap: var(--space-2); margin-top: -32px; }
/* Not .guild: that carries the rail's unread pill and hover morph, neither of
   which means anything on a card. Same squircle, none of the behaviour.
   56px outer so the 4px ring leaves the icon itself at --guild-size. */
.scard__icon {
  width: 56px; height: 56px;
  flex: none;
  display: grid;
  place-items: center;
  border: 4px solid var(--bg-surface);
  border-radius: var(--guild-radius);
  background: var(--guild-tint, var(--bg-elevated));
  color: var(--fg);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: -.02em;
}
.scard__name { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -.01em; }
.scard__desc { font-size: var(--fs-small); line-height: 1.45; color: var(--fg-muted); flex: 1; }
.scard__meta { display: flex; align-items: center; gap: var(--space-4); font-size: var(--fs-caption); color: var(--fg-muted); }
.scard__meta b { display: inline-flex; align-items: center; gap: var(--space-1); font-weight: 600; color: var(--fg); }

/* ===========================================================================
   DM LIST
   The DM sidebar reuses the channel sidebar frame; only the rows differ,
   because a conversation needs a face and a channel needs a glyph.
   =========================================================================== */
.dmrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 42px;
  padding: 0 var(--space-2);
  margin-top: 2px;
  border-radius: var(--radius-sm);
  color: var(--fg-muted);
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.dmrow:hover { background: var(--row-hover); color: var(--fg); }
.dmrow[aria-current="page"] { background: var(--row-active); color: var(--fg); }
.dmrow__text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.dmrow__name { font-size: var(--fs-small); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dmrow__sub { font-size: var(--fs-caption); color: var(--fg-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dmrow--unread .dmrow__name { color: var(--fg); font-weight: 700; }
.dmrow__close { opacity: 0; color: var(--fg-subtle); }
.dmrow:hover .dmrow__close { opacity: 1; }
.dmrow__close:hover { color: var(--fg); }

/* The "Arkadaşlar" header row above the DM list behaves like a channel. */
.dmnav {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 42px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-msg);
  font-weight: 600;
  color: var(--fg-muted);
  transition: background-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.dmnav:hover { background: var(--row-hover); color: var(--fg); }
.dmnav[aria-current="page"] { background: var(--row-active); color: var(--fg); }
.dmnav svg { width: var(--icon-md); height: var(--icon-md); flex: none; }
.dmnav__count {
  min-width: 16px; height: 16px;
  display: grid; place-items: center;
  padding: 0 var(--space-1);
  border-radius: var(--radius-full);
  background: var(--live);
  color: #fff;
  font-size: var(--fs-micro);
  font-weight: 700;
  line-height: 1;
}

/* ===========================================================================
   SKELETON — message list
   Shaped like the thing it is standing in for: a 40px round avatar, a short
   name line, then one or two text lines of uneven length.
   =========================================================================== */
.mskel { padding: var(--space-2) var(--space-4) var(--space-2) 72px; position: relative; margin-top: var(--space-4); }
.mskel__av { position: absolute; left: var(--space-4); top: var(--space-2); }
.mskel__lines { display: flex; flex-direction: column; gap: var(--space-2); }

/* ===========================================================================
   MOBILE
   Two breakpoints, two different problems.
   1180px: the member list is the first thing to go — it is the only column
   that repeats information available elsewhere.
   760px:  the rail and the channel list become one drawer over the message
   column, and a bottom tab bar replaces the rail's navigation.
   =========================================================================== */
@media (max-width: 1180px) {
  .members, .rpanel { display: none; }
  .set__inner { padding-left: var(--space-6); padding-right: var(--space-6); }
}

@media (max-width: 760px) {
  .shell { position: relative; }

  /* The drawer is the rail plus the channel list, moved out of the flow and
     slid in. transform, not width: animating width relayouts the message
     column on every frame. */
  .drawer {
    position: absolute;
    inset: 0 auto 0 0;
    z-index: var(--z-dropdown);
    display: flex;
    transform: translateX(-100%);
    transition: transform var(--dur-base) var(--ease-out);
    box-shadow: var(--shadow-lg);
  }
  body.is-drawer .drawer { transform: translateX(0); }

  .drawer__scrim {
    position: absolute;
    inset: 0;
    z-index: var(--z-scrim);
    background: var(--bg-scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  body.is-drawer .drawer__scrim { opacity: 1; pointer-events: auto; }

  .chatcol, .voice, .disc { padding-bottom: var(--mbar-h); }
  .chead { padding-left: var(--space-2); }
  .chead__sep, .chead__topic, .chead__search { display: none; }
  .m { padding-right: var(--space-4); }
  .composer { padding: 0 var(--space-3) var(--space-3); }

  /* The rail's navigation has to exist somewhere once the rail is in a
     drawer — a bottom bar is reachable with a thumb, the drawer is not. */
  .mbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: var(--z-sticky);
    height: calc(var(--mbar-h) + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    display: flex;
    background: var(--channels-bg);
    border-top: 1px solid var(--border);
  }
  .vgrid { grid-template-columns: minmax(0, 1fr); }
  .vbar { flex-wrap: wrap; }

  .set { flex-direction: column; }
  .set__nav { width: auto; justify-content: flex-start; padding: var(--space-4); overflow-x: auto; }
  .set__navinner { width: auto; flex-direction: row; gap: var(--space-1); }
  .set__navhead, .set__sep, .set__brand { display: none; }
  .set__link { white-space: nowrap; }
  .set__inner { padding: var(--space-5) var(--space-4) var(--space-12); }
  .set__close { top: var(--space-4); right: var(--space-4); }

  .disc__hero { padding: var(--space-8) var(--space-4); }
  .disc__body { padding: 0 var(--space-4) var(--space-12); }
}

/* Shown only in the mobile layout; a media query is the switch so the markup
   carries them unconditionally and nothing has to be re-rendered on resize. */
.mbar { display: none; }
.m-only { display: none; }
@media (max-width: 760px) {
  .m-only { display: grid; }
  .d-only { display: none !important; }
}

.mbar__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--fg-subtle);
  font-size: 10px;
  font-weight: 600;
  transition: color var(--dur-fast) var(--ease-out);
}
.mbar__item svg { width: 22px; height: 22px; }
.mbar__item[aria-current="page"] { color: var(--accent); }
.mbar__item:hover { color: var(--fg); }
.mbar__badge {
  position: absolute;
  margin: -18px 0 0 16px;
  min-width: 16px; height: 16px;
  display: grid; place-items: center;
  padding: 0 4px;
  border-radius: var(--radius-full);
  background: var(--live);
  color: #fff;
  font-size: 10px;
  line-height: 1;
  font-weight: 700;
}

/* ===========================================================================
   PROTOTYPE RIBBON
   Bottom right here, not bottom left: the left corner is the user bar and the
   drawer handle, both of which get tested.
   =========================================================================== */
.protoribbon {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: var(--z-toast);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--control-h-sm);
  padding: 0 var(--space-3);
  background: var(--accent);
  color: var(--accent-fg);
  border-radius: var(--radius-full);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .1em;
  box-shadow: var(--shadow-md);
}
.protoribbon:hover { background: var(--accent-hover); color: var(--accent-fg); }
.protoribbon svg { width: 14px; height: 14px; }
@media (max-width: 760px) { .protoribbon { bottom: calc(var(--mbar-h) + var(--space-3)); } }

/* ===========================================================================
   POPOVER — account menu, add-reaction, channel menu
   =========================================================================== */
.pop { position: relative; }
.pop__panel {
  position: absolute;
  z-index: var(--z-dropdown);
  bottom: calc(100% + var(--space-2));
  left: 0;
  width: 240px;
}
.pop__panel--up-right { left: auto; right: 0; }
.pop__panel--down { bottom: auto; top: calc(100% + var(--space-2)); }
.menu__head {
  padding: var(--space-2) var(--space-3);
  font-size: var(--fs-micro);
  line-height: var(--lh-micro);
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--fg-subtle);
}
.menu__item svg { width: var(--icon-sm); height: var(--icon-sm); flex: none; color: var(--fg-muted); }
.menu__item--danger svg { color: var(--danger); }
.menu__item .sdot { position: static; width: 10px; height: 10px; background: none; }
.menu__item .sdot::before { width: 10px; height: 10px; }

/* Emoji picker, opened from the composer. */
.emopick { width: 320px; display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); }
.emopick__grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.emopick__cell {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  font-size: 20px;
  line-height: 1;
  transition: background-color var(--dur-micro) var(--ease-out);
}
.emopick__cell:hover { background: var(--row-active); }
.emopick__head { font-size: var(--fs-caption); font-weight: 700; color: var(--fg-subtle); text-transform: uppercase; letter-spacing: .02em; }

/* ===========================================================================
   3D ODA KATMANI
   The room is an overlay, not a region of the app shell. The chat app rebuilds
   its tree on every socket frame and a WebGL canvas inside it would not
   survive the next message, so the room sits above everything on its own
   element. Red line 10: this is a layer, and the voice channel underneath
   keeps working without it.
   =========================================================================== */
.roomlayer {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  grid-template-rows: var(--chead-h) 1fr;
  background: var(--bg-base);
  animation: roomin var(--dur-base) var(--ease-out);
}

@keyframes roomin {
  from { opacity: 0; transform: scale(.985); }
  to   { opacity: 1; transform: none; }
}

.roomlayer:focus { outline: none; }
.roomlayer .room { min-height: 0; }

.vlist { display: flex; flex-direction: column; gap: var(--space-1); }

.vlist__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  transition: background var(--dur-fast) var(--ease-out);
}
.vlist__row:hover { background: var(--row-hover); }

.vlist__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-small);
  color: var(--fg);
}

.vlist__icon { color: var(--fg-subtle); display: inline-flex; }

/* The channel you are talking in. A dot rather than a colour change on the
   row: aria-current already owns "the channel you are reading", and the two
   are independent — you can read one channel and talk in another. */
.chan--incall .chan__name { color: var(--fg); font-weight: 600; }
.chan__live {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--success);
}

/* ---- voice bar ----------------------------------------------------------
   Above the user bar in every sidebar. Being in a call survives switching
   channels and switching to the DM view, so the thing that gets you out of
   it has to be visible from all of them. */
.vsess {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  background: var(--userbar-bg);
  border-top: 1px solid var(--border);
}
.vsess__who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.vsess__name {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--fg);
}
.vsess__state { font-size: var(--fs-caption); color: var(--success); }
/* The state colour is the whole message when the label is glanced at rather
   than read: connecting is not a failure and failure is not a warning. */
.vsess[data-state="connecting"] .vsess__state { color: var(--fg-subtle); }
.vsess[data-state="failed"] .vsess__state { color: var(--danger); }
.vsess[data-state="disabled"] .vsess__state { color: var(--fg-subtle); }
.vsess__acts { display: flex; align-items: center; gap: var(--space-1); }
.vsess__off:hover { color: var(--danger); }

/* Who is talking. A ring rather than a background: the row already uses
   background for hover, and two meanings on one property read as neither. */
.vrow--speaking { box-shadow: inset 0 0 0 2px var(--success); }

@media (prefers-reduced-motion: reduce) {
  .roomlayer { animation: none; }
  .vlist__row { transition: none; }
}

/* ===========================================================================
   DİREKT MESAJLAR VE ARKADAŞLAR
   The conversation list and the friends panel. The message column itself is
   shared with server channels — a conversation is a channel without a guild,
   so there is nothing to restyle there.
   =========================================================================== */

/* A count on the rail's home button: a friend request waiting is the only
   thing in the app that has to be visible with no view open. */
.guild__badge {
  position: absolute;
  right: -2px;
  bottom: -2px;
  min-width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  padding: 0 4px;
  border-radius: var(--radius-full);
  border: 2px solid var(--rail-bg);
  background: var(--danger);
  color: var(--danger-fg);
  font-size: var(--fs-micro);
  font-weight: 700;
  line-height: 1;
}

/* A conversation row carries a face instead of a hash, so it is taller than
   a channel row and the avatar sets the height rather than --chan-h. */
.chan--dm { height: auto; padding: var(--space-1) var(--space-2); }
.chan--wide { height: auto; padding: var(--space-2); }

.fpanel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--space-5) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  background: var(--chat-bg);
}

.fadd {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--border);
}

.fsec { display: flex; flex-direction: column; gap: var(--space-2); }

/* The action buttons on a friend row appear on hover at desktop width and
   stay put on touch, where there is no hover to reveal them. */
.fsec .vlist__row { padding: var(--space-2); }
.fsec .vlist__row .btn-row { opacity: 1; }

@media (hover: hover) and (min-width: 861px) {
  .fsec .vlist__row .btn-row {
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-out);
  }
  .fsec .vlist__row:hover .btn-row,
  .fsec .vlist__row:focus-within .btn-row { opacity: 1; }
}

@media (max-width: 860px) {
  .fpanel { padding: var(--space-4); }
  .fadd { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  .fsec .vlist__row .btn-row { transition: none; }
}

/* Ses durumu, oda başlığında. Metin olarak, ikon olarak değil: "dinliyorsun"
   ile "ses açık" arasındaki fark bir simgeye sığmıyor ve bu ikisi arasındaki
   belirsizlik odada en çok sorulan şey. */
.room__voice {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--bg-overlay);
  color: var(--fg-muted);
  font-size: var(--fs-caption);
  font-weight: 600;
  white-space: nowrap;
}
.room__voice::before {
  content: "";
  width: 6px; height: 6px; flex: none;
  border-radius: var(--radius-full);
  background: var(--fg-subtle);
}
.room__voice[data-kind="on"]     { color: var(--success); }
.room__voice[data-kind="on"]::before     { background: var(--success); }
.room__voice[data-kind="listen"] { color: var(--info); }
.room__voice[data-kind="listen"]::before { background: var(--info); }
.room__voice[data-kind="wait"]::before   { background: var(--warning); }
.room__voice[data-kind="off"]    { color: var(--fg-subtle); }

@media (max-width: 720px) {
  /* Dar ekranda başlıkta yer yok; durum, mikrofon ikonunun kendisinden
     okunuyor. */
  .room__voice { display: none; }
}

/* ===========================================================================
   DOSYA EKLERİ
   Bestecideki tepsi (gönderilmeyi bekleyen dosyalar) ve mesajdaki görseller.
   =========================================================================== */

/* ---- besteci tepsisi ----------------------------------------------------
   Mesajdan önce yüklenen dosyalar burada duruyor. Bir satırda yatay kayıyor:
   on dosya seçildiğinde bestecinin yazma alanını aşağı itmesi, yazarken
   metnin kaybolması demek. */
.tray {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  padding: var(--space-2) 0;
  scrollbar-width: thin;
}

.tray__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  max-width: 260px;
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
}

/* Yüklenirken ve hata durumunda görünür fark: metin tek başına, otuz
   dosyalık bir tepside taranamıyor. */
.tray__item.busy { opacity: .7; }
.tray__item.busy .tray__thumb { animation: traypulse 1.2s var(--ease-out) infinite; }
.tray__item.error {
  border-color: var(--danger);
  background: var(--danger-soft);
}
.tray__item.error .tray__note { color: var(--danger); }

@keyframes traypulse {
  0%, 100% { opacity: .45; }
  50%      { opacity: 1; }
}

.tray__thumb {
  width: 40px;
  height: 40px;
  flex: none;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: var(--bg-overlay);
}
.tray__thumb--blank {
  display: grid;
  place-items: center;
  color: var(--fg-subtle);
}

.tray__meta { display: flex; flex-direction: column; min-width: 0; }
.tray__name {
  font-size: var(--fs-small);
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tray__note { font-size: var(--fs-caption); color: var(--fg-muted); }

/* ---- mesajdaki görseller ------------------------------------------------
   aspect-ratio satır içinde veriliyor (sunucu boyutları biliyor), böylece
   görsel yüklenirken yer kaplıyor ve altındaki mesajlar zıplamıyor. */
.files {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-1);
  max-width: 560px;
}

.files__item {
  display: block;
  overflow: hidden;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-overlay);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.files__item:hover { border-color: var(--border-strong); }
.files__item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.files__img {
  display: block;
  max-width: 100%;
  max-height: 340px;
  width: auto;
  height: auto;
}

/* İkiden fazla görselde ızgara: yan yana dört görsel her birini okunamaz
   kılıyor. */
.files--grid .files__item { flex: 1 1 160px; max-width: 260px; }
.files--grid .files__img { width: 100%; max-height: 180px; object-fit: cover; }

/* A file that is not an image: what it is, how big, a download; audio and
   video get a player above. Capped at the width images use. */
.fcard {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 420px;
  margin-top: var(--space-1);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-surface);
}
.fcard__row { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.fcard__icon { display: grid; place-items: center; width: 36px; height: 36px; flex: none;
  border-radius: var(--radius-md); background: var(--bg-overlay); color: var(--fg-muted); }
.fcard__meta { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.fcard__name { font-size: var(--fs-small); font-weight: 600; color: var(--info);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fcard__sub { font-size: var(--fs-caption); color: var(--fg-subtle); }
.fcard__media { width: 100%; }
.fcard__media--video { max-height: 320px; border-radius: var(--radius-sm); background: var(--bg-base); }

/* ---- sürükle bırak ------------------------------------------------------ */
.chatcol { position: relative; }
.chatcol--drop::after {
  content: "Bırak, yüklenecek";
  position: absolute;
  inset: var(--space-3);
  z-index: var(--z-dropdown);
  display: grid;
  place-items: center;
  pointer-events: none;
  border: 2px dashed var(--accent);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

/* ---- avatar seçici ------------------------------------------------------ */
.userbar__pick { position: relative; display: inline-flex; cursor: pointer; }
.userbar__pick-hint {
  position: absolute;
  right: -2px;
  bottom: -2px;
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  border: 2px solid var(--userbar-bg);
  background: var(--accent);
  color: var(--accent-fg);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.userbar__pick:hover .userbar__pick-hint,
.userbar__pick:focus-within .userbar__pick-hint { opacity: 1; }

/* Dosya ekleme düğmesi bir etiket: tıklanabilir olduğu görünmeli. */
label.composer__add { cursor: pointer; }
label.composer__add:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (max-width: 720px) {
  .files { max-width: 100%; }
  .files__img { max-height: 240px; }
}

@media (prefers-reduced-motion: reduce) {
  .tray__item.busy .tray__thumb { animation: none; }
  .files__item, .userbar__pick-hint { transition: none; }
}

/* ===========================================================================
   ARAMA VE SABİTLER PANELİ
   Üye listesinin yerini alıyor, yanına değil: dört dikey yüzeyin üstüne
   beşinci bir sütun koymak 1280 pikselde mesaj sütununu okunamaz hâle
   getiriyor. İkisi aynı soruyu cevaplıyor ("o mesaj neredeydi"), o yüzden
   tek panel.
   =========================================================================== */
.side {
  width: var(--members-w);
  flex: none;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--channels-bg);
  border-left: 1px solid var(--border);
}

.side__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--chead-h);
  flex: none;
  padding: 0 var(--space-2) 0 var(--space-4);
  border-bottom: 1px solid var(--border);
}

.side__title {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--fg);
}

.side__form { flex: none; padding: var(--space-3); }

.side__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 var(--space-2) var(--space-4);
}

.side__count {
  padding: var(--space-1) var(--space-2) var(--space-2);
  font-size: var(--fs-caption);
  color: var(--fg-muted);
}

.side__list { display: flex; flex-direction: column; gap: var(--space-1); }

.side__more { width: calc(100% - var(--space-4)); margin: var(--space-2); }

/* ---- bir sonuç ---------------------------------------------------------- */
.hit {
  position: relative;
  border-radius: var(--radius-md);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.hit:hover { background: var(--row-hover); }

/* Satırın tamamı bir düğme: sonuca tıklayıp mesaja gitmek en sık yapılan
   şey, ve tıklanabilir alanı bir simgeye indirmek onu zorlaştırıyor. */
.hit__go {
  display: flex;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2);
  text-align: left;
  border-radius: var(--radius-md);
}
.hit__go:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.hit__lines { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }

.hit__head { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }

.hit__name {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hit__time { font-size: var(--fs-micro); color: var(--fg-subtle); flex: none; }

/* Üç satırda kesiliyor: bir sonuç listesi, mesajların kendisi değil. */
.hit__text {
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--fg-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}

.hit__text mark {
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 2px;
  padding: 0 1px;
}

.hit__note {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-micro);
  color: var(--fg-subtle);
}

/* Sabiti kaldırma düğmesi: masaüstünde hover ile, dokunmatikte her zaman. */
.hit__drop {
  position: absolute;
  right: var(--space-1);
  top: var(--space-1);
}

@media (hover: hover) and (min-width: 861px) {
  .hit__drop { opacity: 0; transition: opacity var(--dur-fast) var(--ease-out); }
  .hit:hover .hit__drop,
  .hit:focus-within .hit__drop { opacity: 1; }
}

.hit--skel { display: flex; gap: var(--space-2); padding: var(--space-2); }

/* ---- mesajdaki sabit işareti ------------------------------------------- */
.m--pinned { background: var(--accent-soft); }
.m__pin {
  position: absolute;
  left: var(--space-1);
  top: var(--space-1);
  color: var(--accent);
  display: inline-flex;
}

/* Aramadan atlanınca mesaj kısa süre vurgulanıyor: kaydırma bitince
   hangisine geldiğini söylemenin tek yolu. */
.m--flash { animation: mflash 1.6s var(--ease-out); }
@keyframes mflash {
  0%, 60% { background: var(--accent-soft); }
  100%    { background: transparent; }
}

@media (max-width: 1100px) {
  /* Dar ekranda panel mesaj sütununu ezmek yerine onun üstüne biniyor. */
  .side {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: var(--z-dropdown);
    width: min(320px, 90vw);
    box-shadow: var(--shadow-lg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hit, .hit__drop { transition: none; }
  .m--flash { animation: none; }
}

/* ===========================================================================
   KONU BAŞLIKLARI
   Bir thread bir kanal, yani mesaj sütunu aynı. Buradaki şeyler girişi ve
   çıkışı: listedeki satır, mesajın altındaki gösterge, ve geri yolu.
   =========================================================================== */

/* Mesajın altındaki "3 yanıt" göstergesi. Mesajın parçası gibi değil, ona
   bağlı bir şey gibi duruyor: soldaki çizgi bağı kuruyor. */
.treply {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-1);
  padding: var(--space-1) var(--space-2);
  max-width: 100%;
  border-radius: var(--radius-md);
  border-left: 2px solid var(--accent);
  background: var(--bg-overlay);
  color: var(--fg-muted);
  font-size: var(--fs-caption);
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.treply:hover { background: var(--row-hover); color: var(--fg); }
.treply:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.treply__count { font-weight: 600; color: var(--accent); flex: none; }
.treply__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Thread satırındaki simge: listedeki diğer satırlarda avatar olan yerde
   duruyor, o yüzden aynı ölçüyü tutuyor. */
.hit__icon {
  display: grid;
  place-items: center;
  width: var(--avatar-sm);
  height: var(--avatar-sm);
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--bg-overlay);
  color: var(--accent);
}

/* Thread başlığında geri yolu. Bir thread kanal gibi görünüyor ama
   çıkılamayan bir kanal gibi görünmemeli. */
.chead__back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--bg-overlay);
  color: var(--fg-muted);
  font-size: var(--fs-caption);
  flex: none;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.chead__back:hover { background: var(--row-hover); color: var(--fg); }
.chead__back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .treply, .chead__back { transition: none; }
}
