/* =====================================================================
   /orb/ — Liquid Orb (WebGPU glass-liquid orb)
   ---------------------------------------------------------------------
   The studio HTML ships its CSS inline, which the site CSP
   (style-src 'self') would block, so it lives here as an external sheet.
   The canvas is full-bleed; the caption and state switch sit on top.
   ===================================================================== */

.orb-page {
  background: #030409;
  margin: 0;
  overflow: hidden;
}

/* site.css constrains every <main> to min(1120px, 100% - 32px) and centres
   it, so this page's shell has to opt back out. */
main.orb-shell {
  height: 100dvh;
  margin: 0;
  max-width: none;
  padding: 0;
  position: relative;
  width: 100%;
}

/* Fixed, not absolute: the stage must be the viewport even though its
   <main> ancestor is width-constrained. */
.orb-stage {
  inset: 0;
  overflow: hidden;
  position: fixed;
  z-index: 0;
}

/* The canvas needs its own size -- putting 100% only on the wrapper left it
   at the 300x150 default, which is why the orb looked missing. */
.orb-canvas,
.orb-canvas canvas {
  display: block;
  height: 100%;
  width: 100%;
}

/* Entry dialog. Once dismissed the page is bare: the orb, and the
   hold-to-talk control centred beneath it. */
.orb-intro {
  align-items: center;
  background: rgba(3, 4, 9, 0.66);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
  backdrop-filter: blur(14px) saturate(130%);
  display: grid;
  inset: 0;
  justify-items: center;
  padding: 24px;
  position: fixed;
  /* Above the injected site nav (z-index 950) so it reads as a real modal. */
  z-index: 1200;
}

.orb-intro[hidden] {
  display: none;
}

.orb-intro__card {
  background: linear-gradient(145deg, rgba(18, 26, 52, 0.92), rgba(4, 8, 20, 0.96));
  border: 1px solid rgba(124, 246, 255, 0.22);
  border-radius: 4px;
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  display: grid;
  gap: 16px;
  justify-items: start;
  max-width: min(400px, calc(100vw - 40px));
  padding: 26px 24px;
  position: relative;
  text-align: left;
}

.orb-intro__close {
  appearance: none;
  background: #f5f7ff;
  border: 1px solid #f5f7ff;
  border-radius: 999px;
  color: #07101e;
  cursor: pointer;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  min-height: 44px;
  padding: 0 26px;
  width: 100%;
}

.orb-intro__close:hover {
  background: #7cf6ff;
  border-color: #7cf6ff;
}

.orb-intro__close:focus-visible {
  outline: 2px solid #7cf6ff;
  outline-offset: 3px;
}

.orb-kicker {
  color: #7cf6ff;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.2em;
  margin: 0;
}

.orb-title {
  color: #f5f7ff;
  font-size: clamp(26px, 5vw, 40px);
  font-weight: 560;
  letter-spacing: -0.05em;
  line-height: 1;
  margin: 0;
}

.orb-copy {
  color: rgba(215, 223, 245, 0.62);
  font-size: 12px;
  line-height: 1.75;
  margin: 0;
  max-width: 300px;
}

.orb-switch {
  display: flex;
  gap: 8px;
}

.orb-switch button {
  appearance: none;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(124, 246, 255, 0.26);
  border-radius: 999px;
  color: rgba(245, 247, 255, 0.86);
  cursor: pointer;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.1em;
  min-height: 34px;
  padding: 0 14px;
}

.orb-switch button[aria-pressed="true"] {
  background: #7cf6ff;
  border-color: #7cf6ff;
  color: #07101e;
}

.orb-switch button:focus-visible {
  outline: 2px solid #7cf6ff;
  outline-offset: 2px;
}

/* Press-and-hold voice, centred under the orb. The shader draws the ball at
   0.36 x min(viewport) radius, so its lower limb sits 36vmin below centre. */
.orb-talk-wrap {
  display: grid;
  gap: 10px;
  justify-items: center;
  left: 50%;
  position: fixed;
  top: min(calc(50% + 36vmin + clamp(14px, 2.6vmin, 30px)), calc(100% - 88px));
  transform: translateX(-50%);
  z-index: 12;
}

.orb-talk-wrap[hidden] {
  display: none;
}

.orb-talk {
  align-items: center;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(124, 246, 255, 0.32);
  border-radius: 999px;
  color: #f5f7ff;
  cursor: pointer;
  display: inline-flex;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 11px;
  gap: 9px;
  letter-spacing: 0.08em;
  min-height: 44px;
  padding: 0 18px;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  transition: background 180ms ease, border-color 180ms ease, transform 120ms ease;
}

.orb-talk__dot {
  background: #7cf6ff;
  border-radius: 50%;
  box-shadow: 0 0 10px rgba(124, 246, 255, 0.75);
  display: block;
  height: 8px;
  width: 8px;
}

.orb-talk.is-recording {
  background: rgba(245, 118, 197, 0.16);
  border-color: rgba(245, 118, 197, 0.6);
  transform: scale(1.02);
}

.orb-talk.is-recording .orb-talk__dot {
  animation: orb-talk-pulse 1s ease-in-out infinite;
  background: #f576c5;
  box-shadow: 0 0 12px rgba(245, 118, 197, 0.9);
}

.orb-talk:focus-visible {
  outline: 2px solid #7cf6ff;
  outline-offset: 2px;
}

.orb-talk-hint {
  color: rgba(206, 216, 242, 0.45);
  font-size: 10px;
  line-height: 1.6;
  margin: 0;
  max-width: min(300px, 80vw);
  text-align: center;
}

/* Nothing to say most of the time: the stage stays just the orb + the button. */
.orb-talk-hint:empty {
  display: none;
}

@keyframes orb-talk-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.55; transform: scale(1.35); }
}

/* Saved recordings: a discreet corner toggle and a glass panel above it. */
.orb-clips-toggle {
  align-items: center;
  appearance: none;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  background: rgba(10, 16, 30, 0.7);
  border: 1px solid rgba(124, 246, 255, 0.24);
  border-radius: 999px;
  bottom: max(18px, env(safe-area-inset-bottom, 0px) + 14px);
  color: rgba(245, 247, 255, 0.86);
  cursor: pointer;
  display: inline-flex;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 10px;
  gap: 7px;
  letter-spacing: 0.1em;
  min-height: 36px;
  padding: 0 14px;
  position: fixed;
  right: max(16px, env(safe-area-inset-right, 0px) + 14px);
  z-index: 900;
}

.orb-clips-toggle:hover {
  border-color: rgba(124, 246, 255, 0.6);
  color: #7cf6ff;
}

.orb-clips-toggle__count {
  background: rgba(124, 246, 255, 0.16);
  border-radius: 999px;
  min-width: 18px;
  padding: 1px 5px;
  text-align: center;
}

.orb-clips {
  background: linear-gradient(145deg, rgba(18, 26, 52, 0.94), rgba(4, 8, 20, 0.97));
  border: 1px solid rgba(124, 246, 255, 0.2);
  border-radius: 4px;
  bottom: max(64px, env(safe-area-inset-bottom, 0px) + 60px);
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.5);
  color: rgba(215, 223, 245, 0.75);
  display: grid;
  gap: 10px;
  max-height: min(52vh, 420px);
  overflow: auto;
  padding: 16px;
  position: fixed;
  right: max(16px, env(safe-area-inset-right, 0px) + 14px);
  width: min(300px, calc(100vw - 32px));
  z-index: 910;
}

.orb-clips[hidden] {
  display: none;
}

.orb-clips__head {
  align-items: center;
  display: flex;
  justify-content: space-between;
}

.orb-clips__head strong {
  color: #f5f7ff;
  font-size: 13px;
  font-weight: 600;
}

.orb-clips__close {
  appearance: none;
  background: transparent;
  border: 0;
  color: rgba(225, 232, 250, 0.6);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  min-height: 32px;
  min-width: 32px;
}

.orb-clips__close:hover {
  color: #7cf6ff;
}

.orb-clips__list {
  display: grid;
  gap: 6px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.orb-clip {
  align-items: center;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  display: grid;
  gap: 10px;
  grid-template-columns: 32px 1fr 28px;
  padding: 8px 10px;
}

.orb-clip__play {
  appearance: none;
  background: rgba(124, 246, 255, 0.12);
  border: 1px solid rgba(124, 246, 255, 0.3);
  border-radius: 50%;
  color: #7cf6ff;
  cursor: pointer;
  font-size: 11px;
  height: 30px;
  line-height: 1;
  width: 30px;
}

.orb-clip__play:hover {
  background: rgba(124, 246, 255, 0.24);
}

.orb-clip__meta {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.orb-clip__meta strong {
  color: #f5f7ff;
  font-size: 12px;
  font-weight: 600;
}

.orb-clip__meta span {
  color: rgba(206, 216, 242, 0.42);
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 9px;
}

.orb-clip__delete {
  appearance: none;
  background: transparent;
  border: 0;
  color: rgba(225, 232, 250, 0.45);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  min-height: 28px;
}

.orb-clip__delete:hover {
  color: #f576c5;
}

.orb-clips__empty,
.orb-clips__note {
  color: rgba(206, 216, 242, 0.42);
  font-size: 10px;
  line-height: 1.6;
  margin: 0;
}

.orb-clips__empty[hidden],
.orb-clips__clear[hidden] {
  display: none;
}

.orb-clips__clear {
  appearance: none;
  background: transparent;
  border: 1px solid rgba(245, 118, 197, 0.34);
  border-radius: 999px;
  color: rgba(245, 190, 225, 0.9);
  cursor: pointer;
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  min-height: 32px;
  padding: 0 14px;
}

.orb-clips__clear:hover {
  border-color: rgba(245, 118, 197, 0.7);
}

/* Shown when WebGPU is missing or the shader fails to build. A pure-CSS orb
   stands in so phones without WebGPU still see the piece, not an error. */
.orb-fallback {
  align-content: center;
  background: radial-gradient(circle at 50% 42%, rgba(124, 246, 255, 0.13), transparent 46%), #030409;
  color: rgba(226, 232, 240, 0.72);
  display: grid;
  font-size: 13px;
  gap: 14px;
  inset: 0;
  justify-items: center;
  line-height: 1.7;
  padding: 32px;
  position: fixed;
  text-align: center;
  z-index: 20;
}

/* `hidden` must win: an author `display: grid` outranks the UA rule. */
.orb-fallback[hidden] {
  display: none;
}

.orb-fallback__ball {
  animation: orb-fallback-float 9s ease-in-out infinite;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.82), transparent 22%),
    radial-gradient(circle at 30% 32%, rgba(124, 246, 255, 0.5), transparent 56%),
    radial-gradient(circle at 72% 74%, rgba(245, 118, 197, 0.42), transparent 58%),
    radial-gradient(circle at 46% 52%, rgba(139, 132, 232, 0.4), transparent 62%),
    radial-gradient(circle at 50% 50%, #16224a, #05070f 74%);
  border: 1px solid rgba(124, 246, 255, 0.26);
  border-radius: 50%;
  box-shadow: 0 0 90px rgba(124, 246, 255, 0.2), inset 0 0 60px rgba(124, 246, 255, 0.12);
  display: block;
  height: min(46vw, 240px);
  width: min(46vw, 240px);
}

@keyframes orb-fallback-float {
  0%, 100% { transform: translateY(-6px) scale(1); }
  50% { transform: translateY(6px) scale(1.03); }
}

.orb-fallback strong {
  color: #f5f7ff;
  font-size: 15px;
  font-weight: 600;
}

.orb-fallback code {
  color: rgba(124, 246, 255, 0.9);
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 11px;
  max-width: min(560px, 92vw);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Live status line in the caption, so a screenshot names the cause. */
.orb-diag {
  color: rgba(206, 216, 242, 0.45);
  font-family: "SF Mono", "Cascadia Mono", ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.04em;
  margin: 0;
}

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

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

  .orb-talk,
  .orb-talk.is-recording .orb-talk__dot {
    animation: none;
    transition: none;
  }
}
