/* Cuppa shell. Dark surround so the pixel world is the only lit thing.
   Everything here is hard-edged on purpose: 1px borders, no radii above 2px,
   no blur, no gradient fields. The UI is furniture, the world is the subject.
   The room's own signs (the notice board, the host lamp) are NOT in here: they
   are drawn in the world, because a sign in a sidebar is not a room's sign. */

:root {
  --void: #08080d;
  --surround: #0b0b11;
  --panel: rgba(14, 14, 22, 0.92);
  --line: #2a2a3d;
  --line-hot: #3d3d5c;
  --ink: #cfd0dd;
  --ink-dim: #7c7d94;
  --gold: #e8b45a;
  --cyan: #7fb3d5;
  --warn: #e8735a;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

* { box-sizing: border-box; }

/* The hidden attribute must beat every display rule below it, or the name
   popover sits open on load and reads as the join gate C1 exists to forbid. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--void);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 13px;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 50;
  background: var(--gold); color: #14141f; padding: 8px 12px; font-weight: 700;
}
.skip:focus { left: 8px; top: 8px; }
#exitLink:focus { top: 44px; }

#stage {
  position: fixed;
  inset: 0;
  background: var(--surround);
}

#world {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  cursor: crosshair;
  touch-action: none;
}

/* ---- top bar ---------------------------------------------------------- */

#hud {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 40px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 8px;
  background: linear-gradient(180deg, rgba(8, 8, 13, 0.85), rgba(8, 8, 13, 0));
  pointer-events: none;
}
#hud > * { pointer-events: auto; }
.spacer { flex: 1; }

.brand { display: flex; align-items: center; gap: 8px; }
.mark {
  width: 14px; height: 14px;
  background:
    linear-gradient(var(--gold), var(--gold)) 0 2px / 14px 2px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) 0 7px / 10px 2px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) 0 12px / 6px 2px no-repeat;
}
.wordmark {
  font-size: 11px; letter-spacing: 0.22em; font-weight: 700; color: var(--ink);
}

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 9px;
  font: inherit; font-size: 11px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 2px;
  cursor: pointer;
}
.chip:hover { border-color: var(--line-hot); }
.chip:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
#nameLabel { max-width: 18ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.conn { cursor: default; color: var(--ink-dim); }
.conn .dot { width: 6px; height: 6px; background: var(--ink-dim); }
.conn[data-state="live"] { color: var(--ink); }
.conn[data-state="live"] .dot { background: #6fbf73; }
.conn[data-state="connecting"] .dot { background: var(--gold); animation: pulse 1s steps(2, end) infinite; }
.conn[data-state="offline"] { color: var(--warn); }
.conn[data-state="offline"] .dot { background: var(--warn); }
@keyframes pulse { 50% { opacity: 0.25; } }

/* Ringing out, and in a call. The caller's whole view of their own call: gold
   because it is live, pulsing only while it is still a question. `data-state`
   rather than a class so the one chip is one chip in two truths, the way conn
   already is. */
.chip.call { color: var(--gold); border-color: var(--gold); }
.chip.call[data-state="out"] .dot { background: var(--gold); animation: pulse 1s steps(2, end) infinite; }
.chip.call[data-state="in"] .dot { background: var(--gold); }
.chip.call .dot { width: 6px; height: 6px; }

.gwrap { display: flex; align-items: center; min-height: 24px; }
.gwrap .stub {
  height: 24px; padding: 0 9px;
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 11px;
  color: var(--ink-dim);
  background: var(--panel);
  border: 1px dashed var(--line);
  border-radius: 2px;
  cursor: not-allowed;
}

/* ---- name popover ----------------------------------------------------- */

.popover {
  position: absolute;
  top: 44px; right: 8px;
  display: flex; align-items: center; gap: 6px;
  flex-wrap: wrap;
  max-width: 384px;
  padding: 8px;
  background: var(--panel);
  border: 1px solid var(--line-hot);
  border-radius: 2px;
  z-index: 6;
}

/* ---- the mirror (avatar picker) ---------------------------------------- */
.lookWrap {
  flex-basis: 100%;
  display: flex; gap: 12px; align-items: flex-start;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}
.mirror {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  flex: 0 0 auto;
}
#lookPrev {
  width: 80px; height: 120px;
  image-rendering: pixelated;
  background: #05050a;
  border: 1px solid var(--line);
  border-radius: 2px;
}
.dice {
  width: 80px;
  font: inherit; font-size: 10px; line-height: 1.7;
  color: var(--ink); background: #05050a;
  border: 1px solid var(--line); border-radius: 2px;
  cursor: pointer;
}
.dice:hover { border-color: var(--gold); color: var(--gold); }
.dice:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.lookRows { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.lookRow { display: flex; align-items: flex-start; gap: 4px; }
.lookRow > span {
  width: 7.5ch; flex: 0 0 auto;
  padding-top: 2px;
  font-size: 10px; color: var(--ink-dim);
}
/* wrapped option lines align under the options, never under the label */
.lookRow .opts { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; min-width: 0; }
.swatch {
  width: 14px; height: 14px;
  border: 1px solid var(--line);
  border-radius: 2px;
  cursor: pointer;
  display: inline-block;
}
.lookRow .chipTall { height: 44px !important; width: 28px !important; }
.lookRow .chip {
  width: 32px; height: 26px;
  image-rendering: pixelated;
  background: #05050a;
  border: 1px solid var(--line);
  border-radius: 2px;
  cursor: pointer;
}
.swatch:hover, .lookRow .chip:hover { border-color: var(--line-hot); }
.swatch:focus-visible, .lookRow .chip:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.swatch.sel, .lookRow .chip.sel { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
.claimNote { flex-basis: 100%; margin: 2px 0 0; font-size: 10px; color: var(--ink-dim); }
#nameBtn[data-verified="1"] #nameLabel::after {
  content: ' \2713';
  color: var(--gold);
}
.popover label { font-size: 11px; color: var(--ink-dim); }
.popover input {
  width: 16ch;
  font: inherit; font-size: 12px;
  color: var(--ink);
  background: #05050a;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4px 6px;
}
.popover input:focus { outline: none; border-color: var(--gold); }
.btn {
  font: inherit; font-size: 11px;
  color: #14141f; background: var(--gold);
  border: 0; border-radius: 2px;
  padding: 5px 9px; cursor: pointer; font-weight: 700;
}

/* ---- hint ------------------------------------------------------------- */

.hint {
  position: absolute;
  left: 50%; top: 52px;
  transform: translateX(-50%);
  padding: 6px 12px;
  font-size: 11px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 2px;
  letter-spacing: 0.04em;
  transition: opacity 900ms linear;
  pointer-events: none;
}
.hint b { color: var(--gold); font-weight: 700; }
.hint.gone { opacity: 0; }

/* ---- person chip (click a nearby avatar) ------------------------------- */

.personChip {
  position: fixed;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 7px;
  font-size: 11px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 2px;
  letter-spacing: 0.04em;
}
/* Stacked, for the one caller whose items are sentences rather than words: a
   list of microphones laid out in a row is a menu as wide as the window. The
   items keep the same button, the same hover and the same ink; only the axis
   changes, because only the axis was wrong. */
.personChip.col {
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  max-width: 260px;
}
.personChip.col .who { padding: 0 0 2px; }
.personChip.col button {
  text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.personChip .who { color: var(--gold); font-weight: 700; padding-right: 2px; }
.personChip button {
  font: inherit; font-size: 11px;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 3px 8px;
  cursor: pointer;
}
.personChip button:hover, .personChip button:focus-visible {
  color: #14141f; background: var(--gold); border-color: var(--gold); outline: 0;
}

/* ---- chat ------------------------------------------------------------- */

#chat {
  position: absolute;
  left: 8px; bottom: 8px;
  width: min(380px, calc(100vw - 16px));
  display: flex; flex-direction: column; gap: 6px;
}

#log {
  list-style: none;
  margin: 0; padding: 0;
  max-height: 26vh;
  overflow-y: auto;
  overflow-x: hidden;
  font-size: 11.5px;
  line-height: 1.5;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
  mask-image: linear-gradient(180deg, transparent, #000 22px);
}
#log:empty { display: none; }
/* Each line carries its own dark plate. Round 1's world was a dark office and
   bare text read fine on it; this room is warm, bright wood, and it changes
   colour four times a year. Text that relies on the floor being dark is text
   that vanishes in summer. The plate is the only thing that reads on all of
   them, so the line owns its background rather than borrowing the room's. */
#log li {
  display: table;
  max-width: 100%;
  margin: 1px 0;
  padding: 1px 5px;
  color: var(--ink);
  background: rgba(8, 8, 13, 0.72);
  overflow-wrap: anywhere;
}
#log li .who { color: var(--cyan); }
#log li.self .who { color: var(--gold); }
#log li.host .who { color: var(--gold); }
#log li.sys { color: #9a9bb4; }
#log li.sys::before { content: "* "; }
#log li.warn { color: var(--warn); }
#log li.warn::before { content: "! "; }

#sayForm {
  display: flex; align-items: center; gap: 6px;
  padding: 0 8px;
  height: 30px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 2px;
}
#sayForm:focus-within { border-color: var(--gold); }
.prompt { color: var(--gold); font-weight: 700; }
#say {
  flex: 1;
  font: inherit; font-size: 12px;
  color: var(--ink);
  background: transparent;
  border: 0;
  padding: 0;
}
#say::placeholder { color: #55566b; }
#say:focus { outline: none; }

/* ---- the ring ---------------------------------------------------------- */
/* Someone is calling you, and this is the whole screen saying so. Written
   directly under the gate below, and deliberately built out of the same three
   parts, because it is the same move: one dark field, one hard card, one gold
   hairline. The room only takes the whole screen for two things, and both of
   them are a person at a door.
   The field is TRANSLUCENT where the gate's is opaque, and that is the one
   difference that matters: at the gate you are not in the room yet, so there is
   nothing behind it. Here you are standing in it, so the room stays visible,
   dimmed and pushed back behind the person in front of you. A ring that painted
   the room out would be a phone app wearing the room's clothes. */

.ring {
  position: fixed;
  inset: 0;
  z-index: 90;                 /* over the world and the HUD, under the gate:
                                  a member who is not in the room cannot be rung */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(232, 180, 90, 0.10), transparent 60%),
    rgba(6, 6, 10, 0.88);
  animation: ringIn 140ms ease-out;
}
.ring:focus { outline: none; }
@keyframes ringIn { from { opacity: 0; } }

.ringCard {
  width: min(360px, 100%);
  padding: 24px 24px 18px;
  text-align: center;
  background: rgba(14, 14, 22, 0.97);
  border: 1px solid var(--line-hot);
  border-top: 1px solid var(--gold);      /* the gold hairline the notice wears */
  border-radius: 4px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(232, 180, 90, 0.06);
}

/* The caller, drawn from the sprite the whole room already sees them wearing.
   This is #lookPrev's frame on purpose: the mirror in the avatar picker is where
   this room had already decided how a person looks when you look straight at
   them, so the ring did not need to invent anything. No camera opens for this,
   ever: they have published nothing, and a face shown to someone who has not
   accepted is the exact violation the whole call design exists to refuse.

   The frame is also the ONLY thing on this card that moves, and that is the
   result of throwing the first version away. It had a ☎ glyph pulsing above the
   portrait, and rendered it was the one piece of the card that looked pasted on:
   an emoji, drawn by a font this room does not own, sitting over a world drawn
   pixel by pixel. It also said nothing that "is calling you" was not already
   saying two lines below it. So it is gone, and its job moved onto the person:
   the frame blinks, in two hard steps, in the same gold at the same cadence the
   conn dot has always used for "live, right now". The motion is on the caller,
   which is where a ring is actually coming from. */
.ringArt {
  width: 96px; height: 144px;
  image-rendering: pixelated;
  background: #05050a;
  border: 1px solid var(--gold);
  border-radius: 2px;
  animation: ringLive 1s steps(2, end) infinite;
}
@keyframes ringLive { 50% { border-color: var(--line); } }

.ringWho {
  margin: 14px 0 2px;
  font-size: 15px; font-weight: 700; letter-spacing: 0.18em;
  color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ringSub {
  margin: 0 0 18px;
  font-size: 12px; letter-spacing: 0.04em;
  color: var(--ink-dim);
}

.ringActions { display: flex; gap: 8px; }
.ringBtn {
  flex: 1 1 0;                 /* peers: the same width, forever, by construction */
  min-height: 46px;            /* a thumb, not a mouse */
  font: inherit; font-size: 12px; letter-spacing: 0.08em;
  background: #05050a;
  border: 1px solid var(--line-hot);
  border-radius: 2px;
  cursor: pointer;
}
.ringBtn.yes { color: var(--gold); border-color: var(--gold); }
.ringBtn.no { color: var(--ink); }
/* Note what is NOT here: no dimming of `no`, no fill on `yes`, no size
   difference. Gold means live in this room, not correct. */
.ringBtn:hover { background: #0d0d18; }
.ringBtn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.ringBtn:active { transform: translateY(1px); }

.ringNote {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 10px; line-height: 1.6;
  color: #6a6b82;
}
/* An iPhone has no Escape key, so on a touch device that half of the sentence is
   instructions for hardware that is not there. This room has already made this
   ruling once, about the speaker chip that WebKit could never have honoured: a
   platform that cannot do the thing must not grow a control that pretends to.
   The second half is the half that matters anyway, and it is true everywhere. */
@media (pointer: coarse) { .ringKey { display: none; } }

/* The phone, one-handed. The card sits low rather than centred so the buttons
   land under a thumb instead of in the middle of the screen, and the portrait
   gives up height first because the name is what identifies a caller. */
@media (max-height: 700px), (max-width: 420px) {
  .ring { align-items: flex-end; padding-bottom: max(24px, env(safe-area-inset-bottom)); }
  .ringArt { width: 72px; height: 108px; }
}
@media (prefers-reduced-motion: reduce) {
  .ring { animation: none; }
  .ringArt { animation: none; border-color: var(--gold); }
}

/* ---- the members-only front door -------------------------------------- */

.gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(232, 180, 90, 0.08), transparent 60%),
    linear-gradient(180deg, #07070c, #0b0b11 60%, #06060a);
}
.gateCard {
  width: min(440px, 100%);
  padding: 34px 30px 26px;
  text-align: center;
  background: rgba(14, 14, 22, 0.96);
  border: 1px solid var(--line-hot);
  border-radius: 4px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(232, 180, 90, 0.06);
}
.gateMark {
  width: 30px; height: 30px;
  margin: 0 auto 14px;
  background:
    linear-gradient(var(--gold), var(--gold)) 0 5px / 30px 3px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) 0 15px / 22px 3px no-repeat,
    linear-gradient(var(--cyan), var(--cyan)) 0 25px / 13px 3px no-repeat;
}
.gateWordmark {
  font-size: 12px; letter-spacing: 0.34em; font-weight: 700;
  color: var(--ink-dim);
  margin-bottom: 18px;
}
.gateCard h1 {
  margin: 0 0 10px;
  font-size: 20px; font-weight: 700; letter-spacing: 0.01em;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#gateMsg {
  margin: 0 auto 22px;
  max-width: 34ch;
  font-size: 13px; line-height: 1.6;
  color: var(--ink-dim);
}
.gateBtn {
  display: flex; justify-content: center;
  min-height: 44px;
  margin-bottom: 20px;
}
/* The way back for a tab the room asked to step out. Gold, because in this room
   gold is already the word for "this one is live", and coming back is the live
   choice on this screen. */
.gateBack {
  font: inherit;
  font-size: 13px;
  letter-spacing: 0.02em;
  padding: 10px 22px;
  color: #0b0b11;
  background: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 999px;
  cursor: pointer;
}
.gateBack:hover { filter: brightness(1.08); }
.gateBack:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.gateNote {
  margin: 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 11px; line-height: 1.6;
  color: #6a6b82;
}

@media (max-width: 560px) {
  .wordmark { display: none; }
  #log { max-height: 18vh; }
  .gateCard { padding: 28px 20px 22px; }
}


/* ---- the notice (hover the brand) ------------------------------------- */
/* Was painted on the canvas over the floor and followed the board around the
   room. It is chrome now: it hangs off the brand, it is hard-edged like every
   other panel here, and it never covers the world unless someone asks for it. */

.brand { position: relative; cursor: default; }
.brand:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.notice {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 40;
  min-width: 210px;
  padding: 7px 9px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 1px solid var(--gold);      /* the gold hairline, kept */
  font-size: 11px;
  letter-spacing: 0.04em;
  line-height: 1.6;
  white-space: nowrap;
}
.notice .nTitle { color: var(--gold); font-weight: 700; }
.notice .nStatus { color: var(--ink-dim); font-size: 10px; }
.notice .nStatus.hot { color: var(--ink); }
/* Where the rabbit is. The room answers it in the same quiet voice it answers
   "is anyone home", because that is what he is: a fact about the room, not a
   feature of the product. No gold, no weight, no dot that blinks. */
.notice .nLiam { color: var(--ink-dim); font-size: 10px; }
.notice .nTiers { margin-top: 5px; padding-top: 5px; border-top: 1px solid var(--line); }
.notice .nTier { color: #f2efe6; padding-left: 7px; position: relative; }
.notice .nTier::before {                 /* the gold bar per tier, kept */
  content: ''; position: absolute; left: 0; top: 3px; bottom: 3px; width: 3px;
  background: var(--gold);
}
.notice .nNote { margin-top: 4px; color: var(--ink-dim); font-size: 10px; }

/* ---- your voice and your face (PLAN-VIDEO wave V1) --------------------- */
/* Off is the resting state, and it is drawn as off: dim, with a hollow dot.
   Live is gold with a filled dot, because gold is already this room's word for
   "this is on" (the host lamp, the caret, the connection chip). A member must
   never have to wonder. */

.chip.av { color: var(--ink-dim); letter-spacing: 0.06em; }
.chip.av .dot {
  width: 6px; height: 6px;
  background: transparent;
  border: 1px solid var(--ink-dim);
}
.chip.av[data-live="1"] { color: var(--gold); border-color: var(--gold); }
.chip.av[data-live="1"] .dot { background: var(--gold); border-color: var(--gold); }

/* THE FAULT. A device that is genuinely on, whose track the room could not
   carry.

   This state was invisible until 2026-07-17 and it cost the product its one
   sentence. The failure was written to the chip's `title` and nowhere else: a
   tooltip, which needs a mouse and a hover, and which does not exist on the
   phone the bug was reported from. So a member stood in the room with a gold
   chip, three level bars dancing off his own real microphone, and not one pixel
   anywhere saying that his voice was reaching nobody. Reproduced by answering
   502 to every tracks/new: mic=true, publishing.audio=true, deaf=[], silence.

   Warn, not gold, and for the same reason "hear the room" is warn: gold means
   "this is on", and the room not carrying you is the opposite of on. But the
   chip keeps its live dot rather than going dark, because the mic IS on and the
   camera light IS lit; going dark would trade this lie for the mirror-image one.
   Live and faulted is exactly what it is: your device works, the room does not
   have it. The pulse is borrowed from the same place, to reach the member who is
   sitting perfectly still wondering why nobody is answering him. */
.chip.av[data-fault="1"] { color: var(--warn); border-color: var(--warn); }
.chip.av[data-fault="1"] .dot {
  background: var(--warn); border-color: var(--warn);
  animation: pulse 1s steps(2, end) infinite;
}
.chip.av[data-fault="1"]:hover { border-color: var(--warn); color: #fff; }

/* "hear the room": the browser refused to play a voice. Warn, not gold: gold is
   this room's word for "this is on", and a refusal is the opposite of on. Warn
   is already the word for "a thing that should be working is not" (the
   connection chip says offline in exactly this colour), which is precisely what
   this is. It borrows the connecting dot's pulse to catch the eye of a member
   who is sitting still, because a member who is sitting still is the only one
   this chip has to reach: anybody who walks or types fixes it without reading a
   word. */
.chip.hear { color: var(--warn); border-color: var(--warn); }
.chip.hear .dot {
  width: 6px; height: 6px;
  background: var(--warn); border: 1px solid var(--warn);
  animation: pulse 1s steps(2, end) infinite;
}
.chip.hear:hover { border-color: var(--warn); color: #fff; }

/* THE RECORD BUTTON. Not another av chip. During a live lecture the host hunted
   for it and could not find it: it was display:none unless he happened to be
   standing on the stage tiles, and even when shown it wore the same 24px grey
   grammar as mic/cam/screen and vanished among them. So it is deliberately
   louder than everything beside it: taller, a pill, a filled red dot and the
   word REC, and a red border it never loses. It is always on the host's HUD;
   off the stage it is dimmed (not hidden, never struck through) and the title
   carries the reason. Live: a pulsing red ring and the elapsed clock. */
.chip.rec {
  height: 30px; padding: 0 14px; gap: 8px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  border-radius: 999px;
  color: #ff6a6a;
  border: 1.5px solid #ff4d4d;
  background: rgba(255, 77, 77, 0.08);
}
.chip.rec .dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: #ff4d4d; border: none;
  box-shadow: 0 0 6px rgba(255, 77, 77, 0.7);
}
.chip.rec:hover { border-color: #ff8080; color: #ff8a8a; }
.chip.rec[data-host="0"] { cursor: default; }
/* Off the stage: still unmistakably a record button, plainly not armed yet. */
.chip.rec[data-can="0"] {
  opacity: 0.42; cursor: default;
  background: transparent;
}
.chip.rec[data-can="0"]:hover { border-color: #ff4d4d; color: #ff6a6a; }
/* Recording live: solid, a pulsing ring, the clock carried in the label. */
.chip.rec[data-live="1"] {
  color: #fff; border-color: #ff4d4d;
  background: rgba(255, 77, 77, 0.16);
  opacity: 1;
  animation: recring 1.6s ease-in-out infinite;
}
.chip.rec[data-live="1"] .dot { animation: recdot 1.2s ease-in-out infinite; }
/* Armed to stop: the next click ends the tape, so it says so and looks it. */
.chip.rec[data-arm="1"] {
  color: #fff; background: #ff4d4d; border-color: #ff9a9a;
  animation: none;
}
.chip.rec[data-arm="1"] .dot { background: #fff; box-shadow: none; animation: none; }
/* The upload fault still wins the colour, the amber the chunk path paints. */
.chip.rec[data-fault="1"] { color: var(--warn); border-color: var(--warn); background: rgba(232, 115, 90, 0.12); animation: none; }
.chip.rec[data-fault="1"] .dot { background: var(--warn); box-shadow: none; }
@keyframes recring {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 77, 77, 0.5); }
  50% { box-shadow: 0 0 0 6px rgba(255, 77, 77, 0); }
}
@keyframes recdot { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  .chip.rec[data-live="1"], .chip.rec[data-live="1"] .dot { animation: none; }
}

/* The self portrait and the voice mark, pinned over the canvas by the frame
   loop. They hang by their foot off the same head anchor the caret is drawn
   from, so they walk when the body walks. Never a click target: the world is
   underneath them. */
.rtcSelf {
  position: fixed;
  left: 0; top: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  pointer-events: none;
  will-change: transform;
}

/* Hard-edged, small, and framed in the room's own furniture: the 2px ink border
   and the 1px top rule are the name tag's language, one size up. No radius, no
   blur, no glow. The FRAME belongs to the pixel world; the face deliberately
   does not get pixelated, because the face is the one thing here whose fidelity
   is the entire point of walking over to someone. */
.rtcCam {
  position: relative;
  padding: 2px;                        /* the mat: this room prints its photographs */
  background: #f2efe6;                 /* the same parchment the speech bubble is cut from */
  border: 1px solid #14141f;           /* and the same ink hairline around it */
  line-height: 0;
}
.rtcCam::after {                       /* the top rule: parchment for members, gold for the host */
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0; height: 2px;
  background: #f2efe6;
}
.rtcCam[data-host="1"]::after { background: var(--gold); }
.rtcCam video {
  display: block;
  width: 64px; height: 48px;
  object-fit: cover;
  transform: scaleX(-1);               /* a mirror is what you expect of yourself */
  filter: saturate(0.85) contrast(1.05);   /* seated in the palette, not lied about */
  background: #0b0b11;
}

/* Mic on, camera off is a normal way to be in a room, not a broken way to be on
   camera: it gets its own mark rather than a black rectangle apologising. Three
   gold bars that move with your real level, quantised to whole pixels so they
   step like everything else here. */
.rtcMic {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 13px;
  padding: 1px 3px 2px;
  background: rgba(11, 11, 17, 0.92);
  border-top: 1px solid var(--gold);
}
.rtcMic i { width: 2px; height: 2px; background: var(--gold); }

/* The shared screen, for the audience. A face is small furniture over a head; a
   screen is the thing the room came to look at, so it is large and centred and
   framed in the room's own language: the 2px ink border and the parchment mat
   the portraits and speech bubbles are cut from, one size up. Auto-shown the
   moment a screen track arrives; a click toggles the full-viewport read. */
.rtcScreenStage {
  position: fixed;
  left: 50%;
  top: 72px;                              /* clear of the header */
  transform: translateX(-50%);
  width: min(68vw, 880px);
  max-width: calc(100vw - 24px);
  z-index: 5;
  padding: 3px;
  background: #f2efe6;
  border: 2px solid #14141f;
  line-height: 0;
  cursor: zoom-in;
  box-shadow: 0 8px 28px rgba(11, 11, 17, 0.45);
}
.rtcScreenStage::after {                  /* the gold top rule: this is the host's broadcast */
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0; height: 3px;
  background: var(--gold);
}
.rtcScreenStage video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
  background: #0b0b11;
}
.rtcScreenStage.max {
  top: 12px;
  width: calc(100vw - 24px);
  cursor: zoom-out;
}
