/* Junto "Sage & Dune" theme: blue/aqua/teal diagonal gradient backdrop with
   a dark scrim for text legibility, Fredoka wordmark + Nunito UI, teal brand
   mark and blue (#598EAD) accents. Room header top, icon toolbar bottom,
   camera card centered until screen sharing starts (body.sharing). */
@font-face {
  font-family: "Fredoka";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("fonts/fredoka.woff2") format("woff2");
}
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 400 800; /* variable file covers the whole range */
  font-display: swap;
  src: url("fonts/nunito.woff2") format("woff2");
}

:root {
  --brand-teal: #84D6D6;
  --accent: #598EAD;            /* active mic/cam/leave solid blue */
  --accent-soft: #598EAD40;     /* translucent tint for idle blue-accent icons */
  --accent-deep: #24566F;       /* same blue, dark enough for white text on a light bg */
  --invite: #CF6363;            /* coral invite button */
  --ink: #2b2320;               /* dark text on light chips */
  --video-fill: #6F6E6BB4;      /* camera-feed placeholder */
}

* { box-sizing: border-box; }

body {
  font-family: "Nunito", -apple-system, system-ui, sans-serif;
  margin: 0;
  color: #fff;
}

/* Blue/aqua/teal diagonal sweep + dark scrim (both on one layer so the
   weather-on toggle can hide it with a single rule). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  /* Movie mode: going fullscreen dims the whole wallpaper to near-black over
     ~0.7s so the picture is the only bright thing left. */
  transition: filter 0.7s ease;
  background:
    linear-gradient(180deg, rgba(15, 12, 8, 0.22) 0%, rgba(15, 12, 8, 0.06) 22%, rgba(15, 12, 8, 0.08) 78%, rgba(15, 12, 8, 0.28) 100%),
    radial-gradient(circle at 0% 0%, oklch(98% 0.02 190 / 0.9) 0%, oklch(98% 0.02 190 / 0.45) 25%, oklch(98% 0.02 190 / 0) 60%),
    linear-gradient(300deg, oklch(85% 0.06 225) 0%, oklch(89% 0.07 195) 34%, oklch(92% 0.035 185) 64%, oklch(87% 0.05 210) 100%);
}

/* Location-weather background (opt-in, pre-share only): two halves, each
   independently tinted to a real weather condition. Hidden by default so
   anyone who never enables it sees exactly the static wallpaper above. */
.wx-half { display: none; position: fixed; inset: 0; width: 50vw; z-index: -1; transition: filter 0.7s ease; }
.wx-right { left: 50vw; }
body.weather-on .wx-half { display: block; }
body.weather-on::before { display: none; }

/* Custom photo backdrop: keeps the same dark scrim (for text legibility)
   but swaps the color-sweep layer for the picked image. wireCustomBackground
   and wireWeather turn each other off, but this stays as a defensive
   backstop in case both classes are ever on at once. */
body.custom-bg-on::before {
  background:
    linear-gradient(180deg, rgba(20, 15, 10, 0.32) 0%, rgba(20, 15, 10, 0.06) 22%, rgba(20, 15, 10, 0.1) 78%, rgba(20, 15, 10, 0.4) 100%),
    var(--custom-bg) center / cover no-repeat;
}
body.custom-bg-on .wx-half { display: none; }

.wx-clear { background: linear-gradient(180deg, #6fb3ff 0%, #bfe0ff 55%, #ffe9b8 100%); }
.wx-cloudy { background: linear-gradient(180deg, #8fa3c2 0%, #b7c3d9 60%, #d8dee8 100%); }
.wx-fog { background: linear-gradient(180deg, #aab3bd 0%, #c9ced4 100%); }
.wx-rain {
  background:
    repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.12) 0 2px, transparent 2px 26px),
    linear-gradient(180deg, #435b7a 0%, #5b7699 100%);
}
.wx-snow { background: linear-gradient(180deg, #b9c6d6 0%, #e8edf3 100%); }
.wx-storm { background: linear-gradient(180deg, #2b3350 0%, #48507a 100%); }
/* Sun glow, clear-daytime only — echoes the reference photo's soft radial sun. */
.wx-clear:not(.wx-night)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 70% 22%, rgba(255, 244, 205, 0.85), transparent 45%);
}
/* Night: a translucent navy wash over whatever bucket, instead of a full
   second set of gradients. */
.wx-night::before { content: ""; position: absolute; inset: 0; background: rgba(8, 14, 40, 0.55); }

/* Every glass surface keeps a faint dark underlay beneath the white sheen,
   so white icons/text stay readable even over a blown-out bright feed. */
.glass {
  background:
    linear-gradient(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.08)),
    rgba(36, 30, 62, 0.35);
  backdrop-filter: blur(28px) saturate(1.8);
  -webkit-backdrop-filter: blur(28px) saturate(1.8);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px;
  box-shadow:
    0 8px 32px rgba(20, 15, 50, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

button {
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 10px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 3px rgba(20, 15, 50, 0.35);
  cursor: pointer;
  background:
    linear-gradient(rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.07)),
    rgba(36, 30, 62, 0.42);
  backdrop-filter: blur(20px) saturate(1.8);
  -webkit-backdrop-filter: blur(20px) saturate(1.8);
  box-shadow:
    0 4px 16px rgba(20, 15, 50, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08);
  transition: background 0.15s, transform 0.12s cubic-bezier(0.34, 1.56, 0.64, 1);
}
button:hover:not(:disabled) {
  background:
    linear-gradient(rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0.18)),
    rgba(36, 30, 62, 0.42);
  transform: translateY(-1px);
}
button:active:not(:disabled) {
  transform: scale(0.92);
  background:
    linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.12)),
    rgba(36, 30, 62, 0.42);
}
button:disabled { opacity: 0.5; cursor: default; }
button.primary, button.accent {
  background:
    linear-gradient(rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.26)),
    rgba(36, 30, 62, 0.3);
}

input[type="text"], input:not([type]) {
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 10px;
  padding: 8px 14px;
  font-size: 13px;
  color: #fff;
  background: rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(20px) saturate(1.8);
  outline: none;
}
input::placeholder { color: rgba(255, 255, 255, 0.65); }
input:focus { border-color: rgba(255, 255, 255, 0.7); }

label { font-size: 12px; font-weight: 600; display: inline-flex; align-items: center; gap: 6px; text-shadow: 0 1px 3px rgba(20, 15, 50, 0.35); }

input[type="range"] {
  -webkit-appearance: none;
  width: 110px;
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.25);
  box-shadow: inset 0 1px 2px rgba(20, 15, 50, 0.25);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 8px rgba(20, 15, 50, 0.35);
  cursor: pointer;
}

/* Junto header bar: brand mark + wordmark + room-code pill on the left,
   Invite on the right. */
#header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 26px;
}
#header .brand { display: flex; align-items: center; gap: 10px; }
/* The mark sits on a solid white squircle so the blue/pink shapes pop
   instead of washing into the backdrop. */
.brand-mark {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px;
  border-radius: 11px;
  background: #fff;
  box-shadow:
    0 4px 14px rgba(20, 15, 50, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.brand-mark svg,
.brand-mark img { width: 100%; height: 100%; object-fit: contain; }
.wordmark { font-family: "Fredoka", sans-serif; font-weight: 600; font-size: 19px; color: #fff; }
/* Brand lockup (mark + wordmark) reused by the popup and landing page. */
.brand-lockup { display: flex; align-items: center; gap: 9px; }

/* Guest join screen: a full-cover overlay with a glass card asking for a
   name before connecting. viewer.js removes it from the DOM on enter. */
#name-gate {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.gate-card {
  width: 320px;
  max-width: 100%;
  padding: 26px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  border-radius: 20px;
}
.gate-card .brand-lockup { margin-bottom: 2px; }
.gate-card .wordmark { font-size: 24px; }
.gate-sub { margin: 0; font-size: 14px; color: rgba(255, 255, 255, 0.9); }
.gate-card input { width: 100%; text-align: center; font-size: 15px; padding: 11px 14px; }
.gate-card #name-go { width: 100%; padding: 11px; font-weight: 800; }
.hdivider { width: 1px; height: 16px; background: rgba(255, 255, 255, 0.3); margin: 0 2px; }
.room-tag { font-size: 12.5px; color: rgba(255, 255, 255, 0.85); }
/* Room-code pill doubles as the copy button. */
#copy.code-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.18);
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  font-weight: 700;
  color: #fff;
  transition: background 0.15s;
}
#copy.code-pill:hover:not(:disabled) { background: rgba(255, 255, 255, 0.28); transform: none; }
#copy.code-pill svg { width: 12px; height: 12px; }
#copy.code-pill.copied { background: var(--accent); }
#status { font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, 0.85); margin-left: 4px; }
/* Coral Invite pill, top-right. */
#invite.invite {
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 13px;
  padding: 9px 16px;
  border: none;
  border-radius: 10px;
  color: #fff;
  background: var(--invite);
  box-shadow: 0 4px 14px rgba(120, 40, 40, 0.3);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
#invite.invite:hover:not(:disabled) { filter: brightness(1.08); background: var(--invite); transform: translateY(-1px); }
/* Right side of the header: who's in the room, then Invite. */
.hdr-right { display: flex; align-items: center; gap: 14px; }
/* Live face circles, overlapped like an avatar stack. */
#peers { display: flex; }
#peers video {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255, 255, 255, 0.55);
}
#peers video + video { margin-left: -9px; }
/* Each circle gets its own brand-spectrum fill, cycling every four, so a
   camera-off face is still a recognisable dot rather than grey. */
#peers video:nth-child(4n + 1) { background: var(--brand-teal); }
#peers video:nth-child(4n + 2) { background: var(--invite); }
#peers video:nth-child(4n + 3) { background: var(--accent); }
#peers video:nth-child(4n + 4) { background: #F0C46A; }

/* The movie: hidden until sharing starts, then fills the window. */
video { border-radius: 14px; background: #10202b; }
#main { display: contents; }
video#preview, video#remote {
  display: none;
  position: fixed;
  top: 10px;
  left: 10px;
  width: calc(100vw - 20px);
  height: calc(100vh - 20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 8px 32px rgba(20, 15, 50, 0.25);
  object-fit: contain;
}
body.sharing video#preview, body.sharing video#remote { display: block; }

/* Icon-only toolbar centered at the bottom, all buttons in one glass pill;
   each button expands to show its label on hover and collapses back to a
   square when the mouse leaves. */
#toolbar {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  gap: 8px;
  padding: 10px;
  border-radius: 18px;
  background:
    linear-gradient(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.08)),
    rgba(36, 30, 62, 0.35);
  backdrop-filter: blur(28px) saturate(1.6);
  -webkit-backdrop-filter: blur(28px) saturate(1.6);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow:
    0 12px 32px rgba(40, 25, 90, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
#toolbar button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  padding: 0 13px;
}
#toolbar svg, #cam-controls svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}
/* Icon buttons everywhere share the expand-on-hover label. */
button .label {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width 0.25s ease, margin-left 0.25s ease;
}
button:hover .label,
button:focus-visible .label { max-width: 160px; margin-left: 8px; }

/* Camera window: always draggable from the middle (logic in signaling.js).
   While sharing it's also resizable from any edge or corner. Before sharing
   it starts centered, hugging the camera tiles as they grow with more
   people — until dragged, then it stays wherever it's put. */
#cam-window {
  position: fixed;
  bottom: 20px;
  left: 24px;
  z-index: 3;
  width: 320px;
  height: 220px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  cursor: grab;
}
/* While sharing, only the width is set: the height falls out of the tiles'
   own aspect ratio, so the feed never letterboxes or crops into slivers no
   matter how many people are in the room. inline-size (not size) keeps the
   cqw units working while leaving the height content-driven. */
body.sharing #cam-window {
  container-type: inline-size;
  height: auto;
  min-width: 160px;
  max-width: 720px;
}
/* Pre-share, once the user grabs an edge to resize: same width-driven model
   as sharing, so the box is resizable (and the tiles fill it) in every state. */
body:not(.sharing) #cam-window.sized {
  container-type: inline-size;
  height: auto;
  min-width: 160px;
  max-width: 720px;
}
body:not(.sharing) #cam-window.sized .bubble { flex: 1 1 0; min-width: 0; height: auto; }
/* Tiles split the window width evenly, each keeping the camera's own 4:3. */
body.sharing .bubble {
  flex: 1 1 0;
  min-width: 0;
  height: auto;
}
/* Controls shrink with the window instead of getting cut off. */
body.sharing #cam-controls { gap: 2.5cqw; padding: 2.5cqw 3cqw; }
body.sharing .cam-btn {
  height: auto;
  padding: 1.6cqw 2.2cqw;
  font-size: clamp(8px, 3.8cqw, 12px);
}
body.sharing #cam-controls svg { width: clamp(9px, 4.7cqw, 15px); height: clamp(9px, 4.7cqw, 15px); }
body.sharing .cam-btn:hover .label { max-width: 30cqw; }
body:not(.sharing) #cam-window {
  left: 50%;
  top: 50%;
  bottom: auto;
  transform: translate(-50%, -50%);
  width: max-content;
  height: max-content;
  max-width: 92vw;
}
/* Fixed tile size pre-share so the box hugs the faces and grows per person
   (height:100% can't resolve inside a max-content box). */
body:not(.sharing) .bubble { height: min(300px, 40vh); }
/* No cameras yet: a landscape placeholder screen instead of a sliver. */
body:not(.sharing) #bubbles:empty { min-width: 400px; min-height: 260px; }
/* Control panel: a bar attached to the bottom of the camera card, with its
   own dark tint so the icons read over any feed brightness. */
#cam-controls {
  display: flex;
  gap: 8px;
  justify-content: center;
  padding: 10px;
  background: rgba(28, 40, 52, 0.5);
}
.cam-btn { display: inline-flex; align-items: center; justify-content: center; height: 34px; padding: 0 9px; font-size: 12px; }
.cam-btn svg { width: 15px; height: 15px; }
#cam-chat { position: relative; }
/* Junto blue accents, shared by the camera control row and the bottom
   toolbar: idle is plain glass, hover tints soft blue, and engaged — held
   down, or toggled on (.on) — goes solid blue. */
#cam-controls button:hover:not(:disabled),
#toolbar button:hover:not(:disabled) {
  background: var(--accent-soft);
  border-color: rgba(255, 255, 255, 0.2);
}
#cam-controls button:active:not(:disabled),
#toolbar button:active:not(:disabled),
#cam-controls button.on,
#toolbar button.on {
  background: var(--accent);
  border-color: transparent;
}
/* The feed area: dark striped screen behind the camera tiles. Tiles reach
   flush to the card edge (no gutter) in every state; the card's rounded
   overflow clips the top corners. */
#bubbles {
  flex: 1;
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 0;
  min-height: 0;
  justify-content: center;
  overflow-x: auto;
  background: rgba(40, 54, 66, 0.6);
}
#bubbles:empty::after {
  content: "camera feed";
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.55);
}
/* Tiles carry the webcam's native 4:3, so `cover` has nothing to crop and
   the striped backdrop never peeks out around the feed. No own
   border/radius — the feed meets the card edge; a thin seam only separates
   adjacent tiles. */
.bubble { position: relative; height: 100%; aspect-ratio: 4 / 3; width: auto; flex: 0 0 auto; overflow: hidden; }
.bubble + .bubble { border-left: 1px solid rgba(255, 255, 255, 0.25); }
.bubble video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Camera disabled (locally or by the far side): hide the frozen last frame
   behind a flat placeholder instead of leaving a "ghost" feed on screen. */
.bubble.cam-off video { visibility: hidden; }
.bubble.cam-off { background: var(--video-fill); }
.bubble .name {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 2px 9px;
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.4);
  font-size: 11px;
  font-weight: 700;
}

/* Chat docks into the bottom of the camera window; toggled by the Chat
   hover button, so the summary is hidden. */
#chat summary { display: none; }
#chat { display: none; }
#chat[open] {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto; /* fixed block below the feed — never squeezes the cameras */
  min-height: 0;
  padding: 8px 10px 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  /* darker + heavier blur than the window so text stays readable over video */
  background: rgba(18, 30, 40, 0.6);
  backdrop-filter: blur(32px) saturate(1.5);
  -webkit-backdrop-filter: blur(32px) saturate(1.5);
}
/* Chrome wraps details content in ::details-content — flex it so the log
   fills the panel and the input sits at the bottom. */
#chat[open]::details-content { display: flex; flex-direction: column; gap: 6px; flex: 1; min-height: 0; }
.chat-head { display: flex; justify-content: space-between; align-items: center; font-size: 12px; font-weight: 600; }
/* Minimize "–" blends into the chat panel: no glass chrome of its own. */
.chat-head button {
  padding: 0 6px;
  font-size: 15px;
  line-height: 1.5;
  background: none;
  border: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
#chat-log { height: 100px; flex: none; overflow-y: auto; font-size: 12px; line-height: 1.45; overflow-wrap: anywhere; text-shadow: 0 1px 2px rgba(20, 15, 50, 0.3); }
#chat-input { font-size: 12px; padding: 6px 12px; }

/* Unread-chat badge riding the Chat hover button */
#chat-badge {
  position: absolute;
  top: -7px;
  right: -7px;
  z-index: 3;
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: #ff5e3a;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}

/* Floating dropdowns (Sound mixer, reaction picker) anchored to their button */
.dropdown { position: fixed; z-index: 5; display: flex; gap: 8px; align-items: center; padding: 8px 12px; }
.dropdown[hidden] { display: none; }
#react-picker button { padding: 5px 9px; font-size: 16px; }

/* In fullscreen the chrome fades away; hovering the toolbar area brings it
   and the header (with the room's face circles) back together. */
:fullscreen body::before, :fullscreen .wx-half { filter: brightness(0.1) saturate(0.35); }
:fullscreen #toolbar, :fullscreen #header { opacity: 0; transition: opacity 0.2s; }
:fullscreen #toolbar:hover,
:fullscreen #main:has(#toolbar:hover) #header { opacity: 1; }
.reaction {
  position: fixed;
  bottom: 40px;
  z-index: 4;
  font-size: 42px;
  pointer-events: none;
  animation: react-float 2.9s ease-out forwards;
}
@keyframes react-float {
  from { opacity: 1; transform: translateY(0) scale(0.8); }
  30%  { transform: translateY(-18vh) scale(1.25) rotate(-6deg); }
  60%  { transform: translateY(-38vh) scale(1.1) rotate(5deg); }
  to   { opacity: 0; transform: translateY(-60vh) scale(1.3); }
}
