:root {
  /*
   * A near-black base with a violet cast rather than a neutral grey.
   *
   * Pure #000 makes every surface above it look like a separate window, and
   * neutral greys next to a purple accent read as dirty. Tinting the whole
   * scale towards the accent is what makes the dark feel deliberate instead of
   * merely unlit.
   */
  /*
   * Paltalk's palette: a light interface with one strong blue.
   *
   * The whole scheme rests on the blue being the only saturated colour. Panels
   * are white, the page behind them is a barely-there grey so those panels read
   * as raised, and every divider is faint - close enough to the background that
   * it separates without drawing a line you notice. Add a second bright colour
   * and the blue stops meaning "this is the thing to press".
   */
  /*
   * Near-black with a magenta-to-violet accent.
   *
   * The reference gets its look from restraint: one gradient, used sparingly,
   * against a background that is almost but not quite black. The surfaces are
   * barely lighter than the page - a few points of luminance - so panels read as
   * edges rather than as boxes, and the accent is the only thing on screen with
   * any saturation. Lighten the greys or add a second bright colour and it turns
   * into an ordinary dark theme.
   */
  --bg: #08070c;
  --surface: #0e0d14;
  --surface-2: #14121c;
  --surface-3: #1c1926;
  --line: #221f2e;
  --line-strong: #322d43;
  --text: #f5f2fa;
  --muted: #9b93ac;

  /* Gender tints lifted for a dark page, and kept away from the accent's own
     range so a name never reads as a button. */
  --male: #6fb8ff;
  --female: #ff8ad4;
  --couple: #b98cff;
  --other: #98a0b0;
  --online: #3ddc84;

  /* The brand gradient runs magenta into violet; --accent is its midpoint, used
     wherever a single flat colour is needed. */
  --accent: #d43ce0;
  --accent-2: #7c4dff;
  --accent-hot: #ff2fb3;
  --accent-deep: #a020c8;
  --accent-soft: #1e1230;
  --danger: #ff4d68;

  --grad: linear-gradient(135deg, var(--accent-hot) 0%, var(--accent) 48%, var(--accent-2) 100%);

  /*
   * On a near-black page a drop shadow does nothing - there is nothing darker to
   * cast onto. Depth here comes from a faint coloured glow instead, which is
   * also what gives the reference its neon feel.
   */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow-md: 0 4px 18px rgba(0, 0, 0, .55);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, .65);
  --glow: 0 0 24px rgba(212, 60, 224, .28);
  --glow-hot: 0 6px 26px rgba(255, 47, 179, .38);

  --radius: 14px;
  --bar: 56px;
  --shell: 620px;
  /* Landing background. Swap this one line to change the hero image. */

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

/* The UA rule for [hidden] is display:none, but any author display rule beats
   it. .screen and .composer both set display, so hidden must be forced here or
   every screen renders at once. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

body { overflow: hidden; }

input, textarea, select, button { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: var(--accent); }

.ic {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

/* ---------- screens ---------- */

.screen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  max-width: var(--shell);
  margin: 0 auto;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
}

.screen--overlay {
  z-index: 20;
  animation: slide-in .18s ease-out;
}

@keyframes slide-in {
  from { transform: translateX(18px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .screen--overlay { animation: none; }
}

/* ---------- join ---------- */

.screen--join { overflow-y: auto; display: block; }

.join {
  max-width: 420px;
  margin: 0 auto;
  padding: 40px 20px calc(40px + env(safe-area-inset-bottom));
}

.join__head { margin-bottom: 28px; }

.brand {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
}

.brand span { color: var(--accent); }

.join__lead {
  margin: 10px 0 0;
  color: var(--muted);
  font-size: 15px;
}

.join__note {
  margin: 14px 0 0;
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
}

.form { display: flex; flex-direction: column; gap: 16px; }

.field { display: flex; flex-direction: column; gap: 7px; }
.field--age { width: 96px; }
.field--grow { flex: 1; }
.row { display: flex; gap: 12px; }

.field__label {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.field__label em {
  font-style: normal;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  opacity: .7;
}

.field input,
.field select,
.field textarea {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 13px 14px;
  outline: none;
  width: 100%;
  resize: none;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--accent);
}

.segment {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 5px;
}

.segment__btn {
  background: none;
  border: 0;
  border-radius: 8px;
  padding: 9px 4px;
  font-size: 14px;
  color: var(--muted);
}

.segment__btn.is-active {
  background: var(--surface);
  color: var(--accent);
  font-weight: 700;
  box-shadow: var(--shadow-sm);
}

.photo-pick {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 108px;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--muted);
  overflow: hidden;
  position: relative;
  cursor: pointer;
}

.photo-pick__hint { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.photo-pick img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.form__error {
  margin: 0;
  color: var(--danger);
  font-size: 14px;
}

/* ---------- buttons ---------- */

.btn {
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: 12px;
  padding: 12px 16px;
  font-weight: 600;
}

.btn--primary {
  background: linear-gradient(135deg, var(--accent) 0%, #5a0bd8 100%);
  border-color: transparent;
  color: #fff;
  font-weight: 700;
}
.btn--primary:hover { box-shadow: 0 6px 18px rgba(29, 161, 228, .32); }
.btn--primary:disabled { opacity: .55; }
.btn--block { width: 100%; }
.btn--ghost { background: none; }
.btn--sm { padding: 8px 12px; font-size: 13px; }
/* Needs its own fill: white text with no background of its own was invisible
   the moment the page went light. */
.btn--danger { background: var(--danger); border-color: transparent; color: #fff; }
.btn--danger:hover { background: #c93a50; }

/* ---------- tabs ---------- */

.tabs {
  display: flex;
  height: var(--bar);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  flex: none;
}

.tab {
  flex: 1;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
  position: relative;
}

.tab.is-active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 650; }
.tab span { display: none; }

@media (min-width: 420px) {
  .tab span { display: inline; }
}

.badge {
  position: absolute;
  top: 9px;
  left: 50%;
  margin-left: 4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

/* ---------- panes ---------- */

/* main column holds the header, tabs, ad slot and the scrolling panes */
.main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* only this part scrolls, so the ad slot stays pinned under the menu */
.panes { flex: 1; min-height: 0; position: relative; }

.pane {
  display: none;
  position: absolute;
  inset: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.pane.is-active { display: block; }

/* ---------- advertising ---------- */

.adslot {
  flex: none;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  overflow: hidden;
  display: block;
}

.adslot iframe {
  border: 0;
  display: block;
  width: 100%;
  margin: 0 auto;
  max-width: 970px;
}

/* ---------- desktop sidebar ---------- */

.sidebar { display: none; }

@media (min-width: 900px) {
  /* Wider than before: the two-column room needs the room, and 1180px left the
     cams squeezed once the 250px sidebar had taken its share. */
  #view-app { max-width: 1700px; flex-direction: row; }

  .sidebar {
    display: flex;
    flex-direction: column;
    width: 250px;
    flex: none;
    border-right: 1px solid var(--line);
    background: var(--surface);
    padding: 16px 12px;
  }

  /* the in-column header and tab bar are the mobile chrome; hide on desktop */
  .main > .topbar,
  .main > .tabs { display: none; }

  .sidebar__brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 8px 16px;
    gap: 8px;
  }

  .sidenav { display: flex; flex-direction: column; gap: 4px; }

  .sidenav__item {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 12px 14px;
    border: 0;
    border-radius: 11px;
    background: none;
    color: var(--muted);
    font-size: 15.5px;
    font-weight: 600;
    text-align: left;
    position: relative;
  }

  .sidenav__item:hover { background: var(--surface-2); color: var(--accent); }
  .sidenav__item.is-active {
    background: linear-gradient(135deg, var(--accent) 0%, #5f1ab8 100%);
    color: #fff;
  }
  .sidenav__item .ic { width: 21px; height: 21px; }

  .badge--inline {
    position: static;
    margin-left: auto;
    top: auto;
    left: auto;
  }

  .sidebar__banner {
    margin-top: auto;
    padding-top: 16px;
    display: flex;
    justify-content: center;
  }

  .sidebar__banner iframe { border: 0; display: block; width: 100%; max-width: 300px; }
}

@media (min-width: 900px) {
  /* Overlays (profile, chat, snap) sit over the main column, not the whole
     window, so the sidebar stays put and visible.

     The app box is centered at up to 1180px. Its left edge is at
     max(0px, (100vw - 1180px) / 2); the main column starts 250px past that. */
  .screen--overlay, .screen--snap {
    max-width: none;
    margin: 0;
    left: calc(max(0px, (100vw - 1180px) / 2) + 250px);
    right: max(0px, (100vw - 1180px) / 2);
    border-right: 1px solid var(--line);
  }
}

.toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg);
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--line);
}

.toolbar__top {
  display: flex;
  align-items: center;
  gap: 10px;
}

.toolbar__search-btn {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.toolbar__search-btn.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }

.search {
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 0 12px;
  color: var(--muted);
  margin-top: 10px;
}

.search input {
  flex: 1;
  background: none;
  border: 0;
  outline: none;
  padding: 11px 0;
  color: var(--text);
}

.search__clear {
  flex: none;
  background: none;
  border: 0;
  color: var(--muted);
  display: flex;
  align-items: center;
  padding: 4px;
}

.chips { display: flex; gap: 7px; overflow-x: auto; scrollbar-width: none; flex: 1; min-width: 0; }
.chips::-webkit-scrollbar { display: none; }

.chip {
  flex: none;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--muted);
  border-radius: 999px;
  padding: 7px 13px;
  font-size: 13.5px;
}

.chip:hover { border-color: var(--line-strong); color: var(--text); }
.chip.is-active {
  background: linear-gradient(135deg, #6a3b74 0%, #a17fff 100%);
  color: #fff;
  border-color: transparent;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(29, 161, 228, .24);
}

/* ---------- lists ---------- */

.list { padding: 10px 12px 16px; display: flex; flex-direction: column; gap: 8px; }

.row-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 13px;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 15px;
  text-align: left;
  box-shadow: var(--shadow-sm);
  /*! transition: transform .13s ease, box-shadow .13s ease, border-color .13s ease; */
}

.row-item:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.row-item:active { transform: none; box-shadow: var(--shadow-sm); }

/* A row that just arrived over the socket slides in, so the list visibly
   reacts instead of silently growing. */
.row-item--enter, .tile--enter { animation: row-in .34s cubic-bezier(.22, 1, .36, 1); }

@keyframes row-in {
  from { opacity: 0; transform: translateY(-8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .row-item--enter, .tile--enter { animation: none; }
}

/* ---------- bottom navigation ---------- */

/* The main column is a flex column, so a nav placed last simply sits at the
   bottom; no fixed positioning and therefore no overlap with the scroll area. */
.tabs--bottom {
  border-bottom: 0;
  border-top: 1px solid var(--line);
  height: auto;
  padding-bottom: env(safe-area-inset-bottom);
  /*! box-shadow: 0 -2px 14px rgba(0, 0, 0, .45); */
}

.tabs--bottom .tab {
  flex-direction: column;
  gap: 3px;
  height: 60px;
  border-bottom: 0;
  border-top: 2px solid transparent;
  font-size: 11.5px;
}

.tabs--bottom .tab .ic { width: 23px; height: 23px; }
.tabs--bottom .tab.is-active { border-top-color: var(--accent); }

/* badge sits on the icon rather than beside the label */
.tabs--bottom .badge { top: 6px; left: 50%; margin-left: 3px; }

/* ---------- profile button in the top bar ---------- */

.topbar__me {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 9px 3px 3px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  flex: none;
}

.topbar__me:hover { background: var(--surface-2); }

.topbar__me.is-active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

.topbar__me .avatar { width: 32px; height: 32px; font-size: 13px; box-shadow: none; }
.topbar__melabel { white-space: nowrap; }

@media (max-width: 400px) { .topbar__melabel { display: none; } }


/* ---------- live cams ---------- */

.cams {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
  padding: 12px 14px 14px;
}

/* "Live now 0/12" kop verwijderd; #cams-count blijft in de DOM voor app.js.
   De strip komt hierdoor hoger en er is meer ruimte voor de chatroom. */
.cams__head { display: none; }

.cams__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 16px;
  font-weight: 750;
  letter-spacing: -0.015em;
}

.cams__pulse {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #e8203f;
  box-shadow: 0 0 8px rgba(232, 32, 63, .7);
  animation: live-pulse 1.8s ease-in-out infinite;
}

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

.cams__count { color: var(--muted); font-weight: 600; font-size: 13.5px; }

/* Five slots side by side, scrollable on a narrow phone. */
.cams__strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(84px, 1fr);
  gap: 7px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}

.cams__strip::-webkit-scrollbar { display: none; }

.cam {
  position: relative;
  z-index: 0;
  isolation: isolate;
  /* Square keeps the strip short so the expanded player gets the room. */
  aspect-ratio: 1 / 1;
  border-radius: 12px;
  overflow: hidden;
  background: #14101a;
  border: 1px solid var(--line);
  padding: 0;
  min-width: 0;
}

.cam__video { position: absolute; inset: 0; background: #14101a; }
.cam__video video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The still that stands in for a live stream in the strip. */
.cam__thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Cross-fade on refresh, so a new frame does not land as a visible jolt every
     ten seconds across ten tiles at once. */
  transition: opacity .25s ease;
}

.cam__badge {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 1;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .06em;
  color: #fff;
  background: #0fe3f9;
  padding: 2px 6px;
  border-radius: 4px;
}

.cam__you {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 1;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .04em;
  color: #14101a;
  background: #fff;
  padding: 2px 6px;
  border-radius: 4px;
}

.cam__eyes {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 2px 6px 2px 5px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(4px);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
}

.cam__eyes .ic { width: 12px; height: 12px; }

.cam__name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 14px 6px 5px;
  font-size: 11.5px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: linear-gradient(to top, rgba(0, 0, 0, .82), transparent);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}

.cam__name i { font-style: normal; font-weight: 400; opacity: .85; }

.cam.is-mine { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }

/* an empty slot invites you to take it */
.cam--free {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: var(--surface-2);
  border: 1.5px dashed var(--line-strong);
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 600;
}

.cam--free .ic { width: 19px; height: 19px; }
.cam--free:hover { border-color: var(--accent); color: var(--accent); background: var(--surface-2); }

.cams__note {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--danger);
}

@media (min-width: 900px) {
  .cams { padding: 16px 18px 18px; }
  /* Ten tiles across would be postage stamps; let them keep a floor and scroll. */
  .cams__strip { grid-auto-columns: minmax(96px, 1fr); }
}





/* the strip stays visible but reads as inactive while we wait for a seat */
.cams__strip.is-dimmed { opacity: .45; pointer-events: none; }

/* ---------- modal ---------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .68);
  backdrop-filter: blur(4px);
  animation: fade-in .16s ease-out;
}

.modal__card {
  position: relative;
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border-radius: 20px;
  padding: 26px 24px 22px;
  text-align: center;
  box-shadow: 0 24px 60px rgba(40, 8, 26, .34);
  animation: modal-in .2s cubic-bezier(.22, 1, .36, 1);
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(14px) scale(.97); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .modal__backdrop, .modal__card { animation: none; }
}

.modal__icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 14px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal__icon .ic { width: 27px; height: 27px; }

.modal__title {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 750;
  letter-spacing: -0.02em;
}

.modal__text {
  margin: 0 0 16px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
}

.modal__text b { color: var(--text); font-weight: 700; }

.modal__card--ask { text-align: left; }
.modal__card--ask .modal__icon { margin-left: 0; }
.modal__card--ask .modal__title { text-align: left; }

.modal__icon--danger { background: rgba(232, 69, 91, .12); color: var(--danger); }

.modal__actions {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}

/* The confirming action sits on the right, where the thumb lands last, so a
   destructive one is not the first thing hit by accident. */
.modal__actions .btn { flex: 1; }

.modal__card--ask .field { margin-bottom: 16px; }

.modal__card--ask textarea {
  width: 100%;
  resize: vertical;
  min-height: 78px;
}

.modal__wait {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-bottom: 18px;
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--surface-2);
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

.modal__wait i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: live-pulse 1.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) { .modal__wait i { animation: none; } }

/* the strip stays visible but reads as inactive while we wait for a seat */

/* ---- expanded cam ---- */

/*
 * The expanded cam sits above the slots, everywhere.
 *
 * Done with flex order rather than by moving the element, because the markup
 * order is what a screen reader and keyboard follow: the strip is the list you
 * choose from, and the player is what that choice produced. Visually the player
 * wants to be first - it is the thing being watched, and having it below the
 * grid pushed it under the fold on a phone the moment the grid had more than a
 * few tiles.
 */
.cams {
  display: flex;
  flex-direction: column;
}

/* The player is an overlay now, so it leaves the flow entirely; the order
   rule below only matters if that ever changes back. */
.cams .cambig { order: -1; }
.cams .cams__strip { order: 1; }
.cams .cams__count { order: 2; }

/*
 * The stage is capped in height, not just given a ratio.
 *
 * A 3:4 box on a phone is around 500px tall. Stacked under the strip and above
 * the chat that overflows the pane, and because the pane clips, what gets cut is
 * the bottom of the player - exactly where the name and viewer count sit. The
 * cap keeps the whole player on screen; the video letterboxes inside it, so the
 * full picture is still visible whatever shape the box ends up.
 */
.cambig__stage {
  position: relative;
  z-index: 0;
  isolation: isolate;
  width: 100%;
  aspect-ratio: 3 / 4;
  max-height: 46vh;
  border-radius: 16px;
  overflow: hidden;
  background: #14101a;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}

/* Landscape phones have almost no vertical room, so give the player less of it
   and let the chat keep its share. */
@media (max-height: 520px) {
  .cambig__stage { max-height: 62vh; }
}

.cambig__video { position: absolute; inset: 0; }
.cambig__video video { width: 100%; height: 100%; object-fit: contain; display: block; background: #14101a; }
.cambig__video audio { display: none; }

.cambig__badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .06em;
  color: #fff;
  background: #00cfff;
  padding: 3px 8px;
  border-radius: 5px;
}

.cambig__controls {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1;
  display: flex;
  gap: 8px;
}

.cambig__btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 0;
  background: rgba(20, 16, 26, .62);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(6px);
  transition: background .12s ease;
}

.cambig__btn .ic { width: 21px; height: 21px; }
.cambig__btn:hover { background: rgba(20, 16, 26, .85); }
.cambig__btn.is-on { background: var(--accent); }

.cambig__foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 22px 12px 10px;
  background: linear-gradient(to top, rgba(0, 0, 0, .8), transparent);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}

.cambig__watching {
  flex: none;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .18);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 12.5px;
  font-weight: 700;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
}

.cambig__watching .ic { width: 14px; height: 14px; }

.cambig__who {
  border: 0;
  background: none;
  padding: 0;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}

/* On a narrow screen the name gives way before the count does: knowing how many
   people are watching is the part you cannot get anywhere else on this screen. */
.cambig__who > span:first-child,
.cambig__who { white-space: nowrap; text-overflow: ellipsis; }

.cambig__who i { font-style: normal; font-weight: 400; opacity: .85; }

.cambig__link {
  font-size: 12.5px;
  font-weight: 600;
  color: #ffc4dc;
  border-bottom: 1px solid rgba(255, 196, 220, .5);
}

/* the strip cam currently expanded */
.cam.is-open { box-shadow: 0 0 0 2.5px var(--accent); }

@media (max-width: 380px) {
  .cambig__link { display: none; }
  .cambig__who { font-size: 15px; }
}

@media (min-width: 900px) {
  .cambig__stage { aspect-ratio: 16 / 9; max-height: 540px; margin: 0 auto; }
}

/* ---------- public chatroom ---------- */

/* The room pane is a column: cams keep their natural height at the top and the
   chat takes whatever is left, so the composer sits on the bottom edge rather
   than being pushed off screen by a tall strip. */
#pane-room {
  display: none;
  flex-direction: column;
  overflow: hidden;
}

#pane-room.is-active { display: flex; }

#pane-room .cams { flex: none; }

/* Whatever the cams take, the chat keeps enough to stay usable: a log you can
   read a couple of lines in, plus the composer. */
/* The banner sits inside .room and takes its own height, so the floor has to
   cover both it and a usable log; otherwise adding the banner quietly ate the
   conversation. */
#pane-room .room { min-height: 250px; }

.room {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.room__log {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 12px 12px 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  overscroll-behavior: contain;
}

.rmsg {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 5px 6px;
  border-radius: 10px;
  cursor: pointer;
}

.rmsg:hover { background: var(--surface-2); }

.rmsg--enter { animation: bubble-in .2s cubic-bezier(.22, 1, .36, 1); }
@media (prefers-reduced-motion: reduce) { .rmsg--enter { animation: none; } }

/* Deliberately small: in a busy room the avatars are decoration, the words are
   the content, and 40px portraits would push half the messages off screen. */
.rmsg__av {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
  margin-top: 1px;
}

.rmsg__av img { width: 100%; height: 100%; object-fit: cover; display: block; }

.rmsg__main { min-width: 0; flex: 1; }

.rmsg__head {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 1px;
}

.rmsg__name {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rmsg__time {
  flex: none;
  font-style: normal;
  font-size: 11px;
  color: var(--muted);
  opacity: .8;
}

.rmsg__body {
  display: block;
  font-size: 15px;
  line-height: 1.45;
  color: var(--text);
  word-wrap: break-word;
  overflow-wrap: anywhere;
}

.rmsg__body a { color: var(--accent); }

.rmsg__gif {
  display: block;
  margin-top: 4px;
  max-width: 220px;
  width: 100%;
  border-radius: 12px;
  background: var(--surface-3);
}

.rmsg.is-mine .rmsg__body { color: #00e7ff; }

.room__note {
  margin: 0 12px 6px;
  padding: 8px 12px;
  border-radius: 10px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 13px;
}

.room__composer {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.room__composer input {
  flex: 1;
  min-width: 0;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 11px 16px;
  color: var(--text);
  font-size: 15px;
  outline: none;
}

.room__composer input:focus { border-color: var(--accent); }

.room__gif {
  flex: none;
  height: 40px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .04em;
}

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

.room__send {
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 0;
  background: linear-gradient(135deg, var(--accent) 0%, #00ff58 100%);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 10px rgba(29, 161, 228, .28);
}

.room__send .ic { width: 19px; height: 19px; }

/* ---- GIF picker ---- */

.gifs {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  max-height: 62%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, .5);
}

.gifs__bar {
  flex: none;
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}

.gifs__bar input {
  flex: 1;
  min-width: 0;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 9px 14px;
  color: var(--text);
  outline: none;
}

.gifs__close {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 0;
  background: var(--surface-2);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.gifs__grid {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

@media (min-width: 620px) { .gifs__grid { grid-template-columns: repeat(5, 1fr); } }

.gifs__item {
  padding: 0;
  border: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-3);
  aspect-ratio: 1 / 1;
}

.gifs__item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gifs__item:hover { outline: 2px solid var(--accent); }

.gifs__msg {
  grid-column: 1 / -1;
  padding: 26px 10px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}

/* system notices in the room */
.rsys {
  align-self: center;
  max-width: 90%;
  margin: 4px 0;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
}

/* ---------- admin panel ---------- */

.me__section--admin { border-top: 2px solid var(--accent); }

.admin__head {
  margin: 12px 0 6px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.admin__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-2);
  margin-bottom: 6px;
}

.admin__slot {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: var(--surface-3);
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
}

.admin__who { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.admin__who b { font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin__who i { font-style: normal; font-size: 12px; color: var(--muted); }

.admin__acts { flex: none; display: flex; gap: 6px; }

.admin__msg {
  padding: 12px 10px;
  color: var(--muted);
  font-size: 13.5px;
}

/* ---------- people rows ---------- */

/* Full-bleed rows with hairline separators: no cards, no shadows. */
.list--rows {
  display: block;
  padding: 0;
}

.list--rows .empty { padding: 40px 20px; }

.srow {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px 0 0;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.srow:last-child { border-bottom: 0; }
.srow:hover { background: var(--surface); }

/* the whole left area opens the profile */
.srow__open {
  display: flex;
  align-items: center;
  gap: 13px;
  flex: 1;
  min-width: 0;
  padding: 12px 4px 12px 16px;
  border: 0;
  background: none;
  text-align: left;
}

.srow__avatar {
  position: relative;
  flex: none;
  width: 62px;
  height: 62px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
}

.srow__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.srow__initial {
  font-size: 24px;
  font-weight: 800;
  color: var(--accent);
}

/* Ring for people who are online. A box-shadow paints outside the element, so
   the avatar can keep clipping its image while still showing the ring. */
.srow__avatar.is-online {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4.5px var(--online);
}

.srow__dot {
  position: absolute;
  right: 0;
  bottom: 1px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--online);
  border: 2.5px solid var(--bg);
}

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

.srow__top {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

/* Gender colour comes from the .g-* class the row adds; this is only the
   fallback for anyone without one. */
.srow__name {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.srow__age { flex: none; font-size: 15px; color: var(--muted); font-weight: 500; }

.srow__sub {
  font-size: 14.5px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the action on the right, mirroring the camera button in the reference */
.srow__act {
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 0;
  background: none;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .12s ease, color .12s ease;
}

.srow__act .ic { width: 25px; height: 25px; stroke-width: 1.9; }
.srow__act:hover { background: var(--accent); color: #fff; }
.srow__act:active { transform: scale(.94); }

.srow--enter { animation: row-in .34s cubic-bezier(.22, 1, .36, 1); }
@media (prefers-reduced-motion: reduce) { .srow--enter { animation: none; } }

.avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--surface-3);
  flex: none;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 19px;
  color: var(--muted);
  overflow: hidden;
  box-shadow: 0 0 0 2px var(--line);
}

/* subtle glow ring when online */
.row-item .avatar:has(.dot.is-online),
.avatar.is-online-ring {
  box-shadow: 0 0 0 2px rgba(23, 191, 95, .5);
}

.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--sm { width: 34px; height: 34px; font-size: 14px; box-shadow: none; }
.avatar--lg { width: 100%; height: auto; aspect-ratio: 1; border-radius: 18px; font-size: 48px; box-shadow: none; }

.dot {
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #cfc6cd;
  border: 3px solid var(--bg);
}

.dot.is-online {
  background: var(--online);
  box-shadow: 0 0 6px rgba(23, 191, 95, .55);
}
.avatar--sm .dot { width: 10px; height: 10px; border-width: 2px; }

.row-item__main { flex: 1; min-width: 0; }

.row-item__name {
  font-weight: 650;
  font-size: 16.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: -0.01em;
  min-width: 0;
  flex-shrink: 1;
}

.g-male { color: var(--male); }
.g-female { color: var(--female); }
.g-couple { color: var(--couple); }
.g-other { color: var(--other); }

/* envelope icon before the avatar */
.row-item__env {
  flex: none;
  width: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  opacity: .7;
}
.row-item__env .ic { width: 19px; height: 19px; }

/* name + age + New badge on one line */
.row-item__top {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

.row-item__age {
  color: var(--muted);
  font-size: 14px;
  font-weight: 400;
  flex: none;
}

.tag-new {
  flex: none;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #fff;
  background: linear-gradient(100deg, var(--accent), #ff6aa4);
  padding: 2px 7px;
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(255, 45, 122, .4);
}

.row-item__sub {
  color: var(--muted);
  font-size: 13.5px;
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* country in its own right-aligned column */
.row-item__country {
  flex: none;
  max-width: 34%;
  color: var(--muted);
  font-size: 13px;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-left: 8px;
}

.row-item__side { text-align: right; flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.row-item__time { color: var(--muted); font-size: 12px; }

.pill {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
}

.list-end { padding: 18px; text-align: center; color: var(--muted); font-size: 13.5px; }

.empty { padding: 60px 26px; text-align: center; color: var(--muted); }
.empty strong { display: block; color: var(--text); font-size: 17px; margin-bottom: 6px; }

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

.bar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: var(--bar);
  padding: 0 6px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  flex: none;
}

.bar__btn {
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  border-radius: 10px;
  color: var(--text);
}

.bar__title { font-weight: 600; font-size: 16px; }
.bar__spacer { flex: 1; }

.bar__peer {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  min-width: 0;
  padding: 0 4px;
  text-align: left;
}

.bar__peerinfo { min-width: 0; }
.bar__peername { display: block; font-weight: 600; font-size: 15.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar__peerstate { display: block; font-size: 12px; color: var(--muted); }
.bar__peerstate.is-online { color: var(--online); }

/* ---------- profile layout ---------- */

.profile__grid { display: block; }

/* gallery */

.gallery { margin-bottom: 14px; }

.gallery__hero {
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: 18px;
  overflow: hidden;
  background: var(--surface-3);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}

.gallery__hero img { width: 100%; height: 100%; object-fit: cover; display: block; }

.gallery__hero--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 54px;
  font-weight: 800;
  color: var(--accent);
  background: linear-gradient(160deg, var(--surface-2), var(--surface-3));
}

.gallery__thumbs { display: flex; gap: 8px; margin-top: 8px; }

.gallery__thumb {
  width: 62px;
  height: 62px;
  padding: 0;
  border-radius: 12px;
  overflow: hidden;
  border: 2px solid transparent;
  background: var(--surface-2);
  flex: none;
  transition: border-color .12s ease;
}

.gallery__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery__thumb.is-active { border-color: var(--accent); }
.gallery__thumb:hover { border-color: var(--line-strong); }

/* fact list */

.profile__site {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding: 10px 14px;
  border-radius: 12px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  color: var(--accent-deep);
  font-size: 14.5px;
  font-weight: 650;
  max-width: 100%;
  text-decoration: none;
  transition: background .12s ease, color .12s ease;
}

.profile__site:hover { background: var(--accent); color: #fff; }
.profile__site .ic { width: 17px; height: 17px; flex: none; }
.profile__site span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.field__hint {
  display: block;
  margin-top: 5px;
  font-size: 12.5px;
  color: var(--muted);
}

.profile__h {
  margin: 22px 0 10px;
  font-size: 17px;
  font-weight: 750;
  letter-spacing: -0.015em;
}

.facts {
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}

.fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  background: var(--surface);
  padding: 11px 14px;
}

.fact dt { color: var(--muted); font-size: 13.5px; }
.fact dd { margin: 0; font-weight: 600; font-size: 14.5px; text-align: right; }

/* suggestions sidebar */

.profile__side { margin-top: 22px; }

.sidecard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 14px;
  box-shadow: var(--shadow-sm);
}

.sidecard__title {
  margin: 2px 4px 10px;
  font-size: 15.5px;
  font-weight: 750;
  letter-spacing: -0.015em;
}

.suggest {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 8px;
  border: 0;
  border-radius: 12px;
  background: none;
  text-align: left;
  transition: background .12s ease;
}

.suggest:hover { background: var(--surface-2); }
.suggest .avatar { width: 42px; height: 42px; font-size: 16px; }
.suggest__main { min-width: 0; display: flex; flex-direction: column; }

.suggest__name {
  font-weight: 650;
  font-size: 14.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.suggest__name i { font-style: normal; font-weight: 400; color: var(--muted); }

.suggest__place {
  font-size: 12.5px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Three columns once there is room: gallery, details, suggestions. */
@media (min-width: 900px) {
  .profile { padding: 24px 24px 40px; }

  .profile__grid {
    display: grid;
    grid-template-columns: 262px minmax(0, 1fr) 236px;
    gap: 24px;
    align-items: start;
    max-width: 1160px;
    margin: 0 auto;
  }

  .profile__left { position: sticky; top: 0; }
  .profile__side { margin-top: 0; position: sticky; top: 0; }

  .profile__name { font-size: 34px; }
  .facts { margin-top: 22px; }
}

/* Between tablet and desktop, drop the sidebar under the details. */
@media (min-width: 700px) and (max-width: 899px) {
  .profile__grid {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 26px;
    align-items: start;
  }
  .profile__side { grid-column: 1 / -1; }
}


/* ---------- profile ---------- */

.profile { flex: 1; overflow-y: auto; padding: 18px 16px calc(28px + env(safe-area-inset-bottom)); }
.profile__photo { margin-bottom: 16px; }

.profile__namerow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
}

.profile__name {
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.05;
}

/* premium sheen on the name */
.profile__name.g-male   { background: linear-gradient(100deg, var(--male) 0%, #9cd4ff 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.profile__name.g-female { background: linear-gradient(100deg, var(--female) 0%, #ffb0d4 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.profile__name.g-couple { background: linear-gradient(100deg, var(--couple) 0%, #d9b8ff 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.profile__name.g-other  { background: linear-gradient(100deg, #6b7684 0%, #9aa5b3 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }

/* online badge next to the name */
.profile__live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  padding: 4px 10px 4px 8px;
  border-radius: 999px;
  background: rgba(23, 191, 95, .12);
  border: 1px solid rgba(23, 191, 95, .3);
  color: #0f9d4f;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
}

.profile__live i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #17bf5f;
  box-shadow: 0 0 6px rgba(23, 191, 95, .6);
  animation: live-pulse 1.8s ease-in-out infinite;
}

@keyframes live-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .profile__live i { animation: none; } }

.profile__meta {
  color: var(--muted);
  margin-top: 8px;
  font-size: 14.5px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.profile__meta b { color: var(--text); font-weight: 600; }

.profile__bio {
  margin-top: 18px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  line-height: 1.55;
}

.profile__bio-text {
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Long bios are capped at five lines so they never dominate the screen or push
   the action buttons out of reach. The toggle appears only when clamping
   actually hides something. */
.profile__bio.is-clamped .profile__bio-text {
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.profile__bio-toggle {
  margin-top: 8px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: 13.5px;
  font-weight: 600;
}

.profile__actions { display: flex; gap: 10px; margin-top: 18px; }
.profile__actions .btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; }

/* ---------- me ---------- */

.me { padding: 18px 16px calc(28px + env(safe-area-inset-bottom)); }
.me__section { margin-top: 22px; }
.me__title { font-size: 12.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 600; margin-bottom: 10px; }
.me__actions { display: flex; flex-direction: column; gap: 10px; }
.me__actions .btn { display: flex; align-items: center; justify-content: center; gap: 8px; }
.me__token { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: var(--muted); word-break: break-all; background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }

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

.screen--chat { background: var(--bg); }

.thread {
  flex: 1;
  overflow-y: auto;
  padding: 16px 12px 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
}

.thread__more { text-align: center; padding: 6px 0 14px; }

.bubble {
  max-width: 78%;
  padding: 9px 13px 8px;
  border-radius: 18px;
  line-height: 1.45;
  word-wrap: break-word;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  font-size: 15.3px;
  position: relative;
  animation: bubble-in .22s cubic-bezier(.22, 1, .36, 1);
}

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

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

/* Incoming is a plain card, outgoing carries the brand gradient. The tail is
   only drawn on the last bubble of a run, so a burst of messages reads as one
   block instead of a row of identical speech balloons. */
.bubble--in {
  align-self: flex-start;
  background: var(--surface);
  color: var(--text);
  border-bottom-left-radius: 18px;
}

.bubble--out {
  align-self: flex-end;
  background: linear-gradient(135deg, var(--accent) 0%, #45b6ef 100%);
  border-color: transparent;
  color: #fff;
  border-bottom-right-radius: 18px;
  box-shadow: 0 2px 8px rgba(29, 161, 228, .22);
}

.bubble--in.is-tail  { border-bottom-left-radius: 6px; }
.bubble--out.is-tail { border-bottom-right-radius: 6px; }

/* extra breathing room where the speaker changes */
.bubble.is-first { margin-top: 10px; }

.bubble__time {
  float: right;
  margin: 7px 0 -2px 12px;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--muted);
  line-height: 1;
  opacity: .85;
}

.bubble--out .bubble__time { color: rgba(255, 255, 255, .85); }


/* photo message */
.bubble--photo { padding: 0; overflow: hidden; border-radius: 14px; }

.snapcard {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  min-width: 190px;
  background: none;
  border: 0;
  color: inherit;
  text-align: left;
  width: 100%;
}

.snapcard__icon {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: rgba(255, 45, 122, .16);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.snapcard__label { font-size: 14.5px; font-weight: 600; }
.snapcard__sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.snapcard.is-spent .snapcard__icon { background: var(--surface-3); color: var(--muted); }
.snapcard.is-spent .snapcard__label { color: var(--muted); font-weight: 500; }

.day {
  align-self: center;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: .01em;
  background: var(--surface-3);
  border-radius: 999px;
  padding: 5px 13px;
  margin: 16px 0 8px;
}

.composer {
  display: flex;
  align-items: flex-end;
  gap: 9px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--surface);
  flex: none;
}

.composer textarea {
  flex: 1;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 11px 15px;
  max-height: 130px;
  outline: none;
  resize: none;
  line-height: 1.4;
}

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

.composer__send {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 0;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.composer__blocked {
  margin: 0;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font-size: 14px;
  text-align: center;
}

/* ---------- toast ---------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  z-index: 60;
  background: var(--surface-3);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 11px 17px;
  border-radius: 999px;
  font-size: 14px;
  max-width: 88vw;
  text-align: center;
}

/* ---------- focus ---------- */

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* ---------- wordmark ---------- */

.wordmark { display: flex; align-items: center; gap: 9px; }

/* The mark carries its own gradient fill, so it needs no colour from here. */
.logo-mark { width: 27px; height: 27px; flex: none; }

.wordmark__text {
  font-size: 19.5px;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--text);
}

/* second half of the name in brand pink */
.wordmark__text i { font-style: normal; color: #6120ab; font-weight: 800; }

.wordmark--lg .logo-mark { width: 40px; height: 40px; }
.wordmark--lg .wordmark__text { font-size: 30px; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 52px;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  flex: none;
}

.topbar__count { font-size: 12.5px; color: var(--muted); }
.topbar__count b { color: var(--online); font-weight: 600; }

/* rechterkant van de mobiele header: online-teller + Go live-knop */
.topbar__right { display: flex; align-items: center; gap: 10px; }

.topbar__golive {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  border-radius: 999px;
}
.topbar__golive .ic { width: 16px; height: 16px; }

/* op erg smalle schermen alleen het camera-icoon tonen */
@media (max-width: 360px) {
  .topbar__golive span { display: none; }
  .topbar__golive { padding: 8px; }
}

/* Go live-knop bovenaan de desktop-sidebar */
.sidebar__golive {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 0 0 12px;
}
.sidebar__golive .ic { width: 18px; height: 18px; }

/* ---------- auth / landing ---------- */

.screen--auth { overflow-y: auto; display: block; padding: 0; border: 0; max-width: none; }

.landing {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

/* hero */

.hero {
  position: relative;
  isolation: isolate;
  color: #fff;
  padding: 44px 24px 48px;
  overflow: hidden;
  background-color: #1a0a12;
  background-image: var(--hero-image);
  background-size: cover;
  background-position: center;
}

/*
 * Two layers over the photo: a warm tint so the brand pink carries through, and
 * a darker vignette so white text stays readable wherever the image is bright.
 * Without these the headline disappears against light parts of the picture.
 */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(6, 6, 6, 0.98) 0%, rgba(236, 107, 221, 0.02) 40%, rgba(27, 30, 28, 0) 100%), linear-gradient(115deg, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0.13) 55%, rgba(17, 17, 17, 0.8) 100%);
}

.hero__inner {
  max-width: 620px;
  margin: 0 auto;
  position: relative;
  z-index: 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero__brand { margin-bottom: 30px; }

.hero__brand .logo-mark {
  background: #fff;
  border-radius: 9px;
  padding: 4px;
  width: 34px;
  height: 34px;
  box-shadow: 0 4px 14px rgba(120, 20, 70, .35);
}

.hero__brand .wordmark__text { color: #fff; }
.hero__brand .wordmark__text i { color: rgba(255, 255, 255, .82); }

/* the online pill sits above the headline, as a live signal */
.hero__count {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .28);
  backdrop-filter: blur(8px);
  border-radius: 999px;
  padding: 7px 16px;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 22px;
}

.hero__count b { color: #fff; font-weight: 800; }

.hero__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #2ee06a;
  box-shadow: 0 0 0 3px rgba(46, 224, 106, .28);
}

.hero__title {
  margin: 0 0 18px;
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.06;
  font-size: clamp(34px, 8.5vw, 58px);
  text-shadow: 0 2px 20px rgba(0, 0, 0, .35);
}

.hero__accent {
  background: linear-gradient(100deg, #af7aff 0%, #d2b4ff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.hero__lead {
  margin: 0 0 26px;
  max-width: 520px;
  font-size: 16px;
  line-height: 1.6;
  color: rgba(255, 255, 255, .88);
  text-shadow: 0 1px 12px rgba(0, 0, 0, .45);
}

.hero__feats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 9px;
}

.hero__feats li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 600;
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .2);
  backdrop-filter: blur(6px);
  border-radius: 999px;
  padding: 7px 13px;
}

.hero__check { width: 15px; height: 15px; color: #955ff5; stroke-width: 3; }
.hero__lock { width: 14px; height: 14px; color: #ffd0e4; }

/* login card */

.auth {
  flex: 1;
  padding: 30px 20px calc(36px + env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: var(--bg);
}

.auth__card { width: 100%; max-width: 420px; }

@media (min-width: 860px) {
  .auth__card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 20px;
    padding: 28px 26px 30px;
    box-shadow: var(--shadow-lg);
  }
}
.auth__brand { display: none; margin-bottom: 22px; }
.auth__note { margin: 14px 0 0; color: var(--muted); font-size: 12.5px; text-align: center; }

/* desktop: hero left, card right, both full height */
@media (min-width: 860px) {
  .landing { flex-direction: row; min-height: 100vh; }

  .hero {
    flex: 1;
    display: flex;
    align-items: center;
    padding: 56px 48px;
  }

  .hero__inner { max-width: 560px; }

  /* The form panel floats over the same photo rather than sitting on a flat
     white column, so the picture runs edge to edge like the reference. */
  .auth {
    width: 470px;
    flex: none;
    align-items: center;
    background: rgba(0, 0, 0, 0.88);
    backdrop-filter: blur(18px);
    box-shadow: -20px 0 60px rgba(0, 0, 0, .5);
  }

  .auth__brand { display: none; }
}

.segment--2 { grid-template-columns: repeat(2, 1fr); margin-bottom: 20px; }

.field__pw { position: relative; display: block; }
.field__pw input { padding-right: 46px; }

.field__reveal {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  color: var(--muted);
}

/* ---------- photo slots ---------- */

.slots { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.slot {
  position: relative;
  aspect-ratio: 1;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
}

.slot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.slot__hint { display: flex; align-items: center; justify-content: center; }

.slot__drop {
  position: absolute;
  right: 6px;
  top: 6px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, .62);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

.slot__drop .ic { width: 16px; height: 16px; }

/* profile photo pair */



/* ---------- composer attach ---------- */

.composer__attach {
  width: 40px;
  height: 44px;
  border: 0;
  background: none;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

/* ---------- photo viewer ---------- */

.screen--snap { z-index: 40; background: #000; }
.bar--snap { background: transparent; border-bottom: 0; }
.snap__warn { font-size: 12px; color: var(--muted); padding-right: 10px; }

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

.snap__stage img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 12px; }

/* ---------- inbox row action ---------- */

.row-item__del {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  border: 0;
  background: none;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.row-item__del .ic { width: 18px; height: 18px; }
/* Fallback behind a still: shown until the first frame arrives, and left in
   place if a refresh fails, so a tile is never a black hole. */
.cam__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-3);
  color: var(--muted);
  font-size: 22px;
  font-weight: 800;
}

.cam__poster--letter { object-fit: unset; }

/* The still sits over the fallback and fades in once it has actually loaded. */
.cam__thumb {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .25s ease;
}

.cam__thumb.is-loaded { opacity: 1; }


/* ============ landing, voice and the capacity door ============ */

/* ---- hero ---- */

.hero { position: relative; isolation: isolate; overflow: hidden; }

/* A wall of faces behind the copy. Heavily dimmed: it is texture, not content,
   and legible white text over portraits needs the picture pushed right back. */

@media (min-width: 700px) { .hero__faces { grid-template-columns: repeat(8, 1fr); } }

.hero__faces img { width: 100%; height: 100%; object-fit: cover; display: block; aspect-ratio: 1; }


.hero__cta:hover { background: #3ea520; transform: translateY(-1px); }
.hero__cta:active { transform: none; }






/* ---- capacity door ---- */

.screen--full { overflow-y: auto; display: block; padding: 0; max-width: none; border: 0; }

.full {
  max-width: 460px;
  margin: 0 auto;
  padding: 54px 22px calc(40px + env(safe-area-inset-bottom));
  text-align: center;
}

.full__mark { width: 54px; height: 54px; margin: 0 auto 22px; color: var(--accent); }
.full__mark .logo-mark { width: 100%; height: 100%; }

.full__title { margin: 0 0 14px; font-size: 27px; font-weight: 800; letter-spacing: -0.025em; }
.full__text { margin: 0 0 14px; font-size: 15.5px; line-height: 1.6; color: var(--muted); }

.full__meter { margin: 24px 0 20px; }

.full__bar {
  height: 9px;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
  margin-bottom: 8px;
}

.full__bar span {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), #45b6ef);
}

.full__count { font-size: 13px; color: var(--muted); }
.full__count b { color: var(--text); }

.full__support {
  margin: 20px 0 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
}

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

.voice {
  flex: none;
  display: flex;
  align-items: stretch;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.voice__seats {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 6px;
}

.vseat {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 5px 7px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.vseat--free {
  justify-content: center;
  border-style: dashed;
  color: var(--muted);
}

.vseat__empty { font-size: 11.5px; font-weight: 600; }

.vseat__av {
  position: relative;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
}

.vseat__av img { width: 100%; height: 100%; object-fit: cover; }

/* The ring pulses only while this person is actually speaking, so a glance at
   the bar answers "who is talking" without reading any names. */
.vseat__wave {
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 2px solid transparent;
  pointer-events: none;
}

.vseat.is-talking .vseat__wave {
  border-color: var(--online);
  animation: vwave 1.1s ease-out infinite;
}

@keyframes vwave {
  0%   { transform: scale(.9); opacity: 1; }
  100% { transform: scale(1.25); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .vseat.is-talking .vseat__wave { animation: none; opacity: 1; }
}

.vseat__name {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vseat__you {
  flex: none;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .04em;
  color: var(--accent);
}

.vseat__mute {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 0;
  background: none;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.vseat__mute .ic { width: 15px; height: 15px; }
.vseat__mute:hover { color: var(--accent); }

/* A muted speaker stays visible and still shows as talking; only the sound is
   gone, so the bar never lies about who is in the conversation. */
.vseat.is-muted { opacity: .58; }
.vseat.is-muted .vseat__mute { color: var(--danger); }
.vseat.is-mine { border-color: var(--accent); }

.voice__mic {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
}

.voice__mic .ic { width: 17px; height: 17px; }
.voice__mic:disabled { opacity: .45; }

.voice__mic.is-on {
  background: linear-gradient(135deg, var(--accent), #45b6ef);
  border-color: transparent;
  color: #fff;
}

.voice__note {
  margin: 0;
  padding: 8px 12px;
  font-size: 13px;
  color: var(--danger);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}


/* ---- master mute for the voice channel ---- */

.voice__all {
  flex: none;
  width: 38px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.voice__all .ic { width: 17px; height: 17px; }
.voice__all:hover { color: var(--text); }

.voice__all.is-off {
  background: var(--danger);
  border-color: transparent;
  color: #fff;
}

/* The seats stay readable while the channel is silenced - you can still see who
   is talking, which is the whole reason the indicator is server-driven. */
.voice.is-allmuted .voice__seats { opacity: .55; }

/* ---------- install prompt ---------- */

.install {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  animation: install-in .25s cubic-bezier(.22, 1, .36, 1);
}

@keyframes install-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

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

/* Above the bottom nav on a phone, and out of the way of the thumb on a wide
   screen where it would otherwise stretch across the whole window. */
@media (min-width: 620px) {
  .install { left: auto; right: 18px; max-width: 380px; }
}

.install__icon { width: 42px; height: 42px; border-radius: 10px; flex: none; }

.install__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.install__text strong { font-size: 14.5px; }
.install__text span { font-size: 12.5px; color: var(--muted); line-height: 1.35; }

.install__close {
  flex: none;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.install__close .ic { width: 15px; height: 15px; }

/* The banner after it has turned into instructions: taller, and the text is now
   the point rather than a subtitle under a button. */
.install.is-steps { align-items: flex-start; }
.install.is-steps .install__text span { font-size: 13.5px; color: var(--text); }
.install.is-steps .install__text span b { color: var(--accent); }

/* ---------- room welcome ---------- */

.rintro {
  align-self: stretch;
  margin: 4px 2px 12px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
}

.rintro strong {
  display: block;
  margin-bottom: 5px;
  font-size: 15.5px;
  font-weight: 750;
  letter-spacing: -0.015em;
  color: var(--text);
}

.rintro span {
  display: block;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
}

/* The invitation reads as the point, the rules as the condition. */
.rintro__cta { margin-top: 4px; color: var(--accent); font-weight: 600; }


/* Shown in the expanded player when a stream does not arrive. Black tells the
   viewer nothing; this at least says whether to wait or move on. */
.cambig__msg {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  font-size: 14px;
  line-height: 1.55;
  color: rgba(255, 255, 255, .82);
  background: #14101a;
}

/* ---------- photos in the room ---------- */

.room__photo {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  cursor: pointer;
}

.room__photo:hover { border-color: var(--accent); color: var(--accent); }
.room__photo .ic { width: 18px; height: 18px; }

/* While uploading. The button stays put and pulses rather than being swapped for
   a spinner, so the composer does not reflow mid-send. */
.room__photo.is-busy { opacity: .5; pointer-events: none; animation: live-pulse 1.1s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .room__photo.is-busy { animation: none; } }

.rmsg__photo {
  display: block;
  margin-top: 4px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface-3);
  cursor: zoom-in;

  /* Big enough to see what it is, small enough that three in a row do not push
     the conversation off the screen. The aspect ratio is set inline per photo,
     so tall and wide ones both fit this box without cropping. */
  width: 100%;
  max-width: 230px;
  max-height: 300px;
}

.rmsg__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rmsg__photo:hover { border-color: var(--accent); }

/* ---------- lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, .88);
  backdrop-filter: blur(6px);
  animation: fade-in .15s ease-out;
}

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

.lightbox__frame {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/*
 * Fit the window, never exceed the photo.
 *
 * Two caps, and both matter. Without the viewport limits a tall photo runs off
 * the screen and has to be scrolled; without max-width/height in its own pixels
 * a small photo is stretched to fill the screen and turns to mush. Whichever
 * limit is smaller wins, so every photo is shown as large as is useful and no
 * larger.
 */
.lightbox img {
  max-width: min(100%, 1100px);
  max-height: min(82vh, 1100px);
  width: auto;
  height: auto;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .6);
  cursor: default;
}

.lightbox figcaption {
  font-size: 13px;
  color: rgba(255, 255, 255, .7);
}

.lightbox__close {
  position: absolute;
  top: calc(14px + env(safe-area-inset-top));
  right: 14px;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .14);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox__close .ic { width: 20px; height: 20px; }
.lightbox__close:hover { background: rgba(255, 255, 255, .24); }

/* Links in messages. The break rule matters: a long address in a narrow bubble
   would otherwise stretch the bubble past the edge of the screen. */
.rmsg__body a,
.bubble a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.bubble--out a { color: #fff; text-decoration-color: rgba(255, 255, 255, .6); }

/* The greeter's picture in the moderation panel. */
.admin__slot--pic { width: 34px; height: 34px; border-radius: 50%; overflow: hidden; padding: 0; }
.admin__slot--pic img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- sponsor banner above the chat ---------- */

.roomad {
  flex: none;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);

  /* Height is set from script to match the scaled banner, because the banner is
     a fixed 468x60 and the space it needs depends on how far it had to shrink.
     This is the fallback for the moment before that runs. */
  height: 62px;
}

/*
 * The banner is a fixed pixel size from a third party, so it cannot be made
 * responsive - it can only be scaled. Transform keeps it sharp and preserves
 * every click target in proportion, where squashing the iframe would just crop
 * it.
 */
.roomad__fit {
  width: 468px;
  height: 60px;
  flex: none;
  transform-origin: center center;
  transform: scale(var(--ad-scale, 1));
}

.roomad iframe {
  display: block;
  width: 468px;
  height: 60px;
  border: 0;
}

/* Nothing to show - a blocked or failed banner should not leave a gap. */
.roomad.is-empty { display: none; }

/* ============ desktop: cams left, chat right ============ */

@media (min-width: 1000px) {
  /*
   * Two columns instead of a stack.
   *
   * On a wide screen the stacked layout wastes most of the width and leaves the
   * cams as a thin strip with the conversation pushed far below the fold. Side
   * by side, the cams get the room to be watched and the chat stays in view
   * while you watch - which is the whole point of having both.
   *
   * The pane owns the height and neither column scrolls as a whole; only the
   * cam area and the message log scroll, so the composer and the banner stay
   * where they are.
   */
  /*
   * Only when it is the visible tab.
   *
   * This carried no .is-active before, and an id outweighs the `.pane { display:
   * none }` that hides inactive tabs - so the room stayed rendered underneath
   * whatever else was open. Messages appeared to float over the cams because
   * both panes were genuinely on screen at once.
   */
  #pane-room.is-active {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 400px;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "ad    voice"
      "cams  chat";
    gap: 0;
    overflow: hidden;
  }

  #pane-room > .roomad { grid-area: ad; border-right: 1px solid var(--line); }
  #pane-room > .cams   { grid-area: cams; overflow-y: auto; min-height: 0; border-right: 1px solid var(--line); }
  #pane-room > .voice  { grid-area: voice; }
  #pane-room > .room   { grid-area: chat; min-height: 0; }

  /* The strip becomes a wall. Ten tiles in a row would be postage stamps, so
     they wrap into as many columns as the width allows. */
  #pane-room .cams__strip {
    display: grid;
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    grid-auto-columns: unset;
    gap: 10px;
    overflow: visible;
  }

  /* The expanded cam takes the left column rather than floating over the page,
     so the grid stays visible underneath and switching cams is one click. */
  /* The player is an overlay on desktop too - see the block further down - so
     nothing here should try to place it inside the column. */

  .voice { border-left: 0; }
}

/* Wider still: give the chat a little more room rather than stretching the
   cams beyond a comfortable size. */
@media (min-width: 1500px) {
  #pane-room.is-active { grid-template-columns: minmax(0, 1fr) 460px; }
  #pane-room .cams__strip { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
}


/* ============ expanded cam: fullscreen on mobile, modal on desktop ============ */

/*
 * Watching gets the whole screen.
 *
 * In the flow the player competed with the grid and the chat for height, which
 * on a phone left it a band in the middle of a busy page. Lifting it out means
 * the stream is the only thing on screen, which is what someone who tapped a cam
 * asked for. The close button returns them exactly where they were - nothing
 * else changes, and no history entry is spent.
 */
.cambig {
  position: fixed;
  inset: 0;
  z-index: 85;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #07050a;
  margin: 0;
  padding: 0;
  animation: fade-in .16s ease-out;
}

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

/* The blurred still behind the video. Scaled up past the edges so the blur has
   nothing to fade into, and dimmed so it never competes with the stream. */
.cambig__wash {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center;
  filter: blur(34px) brightness(.45) saturate(1.2);
  transform: scale(1.15);
  pointer-events: none;
}

.cambig__wash:empty { background-color: #07050a; }

/*
 * Portrait by default, because that is what a phone camera produces and what a
 * phone screen wants. The video is contained rather than cropped, so nothing is
 * cut off; the blurred wash fills whatever is left.
 */
.cambig__stage {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  max-width: min(100vw, calc(100vh * 9 / 16));
  max-height: 100vh;
  aspect-ratio: auto;
  border-radius: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  overflow: visible;
}

.cambig__video video { object-fit: contain; background: transparent; }

/* Controls clear of the notch and the home indicator. */
.cambig__controls {
  top: calc(10px + env(safe-area-inset-top));
  right: calc(10px + env(safe-area-inset-right));
  z-index: 3;
}

.cambig__foot {
  padding-bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 3;
}

.cambig__badge { top: calc(12px + env(safe-area-inset-top)); z-index: 3; }

.cambig__btn {
  width: 42px;
  height: 42px;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(8px);
}

@media (min-width: 1000px) {
  /*
   * On desktop it becomes a window rather than taking the screen. The page
   * behind stays visible and in place, which is the difference between "I opened
   * a cam" and "I left the site".
   */
  .cambig {
    padding: 32px;
    background: rgba(4, 2, 8, .82);
    backdrop-filter: blur(10px);
  }

  /*
   * An explicit width, not auto.
   *
   * Everything inside the stage is absolutely positioned, so it contributes no
   * intrinsic size - with width:auto the box collapsed to zero and the video
   * vanished the moment the window crossed this breakpoint. Height comes from
   * the aspect ratio, and the width is capped by whichever limit binds first,
   * including the one derived from the height so a short window never pushes the
   * player off the screen.
   */
  .cambig__stage {
    width: min(92vw, 1080px, calc(86vh * 16 / 9));
    height: auto;
    max-width: none;
    max-height: 86vh;
    aspect-ratio: 16 / 9;
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 30px 90px rgba(0, 0, 0, .7);
  }

  .cambig__wash { display: none; }   /* the page behind is the backdrop here */

  .cambig__controls { top: 12px; right: 12px; }
  .cambig__foot { padding-bottom: 12px; }
  .cambig__badge { top: 14px; }
}

/* A landscape phone has no vertical room for a 9:16 box. */
@media (max-width: 999px) and (orientation: landscape) {
  .cambig__stage { max-width: 100vw; max-height: 100vh; }
}

/* Nothing behind the overlay should scroll while it is open. */
body.is-camopen { overflow: hidden; }

/* ============ chrome ============ */

/*
 * The top bar carries the gradient, thinly.
 *
 * In the reference the brand colour appears as a strip and then almost nowhere
 * else. That is what keeps it feeling expensive rather than loud: the eye reads
 * one accent, so the accent means something.
 */
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: relative;
}

.topbar::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--grad);
  opacity: .9;
}

.topbar__count b { color: var(--online); }

/* Selected tab: the gradient as a mark under the label rather than a filled
   block, which on a dark page would read as a hole. */
.tab.is-active,
.sidenav__item.is-active {
  color: var(--text);
  background: none;
  position: relative;
}

.tab.is-active .ic,
.sidenav__item.is-active .ic { color: var(--accent); }

.tab.is-active::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 6px;
  width: 22px;
  height: 3px;
  border-radius: 999px;
  background: var(--grad);
}

.sidenav__item.is-active {
  background: var(--surface-2);
  border-radius: 10px;
  box-shadow: inset 2px 0 0 var(--accent);
}

.srow:hover,
.row-item:hover,
.rmsg:hover { background: var(--surface-2); }

/* Inputs are wells cut into the page, not raised cards. */
.room__composer input,
.gifs__bar input,
.field input,
.field select,
.field textarea {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--text);
}

.room__composer input:focus,
.field input:focus,
.field textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(212, 60, 224, .16);
  outline: none;
}

.rmsg__body { color: var(--text); }
.bubble--in { background: var(--surface-2); border-color: var(--line); }
.thread, .room__log { background: var(--bg); }

/* Anything that was the primary action now carries the gradient. */
.btn--primary,
.room__send,
.voice__mic.is-on,
.cams__go {
  background: var(--grad);
  border-color: transparent;
  color: #fff;
}

.btn--primary:hover { box-shadow: var(--glow-hot); }

.bubble--out {
  background: var(--grad);
  box-shadow: 0 2px 14px rgba(212, 60, 224, .22);
}

/* The admin search box. Full width because a name is the only thing going in
   it, and a narrow field would just make long names awkward to check. */
.admin__find { margin-bottom: 10px; }

.admin__find input {
  width: 100%;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--text);
  font-size: 14.5px;
  outline: none;
}

.admin__find input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Two actions per row on a phone would overflow, so they wrap under the name
   rather than squeezing the name out. */
@media (max-width: 420px) {
  .admin__row { flex-wrap: wrap; }
  .admin__acts { width: 100%; justify-content: flex-end; }
}


/* ============ landing ============ */

.hero { position: relative; isolation: isolate; overflow: hidden; background: var(--bg); }

/*
 * The dot field. Two layers at different scales so it does not read as a
 * regular grid, faded out towards the centre so the copy always sits on plain
 * black - the moment text crosses a pattern it gets harder to read, however
 * faint the pattern is.
 */
.hero__dots {
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image:
    radial-gradient(rgba(212, 60, 224, .30) 1px, transparent 1px),
    radial-gradient(rgba(124, 77, 255, .18) 1px, transparent 1px);
  background-size: 22px 22px, 38px 38px;
  background-position: 0 0, 11px 11px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 35%, #000 100%);
  mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 35%, #000 100%);
}

/* A single soft bloom behind the headline, which is where the reference's
   colour actually comes from. */
.hero__glow {
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 12%;
  width: min(760px, 120vw);
  height: 420px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(212, 60, 224, .22) 0%, rgba(124, 77, 255, .10) 45%, transparent 70%);
  pointer-events: none;
}

.hero__strip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 9px 16px;
  background: var(--grad);
  color: #fff;
  font-size: 13px;
  text-decoration: none;
  text-align: center;
}

.hero__strip .ic { width: 15px; height: 15px; }
.hero__strip b { font-weight: 750; }

.hero__strip-cta {
  padding: 3px 12px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .28);
  font-weight: 700;
  font-size: 12.5px;
}

.hero__inner {
  position: relative;
  max-width: 780px;
  margin: 0 auto;
  padding: 40px 20px calc(48px + env(safe-area-inset-bottom));
  text-align: center;
}

.hero__brand { justify-content: center; margin-bottom: 34px; }

.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 16px;
  margin-bottom: 20px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
}

.hero__eyebrow .ic { width: 14px; height: 14px; color: var(--accent-hot); }

.hero__title {
  margin: 0 0 18px;
  font-size: clamp(30px, 7vw, 52px);
  line-height: 1.12;
  font-weight: 800;
  letter-spacing: -0.035em;
}

/* The one place the gradient touches type. Used on a single word, because a
   whole headline in gradient stops being emphasis and becomes decoration. */
.hero__grad {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero__lead {
  margin: 0 auto 28px;
  max-width: 520px;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--muted);
}

.hero__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 34px;
  border-radius: 999px;
  background: var(--grad);
  color: #fff;
  font-size: 16px;
  font-weight: 750;
  text-decoration: none;
  box-shadow: var(--glow-hot);
  transition: transform .12s ease, box-shadow .12s ease;
}

.hero__cta:hover { transform: translateY(-1px); box-shadow: 0 10px 34px rgba(255, 47, 179, .5); }
.hero__cta:active { transform: none; }
.hero__cta span { font-size: 19px; line-height: 1; }

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

.hero__trust {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin: 18px 0 0;
  font-size: 13.5px;
  color: var(--muted);
}

.hero__trust .ic { width: 15px; height: 15px; color: var(--online); }
.hero__trust b { color: var(--text); }

.hero__feats {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
}

.hero__feats li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  font-size: 13px;
  color: var(--muted);
}

.hero__feats .ic { width: 14px; height: 14px; color: var(--accent); }

.hero__cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin: 38px 0 0;
  text-align: left;
}

@media (min-width: 720px) { .hero__cards { grid-template-columns: repeat(3, 1fr); } }

.hcard {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 14px;
  border-radius: 16px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.hcard__face {
  width: 46px;
  height: 46px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--accent);
}

.hcard figcaption { min-width: 0; }
.hcard b { display: block; font-size: 14px; margin-bottom: 2px; }
.hcard span { font-size: 12.5px; line-height: 1.45; color: var(--muted); }

.hcard--stat { justify-content: center; text-align: center; flex-direction: column; gap: 2px; }

.hcard__num {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.03em;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero__sub { margin: 30px 0 0; font-size: 12.5px; color: var(--muted); }

/* ---------- password reveal ---------- */

.pw { position: relative; display: block; }

/* The field gets room on the right so the eye never sits over the text - at a
   long password the caret would otherwise run underneath it. */
.pw input { width: 100%; padding-right: 46px; }

.pw__eye {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.pw__eye .ic { width: 18px; height: 18px; }
.pw__eye:hover { color: var(--text); }
.pw__eye.is-on { color: var(--accent); }
