/* --------------------------------
   MIC TOGGLE

   Adapted from a CSS-only lighted switch. Two changes worth knowing:

   - Everything is scoped under .toggle. The original set a global
     `* { transition: all }` and its own body layout, which would have
     animated every element on the page and fought the app shell.
   - The checkbox is visually hidden rather than display:none, so it
     stays in the tab order. A switch you cannot reach by keyboard is
     not a switch.
-------------------------------- */

.toggle {
  --sz: clamp(34px, 12vw, 58px);
  /* Inherited from the page palette so the switch cannot drift
     from the wordmark and the waveform. */
  --on: var(--blue);
  --of: var(--blue-muted);
  --tr: all 0.25s ease 0s;

  position: relative;

  width: calc(var(--sz) * 4);
  max-width: 100%;
  height: calc(var(--sz) * 2);

  margin: 10px 0 8px;

  display: flex;
  align-items: center;
  justify-content: center;

  flex-shrink: 0;
}

.toggle * {
  box-sizing: border-box;
  transition: var(--tr);
}

.toggle input {
  position: absolute;

  width: 0;
  height: 0;

  opacity: 0;
}

.toggle input:focus-visible + label {
  outline: 3px solid var(--on);
  outline-offset: 5px;
}

/* --p is how far across the thumb is, 0 (off) to 1 (on). The thumb and
   the blue fill both follow it, so a slide can move them part way with
   --drag and a tap animates them the whole way. */
.toggle label {
  --p: 0;

  position: absolute;

  width: calc(var(--sz) * 4);
  height: calc(var(--sz) * 1.8);

  padding: calc(var(--sz) / 5);

  border-radius: var(--sz);

  background: var(--switch-body);

  box-shadow: 0 0 calc(var(--sz) / 50) calc(var(--sz) / 50) #0002;

  cursor: pointer;
}

.toggle input:checked + label {
  --p: 1;

  box-shadow:
    0 0 calc(var(--sz) / 3) calc(var(--sz) / 14) var(--on),
    0 0 calc(var(--sz) / 50) calc(var(--sz) / 50) #0002;
}

/* --------------------------------
   TRACK
-------------------------------- */

.toggle .track {
  position: absolute;
  left: calc(var(--sz) / 5);
  top: calc(var(--sz) / 5);

  width: calc(100% - calc(var(--sz) * 0.4));
  height: calc(100% - calc(var(--sz) * 0.4));

  border-radius: var(--sz);

  overflow: hidden;
}

.toggle .track::before {
  content: "";

  position: absolute;
  left: calc((var(--p) - 1) * 100%);

  width: 200%;
  height: 100%;

  background: linear-gradient(90deg, var(--on) 50%, var(--of) 50%);
}

/* Sits above the colour fill and the ON/OFF text, so the whole track reads
   as recessed rather than as a flat panel with a lid over it. */
.toggle .track::after {
  content: "";

  position: absolute;
  inset: 0;

  border-radius: var(--sz);

  box-shadow:
    0 calc(var(--sz) / -32) calc(var(--sz) / 8) 0 #0004 inset,
    0 calc(var(--sz) / 8) calc(var(--sz) / 8) 0 #0004 inset;
}

/* --------------------------------
   THUMB
-------------------------------- */

.toggle .thumb {
  position: absolute;
  top: calc(var(--sz) / 5);
  /* Travel is the label (4) less the thumb (1.6) and both insets (0.4). */
  left: calc(var(--sz) / 5 + var(--p) * var(--sz) * 2);

  width: calc(var(--sz) * 1.6);
  height: calc(var(--sz) * 1.4);

  border-radius: var(--sz);

  background: linear-gradient(180deg, #fff, #afafaf);

  box-shadow:
    0 0 0 calc(var(--sz) / 50) #0002,
    0 calc(var(--sz) / 10) calc(var(--sz) / 10) 0 #0008;

  display: flex;
  align-items: center;
  justify-content: center;

  color: #7d7c7c;
  font-size: calc(var(--sz) / 2);
  text-indent: calc(var(--sz) * -0.025);
  text-shadow:
    calc(var(--sz) / -8000) calc(var(--sz) / -150) calc(var(--sz) / 50) #0008,
    calc(var(--sz) / 150) calc(var(--sz) / 100) calc(var(--sz) / 50) #fff;

  cursor: pointer;
  z-index: 1;
}

.toggle input:checked + label .thumb {
  background:
    radial-gradient(
      circle at 7% 50%,
      #fff calc(var(--sz) / 50),
      #fff0 calc(var(--sz) / 2)
    ),
    radial-gradient(circle at 0 50%, var(--on) 10%, #fff0 60%),
    linear-gradient(180deg, #fff, #afafaf);

  color: var(--on);
  text-shadow:
    0 0 calc(var(--sz) / 10) var(--on),
    0 0 calc(var(--sz) / 5) #fff,
    calc(var(--sz) / -8000) calc(var(--sz) / -150) calc(var(--sz) / 50) #0008,
    calc(var(--sz) / 150) calc(var(--sz) / 100) calc(var(--sz) / 50) #fff;
}

.toggle .thumb::before {
  content: "";

  display: block;

  width: 70%;
  height: 70%;

  border: calc(var(--sz) / 50) solid #ddd;
  border-radius: var(--sz);

  background: linear-gradient(180deg, #0008, #ccc, #fff);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.533),
    #ccc,
    #aaaaaa
  );
  position: absolute;
  z-index: -1;
}

/* --------------------------------
   ON / OFF
-------------------------------- */

.toggle .txt {
  position: absolute;
  inset: 0;
}

.toggle .txt::before,
.toggle .txt::after {
  content: "ON";

  position: absolute;
  top: 50%;
  left: 13%;

  transform: translateY(-50%);

  color: #000;
  font-family: inherit;
  font-size: calc(var(--sz) / 1.6);
  /* 3:1 on the blue and on the grey: large text, and it names the state. */
  opacity: 0.75;
  text-shadow:
    0 -1px 1px #000,
    0 1px 2px #fff;

  transition: var(--tr);
}

.toggle .txt::after {
  content: "OFF";

  left: auto;
  right: 11%;
}

/* --------------------------------
   LOCKED — while AppealBuddy is replying

   The switch physically cannot be turned on mid-reply, which is what
   keeps the two of you off each other's turn.
-------------------------------- */

.toggle.is-locked label,
.toggle.is-locked .thumb {
  cursor: not-allowed;
}

.toggle.is-locked {
  opacity: 0.55;
  filter: saturate(0.5);
}

/* --------------------------------
   SLIDING — the thumb under a finger

   While a slide is in progress app.js sets --drag on the shell, and the
   thumb and fill track it with no easing, so they stay under the finger
   instead of trailing behind it. Letting go drops the class, and the
   transition carries the thumb the rest of the way.
-------------------------------- */

.toggle.is-dragging label {
  --p: var(--drag);

  cursor: grabbing;
}

.toggle.is-dragging .thumb,
.toggle.is-dragging .track::before {
  transition: none;

  cursor: grabbing;
}

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

/* --------------------------------
   WAVEFORM — flat until the mic is live

   At rest the bars used their staggered heights, which read as a frozen
   capture. Here they sit as a flat line and rise into the existing
   animation only while the switch is on; switching off, or the agent
   taking its turn, drops them back. Height transitions both ways so it
   settles rather than snapping.
-------------------------------- */

.toggle + .waveform span {
  transition:
    height 0.3s ease,
    opacity 0.3s ease;
}

/* Faded at rest, so the idle line reads as quiet rather than as a row of
   live dots. Opacity lightens the same blue instead of changing it, and
   transitions back to full strength as the bars rise. */
.toggle:not(.is-recording) + .waveform span:nth-child(n) {
  height: 5px;

  opacity: 0.35;
}

/* --------------------------------
   SUBTITLE — fixed height

   The line above the switch changes with the conversation, and some
   messages wrap to two lines while others fit on one. The column is
   centred, so every change of line count moved the switch 10-11px.

   Two lines are always reserved, and the text sits on the bottom of
   that space, so a one-liner stays close to the switch and a two-liner
   grows upward into the reserve. The switch no longer depends on the
   wording.
-------------------------------- */

.subtitle {
  min-height: calc(2 * 1.3em);

  display: flex;
  align-items: flex-start;
  justify-content: center;

  line-height: 1.3;
}

/* --------------------------------
   NO BROWSER FLASHES

   The switch is a label wrapped around real text — the knob's |||. Two
   quick taps read as a double-click and selected that text, drawing a
   blue selection box; on phones the browser also flashed its default tap
   highlight over the whole label. The start button already opts out of
   both; the switch now does too.

   touch-action: manipulation drops the phone's double-tap-to-zoom wait,
   so a second tap toggles straight back instead of hesitating. The label
   narrows that to pan-y: a sideways drag belongs to the slide, not to the
   page, while a vertical swipe that starts on the switch still scrolls.
-------------------------------- */

.toggle,
.toggle label {
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;

  touch-action: manipulation;
}

.toggle label {
  touch-action: pan-y;
}
