/* ==========================================================================
   Parents on a phone (2026-11, Paper "Daily Call — Parent phone join").
   Loaded by the web shell only. Every rule is scoped to body.phone-layout
   (lib/phone-mode.ts) so desktop guests, guides and the Electron app are
   untouched — except the pre-join's, rooted at .phone-prejoin, which only
   mounts on the phone path (test/phone-css.test.ts pins the scoping). The stage-mode grid
   (video-grid.ts) is rearranged, not rebuilt: the guide's .stage-slot tile
   on top, the strip as one swipe row below, your own tile floating in the
   stage's corner.

   #video-stage stays unpositioned here too: call.css's stage notices and
   the reaction layer measure against the viewport on purpose.
   ========================================================================== */

/* --- Desktop vs phone chrome ------------------------------------------- */
body:not(.phone-layout) #phone-top-root,
body:not(.phone-layout) #phone-pager-root,
body:not(.phone-layout) #phone-bar-root,
body:not(.phone-layout) .phone-rec-float,
body:not(.phone-layout) .phone-sheet {
  display: none !important;
}
body.phone-layout .call-header,
body.phone-layout #toolbar-root {
  display: none !important;
}
body.phone-layout {
  height: 100dvh;
  overflow: hidden;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}
/* 100vh on a phone includes the browser's collapsing toolbars: the bottom
   bar would sit under them. The dynamic unit is the visible height. */
body.phone-layout #app {
  height: 100dvh;
}
body.phone-layout .call-screen {
  padding-top: env(safe-area-inset-top);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* --- Top bar (Paper 2A) ------------------------------------------------- */
body.phone-layout .phone-top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 1rem 0.75rem;
}
body.phone-layout .ptb-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
body.phone-layout .ptb-title {
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text-primary);
}
body.phone-layout .ptb-sub {
  font-size: 0.8125rem;
  line-height: 1.3;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* The header's standing facts (the call header is hidden on a phone):
   REC, the breakout room and a live sound-only share, as chips under the
   people count. They wrap rather than cut a word. */
body.phone-layout .ptb-chips:not([hidden]) {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 0.25rem;
}
body.phone-layout .ptb-chip:not([hidden]) {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  padding: 0.1875rem 0.625rem;
  border-radius: 999px;
  background: var(--surface-overlay);
  color: var(--text-primary);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
body.phone-layout .ptb-chip-icon {
  flex: none;
  display: grid;
  place-items: center;
}
body.phone-layout .ptb-chip-icon svg {
  width: 0.875rem;
  height: 0.875rem;
}
/* REC wears the header pill's red (call.css .rec-pill). */
body.phone-layout .ptb-rec:not([hidden]) {
  background: rgba(220, 38, 38, 0.16);
  box-shadow: inset 0 0 0 0.0625rem rgba(248, 113, 113, 0.4);
  color: #f87171;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.08em;
}
body.phone-layout .ptb-rec-dot {
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #ef4444;
}
/* Landscape hides the top bar: this small chip keeps a recording visible,
   top-centre (the stage tile's guide badge sits top-left, the share's
   guide box and the self tile top-right, the bar bottom-centre). */
body.phone-layout:not(.phone-landscape) .phone-rec-float {
  display: none !important;
}
body.phone-layout.phone-landscape .phone-rec-float:not([hidden]) {
  position: fixed;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.625rem;
  border-radius: 999px;
  /* Over video: a dark backing keeps the red legible on any frame. */
  background: rgba(10, 22, 40, 0.85);
  box-shadow: inset 0 0 0 0.0625rem rgba(248, 113, 113, 0.4);
  color: #f87171;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  pointer-events: none;
}
body.phone-layout .ptb-flip {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  background: var(--surface-overlay);
  color: var(--text-primary);
  display: grid;
  place-items: center;
  border: none;
}
body.phone-layout .ptb-flip svg {
  width: 1.375rem;
  height: 1.375rem;
  pointer-events: none;
}

/* --- Stage: guide on top, strip as one swipe row, self floating -------- */
body.phone-layout #video-stage {
  padding: 0 0.5rem 0.5rem;
  gap: 0.5rem;
}
/* One scroll container (the grid owns its tiles directly, so the strip
   cannot scroll on its own): three visible columns, more created as the
   strip needs them. The stage tile and your own tile are sticky, so a
   swipe moves only the strip row beneath them. */
body.phone-layout video-player-container.grid-stage {
  /* The lengths the stage, the strip and the floating self tile share. */
  --phone-gap: 0.5rem;
  --self-w: 6rem;
  --self-m: 0.75rem;
  /* Three columns across: the stage's 0.5rem side padding, two gaps. */
  --phone-col: calc(
    (
        100vw - 1rem - 2 * var(--phone-gap) - env(safe-area-inset-left) -
          env(safe-area-inset-right)
      ) /
      3
  );
  display: grid !important;
  grid-template-columns: repeat(3, var(--phone-col));
  grid-auto-columns: var(--phone-col);
  grid-template-rows: minmax(0, 1fr) auto;
  gap: var(--phone-gap);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
body.phone-layout video-player-container.grid-stage::-webkit-scrollbar {
  display: none;
}
body.phone-layout video-player-container.grid-stage .video-tile.stage-slot {
  grid-column: 1 / span 3;
  grid-row: 1;
  position: sticky;
  left: 0;
  justify-self: stretch;
  align-self: stretch;
  width: 100%;
  height: 100%;
  max-width: none;
  aspect-ratio: auto;
  border-radius: 1.25rem;
}
/* The strip: students, then anyone a guide spotlighted (a second stage
   cell does not fit a phone's width, so a spotlight leads the row). */
body.phone-layout
  video-player-container.grid-stage
  .video-tile:not(.stage-slot) {
  grid-column: auto;
  grid-row: 2;
  justify-self: stretch;
  width: 100%;
  height: calc(var(--phone-col) * 1.22);
  max-width: none;
  aspect-ratio: auto;
  border-radius: 0.875rem;
  scroll-snap-align: start;
}
/* Your own tile floats in the stage's top-right corner (Meet's self view);
   its strip slot closes up. Sticky at its natural x: column 3 ends at
   3 × col + 2 × gap; the tile starts its width and right margin before. */
body.phone-layout
  video-player-container.grid-stage
  .video-tile.self:not(.stage-slot) {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  align-self: start;
  position: sticky;
  left: calc(
    3 * var(--phone-col) + 2 * var(--phone-gap) - var(--self-w) - var(--self-m)
  );
  width: var(--self-w);
  height: 8rem;
  margin: var(--self-m);
  z-index: 2;
  border-radius: 1rem;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.5);
  scroll-snap-align: none;
}
/* call.css mirrors your own tile; on the back camera (phone-top-bar sets
   the class from the active camera's label) it shows the world unmirrored. */
body.phone-layout.phone-rear-camera .video-tile.self .player-slot video {
  transform: none;
}
/* No guide reachable: call.css's placeholder card, held to the visible
   stage instead of spanning the whole scroll width. */
body.phone-layout video-player-container.grid-stage.stage-empty::before {
  grid-column: 1 / span 3;
  position: sticky;
  left: 0;
  width: 100%;
  aspect-ratio: auto;
  padding: 1.5rem;
  text-align: center;
  border-radius: 1.25rem;
  font-size: 1rem;
}

/* Breakout rooms / stage mode off: the grid, two columns, scrolling.
   fitToStage's inline max-width and --grid-cols/--tile-h are overridden. */
body.phone-layout video-player-container:not(.grid-stage):not(.grid-strip) {
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  /* max-content: tiles clip (overflow: hidden), so an auto row would size
     to their zero min-content height and the rows would overlap. */
  grid-auto-rows: max-content;
  gap: 0.5rem;
  max-width: none !important;
  min-height: 0;
  margin: 0;
  overflow-y: auto;
  align-content: start;
}
body.phone-layout
  video-player-container:not(.grid-stage):not(.grid-strip)
  .video-tile {
  height: auto !important;
  aspect-ratio: 3 / 4;
  border-radius: 0.875rem;
}

/* A guide's screen or YouTube share (Paper 6): share on top, strip below,
   the pair centred in the height a portrait phone has to spare. */
body.phone-layout #video-stage.sharing {
  justify-content: center;
}
body.phone-layout #share-stage {
  width: 100%;
  aspect-ratio: 16 / 9;
  flex: none;
  border-radius: 1rem;
}
body.phone-layout video-player-container.grid-strip {
  height: 8rem;
  gap: 0.5rem;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
body.phone-layout video-player-container.grid-strip::-webkit-scrollbar {
  display: none;
}
body.phone-layout video-player-container.grid-strip .video-tile {
  width: 6.75rem;
  height: 8rem;
  aspect-ratio: auto;
  border-radius: 0.875rem;
  scroll-snap-align: start;
}

/* Never ellipsize a name (CLAUDE.md): call.css cuts the tile's name chip
   with an ellipsis, and a 6.75rem strip tile turned "Maria Gonzalez" into
   "Maria Gonzal…". On a phone the chip wraps instead and grows upward from
   its bottom anchor; the tiles are a CSS grid, not a fixed-height
   virtualized list, so a taller chip cannot spill onto another row. The
   pill radius would clip a two-line chip's corners, so it rounds less. */
body.phone-layout .video-tile .tile-footer {
  border-radius: 0.5rem;
}
body.phone-layout .video-tile .tile-footer .tile-name {
  white-space: normal;
  overflow-wrap: anywhere;
  text-overflow: clip;
  overflow: visible;
  min-width: 0;
}
/* The floating self tile is 6rem wide: a wrapped "Maria Gonzalez (You)"
   chip covered most of it. Your own name is redundant on your own view, so
   the chip shows only a "You" badge. The name stays in the DOM, visually
   hidden (never display: none), so a screen reader still reads it; the
   badge carries empty alt text so it is not read twice. A browser without
   the alt syntax keeps the first declaration. */
body.phone-layout
  video-player-container.grid-stage
  .video-tile.self:not(.stage-slot)
  .tile-footer
  .tile-name {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
body.phone-layout
  video-player-container.grid-stage
  .video-tile.self:not(.stage-slot)
  .tile-footer::after {
  content: "You";
  content: "You" / "";
  font-size: 0.75rem;
}

/* --- People pager (components/phone-strip-pager.ts) ---------------------
   Right under the stage: the strip is a hard 6-per-page decode cap and a
   breakout grid pages at 20, and the desktop pager lives in the hidden
   toolbar. The component hides itself with one page. */
body.phone-layout .phone-pager:not([hidden]) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0 0.75rem 0.25rem;
}
body.phone-layout .psp-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0 0.875rem;
  border: none;
  border-radius: 999px;
  background: var(--surface-overlay);
  color: var(--text-primary);
  font-size: 0.9375rem;
  font-weight: 600;
}
body.phone-layout .psp-btn > * {
  pointer-events: none;
}
body.phone-layout .psp-btn svg {
  width: 1.25rem;
  height: 1.25rem;
}
body.phone-layout .psp-btn:active:not(:disabled) {
  filter: brightness(1.2);
}
body.phone-layout .psp-btn:disabled {
  opacity: 0.4;
}
body.phone-layout .psp-label {
  font-size: 0.9375rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* --- Landscape (Paper 6b): the stage or share fills; strip collapses ---- */
/* Landscape has no strip to page (hidden, or two tiles over a share) and
   no height to spare on a 320px-tall screen, where the pager would sit
   under the floating bar: a breakout grid pages with the phone upright. */
body.phone-layout.phone-landscape #phone-pager-root {
  display: none !important;
}
body.phone-layout.phone-landscape #phone-top-root {
  display: none !important;
}
body.phone-layout.phone-landscape .call-screen {
  padding-top: 0;
}
body.phone-layout.phone-landscape #video-stage {
  padding: 0.5rem;
}
body.phone-layout.phone-landscape
  video-player-container.grid-stage
  .video-tile:not(.stage-slot):not(.self) {
  display: none;
}
body.phone-layout.phone-landscape
  video-player-container.grid-stage
  .video-tile.self:not(.stage-slot) {
  /* Nothing scrolls here (the strip is hidden), so no sticky offset. */
  --self-w: 8rem;
  position: relative;
  left: 0;
  height: 4.5rem;
}
body.phone-layout.phone-landscape
  video-player-container:not(.grid-stage):not(.grid-strip) {
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  /* The last row scrolls clear of the floating bar. */
  padding-bottom: 5rem;
}
body.phone-layout.phone-landscape
  video-player-container:not(.grid-stage):not(.grid-strip)
  .video-tile {
  aspect-ratio: 16 / 9;
}
body.phone-layout.phone-landscape #share-stage {
  aspect-ratio: auto;
  flex: 1 1 auto;
  min-height: 0;
}
body.phone-layout.phone-landscape video-player-container.grid-strip {
  position: fixed;
  top: 0.75rem;
  right: calc(0.75rem + env(safe-area-inset-right));
  width: auto;
  height: 4.5rem;
  overflow: hidden;
  z-index: 3;
}
body.phone-layout.phone-landscape
  video-player-container.grid-strip
  .video-tile:nth-child(n + 3) {
  display: none;
}
body.phone-layout.phone-landscape
  video-player-container.grid-strip
  .video-tile {
  width: 8rem;
  height: 4.5rem;
}

/* --- Bottom bar (Paper 2A) --------------------------------------------- */
body.phone-layout .phone-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
  background: var(--surface-base);
}
body.phone-layout.phone-landscape .phone-bar {
  position: fixed;
  left: 50%;
  bottom: calc(0.75rem + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  gap: 0.75rem;
  padding: 0.5rem;
  border-radius: 999px;
  background: rgba(10, 22, 40, 0.9);
  z-index: 4;
}
body.phone-layout .pb-btn {
  position: relative;
  /* An explicit width (not a flex-basis): the landscape pill sizes to its
     content, and a basis would let it collapse every button to min-width. */
  flex: 0 1 auto;
  width: 3.5rem;
  min-width: 2.75rem;
  height: 3.5rem;
  border-radius: 999px;
  border: none;
  background: var(--surface-overlay);
  color: var(--text-primary);
  display: grid;
  place-items: center;
  transition:
    background-color var(--duration-fast) var(--ease-default),
    opacity var(--duration-fast) var(--ease-default);
}
/* A tap anywhere on the button is the button's (never an icon span). */
body.phone-layout .pb-btn > * {
  pointer-events: none;
}
body.phone-layout .pb-icon {
  display: grid;
  place-items: center;
}
body.phone-layout .pb-btn svg {
  width: 1.5rem;
  height: 1.5rem;
}
body.phone-layout .pb-btn:active {
  filter: brightness(1.2);
}
body.phone-layout .pb-btn.is-off {
  background: var(--color-error);
  color: #ffffff;
}
body.phone-layout .pb-btn.is-active {
  background: var(--color-accent);
  color: var(--text-inverse);
}
/* A guide's lock (Paper 5): after .is-off, since a locked mic is also off. */
body.phone-layout .pb-btn.is-locked {
  background: #3a1d24;
  color: var(--color-error-text);
  box-shadow: inset 0 0 0 0.09rem var(--color-error-text);
}
/* Waiting on the device or the server: dimmed, still the same button. */
body.phone-layout .pb-btn.is-pending {
  opacity: 0.6;
}
body.phone-layout .pb-lock {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 999px;
  background: var(--surface-base);
  color: var(--color-error-text);
  box-shadow: inset 0 0 0 0.09rem var(--color-error-text);
}
body.phone-layout .pb-lock:not([hidden]) {
  display: grid;
  place-items: center;
}
body.phone-layout .pb-lock svg {
  width: 0.75rem;
  height: 0.75rem;
}
body.phone-layout .pb-btn.pb-leave {
  width: 4.5rem;
  background: var(--color-error);
  color: #ffffff;
}
/* A 320px phone (iPhone SE 1st gen): smaller circles instead of ovals. */
@media (max-width: 22rem) {
  body.phone-layout .pb-btn {
    width: 3rem;
    height: 3rem;
  }
  body.phone-layout .pb-btn.pb-leave {
    width: 4rem;
  }
}

/* --- Cards that already exist, phone-sized (Paper 4, 5) ----------------- */
body.phone-layout .whisper-banner.whisper-strip {
  margin: 0 0.75rem 0.5rem;
  padding: 0.625rem 1rem;
  border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 1rem;
  font-size: 0.9375rem;
  text-align: center;
}
/* In the flow under the top bar, like the whisper strip: the stage gives
   up the card's height for the lock's length, so it never covers a tile
   or a name (a fixed card over the strip did, for the whole lock). */
body.phone-layout .mute-banner {
  margin: 0 0.75rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 1rem;
  padding: 0.875rem 1rem;
  background: var(--surface-overlay);
  font-size: 0.9375rem;
  text-align: center;
}
/* Landscape: no top bar above it and 320px of height on an iPhone SE, so
   one compact centred card that takes as little of the stage as it can. */
body.phone-layout.phone-landscape .mute-banner {
  margin: 0.5rem auto 0;
  max-width: 36rem;
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
}
/* The other hint-row lines (hold, focus, a lost connection) read at a
   phone's arm length too. */
body.phone-layout .mode-hint-row > *:not(.mute-banner),
body.phone-layout .send-wedge-banner {
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  text-align: center;
}

/* Waiting for a guide (Paper 9): the existing overlay card, phone-sized.
   During the wait call.css hides .call-body (and the phone bar with it);
   the card's own "Leave call" button is the way out. */
body.phone-layout #guide-wait-root .overlay-card {
  width: calc(100vw - 3rem);
  max-width: 24rem;
  padding: 2rem 1.5rem;
}
body.phone-layout #guide-wait-root .overlay-title {
  font-size: 1.625rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
body.phone-layout #guide-wait-root .overlay-message {
  font-size: 1rem;
}
body.phone-layout #guide-wait-root .btn {
  width: 100%;
  min-height: 3.5rem;
  font-size: 1.0625rem;
}

/* A guide's "Ask to unmute" (lib/confirm.ts via media-request-dialog):
   the desktop card's side-by-side buttons do not fit 390px, so they stack
   full width with the answer the guide asked for on top. */
body.phone-layout .confirm-dialog-card {
  width: calc(100vw - 2rem);
  max-width: 24rem;
  padding: 1.75rem 1.25rem 1.25rem;
  gap: 1.25rem;
}
body.phone-layout .confirm-dialog-message {
  font-size: 1.0625rem;
}
body.phone-layout .confirm-dialog-actions {
  flex-direction: column-reverse;
  align-items: stretch;
  gap: 0.625rem;
  width: 100%;
}
body.phone-layout .confirm-dialog-actions.choice-dialog-actions {
  flex-direction: column;
}
body.phone-layout .confirm-dialog-actions .btn {
  width: 100%;
  min-height: 3.25rem;
  padding: 0.75rem 1.25rem;
  font-size: 1.0625rem;
}

/* Toasts (a locked hand's explanation): components.css centers the root
   with left: 50%, which caps a toast at half the screen's width. */
body.phone-layout #toast-root {
  top: calc(env(safe-area-inset-top) + 4.25rem);
  left: 1rem;
  right: 1rem;
  transform: none;
}
body.phone-layout .toast {
  max-width: 100%;
  border-radius: 1rem;
  font-size: 0.9375rem;
}

/* --- Sheets (Paper 3, 8) ------------------------------------------------ */
body.phone-layout .phone-sheet {
  position: fixed;
  inset: 0;
  z-index: 50;
}
body.phone-layout .ps-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}
body.phone-layout .ps-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 80dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.75rem calc(1.25rem + env(safe-area-inset-right))
    calc(2rem + env(safe-area-inset-bottom))
    calc(1.25rem + env(safe-area-inset-left));
  background: var(--surface-overlay);
  border-radius: 1.5rem 1.5rem 0 0;
  box-shadow: 0 -0.5rem 2rem rgba(0, 0, 0, 0.4);
}
/* The handle is the sheet's labelled Close button: a full-width tap target
   over the panel's top padding, drawing the same bar in the same place. */
body.phone-layout .ps-close {
  display: flex;
  justify-content: center;
  width: 100%;
  margin: -0.75rem 0 0;
  padding: 0.75rem 0 1rem;
  border: none;
  background: none;
  cursor: pointer;
}
body.phone-layout .ps-panel:focus {
  outline: none;
}
body.phone-layout .ps-handle {
  display: block;
  width: 2.5rem;
  height: 0.3rem;
  border-radius: 999px;
  background: var(--text-subtle);
}
/* The rows' size (a heading is never smaller than what it heads): weight,
   colour and the raised list's caps carry the hierarchy. */
body.phone-layout .pms-section-label,
body.phone-layout .pps-section-label {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text-muted);
  margin: 0.5rem 0;
}
/* Four to a row: the built-in menu (eight) reads as two even rows, and a
   custom menu of any length fills row by row with full-size targets. */
body.phone-layout .pms-reactions {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  justify-items: center;
  gap: 0.75rem 0.5rem;
  margin-bottom: 1.25rem;
}
body.phone-layout .pms-reaction {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 999px;
  border: none;
  background: var(--surface-raised);
  font-size: 1.625rem;
  line-height: 1;
}
body.phone-layout .pms-reaction:active {
  filter: brightness(1.3);
}
body.phone-layout .pms-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  min-height: 3.75rem;
  border: none;
  border-top: 1px solid var(--border-subtle);
  background: none;
  color: var(--text-primary);
  font-size: 1.0625rem;
  font-weight: 600;
  text-align: left;
}
body.phone-layout .pms-row > * {
  pointer-events: none;
}
body.phone-layout .pms-row-icon {
  display: grid;
  place-items: center;
}
body.phone-layout .pms-row-icon svg {
  width: 1.5rem;
  height: 1.5rem;
}
body.phone-layout .pms-row-label {
  flex: 1;
}
body.phone-layout .pms-row-count,
body.phone-layout .pps-count {
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--text-muted);
}
body.phone-layout .pps-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}
body.phone-layout .pps-title {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0;
}
body.phone-layout .pps-raised-label {
  color: var(--color-accent-text);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
body.phone-layout .pps-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3.5rem;
  border-top: 1px solid var(--border-subtle);
}
body.phone-layout .pps-name {
  flex: 1;
  min-width: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-primary);
  overflow-wrap: anywhere;
}
body.phone-layout .pps-guide {
  flex: none;
  padding: 0.0625rem 0.45rem;
  border-radius: 999px;
  background: var(--color-accent-text);
  color: var(--color-navy);
  font-size: 0.75rem;
  font-weight: 700;
}
body.phone-layout .pps-trailing {
  flex: none;
  display: grid;
  place-items: center;
}
body.phone-layout .pps-trailing svg {
  width: 1.25rem;
  height: 1.25rem;
}
body.phone-layout .pps-trailing.is-hand {
  color: var(--color-accent);
}
body.phone-layout .pps-trailing.is-on {
  color: var(--color-success);
}
body.phone-layout .pps-trailing.is-off {
  color: var(--text-muted);
}

/* --- Pre-join (Paper 1) ------------------------------------------------- */
/* Rooted at .phone-prejoin itself, not body.phone-layout: the landing
   factory picks the pre-join once, and a viewport that later widens past
   959px (an iPad rotated) drops body.phone-layout under a pre-join that is
   still mounted. It only ever mounts on the phone path (app.ts), so the
   root class scopes it; the max-width keeps it a phone-width column on a
   wide screen. */
/* The preview takes the height the page has to spare (a tall phone gets a
   taller preview, never a gap) and gives it up first on a short one; past
   its floor the page scrolls (an iPhone SE, the keyboard up). */
.phone-prejoin {
  flex: 1;
  width: 100%;
  max-width: 30rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  min-height: 0;
  overflow-y: auto;
  padding: calc(1rem + env(safe-area-inset-top))
    calc(1.5rem + env(safe-area-inset-right))
    calc(1.5rem + env(safe-area-inset-bottom))
    calc(1.5rem + env(safe-area-inset-left));
  background: var(--surface-base);
}
.phone-prejoin .pj-eyebrow {
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-accent-text);
}
/* base.css sets h1–h3 in the uppercase display face; Paper's phone
   headings are sentence case in the text face. */
body.phone-layout .pps-title,
body.phone-layout #guide-wait-root .overlay-title,
.phone-prejoin .pj-title {
  font-family: var(--font-sans);
  text-transform: none;
}
.phone-prejoin .pj-title {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--text-primary);
  margin: 0.25rem 0;
}
.phone-prejoin .pj-subtitle {
  font-size: 0.9375rem;
  color: var(--text-muted);
  margin: 0;
}
.phone-prejoin .pj-preview {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  min-height: 13rem;
  aspect-ratio: 6 / 7;
  border-radius: 1.5rem;
  overflow: hidden;
  background: var(--surface-overlay);
}
.phone-prejoin .pj-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1);
}
/* A mirror is right for the front camera only: the back camera shows the
   world, and a page held up to it must read the right way round
   (phone-prejoin sets data-facing from the track). */
.phone-prejoin .pj-preview[data-facing="environment"] .pj-video {
  transform: none;
}
.phone-prejoin .pj-flip {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  color: var(--text-primary);
  display: grid;
  place-items: center;
  border: none;
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: rgba(10, 22, 40, 0.6);
}
.phone-prejoin .pj-flip svg {
  width: 1.375rem;
  height: 1.375rem;
  pointer-events: none;
}
.phone-prejoin .pj-media-error {
  position: absolute;
  inset: 30% 1.5rem auto;
  font-size: 0.9375rem;
  color: var(--text-primary);
  text-align: center;
}
.phone-prejoin .pj-toggles {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1rem;
  display: flex;
  justify-content: center;
  gap: 1rem;
}
.phone-prejoin .pj-toggle {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 999px;
  border: none;
  background: rgba(244, 246, 250, 0.16);
  color: var(--text-primary);
  display: grid;
  place-items: center;
  -webkit-backdrop-filter: blur(0.5rem);
  backdrop-filter: blur(0.5rem);
}
.phone-prejoin .pj-toggle svg {
  width: 1.5rem;
  height: 1.5rem;
  pointer-events: none;
}
.phone-prejoin .pj-toggle.is-off {
  background: var(--color-error);
  color: #ffffff;
}
.phone-prejoin .pj-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: auto;
}
.phone-prejoin .pj-label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-muted);
}
.phone-prejoin .pj-input {
  height: 3.25rem;
  padding: 0 1rem;
  border-radius: 0.875rem;
  border: 1px solid var(--border-strong);
  background: var(--surface-overlay);
  color: var(--text-primary);
  font-size: 1.0625rem; /* ≥ 16px: iOS does not zoom the page on focus */
  -webkit-user-select: text;
  user-select: text;
}
.phone-prejoin .pj-input:focus {
  outline: none;
  border-color: var(--color-accent);
}
.phone-prejoin .pj-error {
  font-size: 0.9375rem;
  color: var(--color-error-text);
  margin: 0;
}
.phone-prejoin .pj-join {
  height: 3.5rem;
  border-radius: 999px;
  border: none;
  background: var(--color-accent);
  color: var(--color-navy);
  font-size: 1.0625rem;
  font-weight: 700;
}
.phone-prejoin .pj-join:active:not(:disabled) {
  filter: brightness(1.1);
}
.phone-prejoin .pj-join:disabled {
  opacity: 0.6;
}
.phone-prejoin .pj-footnote {
  font-size: 0.875rem;
  color: var(--text-muted);
  text-align: center;
  margin: 0;
}
/* The static recording notice (a guest cannot read live recording state).
   Primary text, not muted: it is a disclosure, not a hint. */
.phone-prejoin .pj-recording {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  margin: 0;
}
