/* ChimeChat — minimal, calm, low-residue. Black / white / lime palette. */

:root {
  /* lime is constant across themes (buttons, own bubbles: black text on lime) */
  --lime: #a3e635;
  --lime-deep: #84cc16;
  --on-lime: #0a0a0a;
  /* dark theme (default): black background, white text */
  --bg: #0a0a0a;
  --ink: #f5f5f5;
  --ink-soft: #a3a3a3;
  --ink-faint: #6f6f6f;
  --accent: #a3e635;      /* lime as a TEXT/border color — readable on black */
  --accent-deep: #84cc16;
  --accent-soft: rgba(163, 230, 53, 0.12);
  --card: #161616;
  --line: #2a2a2a;
  /* Bubbles are theme-invariant: lime for your own, white for theirs, dark ink
     on both. In light mode the white bubble has no fill contrast against the
     white ground, so the 1px border below is what makes it read as a bubble —
     do not remove it. */
  --bubble-mine: #a3e635;
  --bubble-theirs: #ffffff;
  --bubble-ink: #141416;
  --bubble-mine-edge: rgba(101, 163, 13, 0.55);
  --alert: #ffffff;       /* export notices: bright white on black */
  --radius: 18px;
  --fade-ms: 747ms; /* dissolve-to-sparks at 0.75x */
  --msg-scale: 1;   /* user-adjustable message text size */
  font-size: 16px;
}

/* light theme: white background, black text (toggle in the chat header) */
body.light {
  --bg: #ffffff;
  --ink: #111111;
  --ink-soft: #52525b;
  --ink-faint: #8f8f97;
  --accent: #4d7c0f;      /* darker lime so text/borders stay readable on white */
  --accent-deep: #3f6212;
  --accent-soft: rgba(101, 163, 13, 0.10);
  --card: #fafafa;
  --line: #e4e4e7;
  /* Bubbles deliberately match the dark theme (see :root). The white received
     bubble is defined by its border here, not by its fill. */
  --bubble-mine: #a3e635;
  --bubble-theirs: #ffffff;
  --bubble-ink: #141416;
  --bubble-mine-edge: rgba(77, 124, 15, 0.65);
  --alert: #0a0a0a;       /* export notices: black on white */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Background animations removed (founder decision, 2026-07-19): the ambient
   mote canvas, the static radial glow, the room-entry veil field and the
   empty-room pulse are all gone. The ground is flat in both themes.
   Deletion sparks, the typing ✦ and the wordmark ✦ are deliberately kept. */
.ether { display: none !important; }

/* Content sits on a flat ground. */
.screen { height: 100%; position: relative; z-index: 1; }

/* Mobile browsers: track the real visible viewport (iOS Safari's toolbar
   collapses/expands), not the static 100%. */
@supports (height: 100dvh) {
  .screen { height: 100dvh; }
}

/* display rules below would otherwise override the hidden attribute */
[hidden] { display: none !important; }

/* ------------------------------------------------------------ landing */
#landing {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.landing-card {
  width: min(420px, 100%);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 24px;
  padding: 36px 32px 28px;
  box-shadow: 0 24px 60px -30px rgba(163, 230, 53, 0.18);
  text-align: center;
}

.logo {
  font-family: 'Fraunces', serif;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.logo-mark { color: var(--accent); }

.beta-tag {
  display: inline-block;
  vertical-align: super;
  margin-left: 2px;
  padding: 2px 8px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tagline {
  margin: 6px 0 4px;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.95rem;
}

.support-line {
  margin: 0 0 14px;
  color: #ffffff;
  font-size: 0.85rem;
  font-style: italic;
}

/* Offered after leaving, only while the old room is verifiably occupied */
.rejoin-bar {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px dashed var(--accent);
  border-radius: 14px;
  background: var(--accent-soft);
}

.rejoin-text {
  margin: 0 0 10px;
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 600;
}

.rejoin-actions { display: flex; gap: 8px; justify-content: center; }
#rejoinMembershipLink,
#goneMembershipLink { display: block; margin: 10px auto 0; }

.explain {
  margin: 0 0 24px;
  color: var(--ink-soft);
  font-size: 0.875rem;
  line-height: 1.55;
}

.explain-home {
  margin-bottom: 6px;
  text-align: center;
}

.learn-more-link {
  display: inline-block;
  margin: 0 0 20px;
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.learn-more-link:hover { color: var(--ink); }

.field {
  display: block;
  text-align: left;
  margin-bottom: 14px;
}

.field span {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  margin-bottom: 6px;
}

input[type="text"], input[type="date"], input[type="time"] {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  outline: none;
  transition: border-color 120ms;
}

input[type="text"]::placeholder { color: var(--ink-faint); }

input[type="text"]:focus, input[type="date"]:focus, input[type="time"]:focus { border-color: var(--accent); }

/* Safari/Chrome render the native calendar/clock glyph in the input's own
   text color by default, which reads as invisible on a dark background. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(0.6);
  cursor: pointer;
}
body.light input[type="date"]::-webkit-calendar-picker-indicator,
body.light input[type="time"]::-webkit-calendar-picker-indicator {
  filter: none;
}

.btn {
  width: 100%;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: transform 100ms, background 120ms, border-color 120ms;
}

.btn:hover { border-color: var(--accent); }
.btn:active { transform: scale(0.98); }

.btn.primary {
  background: var(--lime);
  border-color: var(--lime);
  color: var(--on-lime);
}

.btn.primary:hover { background: var(--lime-deep); border-color: var(--lime-deep); }

.divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0;
  color: var(--ink-faint);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.divider::before, .divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

.join-row {
  display: flex;
  gap: 10px;
}

.join-row input {
  flex: 1;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  font-weight: 600;
}

.join-row .btn { width: auto; padding-inline: 22px; }

.landing-error {
  margin: 14px 0 0;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.85rem;
}

.joining-status {
  margin: 6px 0 0;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.9rem;
}

.present-line {
  color: var(--accent);
  font-weight: 700;
  letter-spacing: 0.06em;
}

.about-link {
  margin: 26px 0 0;
  padding: 6px 10px;
  border: none;
  background: transparent;
  color: var(--accent);
  font: inherit;
  font-size: 0.78rem;
  cursor: pointer;
  transition: color 0.15s;
}
.about-link:hover { color: #ffffff; }
/* Stacked account/about links (landing + invite footer). */
.account-links { display: flex; flex-direction: column; align-items: center; gap: 2px; margin-top: 26px; }
.account-links .about-link { margin: 0; }
.account-links + .legal-links { margin-top: 8px; }
.invite-footer .about-link { margin: 0; }

/* ---------------------------------------------------- Terms gate (paid) */
.tos-gate {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(10, 10, 10, 0.6);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.tos-card {
  width: 100%;
  max-width: 520px;
  max-height: 94%;
  overflow-y: auto;
  background: var(--card);
  border: 2px solid var(--accent);
  border-radius: 22px;
  padding: 22px 20px 18px;
  display: flex;
  flex-direction: column;
  gap: 13px;
  animation: tos-sheet-up 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.tos-decline {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-faint);
}
.tos-decline:hover { border-color: var(--ink-faint); color: var(--ink-soft); }
@keyframes tos-sheet-up { from { transform: translateY(40px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .tos-card { animation: none; } }
.tos-card h3 {
  font-family: var(--font-display, inherit);
  font-size: 1.2rem;
  font-weight: 700;
  display: flex;
  gap: 8px;
  align-items: center;
}
.tos-star { color: var(--accent); }
.tos-plain { display: flex; flex-direction: column; gap: 9px; }
.tos-pl {
  display: flex;
  gap: 9px;
  font-size: 0.82rem;
  color: var(--ink-soft, var(--ink-faint));
  line-height: 1.45;
}
.tos-pl > span:first-child { color: var(--accent); flex: none; font-size: 0.72rem; margin-top: 2px; }
.tos-pl strong { color: var(--ink); }
.tos-dob { display: flex; gap: 8px; }
.tos-dob .field { flex: 1; }
.tos-dob select {
  width: 100%;
  background: var(--bg-input, var(--card));
  border: 1px solid var(--line);
  border-radius: 11px;
  color: var(--ink);
  font: inherit;
  font-size: 0.92rem;
  padding: 11px 10px;
}
.tos-dob select:focus { border-color: var(--accent); outline: none; }
.tos-denied {
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.85rem;
  padding: 9px 6px;
  border: 1px dashed var(--line);
  border-radius: 12px;
}
.tos-agreeline {
  font-size: 0.7rem;
  color: var(--ink-faint);
  text-align: center;
  line-height: 1.5;
}
.tos-agreeline a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

/* ---- membership screen (reuses .tos-gate / .tos-card) ---- */
.member-lead { font-size: 0.9rem; color: var(--ink-soft, var(--ink-faint)); line-height: 1.5; }
.member-lead strong { color: var(--ink); }
.member-msg {
  font-size: 0.82rem; color: var(--ink-soft, var(--ink-faint)); line-height: 1.5;
  border: 1px dashed var(--line); border-radius: 10px; padding: 11px 13px;
}
.member-msg a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.member-msg.ok { border-color: var(--accent); }
.member-plan {
  border: 1px solid var(--line); border-radius: 14px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px; text-align: center;
}
.member-price {
  font-family: var(--font-display, inherit); font-size: 1.9rem; font-weight: 700; color: var(--ink);
}
.member-price span { font-size: 0.95rem; font-weight: 400; color: var(--ink-faint); }
.member-plan-note { font-size: 0.78rem; color: var(--ink-faint); }
.member-fine { font-size: 0.7rem; color: var(--ink-faint); text-align: center; line-height: 1.5; }
.member-fine a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

/* Membership + account modals (About-style card) */
.member-card { display: flex; flex-direction: column; gap: 10px; max-height: 86vh; max-height: 86dvh; overflow-y: auto; }
.member-benefits { display: flex; flex-direction: column; gap: 8px; text-align: left; margin: 2px 0 4px; }
.member-benefits p { font-size: 0.84rem; color: var(--ink-soft); line-height: 1.45; position: relative; padding-left: 20px; margin: 0; }
.member-benefits p span { color: var(--accent); position: absolute; left: 0; }
.member-benefits strong, .member-benefits em { color: var(--ink); font-style: normal; }
.member-promo-row { display: flex; gap: 8px; }
.member-promo-row input {
  flex: 1;
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 11px;
  color: var(--ink);
  font: inherit;
  font-size: 0.82rem;
  padding: 10px 12px;
  text-transform: uppercase;
}
.member-promo-row input:focus { border-color: var(--accent); outline: none; }
.member-promo-row button {
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  border-radius: 999px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  padding: 10px 18px;
  cursor: pointer;
}
.member-card .about-link { margin: 0 auto; }

/* Member mark (paid): the brand ✦ after a member's name in the chat
   header. Positive marking only — guests carry no mark. */
/* Paid member mark: a native ✦ star sized to match the peer avatar (30px),
   with an always-on "Member" micro-label to its right in the same accent
   colour. No pill, no tap behaviour — it just states what it is. */
.member-mark {
  display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
  color: var(--accent); line-height: 1; margin-left: 2px;
}
.member-mark svg { width: 1.15rem; height: 1.15rem; display: block; } /* matches the e2e lock icon */
.member-label {
  font-size: 0.6rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--accent); white-space: nowrap;
}

/* Account chip (paid): top-right of the landing — ghost person glyph when
   signed out, lime ring + initial/photo when signed in. */
.acct-chip {
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + 14px);
  /* Track the centered start-card column (420px) on wide screens instead
     of drifting to the viewport edge; 16px inset on small screens. */
  right: max(16px, calc((100% - 420px) / 2));
  z-index: 30;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  background: var(--card);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  overflow: hidden;
  box-shadow: 0 0 14px rgba(163, 230, 53, 0.18);
}
.acct-chip:hover { background: rgba(163, 230, 53, 0.12); }
.acct-chip.in { border-color: var(--accent); color: var(--accent); }
.acct-chip img { width: 100%; height: 100%; object-fit: cover; }
.acct-chip span { font-weight: 800; font-size: 0.95rem; line-height: 1; }
.acct-chip svg { width: 19px; height: 19px; }

/* Device-local profile section in the account sheet */
.prof-head { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-faint); margin-top: 6px; text-align: left; }
.prof-note { text-align: left; }
.prof-tog { display: flex; gap: 8px; align-items: center; font-size: 0.8rem; color: var(--ink-soft); cursor: pointer; text-align: left; }
.prof-tog input { accent-color: var(--accent); }
#profNameInput {
  width: 100%;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 11px;
  color: var(--ink);
  font: inherit;
  font-size: 0.85rem;
  padding: 9px 12px;
}
#profNameInput:focus { border-color: var(--accent); outline: none; }
#profPhotoHint { text-align: left; }

/* Membership Account sheet: comfortable reading sizes and contrast —
   the sheet is an operating surface, not fine print. */
#accountSheet .member-msg { font-size: 0.95rem; color: var(--ink); }
#accountSheet .member-fine { font-size: 0.82rem; color: var(--ink-soft); }
#accountSheet .prof-tog { font-size: 0.9rem; color: var(--ink); }
#accountSheet .prof-head { font-size: 0.78rem; color: var(--ink-soft); }
#accountSheet .gp-row { font-size: 0.85rem; }
#accountSheet .gp-row strong { font-size: 0.88rem; }

/* Sign-in "where are you" choice: personal device vs shared computer */
.signin-where { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 12px; text-align: left; }
.where-opt { display: flex; gap: 9px; align-items: flex-start; font-size: 0.85rem; color: var(--ink); line-height: 1.4; cursor: pointer; }
.where-opt input { accent-color: var(--accent); margin-top: 3px; flex: 0 0 auto; }
.where-opt .where-sub { color: var(--ink-faint); font-size: 0.76rem; font-weight: 400; }

/* "What lives where" transparency block in the account sheet */
.lives-where { display: flex; flex-direction: column; gap: 8px; text-align: left; }
.lives-where p { font-size: 0.8rem; color: var(--ink-soft); line-height: 1.5; margin: 0; }
.lives-where .lw-k { display: block; color: var(--ink); font-weight: 700; margin-bottom: 2px; }

/* Quiet one-tap profile prompts on the landing (paid, ignorable) */
.save-hint { display: block; margin: 4px auto 0; font-size: 0.76rem; }

/* Guest-pass list rows in the account sheet */
.gp-divider { border-top: 1px solid var(--line); margin: 4px 0 2px; }
.gp-cancel {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-faint);
  border-radius: 50%;
  width: 20px;
  height: 20px;
  font: inherit;
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
  margin-left: 6px;
  vertical-align: middle;
}
.gp-cancel:hover { border-color: #fb7185; color: #fb7185; }
.gp-list { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; }
.gp-row { display: flex; justify-content: space-between; gap: 10px; font-size: 0.74rem; color: var(--ink-soft); }
.gp-row strong { color: var(--ink); letter-spacing: 0.04em; }
.gp-row.dead { opacity: 0.55; }
.gp-row.dim { opacity: 0.7; }
.gp-row.dead strong { text-decoration: line-through; }

/* Invite-card wordmark links home (the conventional front door). */
.logo-link { color: inherit; text-decoration: none; }
.logo-link:hover { color: var(--accent); }

/* Landing CTA in non-member state: the free-to-join promise under the
   honest button, and the sign-in path for members on a new device. */
.member-cta-note { font-size: 0.76rem; color: var(--accent); text-align: center; line-height: 1.45; margin: 8px auto 0; max-width: 34ch; }
.member-signin { display: block; margin: 6px auto 0; font-size: 0.76rem; }

/* "How it works" strip in the membership modal — the 2-step process,
   stated before anything is asked for. */
.member-steps { display: flex; flex-direction: column; gap: 8px; text-align: left; }
.member-step { display: flex; gap: 10px; align-items: flex-start; font-size: 0.8rem; color: var(--ink-soft); line-height: 1.45; }
.member-step strong { color: var(--ink); }
.step-n {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 0.72rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}
.member-email-row input { text-transform: none; }

/* Post-leave conversion wording (paid, non-members only): the question
   reads as quiet body text; only the action carries the accent. Used by
   the rejoin-bar link and the post-leave pitch card. */
.aside-q { color: var(--ink-faint); font-weight: 400; }
#leavePitchBar .rejoin-text .aside-q { display: block; margin-bottom: 2px; color: var(--ink); font-weight: 600; }

.legal-links {
  text-align: center;
  font-size: 0.68rem;
  color: var(--ink-faint);
  margin-top: 2px;
}
.legal-links a {
  color: var(--ink-faint);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal-links a:hover { color: var(--accent); }

/* Invite-page footer: About + legal (+ membership on paid), stacked. */
.invite-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* ------------------------------------------------------------- about */
.leave-card.about-card {
  text-align: left;
  max-width: min(440px, 100%);
  display: flex;
  flex-direction: column;
  max-height: min(640px, 88vh);
}

.about-head { text-align: center; margin-bottom: 14px; }
.about-mark { font-size: 1.5rem; color: var(--accent); }
.about-title { font-weight: 700; font-size: 1.05rem; margin-top: 2px; }
.about-sub { color: var(--ink-faint); font-size: 0.72rem; margin-top: 2px; }

.about-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3px;
  padding: 3px;
  background: rgba(127, 127, 127, 0.1);
  border-radius: 10px;
}
.about-tabs-row2 { grid-template-columns: repeat(2, 1fr); margin-top: 3px; }

.about-tab {
  border: none;
  background: transparent;
  color: var(--ink-faint);
  font: inherit;
  font-size: 0.74rem;
  font-weight: 600;
  padding: 7px 4px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
}
.about-tab.active { background: var(--lime); color: var(--on-lime); }

.about-body {
  margin-top: 14px;
  overflow-y: auto;
  min-height: 0;
  flex: 1;
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.about-p { margin: 0 0 12px; }
.about-p-soft { color: var(--ink-faint); }
.about-pull {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--lime);
  background: rgba(163, 230, 53, 0.08);
  border-radius: 0 10px 10px 0;
  color: var(--ink);
  font-weight: 600;
}
.about-byline {
  margin: 16px 0 0;
  color: var(--ink-faint);
  font-size: 0.7rem;
  text-align: center;
  line-height: 1.5;
}
.about-byline span { color: var(--accent); font-weight: 600; }

.about-feat, .about-step {
  display: flex;
  gap: 10px;
  margin: 0 0 12px;
  align-items: flex-start;
}
.about-feat strong, .about-step strong { color: var(--ink); }
.about-feat-icon { font-size: 1.05rem; line-height: 1.4; color: var(--accent); flex: none; }
.about-feat-icon .ci { width: 24px; height: 24px; }
.about-chip .ci { width: 26px; height: 26px; color: var(--accent); }
.invite-title .ci { width: 22px; height: 22px; vertical-align: -0.32em; color: var(--accent); }
.inline-ico { display: inline-flex; vertical-align: -0.28em; color: var(--accent); }
.inline-ico .ci { width: 18px; height: 18px; }
.about-step-num {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--lime);
  color: var(--on-lime);
  font-weight: 700;
  font-size: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
}
.about-lime { color: var(--accent); font-style: normal; font-weight: 600; }
.about-red { color: #f87171; font-style: normal; font-weight: 600; }
body.light .about-red { color: #b91c1c; }

.about-chip-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin: 0 0 14px;
  text-align: center;
}
.about-chip {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 2px;
  font-size: 0.68rem;
  color: var(--ink-faint);
  line-height: 1.7;
}
.about-note { margin: 0 0 12px; }
.about-note strong { color: var(--ink); }

.about-beta-badge {
  margin: 0 0 14px;
  padding: 8px 12px;
  border: 1px solid rgba(251, 191, 36, 0.4);
  background: rgba(251, 191, 36, 0.1);
  border-radius: 10px;
  color: #d97706;
  font-weight: 600;
  font-size: 0.76rem;
  text-align: center;
}
.about-legal-h {
  margin: 14px 0 4px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink);
}
.about-legal-h:first-of-type { margin-top: 0; }
.about-legal-p { margin: 0 0 4px; font-size: 0.78rem; }
.about-legal-p strong { color: var(--ink); }
.about-agree {
  margin: 16px 0 0;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.06);
  font-size: 0.76rem;
}
.about-agree span { color: var(--accent); font-weight: 700; }
.about-legal-footer {
  margin: 14px 0 0;
  color: var(--ink-faint);
  font-size: 0.68rem;
  text-align: center;
}

/* -------------------------------------------------------------- chat */
#chat {
  display: flex;
  flex-direction: column;
  max-width: 760px;
  margin: 0 auto;
  border-inline: 1px solid var(--line);
  /* Translucent so the ether glows faintly behind the conversation, while
     header/composer keep their own solid --card for crisp controls. */
  background: color-mix(in srgb, var(--card) 82%, transparent);
  backdrop-filter: blur(2px);
}

.peer-topbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 16px 6px;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}

.peer-name {
  font-weight: 700;
  color: var(--ink);
  max-width: 60vw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: center;
}

/* End-to-end encryption badge: the native lock-with-star icon, sitting
   right beside the peer's name where the security applies. */
.peer-e2e {
  flex: none;
  display: inline-flex;
  align-items: center;
  color: var(--accent);
}
.peer-e2e .ci { width: 1.15rem; height: 1.15rem; }

.peer-status-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.peer-status-dot.online {
  background: #22c55e;
  animation: dot-blink 1.4s ease-in-out infinite;
}

.peer-status-dot.offline { background: #ef4444; }

@keyframes dot-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

@media (prefers-reduced-motion: reduce) {
  .peer-status-dot.online { animation: none; }
}

.chat-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}

.peer-info {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
}

.peer-texts { flex: 1; min-width: 0; }

.peer-avatar-btn {
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 50%;
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.peer-avatar {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line);
}

.peer-status {
  font-size: 0.75rem;
  color: var(--ink-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-actions { display: flex; gap: 16px; margin-left: auto; } /* roomier — sound/theme/size are easy to mis-tap */

.chip {
  border: 1px solid var(--line);
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 999px;
  padding: 6px 12px;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.chip.subtle { background: transparent; color: var(--ink-faint); }
/* Now that these chips carry drawn icons (sound / text-size / theme),
   use the stronger --ink-soft so the line-art reads clearly in both
   themes — comfortably above the 3:1 graphical-object contrast floor. */
.chip.subtle:has(svg.ci) { color: var(--ink-soft); }

#themeBtn, #sizeBtn { display: inline-flex; align-items: center; justify-content: center; }

/* Leaving is a real action — it vacates your seat — so it reads like one. */
.chip.danger {
  background: transparent;
  border-color: rgba(248, 113, 113, 0.55);
  color: #f87171;
  font-weight: 700;
}

.chip.danger:hover {
  background: #dc2626;
  border-color: #dc2626;
  color: #ffffff;
}

body.light .chip.danger { color: #b91c1c; border-color: rgba(185, 28, 28, 0.5); }
body.light .chip.danger:hover { background: #dc2626; border-color: #dc2626; color: #ffffff; }

/* ------------------------------------------------------ invite bar */
/* One slim line while you're alone — the full options live in a dialog
   so they never crowd the conversation. */
.invite-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 10px 18px 0;
  padding: 8px 10px 8px 14px;
  border: 1px dashed var(--accent);
  border-radius: 999px;
  background: var(--accent-soft);
}

.invite-bar-text {
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.invite-bar .btn.small { flex: 0 0 auto; }

.invite-card { text-align: left; }

.invite-card .invite-row { margin-top: 12px; }

.invite-done { margin-top: 16px; }

.invite-title {
  font-weight: 700;
  color: var(--accent);
  font-size: 0.9rem;
}

.invite-sub {
  margin: 4px 0 10px;
  color: var(--ink-soft);
  font-size: 0.78rem;
  line-height: 1.5;
}

.invite-row {
  display: flex;
  gap: 8px;
}

.invite-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.btn.small {
  width: auto;
  padding: 9px 14px;
  font-size: 0.8rem;
  white-space: nowrap;
}

.share-label {
  margin: 16px 0 8px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  text-align: left;
}

.share-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(78px, 1fr));
  gap: 8px;
}

.share-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 11px 6px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--accent-soft);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
  -webkit-tap-highlight-color: transparent;
}

.share-btn:hover { border-color: var(--accent); }
.share-btn:active { transform: scale(0.94); }

.share-ic { display: inline-flex; align-items: center; justify-content: center; font-size: 1.35rem; line-height: 1; }
.share-lb { font-size: 0.72rem; color: var(--ink-faint); }

@media (prefers-reduced-motion: reduce) {
  .share-btn { transition: none; }
  .share-btn:active { transform: none; }
}

.invite-qr-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 16px;
}

.invite-qr {
  flex: 0 0 auto;
  width: 116px;
  height: 116px;
  padding: 6px;
  background: #ffffff; /* QR needs a light quiet zone in both themes */
  border-radius: 12px;
  border: 1px solid var(--line);
}

.invite-qr svg { display: block; width: 100%; height: 100%; }

.invite-qr-hint {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.78rem;
  line-height: 1.5;
  max-width: 220px;
}

@media (max-width: 480px) {
  .invite-row { flex-wrap: wrap; }
  .invite-row input { flex-basis: 100%; }
  .invite-qr { width: 96px; height: 96px; }
}

/* ----------------------------------------------------------- messages */
.messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px 18px 8px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  scroll-behavior: smooth;
}

.empty-state {
  margin: auto;
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.875rem;
  line-height: 1.6;
}

/* Static ✦ — the empty-room pulse was removed with the other background
   animations. The mark stays; it just no longer breathes. */
.empty-mark {
  font-size: 1.9rem;
  color: var(--accent);
  opacity: 0.6;
}

.empty-line {
  transition: opacity 0.6s ease;
  min-height: 2.8em;
}
.empty-line.swapping { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .empty-line { transition: none; }
}

.msg {
  max-width: 78%;
  padding: 10px 14px;
  border-radius: var(--radius);
  line-height: 1.45;
  font-size: calc(0.95rem * var(--msg-scale));
  overflow-wrap: anywhere;
  white-space: pre-wrap; /* preserve Shift+Enter line breaks */
  animation: pop-in 220ms ease;
}

@keyframes pop-in {
  from { opacity: 0; transform: translateY(6px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.msg.mine {
  align-self: flex-end;
  /* Full lime with dark ink — 12.2:1, AAA. */
  background: var(--bubble-mine);
  color: var(--bubble-ink);
  border: 1px solid var(--bubble-mine-edge);
  border-bottom-right-radius: 6px;
}

/* Your own messages simply appear — no launch, no pop-in (founder decision,
   2026-07-19). Guarded with :not(.fading) so a vanishing bubble still runs
   its dissolve/scatter animation. */
.msg.mine:not(.fading) {
  animation: none;
}

.msg.theirs {
  align-self: flex-start;
  background: var(--bubble-theirs);
  color: var(--bubble-ink);
  border: 1px solid var(--line);
  border-bottom-left-radius: 6px;
}

/* Speech-balloon tail — TEXT messages only (attachments keep the square
   capsule look). More rounded corners + a comic-balloon tail at the bottom,
   pointing left for received and right for sent. The tail is drawn by
   extending the bubble fill (::before) and carving its outer side with the
   ground colour (::after) — the classic mask technique. */
.msg.text-bubble { position: relative; border-radius: 20px; }
.msg.mine.text-bubble { border-bottom-right-radius: 20px; }
.msg.theirs.text-bubble { border-bottom-left-radius: 20px; }
.msg.text-bubble::before,
.msg.text-bubble::after { content: ""; position: absolute; bottom: -1px; height: 20px; pointer-events: none; }
/* received: tail on the lower-left */
.msg.theirs.text-bubble::before {
  left: -7px; width: 20px; background: var(--bubble-theirs);
  border-bottom-right-radius: 16px 15px;
}
.msg.theirs.text-bubble::after {
  left: -16px; width: 17px; background: var(--bg);
  border-bottom-right-radius: 14px;
}
/* sent: tail on the lower-right (mirror) */
.msg.mine.text-bubble::before {
  right: -7px; width: 20px; background: var(--bubble-mine);
  border-bottom-left-radius: 16px 15px;
}
.msg.mine.text-bubble::after {
  right: -16px; width: 17px; background: var(--bg);
  border-bottom-left-radius: 14px;
}

/* No-key / undecryptable placeholder: native lock icon inline before the note. */
.msg.locked-msg { font-style: italic; opacity: 0.9; }
.locked-ico { display: inline-block; }
.locked-ico .ci { width: 1.05em; height: 1.05em; vertical-align: -0.2em; }

.msg .meta {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 5px;
  font-size: calc(0.65rem * var(--msg-scale));
  opacity: 0.75;
}

.msg .tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(77, 124, 15, 0.14);
  color: #3f6212;
  font-weight: 600;
}

.msg.mine .tag.answered-tag { animation: pop-in 220ms ease; }

.sysnote {
  align-self: center;
  text-align: center;
  /* --ink-soft (not -faint): these notes explain what just happened —
     they must be comfortably readable on both themes */
  color: var(--ink-soft);
  /* scales with the header's text-size (Tt) control, like bubbles do */
  font-size: calc(0.78rem * var(--msg-scale));
  padding: 2px 10px;
  animation: pop-in 220ms ease;
}

.sysnote.wipe { color: var(--accent); }

/* informational notices (why a send was blocked, encryption failures,
   saved-file confirmations…): a quiet bordered card in full-strength ink —
   these explain something the user needs to actually read, in either theme,
   at whatever text size they chose */
.sysnote.notice {
  color: var(--ink);
  font-size: calc(0.84rem * var(--msg-scale));
  font-weight: 500;
  line-height: 1.45;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  max-width: min(520px, 92%);
}

.sysnote.export {
  color: var(--alert);
  font-weight: 600;
}

/* presence: who's here and who's gone — meant to be noticed */
.sysnote.presence {
  color: var(--accent);
  font-weight: 700;
  font-size: calc(0.82rem * var(--msg-scale));
}

.sysnote.presence.out { color: var(--ink-soft); }

/* ------------------------------------------------------- attachments */
.attach-img {
  display: block;
  max-width: min(260px, 100%);
  border-radius: 12px;
  margin-bottom: 6px;
  /* keep previews legible even when the image matches the bubble color */
  border: 2px solid rgba(0, 0, 0, 0.3);
}

.msg.theirs .attach-img { border-color: rgba(0, 0, 0, 0.25); }

.file-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.07);
  border: 1px solid rgba(0, 0, 0, 0.16);
}

.file-icon { font-size: 1.4rem; }

.file-name {
  font-weight: 600;
  font-size: calc(0.85rem * var(--msg-scale));
  overflow-wrap: anywhere;
}

.file-size {
  font-size: 0.7rem;
  opacity: 0.75;
}

.save-btn {
  display: block;
  margin-top: 8px;
  /* fixed dark-olive on the white bubbles, same in both themes */
  border: 1px solid #4d7c0f;
  border-radius: 9px;
  background: rgba(163, 230, 53, 0.18);
  color: #3f6212;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 6px 12px;
  cursor: pointer;
}

.save-btn:hover:not(:disabled) { background: var(--lime); border-color: var(--lime); color: var(--on-lime); }

.save-btn:disabled {
  border-color: rgba(0, 0, 0, 0.18);
  background: transparent;
  color: #6f6f6f;
  cursor: default;
}

/* View + Save side by side under a file bubble */
.file-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.file-actions .save-btn { margin-top: 8px; }
.save-btn .ci { width: 1.3em; height: 1.3em; vertical-align: -0.3em; margin-right: 2px; }

.attach-img { cursor: zoom-in; }

.attach-audio {
  display: block;
  width: min(250px, 100%);
  margin-bottom: 6px;
}

/* Deletion preview: while the composer holds a draft, the messages that
   the deletion rule will remove on send dim out — the rule becomes visible
   BEFORE it fires, not after. */
.msg, .sysnote { transition: opacity 250ms ease, filter 250ms ease; }

.msg.doomed, .sysnote.doomed {
  opacity: 0.35;
  filter: grayscale(0.7);
}

/* Informational notices soften only slightly under the doom preview —
   they often explain the situation the user is IN right now (e.g. why a
   send was just blocked) and must stay readable while a draft is typed. */
.sysnote.notice.doomed {
  opacity: 0.85;
  filter: none;
}

/* -------------------------------------------------------- profile photo */
.avatar-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0 14px;
}

.avatar-pick {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 9px 12px;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: transparent;
  color: var(--ink-faint);
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.avatar-pick:hover { color: var(--accent); border-color: var(--accent); }

.avatar-thumb {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line);
}

.avatar-clear {
  flex: none;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-faint);
  font: inherit;
  cursor: pointer;
}
.avatar-clear:hover { color: #f87171; border-color: #f87171; }

.photo-card {
  max-width: min(440px, 92vw);
  text-align: center;
}

.photo-card img {
  width: 100%;
  border-radius: 20px;
  border: 1px solid var(--line);
  display: block;
}

.photo-caption {
  margin-top: 10px;
  color: #fff;
  font-weight: 600;
  font-size: 0.9rem;
}

/* ----------------------------------------------------------- QR scanner */
.scan-btn {
  width: 100%;
  margin-top: 10px;
  font-size: 0.85rem;
}

.day-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 12px 0;
}

.day-chips button {
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink-soft);
  border-radius: 999px;
  padding: 8px 13px;
  font: inherit;
  font-size: 0.78rem;
  cursor: pointer;
}

.day-chips button.selected {
  background: var(--lime);
  border-color: var(--lime);
  color: var(--on-lime);
  font-weight: 700;
}

.schedule-summary {
  margin: 10px 0 4px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  min-height: 1.3em;
}

.schedule-summary.invalid { color: #f87171; }

body.light .schedule-summary.invalid { color: #b91c1c; }

.schedule-hint {
  margin: 10px 0 0;
  /* This is the one thing a scheduler must not miss: the link is the only
     way back in. Bold lime, sized up — impossible to skim past. */
  color: var(--accent);
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1.5;
  text-align: left;
}

#scheduledInfo .invite-row { margin-top: 4px; }

.scanner {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  flex-direction: column;
  background: rgba(0, 0, 0, 0.92);
}

.scanner-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  padding-top: max(14px, env(safe-area-inset-top));
}

.scanner-title { color: #f5f5f5; font-size: 0.85rem; font-weight: 600; }

.scanner .chip { background: #1f1f1f; color: #f5f5f5; border-color: #333; }

.scanner-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.scanner-stage video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.scan-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(240px, 70vw);
  height: min(240px, 70vw);
  border: 3px solid var(--lime, #a3e635);
  border-radius: 22px;
  pointer-events: none;
}

.scan-status {
  margin: 0;
  padding: 14px 16px calc(16px + env(safe-area-inset-bottom));
  text-align: center;
  color: #a3a3a3;
  font-size: 0.85rem;
}

.scan-status .btn { width: auto; margin-top: 8px; display: inline-block; }

/* ---------------------------------------------------- leave/burn dialog */
.leave-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.leave-card {
  width: min(380px, 100%);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 26px 24px calc(22px + env(safe-area-inset-bottom));
  text-align: center;
  animation: pop-in 220ms ease;
}

/* Sparks of the ✦ mark rise and dissolve — the room vanishing into the
   ether, not going up in flames. */
.leave-ether {
  position: relative;
  height: 64px;
}

.leave-ether span {
  position: absolute;
  left: 50%;
  bottom: 4px;
  color: var(--accent);
  animation: ether-rise 2.6s ease-in infinite;
  opacity: 0;
}

.leave-ether .e1 { font-size: 1.9rem; margin-left: -14px; }
.leave-ether .e2 { font-size: 1.1rem; margin-left: 16px; animation-delay: 0.9s; }
.leave-ether .e3 { font-size: 0.8rem; margin-left: -34px; animation-delay: 1.7s; }

@keyframes ether-rise {
  0% { transform: translateY(0) scale(1); opacity: 0; }
  18% { opacity: 1; }
  100% { transform: translateY(-44px) scale(0.55); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .leave-ether span { animation: none; opacity: 1; }
  .leave-ether .e2, .leave-ether .e3 { opacity: 0.5; }
}

.vanish-note {
  margin: 0 0 16px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 0.85rem;
  font-style: italic;
  animation: pop-in 400ms ease;
}

.leave-title {
  margin: 10px 0 8px;
  font-family: Fraunces, Georgia, serif;
  font-size: 1.35rem;
  color: var(--ink);
}

.leave-text {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.85rem;
  line-height: 1.6;
}

.leave-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 18px;
}

.btn.burn {
  background: #dc2626;
  border-color: #dc2626;
  color: #ffffff;
  font-weight: 700;
}

.btn.burn:hover { background: #b91c1c; border-color: #b91c1c; }

/* --------------------------------------------------------- file viewer */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  background: rgba(0, 0, 0, 0.88);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.viewer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 16px;
  padding-top: max(12px, env(safe-area-inset-top));
}

.viewer-name {
  color: #f5f5f5;
  font-size: 0.85rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.viewer-actions { display: flex; gap: 8px; flex: 0 0 auto; }

/* chips sit on the dark backdrop regardless of theme */
.viewer .chip { background: #1f1f1f; color: #f5f5f5; border-color: #333; }
.viewer .chip.subtle { background: transparent; color: #a3a3a3; }

.viewer-body {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12px calc(12px + env(safe-area-inset-bottom));
}

.viewer-body img,
.viewer-body video {
  max-width: 100%;
  max-height: 100%;
  border-radius: 10px;
  object-fit: contain;
}

.viewer-body iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 10px;
  background: #fff;
}

/* The document sheet layers ABOVE every modal/gate (60–80): it opens
   from inside them ("Full details", "Billing policy"), slides over, and
   closing reveals the surface you came from — context preserved. */
.doc-viewer { z-index: 90; }

/* Document viewer frame matches the legal pages' own ground so opening
   in dark mode doesn't flash white before the page paints. */
#docViewerFrame { background: #faf9f5; }
@media (prefers-color-scheme: dark) {
  #docViewerFrame { background: #0a0a0a; }
}

.viewer-body audio { width: min(420px, 90%); }

.viewer-body pre {
  max-width: 100%;
  max-height: 100%;
  overflow: auto;
  margin: 0;
  padding: 18px;
  border-radius: 10px;
  background: #161616;
  color: #e5e5e5;
  font-size: 0.8rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.viewer-fallback {
  color: #a3a3a3;
  font-size: 0.85rem;
  text-align: center;
  padding: 24px;
}

/* HTML viewer: a Page ⇄ Source toggle + a safety banner, above a stage that
   holds either the sandboxed page or its source. */
.viewer-body:has(.viewer-htmlbar) { flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 8px; padding-top: 8px; }
.viewer-htmlbar { flex: none; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.viewer-seg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.viewer-seg button { border: 0; background: transparent; color: var(--ink-soft); font: inherit; font-size: 0.78rem; font-weight: 600; padding: 6px 14px; cursor: pointer; }
.viewer-seg button.on { background: var(--lime); color: var(--on-lime); }
.viewer-safety { font-size: 0.7rem; color: var(--ink-faint); flex: 1; min-width: 160px; }
.viewer-safety .s { color: var(--accent); }
.viewer-htmlstage { flex: 1; min-height: 0; display: flex; }
.viewer-htmlframe { width: 100%; height: 100%; border: 0; border-radius: 10px; background: #fff; }
.viewer-htmlstage .viewer-src { flex: 1; }
.viewer-src { max-width: 100%; max-height: 100%; overflow: auto; margin: 0; padding: 16px; border-radius: 10px; background: #161616; color: #e5e5e5; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.76rem; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.viewer-mapframe { width: 100%; height: 100%; border: 0; border-radius: 10px; background: #e9e9e9; }

/* ----------------------------------------------------- voice recording */
.staged-bar.recording { border-color: #f87171; }

.rec-dot {
  color: #f87171;
  display: inline-flex; align-items: center;
  animation: rec-pulse 1.1s ease-in-out infinite;
}
.rec-dot .ci { width: 18px; height: 18px; }

.rec-dot.paused { animation: none; opacity: 0.4; }

@keyframes rec-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

/* --------------------------------------------------------- attach menu */
.attach-menu {
  position: absolute;
  bottom: 100%;
  left: 12px;
  margin-bottom: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  z-index: 20;
}

.attach-menu button {
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 0.85rem;
  padding: 10px 14px;
  border-radius: 9px;
  cursor: pointer;
  text-align: left;
}

.attach-menu button:hover { background: var(--accent-soft); color: var(--accent); }

/* --------------------------------------------------- staged attachment */
.staged-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 14px;
  padding: 8px 12px;
  border: 1px dashed var(--accent);
  border-radius: 12px;
  background: var(--accent-soft);
  font-size: 0.8rem;
}

/* Full-width second row inside a staged bar (audio preview, map preview) */
.staged-wide { flex-basis: 100%; min-width: 0; }

/* ------------------------------------------------- custom audio player */
.audio-player {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 220px;
  padding: 6px 0;
}

.ap-btn {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--card);
  color: var(--ink);
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ap-btn.play { background: var(--lime); border-color: var(--lime); color: var(--on-lime); }
.ap-btn:hover { border-color: var(--accent); }
.ap-btn:active { transform: scale(0.94); }
.ap-btn .ci { width: 20px; height: 20px; }

/* Voice note · waveform — stylized bars that light up on playback. Bars use
   currentColor so they read on any surround (dark composer or light bubble). */
.wave {
  flex: 1 1 auto; min-width: 60px; height: 30px; cursor: pointer;
  display: flex; align-items: center; gap: 2px;
}
.wave i {
  flex: 1 1 0; min-width: 2px; max-width: 4px; border-radius: 2px;
  background: currentColor; opacity: 0.24; transition: opacity 90ms;
}
.wave i.on { opacity: 0.95; }

.ap-time {
  flex: 0 0 auto;
  font-size: 0.7rem;
  color: currentColor; opacity: 0.65;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* In a message bubble the player inherits the dark bubble ink, so its
   transport is a dark circle and its bars are dark on the light bubble. */
.att-voice { color: var(--bubble-ink); }
.att-voice .audio-player { min-width: 0; width: 100%; }
.att-voice .ap-btn { background: rgba(0,0,0,0.06); border-color: rgba(0,0,0,0.18); color: var(--bubble-ink); }
.att-voice .ap-btn.play { background: var(--bubble-ink); border-color: var(--bubble-ink); color: var(--bubble-mine); }
.att-voice .ap-btn.play .ci path[fill] { fill: var(--bubble-mine); }

/* ------------------------------------------------ invite dialog code */
.invite-code-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 12px 0 6px;
}

.invite-code-label {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
}

.invite-code {
  font-size: 1.45rem;
  font-weight: 700;
  letter-spacing: 0.35em;
  margin-right: -0.35em; /* balance the trailing letter-space */
  color: var(--lime);
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------- permission dialog */
.perm-steps {
  margin: 0 0 6px;
  padding-left: 20px;
  text-align: left;
  color: var(--ink);
  font-size: 0.88rem;
  line-height: 1.6;
}

.perm-steps li { margin-bottom: 6px; }
.perm-steps li strong { color: var(--accent); }

.staged-name {
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.staged-size { color: var(--ink-faint); font-size: 0.72rem; }

.staged-hint {
  margin-left: auto;
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

.staged-remove {
  border: none;
  background: transparent;
  color: var(--ink-faint);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  padding: 2px 6px;
}

.staged-remove:hover { color: var(--alert); }

/* ------------------------------------------------------------ typing */
/* In-thread typing bubble — the classic three bouncing dots, styled like
   an incoming message. Not a screen node: it's presence, not content, so
   the deletion rule never touches it. */
.typing-bubble {
  padding: 12px 16px;
  min-width: 0;
}

.typing-bubble .dots { display: inline-flex; align-items: center; gap: 4px; }

.dots i {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45); /* on the white typing bubble */
  animation: dot-bounce 1.2s ease-in-out infinite;
}

.dots i:nth-child(2) { animation-delay: 0.15s; }
.dots i:nth-child(3) { animation-delay: 0.3s; }

@keyframes dot-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }
  30% { transform: translateY(-4px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .dots i { animation: dot-fade 1.2s ease-in-out infinite; }
  @keyframes dot-fade { 0%, 60%, 100% { opacity: 0.35; } 30% { opacity: 1; } }
}

/* The vanishing — reply-triggered removal, made visible. Content blurs,
   lifts, and dissolves into the ether (a ✦ spark rises off each bubble),
   then the node is removed from the DOM. Nothing is retained after. */
.fading {
  animation: dissolve var(--fade-ms) cubic-bezier(0.4, 0, 0.9, 0.4) forwards;
  pointer-events: none;
  position: relative;
}

@keyframes dissolve {
  0% { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
  35% { opacity: 0.85; filter: blur(1px); }
  100% { opacity: 0; transform: translateY(-18px) scale(0.9); filter: blur(7px); }
}

.fading::after {
  content: "✦";
  position: absolute;
  top: -6px;
  right: 12px;
  color: var(--accent);
  font-size: 0.85rem;
  opacity: 0;
  animation: spark-rise var(--fade-ms) ease-out forwards;
}

@keyframes spark-rise {
  0% { opacity: 0; transform: translateY(2px); }
  30% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-26px) scale(0.6); }
}

/* Signature vanish for the Clear action: instead of the quiet dissolve, the
   whole screen's content scatters — bubbles swell, spin off, and throw two
   ✦ sparks in opposite directions before disappearing. */
.fading.scatter {
  animation: scatter var(--fade-ms) cubic-bezier(0.3, 0, 0.2, 1) forwards;
}

@keyframes scatter {
  0% { opacity: 1; transform: translate(0, 0) scale(1) rotate(0); filter: blur(0); }
  30% { opacity: 0.9; transform: scale(1.06) rotate(-1.5deg); filter: blur(1px); }
  100% { opacity: 0; transform: translate(10px, -26px) scale(1.14) rotate(4deg); filter: blur(9px); }
}

.fading.scatter::after {
  content: "✦";
  position: absolute;
  top: -4px;
  right: 14px;
  color: var(--accent);
  font-size: 0.9rem;
  opacity: 0;
  animation: spark-fly-right var(--fade-ms) ease-out forwards;
}
.fading.scatter::before {
  content: "✦";
  position: absolute;
  top: -4px;
  left: 14px;
  color: var(--accent);
  font-size: 0.75rem;
  opacity: 0;
  animation: spark-fly-left var(--fade-ms) ease-out forwards;
}

@keyframes spark-fly-right {
  0% { opacity: 0; transform: translate(0, 2px); }
  30% { opacity: 1; }
  100% { opacity: 0; transform: translate(22px, -30px) scale(0.5) rotate(40deg); }
}
@keyframes spark-fly-left {
  0% { opacity: 0; transform: translate(0, 2px); }
  30% { opacity: 1; }
  100% { opacity: 0; transform: translate(-22px, -34px) scale(0.5) rotate(-40deg); }
}

/* A one-time caption the first time a send clears the screen — teaches the
   whole idea instead of letting the vanish startle a newcomer. */
.sysnote.onboard {
  color: var(--accent);
  font-weight: 600;
  font-size: calc(0.9rem * var(--msg-scale));
  padding: 8px 14px;
  border: 1px solid rgba(163, 230, 53, 0.3);
  border-radius: 999px;
  background: rgba(163, 230, 53, 0.07);
  animation: pop-in 320ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .fading { animation: simple-fade 220ms ease forwards; }
  .fading::after, .fading::before { content: none; }
  .fading.scatter { animation: simple-fade 220ms ease forwards; }
  @keyframes simple-fade { to { opacity: 0; } }
}

/* ---------------------------------------------------------- composer */
.composer {
  position: relative; /* anchors the attach menu */
  display: flex;
  align-items: flex-end; /* buttons hug the bottom as the field grows */
  gap: 8px;
  padding: 12px 14px;
  border-top: 1px solid var(--line);
  background: var(--card);
}

.composer textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  /* max(16px, …) prevents iOS Safari's zoom-on-focus at small text sizes */
  font-size: max(16px, calc(1rem * var(--msg-scale)));
  line-height: 1.4;
  padding: 13px 16px;
  min-height: 50px;
  max-height: 140px;
  outline: none;
  transition: border-color 120ms;
  overflow-y: auto;
}

.composer textarea::placeholder { color: var(--ink-faint); }

.composer textarea:focus { border-color: var(--accent); }

.send-btn {
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 50px;
  height: 50px;
  padding: 0;
  cursor: pointer;
  transition: transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1), background 0.15s, box-shadow 0.15s, border-color 0.15s;
}

.send-btn:hover { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 3px 16px rgba(163, 230, 53, 0.32); }
.send-btn:active { transform: scale(0.92); }
.send-btn.sent-pulse { animation: sent-pulse 360ms ease-out; }

@keyframes sent-pulse {
  0% { box-shadow: 0 0 0 0 rgba(163, 230, 53, 0.5); }
  100% { box-shadow: 0 0 0 16px rgba(163, 230, 53, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .send-btn { transition: background 0.15s; }
  .send-btn:active { transform: none; }
  .send-btn.sent-pulse { animation: none; }
}

.plus-btn {
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 50px;
  height: 50px;
  padding: 0;
  font-size: 1.4rem;
  font-weight: 400;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.plus-btn:hover { color: var(--accent); border-color: var(--accent); }

.chat-footer {
  /* keep clear of the iPhone home-indicator area */
  padding: 8px 16px calc(10px + env(safe-area-inset-bottom, 0px));
  text-align: center;
  font-size: 0.65rem;
  color: var(--ink-faint);
  border-top: 1px dashed var(--line);
}

/* --------------------------------------------- per-device optimization */

/* Touch devices (phones/tablets): comfortable ≥44px tap targets */
@media (pointer: coarse) {
  .chip { padding: 10px 14px; font-size: 0.8rem; }
  .save-btn { padding: 11px 16px; font-size: 0.8rem; }
  .staged-remove { padding: 8px 12px; font-size: 1.05rem; }
  .join-row .btn, .btn.small { min-height: 46px; }
}

/* Phones */
@media (max-width: 660px) {
  #chat { border-inline: none; }
  .msg { max-width: 86%; }
  .messages { padding: 14px 12px 8px; }
  .chat-header { padding: 10px 12px; gap: 6px; }
  .header-actions { gap: 10px; }
  .chip-extra { display: none; } /* " someone" label collapses to ✦ invite */
  .composer { padding: 10px 10px calc(10px + env(safe-area-inset-bottom, 0px) / 2); gap: 6px; }
  .send-btn, .plus-btn { width: 46px; height: 46px; }
  .composer textarea { padding: 13px 12px; }
  .invite-bar { margin: 10px 12px 0; }
  .landing-card { padding: 28px 22px 22px; }
}

/* Phone-width screens: every header chip must fit on one line — shrink
   instead of wrapping or spilling off the edge. */
@media (max-width: 480px) {
  .chat-header { gap: 6px; }
  .header-actions { gap: 8px; }
  .peer-status { font-size: 0.66rem; }
  /* text chips (CLEAR / INVITE / LEAVE) stay compact; icon chips keep
     their thumb-sized circles from the earlier rule */
  .chip { padding: 6px 8px; font-size: 0.66rem; }
}

/* Large desktop monitors: let the conversation breathe */
@media (min-width: 1200px) {
  #chat { max-width: 880px; }
  .msg { max-width: 70%; }
}

/* ================================================================== */
/* The ether — approved motion set (dissolve 0.75x, crystallize 0.75x,
   veil 1.0x, wordmark 1.0x, three-star typing 0.75x) + icon family.   */

/* icon family sizing: inline SVGs inherit the button's text color */
.ci { width: 1.15em; height: 1.15em; vertical-align: -0.24em; flex: none; }
.plus-btn .ci { width: 1.5em; height: 1.5em; vertical-align: middle; }
.send-btn .ci { width: 2.9em; height: 2.9em; vertical-align: middle; } /* 2x per request */
.attach-menu .ci { margin-right: 6px; }

/* Chime-ripple arrival (0.75x): a received bubble lands and a single ring
   rings outward from it — the app's namesake at the moment of arrival.
   Replaces the old crystallize/glass-sweep. Own sent messages get NO effect. */
.msg.chime-in { animation: chime-land var(--cd, 320ms) cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes chime-land {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.chime-ring {
  position: fixed; /* viewport space — matches the dissolve-spark canvas */
  border: 2px solid var(--accent);
  border-radius: 50%;
  pointer-events: none;
  z-index: 61; /* just above the fx canvas (z-index 60) */
  animation: chime-ring var(--rd, 1013ms) ease-out forwards;
}
@keyframes chime-ring {
  from { transform: scale(1); opacity: 0.55; }
  to   { transform: scale(9); opacity: 0; }
}

#chat { position: relative; }
@keyframes settle {
  from { opacity: 0; transform: translateY(16px) scale(0.97); filter: blur(4px); }
  to   { opacity: 1; transform: none; filter: none; }
}

/* Typing indicator — three lime stars, PINNED just above the input area
   (not in the scrolling message list). Stars ~1.5x their former size. */
.typing-area { flex: none; padding: 5px 14px 1px; }
.typing-area[hidden] { display: none; }
.typing-pill {
  display: inline-flex; align-items: center;
  background: var(--bubble-theirs); color: var(--bubble-ink);
  border: 1px solid var(--line);
  border-radius: 18px; border-bottom-left-radius: 6px;
  padding: 7px 15px;
}
.tstars { display: inline-flex; align-items: center; gap: 9px; }
.tstars span {
  color: var(--lime-deep);
  font-size: 1.4em;   /* ~1.5x the previous 0.95em */
  line-height: 1;
  animation: starpulse 2000ms ease-in-out infinite; /* 0.75x pace */
  text-shadow: 0 0 8px rgba(163, 230, 53, 0.55);
}
.tstars span:nth-child(2) { animation-delay: 400ms; }
.tstars span:nth-child(3) { animation-delay: 800ms; }
@keyframes starpulse {
  0%, 100% { opacity: 0.25; transform: scale(0.7) rotate(0deg); }
  50%      { opacity: 1; transform: scale(1.15) rotate(45deg); }
}

/* wordmark entrance: letters settle in, the star crystallizes last */
.logo .wm-l, .logo.wm-play .logo-mark { display: inline-block; }
.logo.wm-play .wm-l { opacity: 0; animation: wm-in 770ms ease both; }
.logo.wm-play .logo-mark {
  opacity: 0;
  animation: wm-star 1100ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: 1210ms;
}
@keyframes wm-in {
  from { opacity: 0; transform: translateY(8px); filter: blur(4px); }
  to   { opacity: 1; transform: none; filter: none; }
}
@keyframes wm-star {
  0%   { opacity: 0; transform: scale(0.2) rotate(-90deg); filter: blur(4px) brightness(3); }
  60%  { opacity: 1; transform: scale(1.35) rotate(10deg); filter: blur(0) brightness(1.8); }
  100% { opacity: 1; transform: scale(1) rotate(0); filter: none; }
}

@media (prefers-reduced-motion: reduce) {
  .msg.chime-in, .chime-ring,
  .tstars span,
  .logo.wm-play .wm-l, .logo.wm-play .logo-mark { animation: none !important; }
  .logo.wm-play .wm-l, .logo.wm-play .logo-mark { opacity: 1; }
  .chime-ring { display: none; }
}

/* ============================================================== */
/* Header chip legibility: the drawn icons need beefier strokes at
   chip size, and the icon-only chips (sound / theme / text-size)
   need real thumb-sized targets on phones.                        */

.chip svg.ci {
  width: 1.5em;
  height: 1.5em;
}
/* CSS stroke-width beats the SVG attribute: thicken the line-art at
   chip scale so it never renders hairline. Fill-only star paths have
   stroke:none and are unaffected. */
.chip svg.ci * { stroke-width: 3.4; }

@media (max-width: 660px) {
  /* Icon-only chips become fixed circular targets at the 44px
     accessibility minimum, with full-strength ink. */
  #soundBtn, #themeBtn, #sizeBtn {
    width: 44px;
    height: 44px;
    min-width: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--ink);
  }
  #soundBtn .chip-extra { display: none; }
  #soundBtn svg.ci, #themeBtn svg.ci, #sizeBtn svg.ci {
    width: 22px;
    height: 22px;
  }
}
@media (max-width: 480px) {
  #soundBtn, #themeBtn, #sizeBtn { width: 40px; height: 40px; min-width: 40px; }
  #soundBtn svg.ci, #themeBtn svg.ci, #sizeBtn svg.ci { width: 20px; height: 20px; }
}
/* Narrow phones (375–410px): tighten the action row just enough to keep a
   comfortable margin from the screen edge — circles to 38px, snug gaps. */
@media (max-width: 410px) {
  .chat-header { padding-inline: 10px; gap: 5px; }
  .header-actions { gap: 6px; }
  #soundBtn, #themeBtn, #sizeBtn { width: 38px; height: 38px; min-width: 38px; }
  .chip { padding: 6px 7px; }
}
/* Very narrow phones (<=360px): only here do we allow a graceful wrap as
   a last resort — the action row is now just CLEAR + five buttons, so it
   fits one line on any modern phone (>=375px). */
@media (max-width: 360px) {
  .chat-header { flex-wrap: wrap; row-gap: 6px; }
  .header-actions { flex-wrap: wrap; row-gap: 6px; justify-content: flex-end; }
}

/* ---------------------------------------------------- link preview */
/* A URL in a message becomes a preview card built purely from the URL
   itself — no fetching, no tracking; nothing leaves the device until
   the user chooses to click. Opens in a new tab. */
.msg a.msg-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  word-break: break-all;
}
.link-card {
  display: block;
  margin-top: 8px;
  padding: 10px 12px;
  border: 1px solid rgba(163, 230, 53, 0.45);
  border-radius: 12px;
  background: rgba(163, 230, 53, 0.08);
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  max-width: 100%;
}
.link-card:hover { border-color: var(--lime-deep); background: rgba(163, 230, 53, 0.14); }
.link-card .lc-domain {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  font-size: calc(0.88rem * var(--msg-scale));
  color: #3f6212;
}
.link-card .lc-domain .lc-star { color: #4d7c0f; font-size: 0.8em; }
.link-card .lc-url {
  margin-top: 2px;
  font-size: calc(0.72rem * var(--msg-scale));
  color: rgba(20, 20, 22, 0.6);
  word-break: break-all;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.link-card .lc-hint {
  margin-top: 6px;
  font-size: calc(0.68rem * var(--msg-scale));
  font-weight: 600;
  color: #4d7c0f;
}

/* ------------------------------------------------- server notice bar */
/* The countdown/broadcast banner: the invite-bar slot, two moods.
   Update countdown = amber, sticky. Broadcast = lime, dismissible. */
.notice-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 16px 0;
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
}
.notice-bar.update {
  border: 1px dashed #d97706;
  background: rgba(217, 119, 6, 0.12);
  color: #f59e0b;
}
body.light .notice-bar.update {
  border-color: #b45309;
  background: rgba(180, 83, 9, 0.08);
  color: #92400e;
}
.notice-bar.update.danger {
  border-color: #ef4444;
  background: rgba(239, 68, 68, 0.12);
  color: #f87171;
}
body.light .notice-bar.update.danger {
  border-color: #b91c1c;
  background: rgba(185, 28, 28, 0.07);
  color: #b91c1c;
}
.notice-bar.info {
  border: 1px dashed var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}
.notice-bar span:first-child { flex: 1; }
.notice-dismiss {
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  padding: 2px 6px;
  flex: none;
}

/* ==================================================================== */
/* UNIFORM ATTACHMENTS — "one bubble size for everything" (2026-07-19/20).
   Every attachment EXCEPT a voice note is a fixed-height "capsule row": a
   native TYPE icon (never an image preview), the name, a kind+size line, and
   a ··· options button. The picture only appears in the full-screen viewer.
   Voice notes are the sole exception — an inline waveform player. */

.msg .att-uni { width: 236px; max-width: 100%; }

/* -- the capsule row -- */
.att-row { display: flex; align-items: center; gap: 9px; min-width: 0; }
.att-cap { height: 52px; }
.att-thumb {
  width: 44px; height: 44px; border-radius: 10px; flex: none;
  display: grid; place-items: center; overflow: hidden; position: relative;
  background: rgba(0, 0, 0, 0.10); color: var(--bubble-ink);
  border: 0; padding: 0; font-family: inherit;
}
.att-thumb .ci { width: 26px; height: 26px; }
.att-info { flex: 1; min-width: 0; }
.att-name {
  font-size: calc(0.82rem * var(--msg-scale)); font-weight: 600; color: var(--bubble-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.att-sub {
  font-size: calc(0.68rem * var(--msg-scale)); color: #5b5b52;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.att-kind {
  display: inline-block; font-size: 0.54rem; font-weight: 800; letter-spacing: 0.07em;
  text-transform: uppercase; border-radius: 5px; padding: 1px 5px; margin-right: 5px;
  background: rgba(0, 0, 0, 0.12); color: #3f4030; vertical-align: 1px;
}
.att-dots {
  flex: none; border: 0; background: rgba(0, 0, 0, 0.08); color: var(--bubble-ink);
  width: 32px; height: 28px; border-radius: 8px; cursor: pointer;
  display: grid; place-items: center; font-family: inherit;
}
.att-dots .ci { width: 22px; height: 22px; }
.att-voice .att-dots { align-self: center; margin-left: 2px; }
.att-dots:focus-visible, button.att-thumb:focus-visible {
  outline: 2px solid var(--accent-deep); outline-offset: 2px;
}
.att-locked .att-thumb { background: rgba(0, 0, 0, 0.18); }

/* -- attachment action sheet: copy / save / view -- */
.att-veil {
  position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, 0.45);
  opacity: 0; transition: opacity 180ms ease;
}
.att-veil.show { opacity: 1; }
.att-sheet {
  position: fixed; left: 50%; bottom: 0; z-index: 61;
  width: min(420px, calc(100% - 16px)); transform: translate(-50%, 110%);
  background: var(--card); border: 1px solid var(--line);
  border-radius: 18px 18px 0 0; padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
.att-sheet.show { transform: translate(-50%, 0); }
.att-sheet .as-head { display: flex; align-items: center; gap: 10px; padding: 2px 4px 11px; border-bottom: 1px solid var(--line); }
.att-sheet .as-head .att-thumb { width: 40px; height: 40px; }
.att-sheet .as-head .att-thumb .ci { width: 24px; height: 24px; }
.att-sheet .as-name { font-size: 0.85rem; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.att-sheet .as-sub { font-size: 0.7rem; color: var(--ink-faint); }
.att-sheet .as-btns { display: flex; flex-direction: column; gap: 7px; margin-top: 11px; }
.att-sheet button {
  width: 100%; border: 1px solid var(--line); background: transparent; color: var(--ink);
  font: inherit; font-size: 0.9rem; font-weight: 600; padding: 11px 14px; border-radius: 12px; cursor: pointer;
  display: flex; align-items: center; gap: 11px; text-align: left;
}
.att-sheet button .ci { width: 22px; height: 22px; flex: none; }
.att-sheet button.as-primary { background: var(--lime); border-color: var(--lime); color: var(--on-lime); }
.att-sheet button:disabled { opacity: 0.55; cursor: default; }
.att-sheet .as-note { font-size: 0.66rem; color: var(--ink-faint); text-align: center; margin-top: 10px; }
.att-sheet .as-note .s { color: var(--accent); }

/* Viewer bar action chips: icon + label */
.viewer .chip .vb-ico { display: inline-flex; vertical-align: -0.28em; }
.viewer .chip .vb-ico .ci { width: 17px; height: 17px; }
.viewer .chip[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .att-veil, .att-sheet { transition: none !important; }
}
