/*
  PLAN-141 the door (D3): the landing shell's only stylesheet. No framework, no web font, no third-party
  request (F6). Elderly-first: one column, large type, 56 px touch targets, and a layout that reads the
  same at 360 px and at 1200 px.
*/

/*
  PLAN-178 T-1 (D2, F1): THE DESIGN'S TOKENS, UNDER THE README'S OWN NAMES, AND NOTHING ELSE.

  public/web/design/README.md section "Design tokens" is the list; public/web/design/Prototype.dc.html
  is the value (the owner's rule 1: where the document and the files disagree, the files win). Every
  number below was read out of the prototype's own CSS at T-0 and set beside the README's in
  public/web/design/NOTES.md section 1.1; they agree on every one, so what stands here is both.

  THERE IS NO LIGHT THEME ANY MORE. The README's must-not list says so in three words, and the call
  stage was already pinned dark by the product's own law. The @media (prefers-color-scheme: dark)
  block that used to redefine nine of these is GONE and its values are what :root now carries, so a
  browser set to light draws the same page as one set to dark. index.html's colour-scheme meta says
  dark for the same reason, which is what stops a browser painting its own light form controls.

  THE OLD NAMES ARE KEPT AS ALIASES, deliberately. Roughly two thousand lines of this sheet, and every
  module's own rules, read --ink, --muted, --page, --card, --line, --accent and the rest; PLAN-179 and
  PLAN-180 replace those rules screen by screen. Until then each alias points at the DESIGN's value,
  so no rule in the file draws a colour the design does not have.
*/
:root {
  color-scheme: dark;

  /* The font, and the body's size and leading (README "Design tokens", first line). */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --body-size: 18px;
  --body-leading: 1.55;

  /* ---- Stage (call, link, ended): pinned, never themed ---------------------------------------- */
  --stage-page: #131314;
  --stage-bar: #1e1f20;
  --stage-surface: #202124;          /* panel and dialog */
  --stage-callout-surface: #1e1f20;
  --stage-field: #2b2c2f;
  --stage-hairline: #444746;
  --stage-hairline-callout: #333537;
  --stage-ink: #f2f5f9;              /* headings */
  --stage-ink-panel: #e3e3e3;        /* panel text */
  --stage-ink-muted: #c4c7c5;
  --stage-ink-avatar-name: #dfe5ef;
  --stage-primary: #1c62d6;
  --stage-primary-hover: #1a58c0;
  /* BUGCHECK ROUND 1, gemini (the stylesheet): THE STAGE'S OWN QUIET HOVER, under its own name. The
     dialog, the toast and the callout are the stage's surfaces wherever they are opened from, and
     their X buttons and outlined pills were reading --card-secondary-hover. The VALUE was already
     right (both are rgba(168,199,250,.12), the accent at 12 per cent); the NAME tied a stage colour
     to the card set, so a future change to the card would have moved the dialog with it. */
  --stage-secondary-hover: rgba(168, 199, 250, 0.12);
  --stage-accent: #a8c7fa;           /* ON states, links, ticks */
  --stage-accent-ground: #062e6f;
  --stage-red: #db372d;              /* End, Cancel, and the OFF states */
  --stage-red-hover: #e24940;
  --stage-round: #333537;            /* the round bar button */
  --stage-chevron: #262729;          /* the chevron half-pill */
  --stage-chevron-open: #4b4d4f;
  --stage-avatar: #1c62d6;           /* avatar and partner circle */
  --stage-avatar-ink: #ffffff;
  --stage-own: #3c4043;              /* own initial circle */
  --stage-own-ink: #f2f5f9;
  --stage-warn: #ff9b7d;
  --stage-warn-wash: #2a1a14;
  --stage-success: #8ee0a1;
  --stage-placeholder: linear-gradient(160deg, #16304a 0%, #0e1f33 55%, #0a1626 100%);
  --stage-placeholder-glow: radial-gradient(ellipse at 30% 20%, rgba(91, 147, 240, 0.25) 0, transparent 55%);

  /* The four overlays. */
  --overlay-dim: rgba(0, 0, 0, 0.5);
  --overlay-pill: rgba(11, 13, 17, 0.85);
  --overlay-name-chip: rgba(19, 19, 20, 0.6);
  --overlay-lower: linear-gradient(to top, rgba(9, 11, 15, 0.9), rgba(9, 11, 15, 0));

  /* The five shadows. */
  --shadow-panel: 0 8px 28px rgba(0, 0, 0, 0.45);
  --shadow-dialog: 0 12px 40px rgba(0, 0, 0, 0.5);
  --shadow-callout: 0 6px 24px rgba(0, 0, 0, 0.38);
  --shadow-self-tile: 0 2px 12px rgba(0, 0, 0, 0.5);
  --shadow-card: 0 20px 60px rgba(0, 0, 0, 0.35);

  /* ---- Card screens (home, register, waiting, message): dark only ----------------------------- */
  --card-page: linear-gradient(170deg, #182538 0%, #12161c 60%, #0e1116 100%);
  --card-glow: radial-gradient(ellipse at 20% 10%, rgba(91, 147, 240, 0.22) 0, transparent 50%), radial-gradient(ellipse at 85% 90%, rgba(142, 224, 161, 0.12) 0, transparent 45%);
  --card-surface: #1b212a;
  --card-border: #2b3340;
  --card-ink: #eef1f6;
  --card-muted: #a5aebd;
  --card-field: #12161c;
  --card-field-name: #1b212a;
  --card-primary: #5b93f0;
  --card-primary-ink: #0d1117;
  --card-primary-hover: #7aa7f3;
  --card-secondary-hover: rgba(168, 199, 250, 0.12);

  /* ---- Radii (README "Radii", every one of the ten) ------------------------------------------- */
  --r-pill: 999px;
  --r-card: 16px;
  --r-panel: 20px;      /* panels and pickers */
  --r-dialog: 24px;
  --r-field: 8px;
  --r-link-box: 14px;
  --r-callout: 16px;
  --r-self-tile: 12px;
  --r-menu-row: 12px;
  --r-toast: 16px;

  /* ---- Transitions (README "Transitions") ----------------------------------------------------- */
  --t-hover: 120ms ease;                                   /* background-color, filter, border-color */
  --t-switch-thumb: left 120ms ease;
  --t-bar-collapse: max-height 260ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 200ms ease;
  --t-bar-drag: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
  --t-self-snap: left 200ms ease, top 200ms ease, right 200ms ease, bottom 200ms ease;
  --t-chevron: transform 200ms ease;
  --t-mic-level: width 300ms ease;

  /* ---- The product's own laws, unchanged -------------------------------------------------------
     56 px is the smallest pressable target on this page (README law 5) and --tap is what every rule
     in this sheet already reads for it. */
  --tap: 56px;
  --bar-h: 84px;

  /* ---- The old names, kept as aliases of the design's values (see the header) ------------------ */
  --ink: #eef1f6;
  --muted: #a5aebd;
  --page: #12161c;
  --card: #1b212a;
  --line: #2b3340;
  --accent: #5b93f0;
  --accent-ink: #0d1117;
  --warn: #ff9b7d;
  --warn-wash: #2a1a14;
  --chat-them-bg: #232b36;
  --chat-mine-bg: #5b93f0;
  --chat-mine-ink: #0d1117;
  --r-bubble: 18px;
  --r-control: 14px;
  /* BUGCHECK ROUND 1, gemini (the stylesheet): --r-field-legacy is GONE rather than kept. It was
     carried over as the old --r-field's 16 px in case a rule read it; measured, NOTHING read the old
     --r-field either (the base commit's stylesheet has zero var(--r-field) uses) and nothing ever
     read the alias. A token no rule reads is a token that can only mislead. --r-field is now the
     design's 8 px and is read by the Register screen's own fields. */
}

/*
  PLAN-178 T-1 (D2, F1): THE RESET. "no framework default styles leaking through (reset them)", the
  owner's rule 2. A button, an input, a select, a heading and a list drawn with no class of ours must
  show none of the browser's own border, background, appearance, margin or bullet, because every one
  of those is a pixel the design did not draw. The FONT is inherited by the same rule: the README's
  token line ends "Buttons inherit font", and a control that does not inherit it renders in the
  browser's own small system face.

  WHAT THE RESET DOES NOT TOUCH: the outline a keyboard focus draws. Every :focus-visible rule in this
  sheet stays exactly as it was, because a reset that takes the focus ring away is how a keyboard
  user loses the page.
*/
* { box-sizing: border-box; }

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button,
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}

button {
  padding: 0;
  border: 0;
  background: none;
  text-align: inherit;
}

select::-ms-expand { display: none; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }

ul, ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

img, svg, video { display: block; max-width: 100%; }

/* The page's own ground, so nothing ever renders on the browser's white. */
html { background: var(--stage-page); }

/*
  PLAN-178 T-1 (D2, F1): THE THREE KEYFRAMES, COPIED EXACTLY.

  "Keyframes (copy exactly)", the README's own words, and these are the three the prototype's <helmet>
  declares byte for byte. lhpulse is the waiting dot and the permission dialog's dot; lhripple is the
  ring on a picture placeholder (3s here, 2.4s with a 1.2s delay on the connecting screen, which the
  rule that uses it sets, not the keyframe); lhdot is the row of three dots on the connecting screen.
  A person who has asked their system for less motion gets none of them, which is the one line the
  design does not say and the product's own accessibility rule does.
*/
@keyframes lhpulse {
  0% { box-shadow: 0 0 0 0 rgba(168, 199, 250, 0.45); }
  100% { box-shadow: 0 0 0 12px rgba(168, 199, 250, 0); }
}

@keyframes lhripple {
  0% { transform: scale(0.6); opacity: 0.55; }
  100% { transform: scale(1.6); opacity: 0; }
}

@keyframes lhdot {
  0%, 100% { opacity: 0.25; transform: translateY(0); }
  50% { opacity: 1; transform: translateY(-4px); }
}

@media (prefers-reduced-motion: reduce) {
  .lh-pulse, .lh-ripple, .lh-dot { animation: none; }
}

body {
  margin: 0;
  /* PLAN-178 T-2 (D3, F2): THE SHELL IS THE PAGE NOW. The body used to be a flex box that centred
     one 560 px card inside a 24 px 20 px 40 px margin; the design's card shell is full height, draws
     its own gradient and glow, and centres the card in its own column. A padding here would inset
     that gradient from the edge of the window, which is a border the design does not draw. */
  padding: 0;
  /* PLAN-207c T-6 (D7, F6): the phone's own viewport height beside the pretended one. See the same
     pair on `.lh-card-shell` for what `100dvh` buys and why it is added rather than substituted. */
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--page);
  color: var(--ink);
  /* PLAN-178 T-1 (F1): the README's first token line, read from the tokens rather than repeated. */
  font: 400 var(--body-size) / var(--body-leading) var(--font);
}

/* PLAN-207c T-6 (D7, F6): `.shell` IS GONE, and so is its wide-screen padding further down. Nothing
   has been a `shell` since PLAN-178 T-2 replaced it - "THE SHELL IS THE PAGE NOW ... the design's
   card shell is full height, draws its own gradient and glow, and centres the card in its own
   column" - and the element that carries the design is `.lh-card-shell`, built by index.html. This
   rule set described a 560 px white box with a two-layer Material shadow that no markup and no line
   of app.js ever built, so every declaration in it was drawn nowhere. */

.brand {
  margin: 0 0 20px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/*
  PLAN-148 T-5 (D4): ONE h1 ON THE PAGE, AND THE OTHER SCREENS' TITLES DRAW EXACTLY AS THEY DID.
  This page is one document with several screens, and every screen used to open with its own h1, so
  what the door served carried seven of them. A search engine reads one document, and the pre-launch
  audit holds these pages to exactly one top-level heading. The home screen's heading is that one;
  the other screens carry .screen-title, which is this same rule, so not a pixel moves.
*/
h1,
.screen-title {
  margin: 0 0 12px;
  font-size: 30px;
  line-height: 1.25;
  font-weight: 700;
}

.sub {
  margin: 0 0 28px;
  font-size: 18px;
  color: var(--muted);
}

.actions {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* PLAN-159 T-2 (D1): MEET'S ACTIONS ARE PILLS. The primary is a filled pill and the secondary an
   outlined one in the accent colour; next to the square-cornered fields below, that is what makes a
   button read as a button. Every size stays: 56 px minimum height, 19 px label, full width in the column. */
.btn {
  min-height: 56px;
  padding: 14px 20px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

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

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

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

/* PLAN-142: one page, several screens, one shown at a time. `hidden` does the hiding; this rule is
   here so a screen that is shown lays itself out the same way whichever one it is. */
.screen[hidden] { display: none; }

.who {
  margin: 28px 0 0;
  font-size: 15px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* PLAN-142 T-8: the Register screen. Elderly-first: the label sits ABOVE its control, never beside
   it, the controls are the same 56 px as the buttons, and nothing depends on colour alone. */
.field {
  text-align: left;
  margin: 0 0 18px;
}

.field label {
  display: block;
  margin: 0 0 6px;
  font-size: 16px;
  font-weight: 600;
}

.field input,
.field select {
  width: 100%;
  min-height: 56px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  /* PLAN-159 T-2 (D1): square-cornered beside pill buttons, which is Meet's pairing. */
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  font: inherit;
}

/* The focused field takes the accent on its own edge AND an outline sitting directly on it, so the two
   together are 3 px of accent around the box: the same weight the 3 px ring had, in Meet's shape. */
.field input:focus-visible,
.field select:focus-visible {
  border-color: var(--accent);
  outline: 2px solid var(--accent);
  outline-offset: 0;
}

.err {
  margin: 0 0 16px;
  font-size: 16px;
  font-weight: 600;
  color: var(--warn);
  text-align: left;
}

.btn[disabled] { opacity: 0.6; cursor: default; }

/* PLAN-142 T-9: the link screen. The link itself is the biggest thing on it after the heading,
   because reading it out loud over the phone is a real way this gets used. */
.linkbox {
  margin: 0 0 18px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--page);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 17px;
  line-height: 1.4;
  overflow-wrap: anywhere;
  user-select: all;
}

.qr {
  width: 200px;
  max-width: 70%;
  margin: 22px auto 0;
  padding: 8px;
  border-radius: 12px;
  background: #ffffff;
}

.qr[hidden] { display: none; }
.qr svg { display: block; }

/* PLAN-142 T-10: the Ask-me switch. A real checkbox, so it is keyboard reachable and a screen reader
   announces it, sized so a shaky finger hits it. The whole row is the label. */
.switch {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 26px 0 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  text-align: left;
  font-size: 17px;
  cursor: pointer;
}

.switch input {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  accent-color: var(--accent);
  cursor: pointer;
}

.switch:focus-within {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* PLAN-142 T-11: the connected screen. The two names are the point of it, so they are the biggest
   thing on the screen after the heading. */
.names {
  margin: 0 0 14px;
  font-size: 22px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.note {
  margin: 20px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  font-size: 16px;
}

.note[hidden] { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-150 T-5: the call, the talking and the camera, on the Connected screen.

   THE CLASS NAMES ARE THE MODULES' OWN. call/screens.js writes .call-line, talk/screens.js writes
   .talk-status, .talk-captions, .talk-hold, .talk-actions and .talk-sheet, and video/screens.js
   writes .video-line. Nothing here renames any of them: the modules own what they draw and this file
   owns only how big it is and where it sits, which is the same boundary every one of their headers
   states.

   THE HOLD BAR IS THE BIGGEST TARGET ON THE SCREEN, on purpose. It is the one control a person uses
   every single turn, they use it while looking at the other person rather than at the screen, and
   they use it mid-sentence. End and the camera sit in a smaller row BELOW it, because pressing either
   by mistake is expensive: one hangs up on your family and the other turns a camera on.
*/
.call-line {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 17px;
}

.call-line-end,
.call-line-busy,
.call-line-error { color: var(--warn); }

.talk-status {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 17px;
}

.talk-captions {
  margin: 0 0 16px;
  padding: 4px 0;
  min-height: 96px;
  max-height: 44vh;
  overflow-y: auto;
}

.talk-caption {
  margin: 0 0 10px;
  padding: 12px 14px;
  border-radius: 14px;
  font-size: 20px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.talk-caption-mine {
  background: var(--card);
  border: 1px solid var(--line);
}

.talk-caption-theirs {
  background: var(--accent);
  color: var(--accent-ink);
}

/* The full width is the point; 88 px so a thumb cannot miss it while its owner is mid-sentence. */
.talk-hold {
  display: block;
  width: 100%;
  min-height: 88px;
  padding: 16px 20px;
  border: 0;
  border-radius: 16px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-size: 22px;
  font-weight: 600;
  cursor: pointer;
  touch-action: none;
  user-select: none;
}

.talk-hold:active { filter: brightness(0.92); }

.talk-hold:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

.talk-hold-hint {
  margin: 8px 0 16px;
  color: var(--muted);
  font-size: 16px;
  text-align: center;
}

.talk-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.talk-actions button {
  flex: 1 1 auto;
  min-height: 56px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  color: var(--ink);
  font: inherit;
  font-size: 17px;
  cursor: pointer;
}

.talk-actions button:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.talk-end { color: var(--warn); }

.talk-camera[aria-pressed='true'],
.talk-mic[aria-pressed='false'] { border-color: var(--warn); color: var(--warn); }

/* The More sheet sits INSIDE the in-call fragment, so the call underneath is never replaced. */
.talk-sheet {
  margin: 16px 0 0;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card);
}

.talk-sheet button {
  display: block;
  width: 100%;
  min-height: 56px;
  margin: 10px 0 0;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--page);
  color: var(--ink);
  font: inherit;
  font-size: 17px;
  cursor: pointer;
}

.talk-sheet-title { margin: 0; font-size: 20px; }

/* PLAN-163 T-1 (D4): THE SOUND CHECK. Three sentences a person READS, so it is not dressed as a
   control: no border, no press target, and a smaller heading than the sheet's own. It is the last
   thing above Close because a person opens More for it when something has already gone wrong. */
/* PLAN-175 T-1 (D1): the language group in the More sheet. Two labelled selects and one sentence.
   Each select is 56 px tall, which is the height of every row and every circle on this page, because
   the elderly-first rule is about the SIZE OF THE TARGET and a select is a target like any other. */
/* PLAN-180 C-1: THE DESIGN'S ONE LANGUAGE ROW. The prototype's own numbers, read off its markup:
   min-height 64, padding 8px 12px, radius 12, no border and no fill, the label at 19 px over the
   language's name at 18 px in the muted grey, and a 22 px chevron. It is a `.talk-sheet button`, so
   the pill border, the 999 radius and the centred block layout of the sheet's other buttons are all
   turned off here rather than inherited: this row is a way INTO something, not a switch. */
.talk-sheet .talk-sheet-hear {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 64px;
  margin: 10px 0 0;
  padding: 8px 12px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 19px;
  text-align: left;
  cursor: pointer;
}
.talk-hear-col { display: flex; flex-direction: column; min-width: 0; }
.talk-hear-title { font-size: 19px; }
.talk-hear-name { font-size: 18px; color: var(--muted, #5f6368); }
.talk-hear-chevron { flex: 0 0 auto; font-size: 22px; color: var(--muted, #5f6368); }

/* PLAN-218 T-4 (D3, F3) - THE LANGUAGE GROUP'S FOURTEEN RULE SETS ARE GONE WITH THEIR BUILDER.

   THE FINDING (the deploy-2 review: the conventions reviewer at Important 80, the web-design
   reviewer at Minor 85). PLAN-207c deleted the only thing that ever built a `.talk-sheet-langs`
   block - the More sheet's two selects - and in the same diff EDITED one of the rules that drew it
   (`.talk-langs-note`, the `--danger` fix of T-6), then pinned that edit with probe row 207c-F6 and
   mutation (vi). Fourteen rule sets nothing renders were left standing, defended by a test: the next
   reader would have been editing a rule that draws nothing, with a green probe telling them it
   mattered, and removing the dead CSS would have been a RED row.

   All fourteen are deleted here: this block, the three pinned-dark rules and the select's own dark
   ground at the theme section, and the five 18px floor rules. Row 207c-F6 asserts the other half now
   - that NOTHING builds the class and the stylesheet no longer draws it - and mutation (vi) restores
   a rule set rather than a colour, so the row is proved by putting the dead CSS back.

   The three probes that already assert the ABSENCE of the markup are untouched and are the other
   half of the proof: probe-web-talk rows at :2136, :2157 and :2866, and probe-web-wiring at :3429. */

.talk-sheet-sound { margin: 16px 0 0; }
.talk-sound-title { margin: 0 0 6px; font-size: 15px; color: var(--muted, #5f6368); }
.talk-sound-line { margin: 4px 0; font-size: 16px; line-height: 1.35; }

/* PLAN-159 T-2: ONE TOGGLE STYLE FOR THE MORE SHEET'S TWO SWITCHES. Read aloud and Show their own
   words are both `aria-pressed` buttons, and until now an ON one looked exactly like an OFF one: the
   only difference was the word inside it. Meet draws a switch and the owner's capture measured its two
   colours (the ON track rgb(168,199,250) with an rgb(6,46,111) thumb); on a button those become the
   fill and the label of the ON state, so both switches say the same thing the same way. The state is
   still carried by aria-pressed and by the word, so nothing here depends on colour alone. */
.talk-sheet button[aria-pressed] { border-radius: 999px; }

.talk-sheet button[aria-pressed='true'] {
  border-color: #a8c7fa;
  background: #a8c7fa;
  color: #062e6f;
  font-weight: 600;
}

/* PLAN-159 T-2 (D1): Meet's post-call screen is one large line with a lot of air around it. */
.talk-ended-title { margin: 0 0 8px; font-size: 28px; }
.talk-ended-reason { margin: 0 0 16px; color: var(--muted); font-size: 18px; }

.talk-ended-again {
  min-height: 56px;
  padding: 12px 20px;
  border: 0;
  /* PLAN-159 T-2 (D1): the same pill as .btn.primary, which is what it is. */
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-size: 18px;
  cursor: pointer;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-153 T-6 (D5): THE STAGE. The in-call screen, and only the in-call screen, stops being a card.

   THE OWNER'S WORDS, 2026-09-10 23:10 UTC: "check google meet designs and try to replicate as current
   version is bunch of buttons in one place". What Meet does, and what this does, is give the WHOLE
   screen to the other person and put one row of round controls along the bottom. What it does NOT
   take is Meet's icons, Meet's font or Meet's colours: the system font stack and this file's own
   tokens stay, and the icons are drawn in T-7 as inline SVG of our own.

   ONE SCREEN, NOT THE PAGE. The rule below is scoped to `#s-connected:not([hidden])`, so home,
   register, link, admit and message are byte for byte the card they were. A person is only ever in
   one of them at a time, and app.js's own show() is what decides which.

   ITS OWN COLOURS, LIGHT MODE AND DARK ALIKE. A stage is dark because a picture is what is being
   looked at, so it does not follow the page's light theme: these four values are literals rather than
   tokens on purpose, and they are the only place in this file that does that.
*/
/* PLAN-178 T-3 (D3, F2): THE FULL-VIEWPORT RULE MOVED UP ONE BOX, to .lh-stage-shell, because the
   design puts a 64 px header ABOVE the stage and a section pinned to inset 0 would be drawn over it.
   What this rule keeps is everything about the section itself: it is the column that grows inside the
   shell, its ground and ink are the design's, and its text is left aligned where a card's is centred.
   Every other rule in this file that names #s-connected is untouched and still applies. */
#s-connected:not([hidden]) {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  /* PLAN-159 T-1 (D2, 159-F2): Meet's page ground, read out of the owner's capture (rgb(19,19,20)). It is
     LIGHTER than the #0b0d11 it replaces on purpose: a black letterbox, a dark tile and a dark bar all
     have to separate from it, and against near-black they read as one void (PLAN-156-bar-1100x900.png). */
  background: #131314;
  color: #f2f5f9;
  text-align: left;
}

/* The text a screen reader still needs and an eye does not. NOT display:none - a hidden-from-layout
   element is hidden from assistive technology too, which is the whole point of keeping the words. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  /* PLAN-159 T-1 (D2, 159-F2): Meet's page ground, read out of the owner's capture (rgb(19,19,20)). It is
     LIGHTER than the #0b0d11 it replaces on purpose: a black letterbox, a dark tile and a dark bar all
     have to separate from it, and against near-black they read as one void (PLAN-156-bar-1100x900.png). */
  background: #131314;
}

/* THE TWO PICTURES. The other person fills the stage; your own is a small check that your camera is
   pointing at you, which is all a self view is ever for. */
/* PLAN-159 T-1 (D2, 159-F2): THE PICTURE IS A TILE, NOT THE WHOLE WINDOW. Meet insets its tile 16 px
   from the stage on every side and clips it at 24 px (the owner's capture: main.axUSnc inset 16/64/16/88,
   div.CNjCjf clip-path inset(0px round 24px)). The ground around it is what makes a dark picture read as
   a picture rather than as the end of the screen. */
.video-tiles {
  position: absolute;
  inset: 16px;
  margin: 0;
  border-radius: 24px;
  overflow: hidden;
  background: #000;
}

.video-tiles[hidden] { display: none; }

.video-remote {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #000;
}

.video-remote[hidden] { display: none; }

/* MIRRORED, because a self view is a mirror: a person raising their right hand expects the hand on
   the right of the tile to move. The picture the OTHER person receives is not mirrored - this is a
   display transform and nothing about it reaches the track. */
.video-self {
  position: absolute;
  right: 14px;
  bottom: 14px;
  width: 30%;
  max-width: 190px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  /* PLAN-159 T-1 (D2): Meet's self tile is a plain rounded rectangle with a hairline, not a 2 px white
     frame; the frame was the loudest edge on a screen whose subject is the other person's face. */
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 12px;
  background: #000;
  transform: scaleX(-1);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}

.video-self[hidden] { display: none; }

/* PLAN-207c T-6 (D7, F6): `.video-self-name` AND ITS TWO COMPANIONS ARE GONE - the rule set that was
   here, the `.video-self[hidden] ~ .video-self-name` partner that stood under it, and the phone
   override in the 719 px block further down. PLAN-159 T-1 wrote them for a label beside the
   self-view tile ("YOUR OWN NAME, BOTTOM LEFT INSIDE YOUR OWN TILE"), and nothing builds that
   element: the string `video-self-name` appears nowhere in index.html and nowhere in app.js, and no
   module under public/web/assets creates it. Three rule sets and PLAN-159 T-12's two measurements
   were describing an element that has never been on a screen. */

/* No picture from the other side: a person, not a black rectangle. */
/* PLAN-159 T-1 (D2, 159-F2): THE NO-PICTURE TILE IS THE SAME TILE. It takes the picture tile's inset and
   its 24 px clip, and its ground is the flat resolve of Meet's tile scrim over the page ground
   (rgba(0,51,83,0.5) over rgb(19,19,20) = rgb(10,35,52)), so a call with the cameras off is a tile with a
   person in it and not a hole in the page. */
.stage-avatar {
  position: absolute;
  inset: 16px;
  border-radius: 24px;
  background: #0a2334;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
  pointer-events: none;
}

.stage-avatar[hidden] { display: none; }

.stage-initial {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 132px;
  height: 132px;
  border-radius: 50%;
  /* PLAN-159 T-1 (D2): the same grey as the round buttons in the bar, so the one circle on the stage and
     the circles under it are one material. The 132 px and the 56 px letter are the elderly sizes and stay. */
  background: #3c4043;
  color: #f2f5f9;
  font-size: 56px;
  font-weight: 600;
  line-height: 1;
}

.stage-avatar-name {
  margin: 0;
  font-size: 20px;
  color: #dfe5ef;
  overflow-wrap: anywhere;
}

/* Who is here, and how long it has been. One chip, top left, over the picture. */
/* PLAN-179 T-1 (D1, F1): THE CHIP IS THE HEADER'S LEFT GROUP, AND IT IS NO LONGER OVER THE PICTURE.

   PLAN-159 T-1 made it a chip floating at the top left of the picture and PLAN-160 T-14 put Meet's
   own four things in it. The design of record draws those four things in the STAGE HEADER instead
   (README, Screen 3 and Screen 6), which is the box PLAN-178 T-3 built and left empty, so the
   element moved there and this rule stopped being an overlay: no position, no ground, no padding
   and no radius, because the header has its own ground (--stage-page) and its own padding.

   ONE LINE STILL, which is PLAN-169 T-8's rule and the design's: four short things, none of which
   wraps, and the code is the one allowed to be clipped rather than push the button onto a second
   row. The two clipped elements (the names and the timer) keep their own rules below. */
.stage-chip {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 12px;
  min-width: 0;
  color: var(--stage-ink);
}

.stage-chip .names { margin: 0; font-weight: 600; overflow-wrap: anywhere; }

/* =================================================================================================
   PLAN-175 T-1 (D1), MOVED BY PLAN-180 T-G BLOCKER 2: THE SYSTEM SENTENCE IS AT THE BOTTOM NOW,
   CENTRED, WITH A WAY TO CLOSE IT.

   It was absolutely placed at the TOP LEFT, under the header chip, as a dark pill with no X. The
   prototype carries its system sentence at the bottom centre just above the button row and puts a
   56 px X on it, and the owner's own instruction of 2026-09-13 is "Put system texts at the bottom
   dont overlap". The gallery review made it blocker 2 because on this one screen it was not done.

   IT IS A ROW IN THE LOWER BAND rather than a box positioned over the picture, which is what stops
   it overlapping anything: the band is the design's own notices box, it sits above the bar, and a
   row in it pushes nothing and is pushed by nothing.
   ================================================================================================= */
.stage-langs-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  /* The band takes no pointer events (NOTES.md F-8), so the row has to take its own back or the
     X would not be pressable. */
  pointer-events: auto;
}

.stage-langs-row[hidden] { display: none; }

.stage-langs-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #f2f5f9;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.stage-langs-close:hover { background: rgba(168, 199, 250, 0.12); }
.stage-langs-close svg { width: 26px; height: 26px; }
.stage-langs-close:focus-visible { outline: 3px solid var(--panel-link, #a8c7fa); outline-offset: 2px; }

.stage-langs {
  margin: 0;
  max-width: min(70%, 560px);
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(19, 19, 20, 0.7);
  color: #f2f5f9;
  /* MATRIX ROW U-07 (PLAN-169 D7/F7): NOTHING UNDER 18 px ON ANY SCREEN. This line was 16 px and the
     row named it on all four surfaces it walks - the stage at 1100 and at 390, and the messages panel
     at both. The rule is the elderly-first floor and it has no exceptions; this is a SENTENCE a person
     reads to find out what is being translated into what, which is the last line on the page to make
     small. */
  font-size: 18px;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.stage-langs[hidden] { display: none; }

.stage-timer {
  font-variant-numeric: tabular-nums;
  color: #c4c7c5;
}

.stage-timer:empty { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-153 T-8 (D5): THE TOAST, AND THE CAPTIONS OVER THE PICTURE.

   THE TOAST IS AT THE TOP CENTRE AND IT LEAVES. Where these lines used to render - below the control
   row, at the bottom of the column - a phone simply did not show them, which is why the owner's own
   screenshots of the failing proof carry no wait line at all. wire.js hides the column six seconds
   after the last line arrives (TOAST_MS), because a sentence over somebody's face has to go.
*/
/* ------------------------------------------------------------------------------------------------
   PLAN-157 T-7 (D8): THE ONE CALLOUT. Design spec section 3.

   The owner, 2026-09-11 07:40 UTC: "4. Collouts design is creap - rework with specialists". M7
   measured FOUR styles for one job - this column at the top, the video notice lines inside it, the
   knock, and the chat refusal - and every one of them left after six seconds, including the ones a
   person had to answer.

   IT IS THE SAME ELEMENT, restyled: every module already writes its own sentence into it, and moving
   four modules' output into a new box would be four more moves to keep in step. What is new is the
   LOOK (bottom centre just above the bar, where a person's eyes and thumb already are, dark because
   it stands on a picture, 20 px because this is an elderly-first product) and the RULE, which is
   callout.js's: `data-kind="sticky"` carries a Close and stands until it is pressed. */
.stage-notices {
  position: absolute;
  left: 50%;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 7;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: max-content;
  max-width: min(560px, calc(100% - 24px));
  padding: 16px 20px;
  /* PLAN-159 T-2 (D1, step 7): the callout is the same two greys as everything else that floats on the
     stage - the bar's rgb(30,31,32) with the round buttons' rgb(51,53,55) as its edge. The design
     inputs named #202124 and #3C4043 here from knowledge; the owner's capture measured the two greys
     Meet actually floats, and D1 says the capture wins. It STAYS bottom centre (Meet's is bottom left):
     it sits directly above the hold pill, which is where the eyes already are on a phone. */
  border: 1px solid #333537;
  border-radius: 16px;
  background: #1e1f20;
  color: #f2f5f9;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.38);
  text-align: center;
  pointer-events: none;
}

.stage-notices[hidden] { display: none; }
.stage-notices > * { pointer-events: auto; }
.stage-notices .sub { margin: 0; color: #f2f5f9; font-size: 20px; line-height: 1.4; }
.stage-notices .sub[hidden] { display: none; }
.stage-notices .mode-line { margin: 0; color: #f2f5f9; font-size: 20px; line-height: 1.4; }
.stage-notices .video-sheet,
.stage-notices .call-state { margin: 0; padding: 0; border: 0; background: none; }
.stage-notices .video-line { margin: 0; color: #f2f5f9; font-size: 20px; line-height: 1.4; }
.stage-notices .video-line-title { font-size: 22px; font-weight: 600; }

/* THE CLOSE, on a sticky and only on a sticky. A 56 px target like every other control on this page,
   and it is the only thing callout.js ever puts into this element. */
.stage-notices .callout-close {
  min-height: var(--tap);
  padding: 0 22px;
  border: 1px solid #333537;
  border-radius: var(--r-control);
  background: transparent;
  color: #f2f5f9;
  font: inherit;
  font-size: 19px;
  font-weight: 600;
  cursor: pointer;
}

.stage-notices .callout-close:focus-visible { outline: 3px solid #7fb0ff; outline-offset: 2px; }

/* A sentence a person must read reads as one: the warn edge the rest of the page uses for a refusal. */
.stage-notices[data-kind='sticky'] { border-left: 6px solid #ff9b7d; }

/* =================================================================================================
   PLAN-180 PASS THREE, ROW A (THE OWNER, 2026-09-15 16:31 UTC, WITH A SCREENSHOT OF STAGING):
   INSIDE THE DESIGN'S BOX THERE IS ONE EDGE, AND IT IS THE BOX'S OWN.

   What he photographed: the call screen's callout, the round "i" icon, the sentence beside it, and a
   thin ORANGE vertical bar between the two. MEASURED at the base by harness row CALLOUT-INFO-NO-BAR:
   the BODY's left edge is 6 px rgb(255, 155, 125) drawn at x 133, with the icon ending at x 117 -
   a bar standing in the 16 px gap between them, on a line whose look is `info`.

   WHERE IT COMES FROM. The rule directly above is older than the box: it dressed `.stage-notices`
   when that column WAS the notice, and it reads "sticky" as "a refusal". Since PLAN-178 T-12 the
   column is the BODY inside `.lh-callout`, the design's warn edge belongs to the WRAPPER
   (`[data-look='warn']`, left of the icon, where a person reads it as the box's colour), and every
   sentence the design's own `say()` draws is STICKY whatever its look (callout.js:
   `paint(CALLOUT_KINDS.STICKY, 'say', look)`). So every information line got a warn-coloured bar.

   THE RULE IS NOT DELETED, IT IS SCOPED. `.stage-notices` can still stand on its own where no box
   has been built around it, and there the old edge is still the only mark a refusal has. Inside the
   box it is switched off, for BOTH looks: the warning keeps its colour on the wrapper, which is where
   the design draws it, and the box never has two edges in it.
   ================================================================================================= */

.lh-callout > .stage-notices[data-kind='sticky'] { border-left: 0; }

/* THE CAPTIONS SIT OVER THE LOWER THIRD, where a person reading them is still looking at the face
   above them. Only the LAST TWO lines are kept on the screen: a scrolling transcript over somebody's
   picture is a wall of text, and the line before the one being spoken is all the context a
   conversation needs. Everything older is still in the document - captions.js owns it and a person can
   still reach it - it is simply not drawn over the picture. */
.stage-captions {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  max-height: 34%;
  margin: 0;
  padding: 18px 20px 22px;
  overflow: hidden;
  background: linear-gradient(to top, rgba(9, 11, 15, 0.88), rgba(9, 11, 15, 0));
  color: #f2f5f9;
  /* PLAN-159 T-2 (design inputs 1.9): 22 px, the same size as the status line directly under it, so the
     lower band has ONE size instead of three. It is a raise and never a cut, so PLAN-157 section 6's
     floor holds. */
  font-size: 22px;
  line-height: 1.4;
  text-align: center;
}

.stage-captions > *:nth-last-child(n + 3) { display: none; }
.stage-captions:empty { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-155 T-2 (D2): THE LOWER BAND, AND THE STATUS LINE BACK INSIDE IT.

   ONE band along the bottom of the stage holds the two things a person reads while they are looking
   at a face: what was just said, and whose turn it is. The captions sit on top and the STATUS LINE
   sits under them, directly above the bar, so the sentence that says "You can talk now" is the last
   thing between the picture and the control the thumb is on.

   The band is a flex column rather than two absolutely positioned boxes, because the captions grow
   and shrink line by line and a status line pinned to bottom:0 under them would be covered by the
   growth. It takes no pointer events of its own so a press goes to the picture behind it. */
.stage-lower {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 0 0 14px;
  pointer-events: none;
}

.stage-lower > * { pointer-events: auto; }

/* Inside the band the captions are a block in the column, not a box pinned to the stage. */
.stage-lower .stage-captions {
  position: static;
  width: 100%;
  max-height: 30vh;
}

/* The line itself: large, on the translucent dark the notices use, centred over the picture. */
.stage-lower .talk-status {
  display: block;
  max-width: calc(100% - 28px);
  margin: 0;
  padding: 10px 22px;
  border-radius: 999px;
  background: rgba(11, 13, 17, 0.78);
  color: #f2f5f9;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
}

.stage-lower .talk-status:empty { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-157 T-5 (D5): THE MORE SHEET, ON THE STAGE AND ABOVE THE BAR.

   The owner's finding 6 was "More buttons do not work", and what the harness measured at 390 x 844
   (S-05, 09:33 UTC) is that the sheet was drawn and reachable there - and that opening it took 263 px
   out of the COLUMN: the stage fell from 691 px to 412 and the bar moved off the bottom of the
   screen. On a phone, where the visible area is the window minus the browser's own chrome, that is
   the whole of the problem. Inside the lower band it is absolutely positioned within the stage, so it
   costs the column nothing: the bar does not move and the stage does not shrink.

   It is the LAST child of the band, so it stands under the captions and the status line and directly
   over the bar. A long sheet scrolls inside itself rather than growing past the picture. */
.stage-lower .talk-sheet {
  width: min(420px, calc(100% - 24px));
  max-height: 44vh;
  margin: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
  /* PLAN-157 T-8: AND IT IS THE TOP OF THIS BAND. MEASURED by harness S-05 at 11:30 UTC, after the
     row was taught to say what is drawn over each control: the sheet was visible, the right size and
     its middle was on top, and "Close" still did nothing - because .mode-line was painted over Close
     and .call-line over "Show original". The band's own lines are positioned, so being the LAST child
     was not enough; a static child cannot win against a positioned sibling. Pressing a control a
     person can plainly see and having nothing happen IS the owner's finding 6 ("More buttons do not
     work"), so the sheet takes a stacking context of its own, above the lines (which are information)
     and above the callout at z-index 7 (which is a notice): while it is open it is the thing being
     used. It is closed by its own Close and by End, so nothing is hidden for longer than that. */
  position: relative;
  z-index: 8;
}

/* AND THE BAND ITSELF HAS TO RISE, which is the half the first cut of this fix missed and the row
   caught again at 11:32 UTC. `.stage-lower` is `position: absolute` with `z-index: 1`, so it is a
   stacking context of its own: a child of it can carry z-index 9999 and still be painted under
   `.stage-notices`, its sibling at z-index 7, where the mode line and the call line live. So the
   BAND rises, and only while it is holding a sheet - the captions and the status line must not
   stand over a notice the rest of the time. The sheet is removed from the band when it closes
   (talk/screens.js), so this reverses itself with no state to keep in step. */
/* THE STATED LIMIT (bugcheck round 2, gemini on packet r2e): :has() is Chrome 105, Firefox 103 and
   Safari 15.4, all of them 2022. A browser older than that keeps the band at z-index 1 and the sheet
   is unpressable again - the defect this rule fixes. It is accepted rather than carried in JavaScript
   because the two browsers this product is used on are current Chrome for Android and current iOS
   Safari, both years past those versions, and a class toggled from JavaScript is one more piece of
   state to keep in step with talk/screens.js's own open and close. */
.stage-lower:has(.talk-sheet) { z-index: 9; }

/* ------------------------------------------------------------------------------------------------
   PLAN-153 T-8: the messages. A side panel where there is width for one, a bottom sheet where there
   is not. It is CLOSED until the button is pressed either way (chat/panel.js's own rule), so this is
   about where it opens and never about whether it is open. */
/* ------------------------------------------------------------------------------------------------
   PLAN-157 T-6b (D7): THE MESSAGES PANEL, REBUILT TO .claude/plans/PLAN-157-design-spec.md.

   THE OWNER, 2026-09-11 07:40 UTC: "3. Chat UI is crap - rewrite" and "5. On mobile if i on messages
   to chat - it brakes screen and i cant of it".

   WHY HE COULD NOT GET OUT, and the four lines that did it: on a phone this panel was a bottom sheet
   at `max-height: 62vh` with `overflow-y: auto` ON THE PANEL, so the header carrying Close was the
   first child of the one scrolling box. A few lines of conversation and Close scrolled up out of the
   visible band; the only other way out - the bar's Messages button - was underneath the sheet, which
   sits above it. There was no way out at all.

   THE FIX IS THE SHAPE AND NOT A SIZE. A three row grid: a header that never scrolls, a list that is
   the only scrolling box, and a composer pinned under it. Neither the header nor the composer is
   inside the scrolling box, so neither can leave the screen whatever is in the conversation. */
/* PLAN-159 T-2 (D3, 159-F2): THE PANEL IS DARK, and it is the capture's dark. Meet's in-call panel is
   rgb(32,33,36) at radius 20 with a rgb(68,71,70) hairline on its composer, sitting 16 px off the page
   edge and 16 px off the stage; it is not a white column beside a black picture, which is what a person
   looking at a face for half an hour would be reading against.

   IT CARRIES ITS OWN TOKENS rather than the page's four. --card, --ink, --line and --muted follow the
   reader's light or dark setting, and this surface is dark whichever way that setting goes; leaving the
   children on the page's tokens would have drawn a white bubble and near-black text on a dark panel for
   every reader whose system is set to light. */
.chat-panel {
  --panel-bg: #202124;
  --panel-ink: #e3e3e3;
  --panel-muted: #c4c7c5;
  --panel-line: #444746;
  --panel-them-bg: #303134;
  --panel-link: #a8c7fa;
  position: fixed;
  z-index: 8;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: var(--panel-bg);
  color: var(--panel-ink);
  border: 0;
  /* THE PANEL ITSELF NEVER SCROLLS. This one line is the defect, undone. */
  overflow: hidden;
}

.chat-panel[hidden] { display: none; }

/* Row 1. Never scrolls, so Close is always where a person left it. */
.chat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* PLAN-159 T-2 (D3): the capture's 64 px header, which ours already nearly was. */
  min-height: 64px;
  padding: 12px 16px;
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  background: var(--panel-bg);
  border-bottom: 1px solid var(--panel-line);
}

.chat-title { margin: 0; font-size: 22px; font-weight: 600; }

.chat-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: var(--tap);
  min-width: 120px;
  padding: 0 18px;
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  background: transparent;
  color: var(--panel-ink);
  font: inherit;
  font-size: 19px;
  font-weight: 600;
  cursor: pointer;
}

.chat-close-x { font-size: 22px; line-height: 1; }

/* Row 2. The ONLY scrolling box on this surface. */
.chat-lines {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.chat-empty { margin: 0; color: var(--panel-muted); font-size: 19px; }

.chat-line {
  display: flex;
  flex-direction: column;
  max-width: 86%;
}

.chat-line.chat-theirs { align-self: flex-start; align-items: flex-start; }
.chat-line.chat-mine { align-self: flex-end; align-items: flex-end; }

/* The name and the time, above the words, so nobody has to guess whose bubble this is. */
.chat-meta {
  display: flex;
  /* PLAN-159 T-12, gemini's UI finding 3: the name, the Typed label and the time are three pieces of
     text of unknown length in three languages, so the row they sit in wraps rather than pushing one of
     them off the end. */
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0 0 4px;
  padding: 0 4px;
  font-size: 18px;
  color: var(--panel-muted);
}

.chat-body {
  margin: 0;
  padding: 12px 16px;
  font-size: 19px;
  line-height: 1.45;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.chat-theirs .chat-body {
  background: var(--panel-them-bg);
  color: var(--panel-ink);
  border-radius: var(--r-bubble) var(--r-bubble) var(--r-bubble) 6px;
}

.chat-mine .chat-body {
  background: var(--chat-mine-bg);
  color: var(--chat-mine-ink);
  border-radius: var(--r-bubble) var(--r-bubble) 6px var(--r-bubble);
}

/* Which words am I looking at? A dashed edge while the ORIGINAL is showing, in the same radius. */
.chat-showing-original .chat-body { border: 2px dashed var(--panel-line); }

.chat-note {
  margin: 6px 0 0;
  max-width: 86%;
  font-size: 18px;
  color: var(--panel-muted);
}

.chat-original {
  margin: 6px 0 0;
  min-height: var(--tap);
  padding: 0 4px;
  border: 0;
  background: none;
  /* PLAN-159 T-2: the accent as it reads on a dark surface. var(--accent) is #1c62d6 for a reader whose
     system is set to light, and #1c62d6 on this panel's rgb(32,33,36) is 3.4:1, which is under AA for an
     18 px link. The capture's own blue-on-dark is rgb(168,199,250). */
  color: var(--panel-link);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}

/* Row 3. Pinned under the list, so the on-screen keyboard shrinks the panel around it. */
.chat-compose {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "refused refused" "box send";
  align-items: end;
  gap: 10px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--panel-bg);
  border-top: 1px solid var(--panel-line);
}

/* PLAN-155 T-7 (D6): the refusal for a message that was not sent, directly above the box the words
   are still sitting in. It is the one line in this panel that has to be read before anything else is
   pressed, so it is the warn colour the rest of the page already uses for a refusal. PLAN-157 T-6b
   moves it INSIDE the composer, spanning both columns, so it cannot be scrolled away from the words
   either, and gives it the size everything else on this surface has. */
.chat-panel .chat-refused {
  grid-area: refused;
  margin: 0;
  padding: 12px 14px;
  /* PLAN-159 T-2: the dark panel's own refusal colours, pinned as literals for the same reason the rest
     of this surface is: the light theme's #a4341f on #fdf1ee is a white chip on a dark panel. */
  border: 1px solid #ff9b7d;
  border-left-width: 6px;
  border-radius: 12px;
  background: #2a1a14;
  color: #ff9b7d;
  font-size: 19px;
  line-height: 1.4;
}

/* PLAN-159 T-2 (D3): the capture's composer is a fully rounded field with a 1 px rgb(68,71,70) edge and
   no fill of its own. Ours keeps its 56 px height and its 19 px words. */
.chat-write {
  grid-area: box;
  min-height: var(--tap);
  max-height: 140px;
  padding: 14px 20px;
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  background: transparent;
  color: var(--panel-ink);
  font: inherit;
  font-size: 19px;
  line-height: 1.4;
  resize: none;
}

.chat-write::placeholder { color: var(--panel-muted); }

.chat-send {
  grid-area: send;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
}

.chat-send-glyph { font-size: 24px; line-height: 1; }

/* ------------------------------------------------------------------------------------------------
   PLAN-159 T-5 (D5): ONE CONVERSATION, drawn into the panel's own list box by assets/conversation.js.

   The entries reuse .chat-line, .chat-meta, .chat-body and .chat-original, because a thing somebody
   said and a thing somebody typed are both a thing somebody said and there is no reason for two
   appearances. What separates them is the LABEL, never the colour alone: the owner asked to "show if
   someone text something additionally", and a tint by itself is the one signal an elderly reader on a
   dimmed screen is most likely to miss. */
.conv-tag {
  /* PLAN-159 T-12, gemini's UI findings 2 and 3. It was 15 px, under the 18 px floor, and it is the
     word that says what KIND of thing a person is reading - the last place to save four pixels. And it
     was `flex: 0 0 auto` in a row that does not wrap, so a long name beside a long Lithuanian or
     Vietnamese word for "Typed" would have pushed the time out of the row: it may shrink now, and the
     row it sits in wraps (.chat-meta below). */
  flex: 0 1 auto;
  padding: 0 8px;
  border-radius: 999px;
  background: rgba(168, 199, 250, 0.16);
  color: var(--panel-link);
  font-size: 18px;
  font-weight: 600;
}

/* AND A TINT BESIDE IT, so the difference is visible before a word is read. */
.conv-typed.chat-theirs .chat-body { background: #3c4043; }

/* THE PICTURE KEEPS NOTHING WHILE THE PANEL IS OPEN (D5 a, and the owner's 14:15 UTC "merged one
   solution instead of one chat and then captions on top"). The panel IS the one place; the last two
   spoken lines come back over the picture the moment it is closed, which is what makes the rule a
   rule and not a loss. */
#s-connected[data-chat='open'] .stage-captions { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-159 T-6 (D5 b): ONE LINE OVER THE PICTURE, AND ONLY ON A PHONE.

   The owner, 14:20 UTC: "show one sentence, one spoken thing at a time, not like a chat way where you
   can see everything, but one, the next one, the next one. You never see all in one place unless you
   click a button and see all conversation in one place." So below 900 px the two-line caption box is
   not drawn at all and this band is: ONE entry, the newest, spoken or typed, replaced when the next
   one arrives. 22 px, the size the status line under it and the captions it replaces already use. */
.conv-line {
  display: none;
  max-width: calc(100% - 28px);
  margin: 0;
  padding: 10px 20px;
  border-radius: 18px;
  background: rgba(19, 19, 20, 0.78);
  color: #f2f5f9;
  font-size: 22px;
  line-height: 1.35;
  text-align: center;
  overflow-wrap: anywhere;
}

.conv-line[hidden] { display: none; }
.conv-line .conv-tag { margin-right: 8px; }

@media (max-width: 899px) {
  /* The band IS the line here, and the caption box it replaces is not drawn. */
  .conv-line:not([hidden]) { display: block; }
  .stage-lower .stage-captions { display: none; }
}

/* ------------------------------------------------------------------------------------------------
   PLAN-159 T-6 (fix): THE SELF TILE SITS ABOVE THE LOWER BAND ON A PHONE, NEVER UNDER IT.

   THE DEFECT, measured at 390 x 844: the self tile is drawn bottom-right inside .video-tiles, and
   .stage-lower - the one conversation line and the status pill - is a full-width box at the bottom of
   the stage at z-index 1. The band painted straight over the tile: its top-left quarter disappeared
   behind the words, and the words sat on a picture of somebody's face instead of on their own dark pill.

   IT IS LIFTED BY THE BAND'S OWN MEASURED HEIGHT and not by a constant, because that height is its
   content's: the one line is a single entry that wraps to two or three lines depending on what was said
   and in which of three languages. wire.js writes --lower-band-h on the stage after every paint and
   from a ResizeObserver on the band. The fallback is 0px, which is where the tile is drawn today, so
   the one frame before the first measurement is the old layout and never an invented number. */
@media (max-width: 719px) {
  .video-self {
    bottom: calc(14px + var(--lower-band-h, 0px));
  }
  /* PLAN-207c T-6 (D7, F6): the `.video-self-name` override that stood here went with the element
     nothing builds. See the note where its main rule set was. */
}

.chat-close:focus-visible,
.chat-original:focus-visible,
.chat-write:focus-visible,
.chat-send:focus-visible {
  /* On a dark panel the focus ring is the panel's own blue, for the reason .chat-original is. */
  outline: 3px solid var(--panel-link);
  outline-offset: 2px;
}

@media (min-width: 900px) {
  /* PLAN-159 T-2 (D3, 159-F2): IT FLOATS, like the capture's. 360 px wide, radius 20, sitting 16 px off
     the page edge and, with the padding below, 16 px off the stage. The border-left that used to join it
     to the picture is gone with the gutter that replaces it. */
  .chat-panel {
    top: 16px;
    right: 16px;
    bottom: 16px;
    left: auto;
    width: 360px;
    max-width: 360px;
    height: auto;
    border-left: 0;
    border-radius: 20px;
  }

  .chat-panel .chat-head { padding-top: 16px; }
  .chat-panel .chat-line { max-width: 94%; }

  /* The stage and the bar give up the panel's width AND its two gutters, so the panel covers neither and
     the gap between the picture and the panel is the same 16 px on both of its sides.
     PLAN-157 section 2 asked for the width to be given up over 140 ms rather than in one frame; the
     landed CSS did not take the line and PLAN-159 T-2 puts it back. */
  /* PLAN-219 T-4 (D4): the More panel is the same column in the same shell, so it takes the same
     width from the stage and the bar. Without it the panel stood over the bar's End and More. */
  #s-connected[data-chat='open'] { padding-right: 392px; }
  #s-connected { transition: padding-right 140ms ease; }

  @media (prefers-reduced-motion: reduce) {
    #s-connected { transition: none; }
  }
}

@media (max-width: 899px) {
  /* A FULL SHEET, not a percentage of the viewport. 100dvh is the one that shrinks when the keyboard
     comes up, which is what keeps the composer above it; 100vh is the fallback for a browser without
     it and is written FIRST so the newer rule wins where it is understood. */
  .chat-panel {
    inset: 0;
    height: 100vh;
    height: 100dvh;
    border-radius: 0;
  }

  /* AND THE BAR IS NOT DRAWN UNDER IT. A person pressing at a control they can see through nothing is
     what "i cant of it" was: the way out is the header's Close, or Back. */
  #s-connected[data-chat='open'] .talk-bar { display: none; }
}

@media (min-width: 720px) and (max-width: 899px) {
  /* PLAN-219 T-4 (D4, F4): the More panel is the same sheet in this band and needs the same answer.
     Measured at 800 x 900 with it open: the sheet ran 12 to 788 and 216 to 900 with the bar's End at
     824 to 880 INSIDE it, which is the defect this row is about, one band down. The band's PADDING
     rules are untouched - under 900 there is no width to give up, because the panel is a sheet over
     the picture rather than a column beside it - and the way out stays the header's 56 px X, the dim
     and Escape, exactly as it is for the Conversation.

     PLAN-227 D1: the band starts at 720 because the phone rows (S-05, U-09) pin the bar DRAWN under
     the sheet at 390: deploy 7 measured the rule at 0 px hiding it there and moving the self tile by
     the bar's own 196 px. Below 720 the rule does not fire. */
  #s-connected[data-more='open'] .talk-bar { display: none; }
}

/* ------------------------------------------------------------------------------------------------
   PLAN-153 T-7 (D5): THE BOTTOM BAR. One centred row of round buttons under the stage.

   THE CLASS NAMES ARE STILL THE MODULES' OWN - .talk-mic, .talk-camera, .talk-chat, .talk-more,
   .talk-end, .talk-hold, .mode-toggle - and wire.js adds two of its own, .talk-bar on the row and
   .bar-button on each control it dressed. Nothing is renamed and no module file is edited.

   THE WORDS ARE CLIPPED, NOT REMOVED. .bar-words is the same pattern as .visually-hidden and it is
   there for the same two readers: a screen reader, and every text lookup the wiring probe makes.
*/
.talk-fragment .talk-screen-incall {
  display: flex;
  flex-direction: column;
}

/* PLAN-159 T-1 (D2, 159-F1): THE BAR IS THE CAPTURE'S BAR. rgb(30,31,32), and the 1 px top border is
   GONE: Meet's bar has no rule above it, because the bar and the ground are two different greys and a
   line between them is a line nobody needs. On a phone it stays two full-width rows (PLAN-156); at 720 px
   and up it becomes the floating pill the capture measured (616 x 72, radius 24, 8 px off the bottom),
   below. z-index 5 is PLAN-157 section 4's z order. */
.talk-bar {
  position: relative;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 0;
  padding: 14px 14px calc(14px + env(safe-area-inset-bottom, 0px));
  background: #1e1f20;
}

.bar-words {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.bar-icon {
  width: 26px;
  height: 26px;
  display: block;
}

/* The round ones. 56 px is this file's own touch target and it does not shrink for a circle. */
.talk-bar .talk-mic,
.talk-bar .talk-camera,
.talk-bar .talk-chat,
.talk-bar .talk-more,
.talk-bar .mode-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* PLAN-155 T-3 (D3): A CIRCLE THAT NEVER GROWS, and this one line is the whole of M3's defect.
     The row carries the module's own .talk-actions class as well as .talk-bar, and
     `.talk-actions button { flex: 1 1 auto }` (app.css:330) still applied to every button in it.
     These rules set the WIDTH and said nothing about flex, so each icon button stretched to fill its
     share of the row and the bar wrapped into three rows at 1100 px: Mic and Camera at half a width
     each, the hold pill alone, then the rest. Measured at 51ec6c92. The owner's sentence was the
     opposite: round icons in one row. */
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  min-height: 56px;
  padding: 0;
  /* PLAN-159 T-1 (D3, 159-F1): the capture's round button - rgb(51,53,55) with a #e3e3e3 icon and NO
     border. The border was doing the separating that the new ground now does. */
  border: 0;
  border-radius: 50%;
  background: #333537;
  color: #e3e3e3;
  font: inherit;
  cursor: pointer;
  transition: background-color 120ms ease, border-radius 350ms cubic-bezier(0.27, 1.06, 0.18, 1);
}

/* HOVER, POINTER DEVICES ONLY: a phone must never keep a hover colour after a tap. The capture draws
   hover as a state layer (#e3e3e3 at 8 percent over rgb(51,53,55)); resolved, that is rgb(65,67,69). */
@media (hover: hover) {
  .talk-bar .talk-mic:hover,
  .talk-bar .talk-camera:hover,
  .talk-bar .talk-chat:hover,
  .talk-bar .talk-more:hover,
  .talk-bar .mode-toggle:hover { background: #414345; }
}

/* PRESSED, AND IT IS THE ONE INTERACTION MEET IS KNOWN BY: the circle squares off. The capture sets
   `border-radius .35s cubic-bezier(.27,1.06,.18,1)` on all fifteen round buttons on the screen, and the
   pressed state layer (#fff at 12 percent over rgb(51,53,55)) resolves to rgb(75,77,79). */
.talk-bar .talk-mic:active,
.talk-bar .talk-camera:active,
.talk-bar .talk-chat:active,
.talk-bar .talk-more:active,
.talk-bar .mode-toggle:active {
  background: #4b4d4f;
  border-radius: 12px;
}

@media (prefers-reduced-motion: reduce) {
  .talk-bar .talk-mic,
  .talk-bar .talk-camera,
  .talk-bar .talk-chat,
  .talk-bar .talk-more,
  .talk-bar .mode-toggle { transition: none; }
}

.talk-bar .talk-mic:focus-visible,
.talk-bar .talk-camera:focus-visible,
.talk-bar .talk-chat:focus-visible,
.talk-bar .talk-more:focus-visible,
.talk-bar .mode-toggle:focus-visible,
.talk-bar .talk-hold:focus-visible,
.talk-bar .talk-end:focus-visible {
  outline: 3px solid #7fb0ff;
  outline-offset: 2px;
}

/* Off is the state that has to be obvious without reading: the button goes red.

   PLAN-159 T-1 (D3, 159-F1): AND IT IS A FILL NOW, NOT AN OUTLINE. A pale outline on a dark circle was
   the weakest signal on the screen and it is the one an elderly person most needs - their microphone is
   off and they are talking to nobody. White on rgb(219,55,45) is 4.0:1, which is above the 3:1 AA asks of
   a graphical object, and a 26 px icon is one; it is also not the only signal, because aria-pressed still
   carries the state and the More sheet says it in words. */
.talk-bar .talk-camera[aria-pressed='false'],
.talk-bar .talk-mic[aria-pressed='false'] {
  border: 0;
  background: #db372d;
  color: #ffffff;
}

.talk-bar .mode-box {
  /* The box is not a button, so .talk-actions button never reached it; it is named here anyway so
     the rule "only the two pills grow" is written once and holds for every item in the row. */
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}

/* THE HOLD PILL IS THE BIGGEST TARGET ON THE SCREEN, on purpose: it is the one control a person uses
   every single turn, while looking at the other person rather than at the screen. */
.talk-bar .talk-hold {
  /* PLAN-155 T-3 (D3): the hold pill and the direct chip are the ONLY items in the row that grow,
     and they stop at 520 px so a wide screen does not turn the pill into a banner. */
  /* PLAN-179 T-6 (D4, F4): the design's own three numbers for this pill - a 220 px basis, a 420 px
     cap and 22 px of air each side. It was 1 1 auto capped at 520 with a 220 px minimum, which is
     the same idea at different sizes; the design's cap is lower because a hold pill that grows to
     520 on a wide screen stops reading as a control and starts reading as a banner. The phone's own
     basis is PLAN-156's arithmetic and is set in its own rule below. */
  flex: 1 1 220px;
  width: auto;
  max-width: 420px;
  min-height: 56px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  /* PLAN-159 T-2 (159-F8): the pinned pair, white on #1c62d6, 6.3:1. It was var(--accent) on
     var(--accent-ink), which follows the reader's light or dark setting; the stage is dark whatever
     that setting says, so the pill drew two different blues on one surface and neither of them was a
     value any contrast row could read. */
  background: #1c62d6;
  color: #ffffff;
  /* PLAN-159 T-3 (D4): the wash is absolutely placed inside the pill and clipped to its 999 px radius.
     `isolation` makes the pill its own stacking context, which is what lets the wash sit BEHIND the
     label: the label is a bare text node that talk/screens.js owns, so it cannot be given a position of
     its own, and a positioned child with no z-index would paint over it (the design inputs' 2.5.3 gives
     .hold-count a position and leaves the label under the wash). */
  position: relative;
  overflow: hidden;
  isolation: isolate;
  font: inherit;
  font-size: 19px;
  font-weight: 600;
  cursor: pointer;
}

.talk-bar .talk-hold[hidden] { display: none; }

/* THE WASH. The phone's Conversation.kt:591: white at 24 percent, anchored left, its WIDTH is the
   REMAINING time. --hold-left is 1 at the press and 0 at the limit, and JavaScript sets only that. */
.talk-bar .talk-hold .hold-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: -1;
  width: calc(var(--hold-left, 0) * 100%);
  background: rgba(255, 255, 255, 0.24);
  pointer-events: none;
  transition: width 120ms linear;   /* the phone's tween(120, LinearEasing), Conversation.kt:426 */
}

/* At rest the wash is not drawn at all. */
.talk-bar .talk-hold:not([data-holding='true']) .hold-fill { display: none; }

/* The number, in its own span so the resting label is never rebuilt. */
.talk-bar .talk-hold .hold-count { position: relative; margin-left: 10px; }

/* THE LAST TEN SECONDS. #DC2626 is the PHONE'S red (Tokens.kt:66) and deliberately not the bar's
   rgb(219,55,45): the owner asked for "the same like in mobile", the warn pill is on the screen only
   for the last ten seconds of a turn, and End keeps its own colour so the two are never confused. */
.talk-bar .talk-hold[data-warn='true'] {
  background: #dc2626;
  color: #ffffff;
}

@media (prefers-reduced-motion: reduce) {
  .talk-bar .talk-hold .hold-fill { transition: none; }
}

/* While the call is direct there is nothing to hold, so the pill is replaced by a sentence. */
.direct-chip {
  /* The pill's stand-in while the call is direct, so it grows and stops exactly where the pill does. */
  flex: 1 1 auto;
  max-width: 520px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: 0 22px;
  /* PLAN-159 T-1 (D3): the pill's stand-in is the same material as the buttons beside it. */
  border: 0;
  border-radius: 999px;
  background: #333537;
  color: #e3e3e3;
  font-size: 17px;
}

.direct-chip[hidden] { display: none; }

/* End: last, red, and shaped like nothing else in the row. A 56 px pill that never grows: a control
   that hangs up on somebody's family must not be the widest target on the screen (PLAN-155 D3). */
.talk-bar .talk-end {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* PLAN-159 T-1 (D3, 159-F1): Meet's End is visibly WIDER than a circle (the capture: 72 x 48 against
     48 x 48 buttons); ours was 76 px beside 56 px circles and read as a fat circle at 1100 px. 96 px at
     our 56 px height keeps the same proportion. The red is the capture's rgb(219,55,45), and it is now
     the only red on the screen apart from an OFF button, which is the same red on purpose. */
  min-width: 96px;
  min-height: 56px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: #db372d;
  color: #ffffff;
  font: inherit;
  cursor: pointer;
  transition: background-color 120ms ease;
}

@media (hover: hover) {
  .talk-bar .talk-end:hover { background: #e24940; }
}

.talk-bar .talk-end:active { background: #c82d24; }

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

.talk-bar .talk-end .bar-icon { transform: rotate(134deg); }

/* The unread count, on the corner of the round Messages button. */
.talk-bar .talk-chat-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 11px;
  /* PLAN-159 T-1 (D3): the same red as End and as an OFF button, so the screen has one red. */
  background: #db372d;
  color: #ffffff;
  font-size: 13px;
  line-height: 22px;
  text-align: center;
}

.talk-bar .talk-chat-badge[hidden] { display: none; }

/* PLAN-155 T-3 (D3): ONE ROW AT 720 PX AND ABOVE, as a RULE and not as an accident of arithmetic.
   Every item in the row is now a fixed width except the two pills, which stop at 520 px, so nothing
   in it can push a control onto a second line. */
@media (min-width: 720px) {
  .talk-bar { flex-wrap: nowrap; }
}

/* PLAN-159 T-1 (D2, 159-F1): AT 720 PX AND UP THE BAR FLOATS. The owner's capture measures Meet's bar as
   a 616 x 72 pill of rgb(30,31,32) at radius 24, centred, 8 px off the bottom of the window, as wide as
   its own controls and no wider - not a band across the screen. Ours keeps its 56 px targets and its 12 px
   gaps, so it is taller and a little wider than Meet's, and it is the same shape. On a phone it stays the
   two full-width rows PLAN-156 measured, because there a pill would waste the width the five circles need. */
@media (min-width: 720px) {
  .talk-bar {
    width: max-content;
    max-width: calc(100% - 32px);
    margin: 0 auto calc(8px + env(safe-area-inset-bottom, 0px));
    padding: 12px;
    border-radius: 24px;
  }
}

/* PLAN-156 T-3 (D3): UNDER 720 PX THE BAR IS TWO ROWS, BY DESIGN AND BY ARITHMETIC.

   PLAN-155 T-3 gave the hold pill a row of its own above the icons (flex: 1 0 100%), which is right
   - on a phone it is the control the thumb is on - but it left End down among the circles, and the
   circles plus End do not fit: five 56 px circles, a 76 px End pill and five 12 px gaps is 396 px
   where a 390 px phone has 362. So the bar wrapped a THIRD time and M3 measured three rows.

   ROW 1 is the pill (or, while the call is direct, the chip that stands in its place) with End
   beside it. The pill's basis is the row minus End and one gap, with End at its own minimum - so row
   1 is exactly full and nothing else can join it, whatever the words in the pill are in any language.
   ROW 2 is then the five 56 px circles: 5 x 56 + 4 x 12 = 328 px, inside 362, with every touch target
   still 56 px. End keeps its own size and colour and is still the only red control on the screen; it
   is simply beside the thing a person is holding rather than in the row they are aiming at.

   PLAN-159 T-7: THE BASIS FOLLOWS END'S WIDTH, and this is a defect a run caught. T-1 grew End from 76
   to 96 px (Meet's End is visibly wider than a circle) and left the basis at calc(100% - 88px), which
   is 76 + one 12 px gap. At 390 px that made row 1 ask for 302 + 12 + 96 = 410 inside 362, so the pill
   and End stopped fitting together and the bar wrapped a THIRD time - the exact defect PLAN-156 spent
   a plan removing, put back by a colour-and-size pass two plans later. B-10 measured three rows at
   390 x 844 and named it. The basis is now calc(100% - 108px) = 96 + the gap, so row 1 is 254 + 12 +
   96 = 362 exactly, and the arithmetic is written beside the two numbers it depends on.

   The order values do the placing: the pill first, End second, everything else in its natural place
   after them. */
/*
  PLAN-179 T-8 (D5, F5) REPLACES THIS ARITHMETIC WITH THE DESIGN'S OWN, and it is the same kind of
  arithmetic: what shares row 1 has changed. PLAN-156 put End beside the hold pill because five
  circles plus End did not fit one row at 390; the design puts the TRANSLATION ROUND there instead
  (56 px, not 96) and moves the red one down into the collapsible row, where it has the width it
  needs. So the pill's basis is the row minus the translation round and one gap, and the two numbers
  it depends on are still written beside it.

  The order values are gone with the layout they belonged to: wire.js puts the phone's rows in the
  document in the order the design draws them (applyBarWidth), so nothing is re-ordered by this file.
*/
@media (max-width: 719px) {
  .talk-bar .talk-hold,
  .talk-bar .direct-chip {
    /* The translation round's 56 px plus the band's 8 px gap. Change one and change the other. */
    flex: 1 1 calc(100% - 64px);
    width: auto;
    min-width: 0;
    max-width: none;
  }
  .talk-bar .bar-row2 .talk-end {
    flex: 0 0 auto;
  }
}

/* The part of the fragment the stage does not show: the hold hint, which the pill itself says.

   PLAN-155 T-2 (D2): .talk-status IS NO LONGER ONE OF THEM, and that display:none was the defect.
   PLAN-153 T-8 hid it on the belief that the chip and the toast carried it; they do not. The talk
   module's four states - Connecting, You can talk now, You are talking, They are talking - were
   drawn on every call and shown on none, so the one line telling a person whose turn it is was
   invisible, and thirteen of the harness's twenty rows failed at that precondition rather than at
   the thing they test. It is a line on the stage again; see .stage-lower below. */
.talk-fragment .talk-hold-hint { display: none; }

/* The consent sheet, the invite card and every notice line the picture can put on a screen. */
.video-sheet:empty { display: none; }

.video-sheet {
  margin: 0 0 16px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card);
}

.video-line { margin: 0 0 10px; font-size: 18px; line-height: 1.4; }
.video-line-title { font-size: 21px; font-weight: 600; }
.video-line-private { color: var(--muted); font-size: 16px; }

.video-line-button {
  display: block;
  width: 100%;
  min-height: 56px;
  margin: 10px 0 0;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--page);
  color: var(--ink);
  font: inherit;
  font-size: 18px;
  cursor: pointer;
}

.video-line-button[data-key='allow'],
.video-line-button[data-key='accept'] {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}

/* One column everywhere; the wide screen only gets more air, never a second column.
   PLAN-207c T-6 (D7, F6): the `.shell` padding that stood here went with the rule set it belonged
   to - see the note where `.shell` was declared. The heading sizes are untouched. */
@media (min-width: 720px) {
  h1,
  .screen-title { font-size: 36px; }
}

/*
  PLAN-148 T-3 (D3, F3): the two legal links under the home screen's controls. 56 px tall and 18 px
  of type, the same target rule every control on this page follows, with enough space between them
  that a shaking hand cannot hit both. Muted rather than accent: they are a footnote on a screen
  whose one job is the New meeting button.
*/
.legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin-top: 32px;
}

.legal-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 4px;
  font-size: 18px;
  color: var(--muted);
  text-decoration: underline;
}

.legal-links a:hover,
.legal-links a:focus-visible {
  color: var(--ink);
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-1 (D1, F1): THE PEOPLE YOU CAN CALL, DRAWN AS PEOPLE.

   WHAT THE AUDIT MEASURED, and it is the plainest of the fifteen: `grep "ring-" app.css` answered
   ZERO. Every element ring/contacts.js and ring/dial.js draw on the home screen has been wearing the
   browser's own defaults since PLAN-149 shipped them - the Call button was 39 x 21 px of grey at
   13.33 px with an outset border, the rows were a bulleted <ul>, and the heading was a 27 px default
   h2 standing over one button. On an elderly-first product whose own floor is 56 px and 18 px, the
   one control that rings your family was the smallest thing on the screen.

   THE ROW IS A CARD, in the shape the rest of this file already uses: a circle with the first letter,
   the name, the language, and the Call pill on the right. Nothing here invents a colour: the circle
   is the stage's own #3c4043 grey scaled down from 132 px to 44, and the pill is .btn.primary's
   accent at .btn's own 56 px.

   IT IS THE PAGE'S CARD SURFACE AND NOT THE STAGE'S, because the home screen is a card in the middle
   of a page and follows the reader's light or dark setting, which is what the tokens are for. The
   stage is the one surface in this file that pins literals, and this is not it. */
.ring-contacts-title {
  margin: 28px 0 12px;
  font-size: 20px;
  font-weight: 700;
  text-align: left;
  color: var(--ink);
}

.ring-contacts-title[hidden] { display: none; }
.ring-contacts-box[hidden] { display: none; }

.ring-contacts {
  /* NO BULLET, and this is the line M1's "a raw <ul> with bullets" names. */
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 0;
}

.ring-contact {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  text-align: left;
}

/* The same circle the stage draws when a camera is off, at a list row's size. It carries no meaning
   of its own - the name beside it is the fact - so it is hidden from a screen reader by the module
   that writes it, and a row with no letter to draw simply has no circle. */
.ring-contact-initial {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #3c4043;
  color: #f2f5f9;
  font-size: 20px;
  font-weight: 600;
  line-height: 1;
}

.ring-contact-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 18px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.ring-contact-lang {
  flex: 0 1 auto;
  font-size: 18px;
  color: var(--muted);
}

/* THE CONTROL THAT RINGS YOUR FAMILY. 56 px tall and 96 px wide, which are this file's own two
   numbers for a target that matters: .btn's height and .talk-bar .talk-end's width. */
.ring-contact-call {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  min-height: 56px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

.ring-contact-call:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.ring-contacts-empty {
  margin: 0;
  text-align: left;
  color: var(--muted);
}

/* The dialling screen under the list. The lines are already 18 px by inheritance; what had no size
   at all was the control that stops a call somebody is regretting. */
.ring-dial-line { margin: 0 0 8px; text-align: left; }

.ring-dial-cancel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  min-height: 56px;
  margin: 6px 0 0;
  padding: 0 22px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--accent);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

.ring-dial-cancel:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* D15: THE INCOMING BOX TAKES THIS BLOCK'S CARD AND NOTHING MORE. Somebody ringing you is the same
   kind of thing as somebody you can ring, so it is the same card; its own rework is a later plan's. */
.ring-incoming-box:empty { display: none; }

.ring-incoming-box {
  margin: 20px 0 0;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  text-align: left;
}

.ring-incoming-line { margin: 0 0 10px; font-size: 18px; }

.ring-incoming-accept,
.ring-incoming-decline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  min-height: 56px;
  margin: 6px 10px 0 0;
  padding: 0 22px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--accent);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

.ring-incoming-accept {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}

.ring-incoming-accept:focus-visible,
.ring-incoming-decline:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-2 (D2, F2): THE MORE SHEET IS DARK IN BOTH THEMES, LIKE THE PANEL BESIDE IT.

   WHAT THE AUDIT MEASURED IN THE LIGHT THEME, and it is the worst single number of the fifteen: the
   sheet's ground was rgb(255,255,255) - var(--card) following the reader's setting - standing on the
   #131314 stage, and its title was #f2f5f9 INHERITED FROM THE STAGE on that white. 1.09 to 1. The
   heading of the sheet a person opens when something has already gone wrong was invisible.

   THE ANSWER IS THE ONE ALREADY SHIPPED TWO CENTIMETRES AWAY. .chat-panel has pinned its own five
   tokens since PLAN-159 T-2 for exactly this reason, in its own words: "this surface is dark
   whichever way that setting goes; leaving the children on the page's tokens would have drawn a
   white bubble and near-black text on a dark panel for every reader whose system is set to light."
   The sheet is the same kind of surface - a floating panel over a dark stage - so it takes the same
   five values rather than a sixth opinion. Q3 of the plan's interview is settled by that.

   IT IS A NEW BLOCK AT THE END OF THE FILE and not an edit of :387-408, so PLAN-163's rows in the
   same file and this one do not meet in the middle. Equal specificity, later in the file: these win. */
.talk-sheet {
  --panel-bg: #202124;
  --panel-ink: #e3e3e3;
  --panel-muted: #c4c7c5;
  --panel-line: #444746;
  --panel-link: #a8c7fa;
  border-color: var(--panel-line);
  background: var(--panel-bg);
  color: var(--panel-ink);
}

.talk-sheet-title {
  /* It was inheriting the STAGE's #f2f5f9 onto a white card. On the pinned ground it is the panel's
     own ink at better than 10 to 1, and it is said here rather than left to inheritance so a future
     move of the sheet cannot take its colour with it. */
  color: var(--panel-ink);
}

.talk-sheet button {
  /* 18 px is the owner's floor and these were 17. A round pill for every one of them, because the
     two switches were already 999 and a Close at radius 14 beside them read as a different kind of
     control - which it is not. */
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  background: transparent;
  color: var(--panel-ink);
  font-size: 18px;
}

/* The ON switch keeps Meet's own pair, which is the one thing on this surface that is not a token:
   rgb(168,199,250) with rgb(6,46,111) on it, measured off the owner's capture (PLAN-159 T-2). */
.talk-sheet button[aria-pressed='true'] {
  border-color: #a8c7fa;
  background: #a8c7fa;
  color: #062e6f;
}

.talk-sheet button:focus-visible {
  outline: 3px solid var(--panel-link);
  outline-offset: 2px;
}

/* PLAN-163 T-1's Sound check reads on the same ground. Its sizes are T-7's row (the 18 px floor);
   what T-2 owes it is a colour that can be read on the pinned dark. */
.talk-sound-title { color: var(--panel-muted); }
.talk-sound-line { color: var(--panel-ink); }

/* PLAN-180 C-1: and the design's one row on the same pinned dark. The rule above turned the sheet's
   pill border and fill off for this row; here it is given the panel's own ink and muted grey, which
   are the #e3e3e3 and #c4c7c5 the prototype's markup carries. The border and the 999 radius are said
   again because the rule at :2205 is the more specific of the two on this surface. */
.talk-sheet .talk-sheet-hear {
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--panel-ink);
}
.talk-hear-title { color: var(--panel-ink); }
.talk-hear-name { color: var(--panel-muted); }
.talk-hear-chevron { color: var(--panel-muted); }

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-3 (D3, F3): END, INSIDE THE MESSAGES PANEL, AND ONLY WHERE THE BAR IS NOT DRAWN.

   Below 900 px this panel is the whole screen and the rule at :1250 does not draw the bar under it,
   which is right: a row of controls behind an opaque sheet is a row a person presses at while
   nothing happens. The cost, which M3 measured, is that while the conversation is open on a phone
   there is NO End anywhere. It is in the header now, beside Close, in the one red this screen has.

   AT 900 PX AND UP IT IS NOT DRAWN AT ALL, because there the panel is a 360 px column with the bar
   and its own End in plain sight beside it, and two Ends on one screen is one too many. */
/* =================================================================================================
   PLAN-180 T-G BLOCKER 3: THE CALL LENGTH, WHERE PLAN-169's End USED TO BE.

   The gallery review of 2026-09-13 saw a large red "End the call" between the title and the X on the
   phone, where the design draws "Conversation" and then the call length in small grey text. The End
   is gone (chat/panel.js carries why, and what the removal costs); .chat-end and its rules go with
   it rather than being left as a class nothing renders.

   THE TIME IS DRAWN AT EVERY WIDTH AND SHOWN AT ONE, which is the same shape the End had and for the
   opposite reason: the prototype's LAPTOP header has no time at all, and NOTES.md F-3 records that
   the README and the prototype agree about it. So it appears only under 900 px, where the panel is
   the design's bottom sheet.

   Its three values are the prototype's own, read off the frame: 18 px, #c4c7c5, tabular-nums - the
   last so the digits do not dance from one second to the next, which is the same reason the stage
   clock is tabular.
   ================================================================================================= */
.chat-time {
  display: none;
  flex: 0 0 auto;
  font-size: 18px;
  color: var(--stage-ink-muted, #c4c7c5);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 899px) {
  .chat-time { display: inline-block; }
  /* The title and the time share a baseline row; the TITLE gives up the width, never a target. */
  .chat-panel .chat-title { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .chat-panel .chat-close { min-width: 96px; }
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-4 (D4, F4, and D7 folds the size in): THE CALL'S OWN LINE READS LIKE THE REST OF THE BOX.

   The callout's other four lines - .sub, .mode-line, .video-line and the knock - are all #f2f5f9 at
   20 px on the box's pinned #1e1f20. .call-line alone was 17 px in var(--muted), which is #4c5563 for
   a reader whose system is set to light: 2.19 to 1 on that ground, and the one line in the box that
   says what the CALL is doing. The tokens are wrong for it for exactly the reason .chat-panel pins
   its own: this surface is dark whichever way the reader's setting goes. */
.stage-notices .call-line {
  color: #f2f5f9;
  font-size: 20px;
  line-height: 1.4;
}

/* The warn colours stay warn, in the shade this dark surface already uses for a refusal
   (.chat-refused's #ff9b7d), rather than the light theme's #a4341f on a near-black box. */
.stage-notices .call-line-end,
.stage-notices .call-line-busy,
.stage-notices .call-line-error { color: #ff9b7d; }

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-5 (D5, F5): "YOU CAN TALK NOW" IS NEVER UNDER A NOTICE.

   WHAT M5 MEASURED: the status pill sits at the bottom of the lower band (y749 of 900) and the
   callout is bottom-anchored 14 px above the same edge at z-index 7, while the band is z-index 1. So
   for the first six seconds of every call - and again every time a new sentence arrives - the one
   line that tells a person whose turn it is was underneath a notice. Invisible at 4 s, visible at
   12 s, on every call.

   TWO HALVES, AND THE FIRST IS GEOMETRY. The callout is raised by the band's OWN measured height, so
   in the normal case the two do not overlap at all and no stacking question is asked. --lower-band-h
   is already written onto the stage by wire.js after every paint and from a ResizeObserver on the
   band (PLAN-159 T-6), which is the right number precisely because the band's height is its
   content's: one conversation line wraps to two or three lines depending on what was said.

   AND THE SECOND IS STACKING, for the case the first cannot cover: the property's fallback is 0px -
   the one frame before the first measurement lands, which app.css's own note at :1187 names - and a
   callout long enough can still reach the pill. `.stage-lower` is a stacking context of its own, so
   a z-index on the pill alone would be painted under a sibling at 7 whatever number it carried
   (PLAN-157 T-8 learned this on the More sheet and wrote it down two rules above). The BAND rises.

   THE STATED CONSEQUENCE: the captions box and the one conversation line rise with it, because they
   are in the same band. Where they overlap a notice they now win. That is the right way round for
   this product - what was just said and whose turn it is are the two things a person is reading -
   and with the raise above, the overlap is the lagging-measurement frame rather than the steady
   state. The sheet's own rule at `:has(.talk-sheet) { z-index: 9 }` still wins over both. */
.stage-lower { z-index: 8; }

.stage-notices {
  bottom: calc(14px + var(--lower-band-h, 0px) + env(safe-area-inset-bottom, 0px));
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-6 (D6, F6, Q2): THE ENDING IS A SCREEN, AND IT LOOKS LIKE ONE.

   WHAT M6 MEASURED: onCallEnded built talk's ended screen into #talk-fragment and called LH.goHome()
   one line later, so the screen was drawn and replaced in the same tick. Measured four times, on
   both people, at once and three seconds after: the visible screen was s-home, every time. The
   28 px title and the 56 px pill PLAN-159 T-2 wrote for this screen were dead CSS in a shipped file.

   THE PICTURE GOES WITH THE CALL. A frozen tile, a dead bar and a chip counting nothing, under a
   line that says the call has ended, is not an ending; Meet's own post-call page is one large line
   with a lot of air around it and a pill. `data-ended` is written on the screen by wire.js at the
   ending and removed when the person leaves it - the same bargain #s-connected[data-chat] keeps -
   so no module reaches into another's element to do this.

   IT IS STILL THE STAGE'S DARK. The screen a person was just looking at does not flash white at
   them; the ground and the ink are the two the stage already pins. */
#s-connected[data-ended='true'] .stage { display: none; }
#s-connected[data-ended='true'] .chat-panel { display: none; }
#s-connected[data-ended='true'] { padding-right: 0; }

#s-connected[data-ended='true'] .talk-fragment {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 32px 24px calc(32px + env(safe-area-inset-bottom, 0px));
  text-align: center;
}

#s-connected[data-ended='true'] .talk-screen-ended {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  max-width: 420px;
}

/* The title and the reason keep the sizes PLAN-159 T-2 gave them; what they gain is the ink of the
   surface they are finally being seen on. */
#s-connected[data-ended='true'] .talk-ended-title { margin: 0; color: #f2f5f9; }
#s-connected[data-ended='true'] .talk-ended-reason { margin: 0; color: #c4c7c5; }

#s-connected[data-ended='true'] .talk-ended-again {
  width: 100%;
  max-width: 320px;
  font-weight: 600;
}

/* The second way on: outlined, under the filled one, at the same 56 px. It is the quieter of the two
   because calling again is the thing a person on this screen most often wants. */
.talk-ended-home {
  width: 100%;
  max-width: 320px;
  min-height: 56px;
  padding: 12px 20px;
  border: 1px solid #444746;
  border-radius: 999px;
  background: transparent;
  color: #a8c7fa;
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

.talk-ended-again:focus-visible,
.talk-ended-home:focus-visible {
  outline: 3px solid #7fb0ff;
  outline-offset: 2px;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-7 (D7, F7): EIGHTEEN PIXELS IS THE FLOOR, AND THE FLOOR HAS NO EXCEPTIONS.

   The owner's standing rule for this product is 56 px targets and 18 px text (PLAN-155 to 157, and
   the elderly-first sentence they all come from). M7 measured eight shipped sizes under it: the field
   label at 16, the link box at 17, the switch label at 17, the call line at 17, the sheet buttons at
   17, the direct chip at 17, and the brand and the signed-in line at 15. PLAN-163 T-1's Sound check
   added two more after the audit was taken, at 15 and 16, and the camera sheet's private line is 16.

   THE OWNER'S FLOOR IS THE FLOOR. D7's own sentence. A size that is small because it is "only" a
   brand line or "only" a badge is exactly the reading an elderly person is asked to do without their
   glasses, and none of these are decorative: every one of them is a word somebody has to read.

   THE TWO SHEET BUTTON SIZES AND .call-line ARE ALREADY AT 18 AND 20 (T-2 and T-4); what is here is
   the rest, in one block at the end of the file so the three plans editing this file today do not
   meet in the middle. */
.brand { font-size: 18px; }
.who { font-size: 18px; }
.field label { font-size: 18px; }
.linkbox { font-size: 18px; }
.switch { font-size: 18px; }
.err { font-size: 18px; }
.note { font-size: 18px; }
.direct-chip { font-size: 18px; }
.talk-hold-hint { font-size: 18px; }

/* PLAN-163 T-1's Sound check: three sentences a person reads when something has already gone wrong,
   which is the last place on this page to save three pixels. */
.talk-sound-title { font-size: 18px; }
.talk-sound-line { font-size: 18px; }

/* The camera sheet's own lines. The private line says what happens to the picture, which is the one
   sentence on that sheet a person is most likely to want to read twice. */
.video-line-private { font-size: 18px; }

/* The unread count on the Messages button. It is a NUMBER a person reads to decide whether to open
   the panel, so it takes the floor and the badge grows to fit it rather than the number shrinking to
   fit the badge. */
.talk-bar .talk-chat-badge {
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border-radius: 13px;
  font-size: 18px;
  line-height: 26px;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-8 (D8, F8): THE CHIP IS ONE LINE, AT EVERY WIDTH.

   M8 measured it 405 x 45 on one line at 1100 and 273 x 107 on THREE lines at 390: `flex-wrap: wrap`
   let the two names break and then pushed the timer onto a line of its own, so a third of the top of
   the picture was chip. The chip is the quiet line that says who you are talking to and how long it
   has been; it is not a banner.

   THE TIMER STAYS ON THE NAMES' LINE because it is the shorter of the two and it never grows: it is
   the names that give up width, to an ellipsis, and the first-names rule in app.js is what keeps that
   ellipsis from eating a whole person under 420 px.

   PLAN-160 T-14 rebuilds what this chip SAYS (the time, the code, the info). The one-line rule is
   this plan's and that row keeps it, which is what D8's last sentence states.

   PLAN-179 T-1 (D1, F1) RE-PIN: the one-line rule survives the move into the header and is now
   written ONCE, in the .stage-chip rule above, where the group itself is described. The 70 per cent
   cap went with the overlay it belonged to - a group inside a 16 px-padded header is bounded by the
   header, and the design caps the CODE at 40vw rather than the group at 70 per cent. */

.stage-chip .names {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stage-chip .stage-timer {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-10 (D11, F11): THE WAITING SCREEN SHOWS LIFE, AND CARRIES A WAY OUT.

   The live line is the page's own .sub, so it is already 18 px and already the muted ink; what it
   gains here is the space that separates a line which CHANGES from the two that do not. The Leave
   pill is .btn - the outlined 56 px pill every other secondary control on this page is - so nothing
   new is invented for it. */
.waiting-still {
  margin: 20px 0 0;
  font-weight: 600;
}

.waiting-still[hidden] { display: none; }

#s-waiting .actions { margin: 24px 0 0; }

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-11 (D12, F12): THE LINK BREAKS AT ITS OWN JOINT.

   `overflow-wrap: anywhere` is what cut "meet.lhtranslator.com" in half at 390 (M12 read the box as
   "https://meet.lhtranslator.co / m/j/FXGZMDY"). `break-word` breaks at an arbitrary point ONLY when
   there is no acceptable break opportunity in the line, and app.js now puts one there - a <wbr>
   before the /j/ segment, which adds no character to the text - so the browser takes the joint
   rather than the middle of the domain wherever the joint is enough.

   PLAN-169 T-11b: AND THE SECOND JOINT, AFTER THE SCHEME. At 390 px this box is 270 px of content
   and "https://meet.lhtranslator.com" at the 18 px floor in this monospace stack is about 287 px,
   so with ONE opportunity the first line was still "https://meet.lhtranslator.c" and the domain was
   cut in half on the real domain - the exact thing D12 exists to stop. A break opportunity cannot
   make a segment fit that does not fit, only choose where an over-long line breaks, so app.js now
   puts a second <wbr> after "://" and the three parts are "https://", "meet.lhtranslator.com" and
   "/j/CODE". The domain is whole on its own line, measured in harness row U-11 with the real
   staging URL through this stylesheet. */
.linkbox {
  overflow-wrap: break-word;
  word-break: normal;
}

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-12 (D13, F13): THE PERSON AT THE DOOR, ON THE SCREEN THAT ASKS ABOUT THEM.

   It is .stage-initial, the circle the stage already draws when somebody's camera is off, so the two
   screens that have to say "this is a person" say it the same way. What it takes here is the card's
   own centring and the air between it and the heading; its size, its colour and its letter are the
   stage rule's and are not repeated. */
.admit-initial {
  margin: 0 auto 20px;
}

.admit-initial[hidden] { display: none; }

/* ------------------------------------------------------------------------------------------------
   PLAN-169 T-14 (D6, F6): AND THE SCREEN STOPS SAYING "You are connected" WHEN IT IS NOT TRUE.

   #s-connected carries a clipped h1 for a screen reader - "You are connected" - because the section
   has no visible heading of its own (index.html:146). Until T-6 that h1 left the screen the instant
   the call ended, because the whole SECTION was hidden and the page went home. Now the section
   stays, holding the ended screen, so a person using a screen reader would have been read "You are
   connected" and then "The call has ended" on the same screen.

   MEASURED by the full matrix at the tip: T-16 went red with "a browser is still showing 'You are
   connected' after the call ended", reading exactly that clipped heading - clipped text is rendered
   text, which is the property the harness relies on everywhere and the reason the words are clipped
   rather than removed.

   display:none is the right tool here and the one place in this file it is: the sentence is no
   longer TRUE, so it should leave the accessibility tree and not merely the picture. The ended
   screen's own 28 px title is the heading from that moment on. */
#s-connected[data-ended='true'] > h1,
#s-connected[data-ended='true'] > h2.visually-hidden { display: none; }
/* The merge seam of 2026-09-12: PLAN-148 made this heading an h2 (one h1 per page for the audit) while
   PLAN-169 wrote the rule above against the h1 it found; both selectors, so the sentence leaves the tree
   whichever element carries it. Found by T-16 against staging at 139ca898. */

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-1 (D1, D2) - THE FIVE MORE ROWS AND THE SOUND AND CAMERA SHEET.

   The rows are `.talk-sheet button`, so every size, colour and radius they have is PLAN-169 T-2's
   pinned dark panel and PLAN-159 T-2's 18 px floor. Nothing is restated here that the sheet already
   says: what IS said here is the one thing the sheet cannot know, which is that two of the five rows
   belong to a screen with a keyboard.

   FULL SCREEN AND PICTURE IN PICTURE ARE A DESKTOP'S (F1). Under 900 px they are not drawn at all:
   a phone browser's own chrome owns the full screen and a phone has no second window to float a
   picture into. The page hides them a SECOND way when the browser has no such API (wire.js
   hideUnsupportedRows), because a wide screen is not the same question as a capable one. */
.talk-sheet-fullscreen,
.talk-sheet-pip { display: none; }

@media (min-width: 900px) {
  .talk-sheet-fullscreen,
  .talk-sheet-pip { display: block; }
  .talk-sheet-fullscreen[hidden],
  .talk-sheet-pip[hidden] { display: none; }
}

/* The Sound and camera sheet carries `.talk-sheet`, so it IS the same panel; these are the three
   things a panel of selects needs that a panel of buttons does not. */
.device-row { margin: 16px 0 0; }

.device-label {
  display: block;
  margin: 0 0 6px;
  font-size: 16px;
  color: var(--panel-muted, #5f6368);
}

.device-select {
  display: block;
  width: 100%;
  min-height: 56px;
  padding: 12px 16px;
  border: 1px solid var(--panel-line, #444746);
  border-radius: 14px;
  background: var(--panel-bg, #202124);
  color: var(--panel-ink, #e3e3e3);
  font: inherit;
  font-size: 18px;
}

.device-select:focus-visible {
  outline: 3px solid var(--panel-link, #a8c7fa);
  outline-offset: 2px;
}

/* A device that was chosen and is no longer there, and a browser that cannot choose a speaker at all.
   Both are sentences a person acts on, so they are drawn at the same size as the Sound check's lines
   and never as a warning colour alone. */
.device-missing,
.device-note {
  margin: 6px 0 0;
  font-size: 16px;
  line-height: 1.35;
  color: var(--panel-muted, #5f6368);
}

/* PLAN-160 T-3 (D3, F4): THE LEVEL BAR. A person who cannot hear the other side asks "is my
   microphone picking anything up", and this answers it without a word: it moves while they speak.
   It is a bar and not a number, and it sits directly under the microphone select it is about. */
.device-meter {
  height: 10px;
  margin: 8px 0 0;
  overflow: hidden;
  border-radius: 999px;
  background: var(--panel-line, #444746);
}

.device-meter-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--panel-link, #a8c7fa);
  transition: width 100ms linear;
}

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

/* Test is a button among selects, so it takes the sheet's own button shape and says what it does. */
.device-test { margin-top: 10px; }

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-4 (D4, F5): TEXT SIZE, AS ONE NUMBER THE WHOLE CONVERSATION READS.

   Meet offers a caption font, a colour and a background (the owner's S13 capture). This offers ONE
   thing, the SIZE, and the reason is the elderly-first rule of PLAN-157 section 6: one high-contrast
   style is fixed and a colour picker is a screen an elderly person has to get past. Size is the one
   of the four that a person with failing eyes actually needs.

   THE THREE PLACES THE SAME SENTENCE CAN APPEAR ARE THE THREE THAT MOVE: the captions over the
   picture, the ONE line a phone draws under it, and the conversation panel's own bubbles. The
   attribute is on the ROOT element, because the panel is not inside the stage and a rule hung on the
   stage would grow the captions and leave the panel where it was.

   THE DEFAULT IS THE NUMBER EACH OF THEM ALREADY HAD, so a page where nobody has chosen anything
   renders exactly as it rendered before: 22 px over the picture and on the phone's line, and the
   panel's bubbles three pixels under that, which is the relationship PLAN-159 T-5 drew them in. */
:root { --caption-size: 22px; }
:root[data-text-size='large'] { --caption-size: 28px; }
:root[data-text-size='largest'] { --caption-size: 34px; }

.stage-captions { font-size: var(--caption-size, 22px); }
.stage-lower .stage-captions { font-size: var(--caption-size, 22px); }
.conv-line { font-size: var(--caption-size, 22px); }
.chat-body { font-size: calc(var(--caption-size, 22px) - 3px); }

/* ------------------------------------------------------------------------------------------------
   PLAN-179 T-4 (D3, F3): THE "YOUR MEETING IS READY" CARD, AS THE DESIGN DRAWS IT.

   PLAN-160 T-6b made this card WHITE, on the owner's Meet capture. The design of record draws the
   same card in the stage's own colours - the panel surface, the panel shadow, radius 20 - anchored
   16 px off the left and the bottom of the picture at 400 px wide, with its children in a 12 px
   column. Every value below was read out of Prototype.dc.html.

   THE CARD FOLDS RATHER THAN CLOSING. Its head keeps the title and one 56 px chevron; open, the
   card is padded 20 all round and shows everything; folded, it is padded 8px 12px 8px 20px and is
   its own title row. Between 720 and 900 (the design's isNarrow) it takes both edges instead of a
   fixed width, and under 720 it is a static block in the phone's own column, which is the design's
   "the card as a static block" for Screen 3.
   ------------------------------------------------------------------------------------------------ */
.meet-card {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 8;
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 400px;
  max-width: calc(100% - 32px);
  max-height: calc(100% - 32px);
  overflow-y: auto;
  padding: 20px;
  border-radius: var(--r-panel);
  background: var(--stage-surface);
  color: var(--stage-ink-panel);
  box-shadow: var(--shadow-panel);
  box-sizing: border-box;
}

.meet-card[hidden] { display: none; }

/* Folded: the design's tighter padding, and the head is all there is. */
.meet-card[data-open='false'] { padding: 8px 12px 8px 20px; }

.meet-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.meet-card-title {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  color: var(--stage-ink);
}

/* The chevron that folds it. It points UP when the card is folded and is turned over when it is
   open, in the design's own 200 ms. */
.meet-card-fold {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-panel);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.meet-card-fold:hover { background: var(--stage-secondary-hover); }

.meet-card-fold:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

.meet-card-fold svg {
  width: 26px;
  height: 26px;
  /* --t-chevron carries its own property (`transform 200ms ease`), so it is used whole. */
  transition: var(--t-chevron);
}

.meet-card[data-open='true'] .meet-card-fold svg { transform: rotate(180deg); }

.meet-card-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.meet-card-body[hidden] { display: none; }

.meet-card-share {
  margin: 0;
  font-size: 18px;
  line-height: 1.45;
  color: var(--stage-ink-muted);
  text-wrap: pretty;
}

/* The link box: the design's field ground behind a hairline, with the link in a mono 18 and a
   56 px copy icon inside the box beside it. */
.meet-card-linkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 6px 6px 6px 14px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-link-box);
  background: var(--stage-field);
}

.meet-card-linkbox .linkbox {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--stage-ink);
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 18px;
  line-height: 1.4;
  /* PLAN-179 T-16b: break-word, NOT anywhere. This rule is two classes and beat `.linkbox`'s own
     one, so rebuilding the card for the design put back the exact defect PLAN-169 D12 fixed: with
     `anywhere` a browser breaks the URL wherever it likes and the two <wbr> joints the page puts at
     the meaningful places (after the host, before the code) stop deciding anything. U-11 measured it
     at the tip, in the words of its own M12. */
  overflow-wrap: break-word;
}

.meet-card-copy-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: var(--r-menu-row);
  background: transparent;
  color: var(--stage-accent);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.meet-card-copy-icon:hover { background: var(--stage-round); }
.meet-card-copy-icon svg { width: 24px; height: 24px; }

.meet-card-copy-icon:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* "Copy link" is the filled pill and "Show QR code to connect" the outlined one, both 56 tall. */
/*
  PLAN-179 T-13b (the gallery review): 56 PX MEANS 56 PX HERE TOO. The reviewer measured "Copy link"
  at 57 and 58 - the same defect PLAN-178's own review found on the card screens' pills (its G-3),
  and the same cause: .btn's 14 px of vertical padding over an 18 px label is taller than the
  minimum, so min-height never decides. The prototype's pills carry no vertical padding.
*/
.meet-card #copy-link,
.meet-card-qr-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 56px;
  margin: 0;
  padding: 0 20px;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.meet-card #copy-link {
  border: 0;
  background: var(--stage-primary);
  color: #fff;
  font-size: 19px;
  font-weight: 600;
}

.meet-card #copy-link:hover { background: var(--stage-primary-hover); }

.meet-card-qr-toggle {
  border: 1px solid var(--stage-hairline);
  background: transparent;
  color: var(--stage-accent);
  font-size: 18px;
  font-weight: 600;
}

.meet-card-qr-toggle:hover { background: var(--stage-secondary-hover); }

.meet-card #copy-link:focus-visible,
.meet-card-qr-toggle:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* The QR block: white, because a square code has to be read by a camera, with the design's own
   caption under it in the card-page ink. */
.meet-card-qr-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 12px;
  border-radius: var(--r-menu-row);
  background: #fff;
  color: #12161c;
}

.meet-card-qr-block[hidden] { display: none; }

.meet-card-qr {
  width: 168px;
  height: 168px;
  max-width: 168px;
  margin: 0;
  padding: 0;
  background: #fff;
}

.meet-card-qr svg { width: 100%; height: 100%; display: block; }

/* PLAN-218 T-7 (D6, F6): 18px. The design record and the prototype raise this caption to 18 and the
   product stayed at 16 with nothing written down (deploy-2 review, web-design reviewer, Important
   85). It is the line under the QR that tells a person what the square is for, on the screen they
   are holding out to somebody else. */
.meet-card-qr-caption {
  margin: 0;
  font-size: 18px;
  text-align: center;
}

/* The switch row: the label and the design's 52 x 32 switch, on a 56 px row. */
/*
  PLAN-179 T-13b (the gallery review): "the ask-me switch row sits in a 1 px #2b3340 box the
  prototype does not draw (a card token on a stage)". The border, the radius and the padding are
  .switch's own from the card screens it used to live on; the design draws a LABEL and a switch on
  one 56 px row and nothing around them.
*/
.meet-card .switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 56px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--stage-ink-panel);
  font-size: 18px;
  cursor: pointer;
}

/* AND #link-back IS NOT DRAWN. The design's way off this screen is the bar's red Cancel, which is
   PLAN-179 T-6's row; the element stays in the tree so nothing that writes to it breaks, and the
   harness row that pressed it is re-pinned onto Cancel there. */
.meet-card #link-back { display: none; }

@media (min-width: 720px) and (max-width: 899px) {
  /* The design's isNarrow: the card takes both edges rather than a fixed width. */
  .meet-card {
    left: 16px;
    right: 16px;
    width: auto;
  }
}

@media (max-width: 719px) {
  /* The phone: no picture, so the card is not floating over one. It is a static block in the
     column, at the card radius, which is README Screen 3's "Phone" line. */
  .meet-card {
    position: static;
    width: auto;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: var(--r-card);
  }
}


/* PLAN-160 T-9b (D8): THE ONE LINE THAT CAME FROM NO PERSON. The server's fifty-five-minute warning
   is neither person's words, so it is drawn as neither: centred, full width, on the panel's own
   muted ground and with no bubble tail either way. The name above it is the one the server put on
   the line ("LH Translator") and never a person's display name. */
.chat-line.chat-system {
  align-self: center;
  align-items: center;
  max-width: 100%;
  text-align: center;
}

.chat-system .chat-body {
  border-radius: 12px;
  background: var(--panel-line, #444746);
  color: var(--panel-ink, #e3e3e3);
  font-style: normal;
}

.chat-system .chat-meta { justify-content: center; }

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-14 (D11, F12): THE HEADER, IN MEET'S OWN ORDER.

   The owner, 2026-09-12 06:43 UTC: "At the top URL name and time. make same design ." His capture
   reads 07:42, a thin divider, the meeting code, an info icon. So the chip carries the CLOCK and the
   MEETING'S NAME - the two things a person glances up for - and the background becomes the design
   inputs' own rgba(32,33,36,0.70), which is the value PLAN-159's inputs measured off Meet and the
   one thing about the chip that was never applied.

   ONE LINE STILL (PLAN-169 T-8's rule): four short things, none of which wraps, and the code is
   allowed to be clipped rather than to push the info button onto a second row.

   PLAN-179 T-1 (D1, F1) RE-PIN: the ground went with the overlay. The design draws these four
   things in the header, on the stage page itself, so a translucent chip ground over the picture is
   no longer a thing that exists; the one-line rule is in the .stage-chip rule near the top of this
   file. What the four things LOOK like is below (.stage-clock, .stage-div, .stage-code) at the
   design's own sizes. */

/* PLAN-175 T-1 (D1) took the header's own ground for this sentence, so the chip and the line read as
   one block. PLAN-180 T-G BLOCKER 2 moved the sentence to the BOTTOM, away from the chip, so the
   reason for sharing the header's ground is gone with it: the pill keeps the darker ground set
   where it is now drawn, which is the ground the design gives a system pill over a picture. */

/* PLAN-179 T-1 (D1, F1): the three things, at the design's own sizes. The time and the code are both
   20px/600 - they are the two things a person glances up for and the design gives them the same
   weight - the time is tabular so its digits do not dance from one second to the next, and the rule
   between them is 1 x 24 of the hairline. The code is the ONLY one that may be clipped, at 40vw,
   which is what keeps the group on one line at every width the design draws. */
.stage-clock {
  flex: 0 0 auto;
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.stage-div {
  flex: 0 0 auto;
  width: 1px;
  height: 24px;
  background: var(--stage-hairline);
}

.stage-code {
  min-width: 0;
  max-width: 40vw;
  overflow: hidden;
  color: var(--stage-ink);
  font-size: 20px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* PLAN-179 T-1 (D1, F1): THE COPY BUTTON, AND THE ONE THING IT SAYS WITHOUT WORDS.

   The design's Screen 3 puts a 44 px copy button straight after the meeting code - the one control
   in this header - and gives it the one piece of feedback a button with no label can give: its icon
   turns the success green while the word "Copied" is its name. It is the header's law-5 exception
   at 44 rather than 56, exactly as the avatar is, and the negative left margin is the design's, so
   the icon sits against the code rather than a gap away from it. */
.stage-copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  margin-left: -8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-accent);
  cursor: pointer;
  transition: background-color var(--t-hover), color var(--t-hover);
}

/* PLAN-179 T-16b: AND WHEN THE PAGE HIDES IT, IT IS HIDDEN. Both buttons are `display` values that
   beat the hidden attribute, so paintStageHeader's `copy.hidden = !link` / `info.hidden = link` drew
   nothing at all: D-07 measured the copy button standing beside the info button in the middle of a
   call, where there is no longer a link to send. The same trap this build hit three times in the
   bar. */
.stage-copy[hidden],
.stage-info[hidden] { display: none; }

.stage-copy svg { width: 22px; height: 22px; }
.stage-copy:hover { background: #2a2b2e; }
.stage-copy[data-copied='true'] { color: var(--stage-success); }

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

/* The phone rule that hides this whole group is at the END of this file, in PLAN-179 T-1's own
   block: .lh-stage-header-left is declared by the stage shell further down (PLAN-178 T-3), and a
   rule of the same weight only wins where it is written after it. */

.stage-info {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid #5f6368;
  border-radius: 999px;
  background: transparent;
  color: #c4c7c5;
  font: inherit;
  font-size: 15px;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
}

.stage-info:hover { border-color: #c4c7c5; color: #f2f5f9; }
.stage-info:focus-visible { outline: 3px solid #a8c7fa; outline-offset: 2px; }

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-11: CLOSE STAYS ON THE SCREEN, WHATEVER THE SHEET HOLDS.

   MEASURED by harness S-05 at 390 x 844, alone, twice: "something is drawn over the sheet's Close
   (null)". Null is the tell - document.elementFromPoint answered NOTHING, because the point was off
   the bottom of the window. The sheet is capped at 44vh and scrolls (.stage-lower .talk-sheet), and
   D1 put five more 56 px rows into it, so Close - the LAST child, by this file's own rule - was
   pushed below the fold. A person could still scroll to it; a person who did not know to scroll
   could not close the sheet, which is the owner's finding 6 ("More buttons do not work") again.

   So Close is STICKY at the bottom of the scroll: the rows scroll under it, it is always the last
   thing and always on the screen. It carries the panel's own ground so nothing shows through, and
   the same rule covers the Sound and camera sheet, whose Close is the same class. */
.stage-lower .talk-sheet .talk-sheet-close {
  position: sticky;
  bottom: 0;
  z-index: 1;
  margin-bottom: 0;
  background: var(--panel-bg, #202124);
}

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-11: THE 18 PX FLOOR, WHICH THIS PLAN BROKE IN FOUR PLACES.

   MEASURED by harness U-07 (PLAN-169 D7/F7): "20 element(s) still render text under 18 px; the list
   of exceptions must be empty" - the info button's "i" at 15, the card's share line at 16, the link
   inside the card at 16, and the shield, "Joined as" and the waiting line at 15. The floor is the
   owner's own (PLAN-157 section 6, elderly-first) and it has no exceptions, so these are raised
   rather than argued about. The info button grows with its letter, because a 28 px circle round an
   18 px character is a target with no room in it.

   It is a LATER block on purpose: same specificity, later in the file, so these win over the sizes
   the T-6b and T-14 blocks above set. */
/* The letter is 18 px because the floor has no exceptions; the CIRCLE stays 28 px, because
   PLAN-169 D8/F8 caps the whole chip at 45 px on one line and 32 + the chip's own 16 px of padding
   is 48. Measured both ways by U-07 and U-08: 18 px text inside a 28 px circle satisfies both. */
.stage-info { width: 28px; height: 28px; font-size: 18px; line-height: 1; }
/* PLAN-179 T-4 (D3, F3): the card's own sizes are the design's now and they are already at or over
   the floor (the sentence 18, the link 18, the QR caption 16 on white inside the block, which is the
   design's own number for a caption under a picture). The permission line and "Joined as" are gone
   with the card the design redrew, so the two rules that sized them are gone with them. */
.device-label { font-size: 18px; }
.device-missing,
.device-note { font-size: 18px; }

/* And the switch that came onto the card with it: .switch's own span is 16 px on the link screen it
   used to live on, which nobody reads any more. On the card it is one of the six lines a person
   reads, so it takes the floor too. */
.meet-card .switch,
.meet-card .switch span { font-size: 18px; }

/* ------------------------------------------------------------------------------------------------
   PLAN-160 T-11: THE LINK BREAKS AFTER THE SCHEME, WHICH IS PLAN-169 D12'S RULE AND NOT THIS PLAN'S.

   MEASURED by harness U-11, alone: in the card the grey box is 322 px wide at 390, and at that width
   "https://meet.lhtranslator.com" FITS on one line - so the browser used the later of the two break
   opportunities app.js puts in, the domain never started a line of its own, and D12's second
   assertion ("a drawn line carries the scheme AND part of the domain") went red. On the link screen
   the box was narrower and the break after the scheme always won.

   The cap is in `ch` and not in pixels on purpose: it is a statement about CHARACTERS - a box wide
   enough for the domain and not for the scheme in front of it - so it holds at any font size and for
   any domain shorter than the cap, which is what the rule is actually about. */
.meet-card-linkbox .linkbox { max-width: 22ch; }

/* =================================================================================================
   PLAN-178 T-2 (D3, F2): THE CARD SHELL.

   Every value here was read out of public/web/design/Prototype.dc.html, which IS the design (the
   owner's rule 1). The prototype writes them as inline styles on the frame's own elements; this is
   the same numbers as rules, reading the tokens T-1 put in :root.

   THE THREE PARTS, in the design's own order:
     .lh-card-shell   the page: the gradient, full height, a column
     .lh-card-glow    the two radial glows over it, inert, under everything else
     .lh-card-header  60 px, the brand at the left, the 44 px avatar at the right
     .lh-card-column  centres the card on a laptop, top-aligns it on a phone
     .lh-card         at most 560 wide, padding 40 at 1100 and 24 20 at 390

   THE BREAKPOINT IS THE DESIGN'S: phone is under 720 px (README "Breakpoints"), measured on the
   frame. Everything outside a query is the laptop value, which is what the prototype does too.
   ================================================================================================= */

.lh-card-shell {
  position: relative;
  display: flex;
  flex-direction: column;
  /* PLAN-207c T-6 (D7, F6): AND THE PHONE'S OWN HEIGHT BESIDE IT. `100vh` on a phone is the viewport
     with the browser's own chrome pretended away, so the bottom of a full-height page sits UNDER the
     address bar and the card's last control can be unreachable. `100dvh` is the one that moves with
     the chrome. It goes BESIDE rather than instead of, so a browser that does not know `dvh` keeps
     exactly the layout it has today; this file already uses `100dvh` for the phone sheet. */
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--card-page);
  color: var(--card-ink);
}

/* PLAN-204 T-8 (M8, F8): THE COMPANION ITS TWIN ALREADY HAS. `.lh-stage-shell[hidden]` is written
   at :3410; this one was not, so the moment a meeting opened and the page set `cardShell.hidden =
   true` the rule above kept drawing it. MEASURED before this rule, with a meeting open: hidden=true
   and `display: flex` in a 1100 x 900 box with the card's own page ground, underneath the call. */
.lh-card-shell[hidden] { display: none; }

/* The glow layer: two radial gradients over the page gradient and under the content. It is inert, so
   a press anywhere on the page still reaches what is under it. */
.lh-card-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--card-glow);
}

.lh-card-header {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 12px;
  min-height: 60px;
  padding: 8px 16px;
}

.lh-brand {
  font-size: 20px;
  font-weight: 600;
}

.lh-card-header-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 2px;
}

/*
  THE AVATAR IS 44 px AND THE DESIGN SAYS SO. The page's own law is a 56 px target and this is the one
  control the handoff sets at 44 ("every pressable target is at least 56 px tall (44 px only where
  this document says 44)", the README's law 5; Screen 1 says "avatar button right: 44x44 circle").
  It is a circle of the primary blue with one white capital, and its title is the only place the
  signed-in e-mail is said at all.
*/
.lh-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--stage-avatar);
  color: var(--stage-avatar-ink);
  font-size: 20px;
  font-weight: 600;
  cursor: pointer;
  transition: filter var(--t-hover);
}

/* PLAN-204 T-8 (M8, F8): AND WHEN THE PAGE HIDES IT, IT IS HIDDEN - the same companion this file
   already writes for .stage-copy, .stage-info and .lh-stage-shell, and for the same reason. Both
   avatars ship `hidden` in index.html (:133 and :441) and app.js's paintAvatar is the only thing
   that ever un-hides one; boot() does not call it when nobody is signed in. MEASURED before this
   rule, on a signed-out visit to the home page: `#account-avatar` carried hidden=true and computed
   `display: flex` in a 44 x 44 box - an empty blue circle offering an Account dialog about an
   account that does not exist. */
.lh-avatar[hidden] { display: none; }

.lh-avatar:hover { filter: brightness(1.15); }

.lh-avatar:focus-visible {
  outline: 3px solid var(--card-primary);
  outline-offset: 2px;
}

.lh-card-column {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 8px 16px 32px;
}

.lh-card {
  position: relative;
  width: 100%;
  max-width: 560px;
  padding: 40px 40px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
  background: var(--card-surface);
  text-align: center;
  box-shadow: var(--shadow-card);
}

/* The phone, which the design measures on the frame at under 720 px. */
@media (max-width: 719px) {
  .lh-card-column { justify-content: flex-start; }
  .lh-card { padding: 24px 20px; }
}

/*
  THE SIGNED-IN LINE IS NOT DRAWN ANY MORE, and this is where it stops. "No visible e-mail in headers
  (avatar only)" is the README's must-not list, and the line under the card said the whole address out
  loud on every screen. The ELEMENT stays and app.js still writes it, because a screen reader user is
  entitled to hear whose account this is and because nothing else on the page carries that sentence;
  it is moved out of sight the same way the connected title and the call timer already are.
*/
.who {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* =================================================================================================
   PLAN-178 T-3 (D3, F2): THE STAGE SHELL.

   The design's second shell, read out of public/web/design/Prototype.dc.html. The page is pinned
   dark and never themed (the product's own law and the README's, in the same words). The header is
   64 px on a laptop and 56 px under 720, with 6 px 16 px of padding, space-between, and it wraps;
   its two groups are empty until PLAN-179 and PLAN-180 fill them. The stage area is the frame the
   picture sits in: 12 px off each side, radius 20, black behind it, and it clips whatever is drawn
   inside.
   ================================================================================================= */

.lh-stage-shell {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  background: var(--stage-page);
  color: var(--stage-ink);
  text-align: left;
}

.lh-stage-shell[hidden] { display: none; }

.lh-stage-header {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  min-height: 64px;
  padding: 6px 16px;
}

/* The two groups. They hold nothing yet, so they take no width and draw no line; what is pinned here
   is where they sit and how their contents will line up when PLAN-179 writes into them. */
.lh-stage-header-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.lh-stage-header-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex: 0 1 auto;
}

.lh-stage-area {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin: 0 12px;
  border-radius: var(--r-panel);
  overflow: hidden;
  background: #000;
}

@media (max-width: 719px) {
  .lh-stage-header { min-height: 56px; }
  /*
    PLAN-180 T-G BLOCKER 1: THE PICTURE KEEPS ITS FRAME ON A PHONE, because the prototype gives it one.

    This rule used to zero the margin and the radius here, citing the README's Screen 3 "Phone". The
    README and the prototype DISAGREE, and this plan's rule is the prototype's own numbers: its stage
    row is written once, for the link screen AND the call screen together, and it is not inside any
    width condition -

      <div style="...flex-direction:{{ stageRowDir }};...;gap:12px;margin:0 12px">
        <div style="...;border-radius:20px;overflow:hidden;background:{{ stageBg }};...">

    Only the DIRECTION and the minimum height are driven by the width; `margin:0 12px` and
    `border-radius:20px` are literal and stand at 390 exactly as they do at 1100. The gallery review
    of 2026-09-13 saw the difference with its own eyes: "The prototype puts the video in a card with
    a black margin all round and softly rounded corners. The build runs it edge to edge, corner to
    corner, square, no margin." So the override goes, and the phone gets the frame the drawing has.

    `--r-panel` is 20px, which is the prototype's own number, so the base rule above already says
    what the design says and nothing has to be written here twice.
  */
  .lh-stage-header-right {
    flex: 1 1 auto;
    justify-content: center;
  }
}

/* =================================================================================================
   PLAN-178 T-4 (D4, F3): HOME, THE DESIGN'S OWN.

   Screen 1 of public/web/design/README.md, with every number read out of Prototype.dc.html: the
   heading at 34px/700 and 1.25 (28 px on a phone), one 18 px muted sentence under it at margin
   0 0 24px, a full-width 56 px pill at 19px/600, and one more 18 px muted sentence at margin 24px 0 0.

   THE CARD'S TYPE IS SET HERE FOR EVERY CARD SCREEN, because the design gives all four the same
   heading and the same muted paragraph; T-5, T-6 and T-7 add only what is theirs alone.

   WHAT IS NO LONGER DRAWN ON HOME, and why it is hidden rather than deleted: "No new screens
   (incoming-call ring, contact list, dialling ...)" is the README's must-not list, and the design's
   Home is four lines with nothing under them. ring/contacts.js and ring/dial.js KEEP their sockets,
   their data and every line of their own logic - they are told about partners and about a call being
   placed exactly as before - and what changes is that nothing they write reaches an eye. Deleting the
   modules is a plan of its own once the design has settled (PLAN-178 KNOWN LIMITS).
   ================================================================================================= */

.lh-card h1,
.lh-card .screen-title {
  margin: 0 0 12px;
  font-size: 34px;
  line-height: 1.25;
  font-weight: 700;
  text-wrap: pretty;
}

.lh-card .sub {
  margin: 0 0 24px;
  font-size: 18px;
  color: var(--card-muted);
  text-wrap: pretty;
}

/* The design's last line on Home: it sits UNDER the pill, so its margin is above it. */
.lh-card .lh-home-after {
  margin: 24px 0 0;
}

.lh-card .actions {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/*
  PLAN-179 T-4 (PLAN-178 gallery review, finding 3): 56 PX MEANS 56 PX.

  The gallery measured Home's and Message's pills at 57 and 58 where the contract says 56, and the
  arithmetic was this padding: 14 px top and bottom over an 18 px label at the body's 1.55 leading is
  57.9, so min-height never got a chance to decide. The prototype's own card pills carry NO vertical
  padding at all - min-height:56px, the border, the radius and the colours, and nothing else - so the
  height IS the minimum, at every label length and in every language. The horizontal padding stays: a
  pill needs air beside its word even when it is full width.
*/
.lh-card .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 56px;
  padding: 0 20px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--card-primary);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--t-hover), filter var(--t-hover), border-color var(--t-hover);
}

/* PLAN-180 U11-C: AND A PILL THE PAGE HIDES REALLY GOES.

   `.lh-card .btn` above sets `display: inline-flex` at specificity 0-2-0, which beats the user
   agent's `[hidden] { display: none }` at 0-1-0. So `el.hidden = true` on one of these pills set the
   attribute and changed NOTHING a person could see - measured, not reasoned: with the attribute set,
   the element reported `display: flex`, one client rect, and the page's own innerText still carried
   "Start a new meeting" on a screen about a meeting that had just been cancelled.

   It is the same shape as the two `[hidden]` rules on `.lh-panel-dim` and `.lh-more-panel` that this
   plan's arbitration found were load bearing for exactly this reason (finding 36, NOT CONFIRMED:
   both must stay). Where an author display rule reaches a hideable element, the `[hidden]` rule has
   to be written here too. */
.lh-card .btn[hidden] { display: none; }

.lh-card .btn:hover { background: var(--card-secondary-hover); }

.lh-card .btn.primary {
  border: 0;
  background: var(--card-primary);
  color: var(--card-primary-ink);
  font-size: 19px;
}

.lh-card .btn.primary:hover { background: var(--card-primary-hover); }

.lh-card .btn:focus-visible {
  outline: 3px solid var(--card-primary);
  outline-offset: 2px;
}

/* Home draws four things. The partner list, the dialling lines and the heading over them are not
   among them; see the block header for why they are hidden and not deleted. */
.ring-contacts-box,
.ring-dial-box,
.ring-contacts-title {
  display: none;
}

@media (max-width: 719px) {
  .lh-card h1,
  .lh-card .screen-title { font-size: 28px; }
}

/* =================================================================================================
   PLAN-178 T-5 (D4, F4): REGISTER, AND THE TOAST THE DESIGN DRAWS OVER A CARD.

   Screen 2 of public/web/design/README.md, every number read out of Prototype.dc.html: a field block
   left aligned with 18 px under it; a label 18px/600 with 6 px under it; the name input 56 px at
   12px 14px on #1b212a behind 1px #2b3340 at radius 8; a help line 18 px #a5aebd 6 px under it; two
   selects the same size on #12161c with the browser's arrow off and a 24 px #a5aebd chevron at
   right 16; and, when the two languages match, a 2 px #ff9b7d edge on the second one with the
   design's alert under it and Continue at opacity .6.
   ================================================================================================= */

.lh-card .field {
  margin: 0 0 18px;
  text-align: left;
}

.lh-card .field label {
  display: block;
  margin: 0 0 6px;
  font-size: 18px;
  font-weight: 600;
}

.lh-card .field input,
.lh-card .field select {
  width: 100%;
  min-height: 56px;
  padding: 12px 14px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-field);
  background: var(--card-field-name);
  color: var(--card-ink);
  font-size: 18px;
}

.lh-card .field input:focus-visible,
.lh-card .field select:focus-visible {
  outline: 3px solid var(--card-primary);
  outline-offset: 1px;
}

.lh-card .field-help {
  margin: 6px 0 0;
  font-size: 18px;
  color: var(--card-muted);
}

/*
  THE SELECT IS A REAL SELECT. appearance:none takes the browser's arrow and its ground away; the
  chevron over it is inert, so every press, every key and every screen reader still reaches the
  control itself. The right padding is 52 px so a long language name never runs under the chevron.
*/
.lh-select {
  position: relative;
  width: 100%;
}

.lh-card .lh-select select {
  padding: 12px 52px 12px 14px;
  background: var(--card-field);
}

.lh-chevron {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  color: var(--card-muted);
  pointer-events: none;
}

/*
  THE SAME LANGUAGE TWICE. The edge is 2 px and the alert stands under the field it is about, which
  is the design's rule and FIXES.md F5's in as many words. The refusal is never a colour alone:
  aria-invalid carries it, and the alert's own words say what to do about it.
*/
.lh-card .field select[aria-invalid='true'] {
  border: 2px solid var(--stage-warn);
}

.lh-card .field-alert {
  margin: 8px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--stage-warn);
  border-left-width: 6px;
  border-radius: 12px;
  background: var(--stage-warn-wash);
  color: var(--stage-warn);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.4;
}

.lh-card .btn[disabled] {
  opacity: 0.6;
  cursor: default;
}

/* BUGCHECK ROUND 1, codex (the stylesheet): A DISABLED BUTTON KEEPS ITS OWN GROUND ON HOVER.
   The rule used to paint --card-primary under every disabled pill, which on the OUTLINED variant put
   the primary blue behind primary-blue words and made the label disappear. Each variant now keeps
   the ground it already has, so a disabled pill looks like itself at .6 and nothing vanishes. */
.lh-card .btn[disabled]:hover { background: transparent; }
.lh-card .btn.primary[disabled]:hover { background: var(--card-primary); }

/* =================================================================================================
   PLAN-178 T-5 (D6, F8): THE TOAST, the shape the design draws for a passing sentence.

   README "Callouts (sticky notices) and toasts": role status, #1e1f20 behind 1px #333537 at radius
   16, padding 6 6 6 20, the text 20 px centred #e3e3e3, a 44 px X, and it goes after 3.5 s or on the
   X. It never carries an action. On a card screen it sits 24 px off the bottom, centred.

   T-13 adds the rest: the stage positions (104 on a laptop, 244 on a phone and 160 with the bar
   collapsed), the full-width-minus-24 phone rule, and wire.js's own notices moving onto this shape.
   ================================================================================================= */

/*
  PLAN-178 T-13 (D6, F8): WHERE THE TOAST SITS, WHICH IS FOUR PLACES AND NOT ONE.

  README "Callouts and toasts": "Position: stage screens bottom 104 (laptop) / 244 (phone, 160 when
  bar collapsed), centred; card screens bottom 24. Full width minus 24 on phone."

  The four are chosen by two attributes the page writes on the host: data-shell, which app.js sets
  from the screen that is showing, and data-bar, which wire.js sets when the phone bar is collapsed.
  Neither is a guess about where the bar is: one is the screen and the other is the bar's own state.
*/
.lh-toast-host {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 35;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: max-content;
  max-width: calc(100% - 32px);
  pointer-events: none;
}

.lh-toast-host:empty { display: none; }

.lh-toast {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 6px 6px 20px;
  border: 1px solid var(--stage-hairline-callout);
  border-radius: var(--r-toast);
  background: var(--stage-callout-surface);
  color: var(--stage-ink-panel);
  box-shadow: var(--shadow-callout);
  pointer-events: auto;
}

.lh-toast-text {
  flex: 1 1 auto;
  font-size: 20px;
  line-height: 1.4;
  text-align: center;
  text-wrap: pretty;
}

.lh-toast-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-panel);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-toast-close:hover { background: var(--stage-secondary-hover); }

.lh-toast-close:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

.lh-toast-close svg { width: 22px; height: 22px; }

/* =================================================================================================
   PLAN-178 T-6 (D4, F5): WAITING TO BE LET IN.

   Screen 4: two sentences at 18 px #a5aebd with 8 px and 20 px under them, a status line 18px/600
   with 24 px under it, and a full-width 56 px Leave pill that is OUTLINED until ninety seconds and
   FILLED after. The status line's colour is the page's ink until ninety seconds and #ff9b7d after,
   which is the prototype's own pair (README names only the second one; NOTES.md 1.2).
   ================================================================================================= */

.lh-card .waiting-first { margin: 0 0 8px; }
.lh-card .waiting-second { margin: 0 0 20px; }

.lh-card .waiting-still {
  margin: 0 0 24px;
  font-size: 18px;
  font-weight: 600;
  color: var(--card-ink);
  text-wrap: pretty;
}

/* Ninety seconds: the sentence changes, and so does its colour. */
.lh-card .waiting-still[data-state='late'] { color: var(--stage-warn); }

/* The Leave pill is the card's outlined secondary until ninety seconds, and the filled primary after,
   because after ninety seconds leaving is the thing the design expects a person to do. */
.lh-card .btn.waiting-filled {
  border: 0;
  background: var(--card-primary);
  color: var(--card-primary-ink);
}

.lh-card .btn.waiting-filled:hover { background: var(--card-primary-hover); }

/* =================================================================================================
   PLAN-178 T-7 (D4, F6): THE MESSAGE SCREEN.

   Screen 8: the title, the body with 28 px under it, a filled "Start a new meeting" and an outlined
   "Home" 12 px under that. The card's own type and pill rules do the rest; what is here is the two
   gaps the design gives this screen and nothing else.
   ================================================================================================= */

.lh-card .message-body { margin: 0 0 28px; }

/* The design's own gap between the two pills on this screen. .actions' 14 px gap is the card's
   general one; Screen 8 draws 12. */
.lh-card #s-message .actions { gap: 12px; }

/* =================================================================================================
   PLAN-178 T-8 (D5, F7): THE DIALOG.

   README "Dialogs", every number read out of Prototype.dc.html: the dim rgba(0,0,0,.5); the box
   centred, min(640px, 100% - 32px) wide, at most 100% - 32px tall and scrolling inside itself,
   padding 24, radius 24, #202124 with #e3e3e3 ink under the dialog shadow, its children in a 14 px
   column; the header row is the title at 24px/600 #f2f5f9 with a 56 px round X at the end of it.

   IT IS DARK EVEN OVER A CARD SCREEN, and that is the design: the dialog set is the STAGE's, and
   Your account opens over Home as readily as over a call.
   ================================================================================================= */

.lh-dialog-dim {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: var(--overlay-dim);
}

.lh-dialog-dim[hidden],
.lh-dialog[hidden] { display: none; }

.lh-dialog {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 31;
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(640px, calc(100% - 32px));
  max-height: calc(100% - 32px);
  overflow-y: auto;
  padding: 24px;
  border-radius: var(--r-dialog);
  background: var(--stage-surface);
  color: var(--stage-ink-panel);
  box-shadow: var(--shadow-dialog);
  text-align: left;
}

.lh-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.lh-dialog-title {
  margin: 0;
  font-size: 24px;
  font-weight: 600;
  color: var(--stage-ink);
}

.lh-dialog-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-panel);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-dialog-close:hover { background: var(--stage-secondary-hover); }

.lh-dialog-close:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

.lh-dialog-close svg { width: 26px; height: 26px; }

/* A dialog that cannot be dismissed has no X at all (the Permission one, T-11). */
.lh-dialog[data-closable='false'] .lh-dialog-close { display: none; }

.lh-dialog-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
}

/* The dialog set's own pills: the stage's colours, not the card's, because the dialog is the stage's
   surface wherever it is opened from. */
/*
  PLAN-179 T-4 (PLAN-178 gallery review, finding 2): THE LABEL IS CENTRED IN THE PILL.

  The gallery showed every dialog pill's word pressed against its left edge while the card screens'
  pills centred theirs. The reason is inheritance, not the button: the stage shell declares
  text-align: left (PLAN-178 T-3) and this sheet's reset leaves a button's alignment to inherit, so
  the pills inside a dialog took the shell's. The prototype's buttons are plain button elements and a
  button centres its own label, which is what these do now - said as a flex row rather than as a
  text-align, so an icon beside a word would be centred too.
*/
.lh-dialog .lh-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: 0 22px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--stage-primary);
  color: #fff;
  font-size: 19px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--t-hover), filter var(--t-hover), border-color var(--t-hover);
}

/* BUGCHECK ROUND 1, codex (the stylesheet): THE FILLED PILL KEEPS ITS BLUE ON HOVER. This rule hits
   EVERY pill in the dialog, so the design's primary action (Keep talking, Copy, Allow) lost its solid
   #1c62d6 for a translucent wash the moment a mouse crossed it - white words on the dim behind. It
   darkens instead, which is what --stage-primary-hover is for; the red and the outlined variants set
   their own ground in the two rules below and are unaffected. */
.lh-dialog .lh-pill:hover { background: var(--stage-primary-hover); }

.lh-dialog .lh-pill.lh-red { background: var(--stage-red); }
.lh-dialog .lh-pill.lh-red:hover { background: var(--stage-red-hover); }

.lh-dialog .lh-pill.lh-outlined {
  border: 1px solid var(--stage-hairline);
  background: transparent;
  color: var(--stage-ink-panel);
}

.lh-dialog .lh-pill.lh-outlined:hover { background: var(--stage-secondary-hover); }

.lh-dialog .lh-pill:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

.lh-dialog p {
  margin: 0;
  font-size: 19px;
  line-height: 1.45;
  color: var(--stage-ink-muted);
}

/* =================================================================================================
   PLAN-178 T-10 (D5, F7): THE TWO DIALOGS THAT SAY WHO AND WHAT.

   Your account: a 56 px circle with the initial, the name at 20px/600 and the address at 18 px
   #c4c7c5 beside it, then two outlined pills. About this call: one sentence and the link box the
   design draws, a 14 px box on #2b2c2f behind 1px #444746 with the link in a mono face and a Copy
   that becomes Copied.
   ================================================================================================= */

.lh-account-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.lh-account-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--stage-avatar);
  color: var(--stage-avatar-ink);
  font-size: 24px;
  font-weight: 600;
}

.lh-account-who { min-width: 0; }

/* Both selectors carry .lh-dialog on purpose: the dialog's own paragraph rule is 19 px #c4c7c5 -
   the design's body line - and it is MORE specific than a bare class, so a bare .lh-account-name
   would lose to it. These two are paragraphs and the design gives them their own size and ink. */
.lh-dialog .lh-account-name {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--stage-ink);
}

.lh-dialog .lh-account-email {
  margin: 0;
  font-size: 18px;
  line-height: 1.4;
  color: var(--stage-ink-muted);
  overflow-wrap: anywhere;
}

.lh-link-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 14px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-link-box);
  background: var(--stage-field);
}

/*
  PLAN-179 T-16b: break-word, NOT anywhere, AND THAT IS PLAN-169's DECISION AND NOT A TASTE.

  U-11 went red at the tip with "the link box wraps with anywhere, not break-word (M12 measured
  anywhere)" - the same words that plan's own measurement used for the DEFECT it fixed. `anywhere`
  lets the browser break the URL at any character it likes, which makes the two <wbr> joints the page
  puts at the meaningful places (after the host and before the code) meaningless: the line breaks
  mid-code instead. T-4 rebuilt this box for the design's card and carried `anywhere` back in with
  it. The design says nothing about which of the two it is; PLAN-169 D12 does, and it wins.
*/
.lh-link-text {
  flex: 1 1 auto;
  min-width: 0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 18px;
  overflow-wrap: break-word;
}

.lh-link-copy {
  flex: 0 0 auto;
  min-height: 56px;
  padding: 0 16px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--stage-accent);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-link-copy:hover { background: var(--card-secondary-hover); }

.lh-link-copy:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* =================================================================================================
   PLAN-178 T-11 (D5, F7): ALLOW THE CAMERA AND MICROPHONE.

   The design's row under the sentence: a 14 px dot that pulses on lhpulse beside "Waiting for your
   answer...", in a 14 px box on #2b2c2f behind 1px #444746 at padding 14 16 with a 12 px gap and
   18 px words. The dialog itself has no X and cannot be dismissed; that is T-8's data-closable and
   the opener's business, not this file's.
   ================================================================================================= */

.lh-waiting-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-link-box);
  background: var(--stage-field);
  font-size: 18px;
}

.lh-waiting-dot {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--stage-accent);
  animation: lhpulse 1.4s ease-out infinite;
}

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

/* =================================================================================================
   PLAN-178 T-12 (D6, F8): THE CALLOUT.

   README "Callouts (sticky notices) and toasts": a row that wraps, gap 12 16, padding 14 14 14 18,
   1px #333537, radius 16, #1e1f20 under the callout shadow; a 44 px round icon slot at the left
   (#333537 with a 22px/700 #e3e3e3 "i" for information, #2a1a14 with a #ff9b7d "!" for a warning,
   and then a 6 px #ff9b7d left edge on the whole box); the sentence at 20px/1.4 #f2f5f9; a second
   line at 18 px #c4c7c5 when others are queued; a 56 px X.

   THE BOX IS BUILT AROUND THE COLUMN THE MODULES ALREADY WRITE INTO (callout.js ensureBox), so these
   rules dress a wrapper whose middle child is that column.
   ================================================================================================= */

.lh-callout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  width: 100%;
  max-width: 640px;
  padding: 14px 14px 14px 18px;
  border: 1px solid var(--stage-hairline-callout);
  border-radius: var(--r-callout);
  background: var(--stage-callout-surface);
  box-shadow: var(--shadow-callout);
  pointer-events: auto;
}

.lh-callout[hidden] { display: none; }

/* The warning's own edge, which the design puts on the box and not on the icon. */
.lh-callout[data-look='warn'] { border-left: 6px solid var(--stage-warn); }

.lh-callout-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--stage-round);
  color: var(--stage-ink-panel);
  font-size: 22px;
  font-weight: 700;
}

.lh-callout[data-look='warn'] .lh-callout-icon {
  background: var(--stage-warn-wash);
  color: var(--stage-warn);
}

.lh-callout-body {
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.lh-callout-text {
  margin: 0;
  font-size: 20px;
  line-height: 1.4;
  color: var(--stage-ink);
  text-wrap: pretty;
}

.lh-callout-queue {
  margin: 0;
  font-size: 18px;
  color: var(--stage-ink-muted);
}

.lh-callout-queue[hidden] { display: none; }

/* The X. The column's old Close was a worded pill; the design draws a 56 px round X beside the
   sentence, and callout.js moves the same element into the wrapper. */
.lh-callout .callout-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-panel);
  font-size: 0;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-callout .callout-close:hover { background: var(--stage-secondary-hover); }

.lh-callout .callout-close:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* The glyph, drawn rather than lettered, because the design's X is two strokes and the word on this
   button is what a screen reader hears (aria-label), not what an eye reads. */
.lh-callout .callout-close::before {
  content: '';
  width: 26px;
  height: 26px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6l12 12M18 6L6 18' stroke='black' stroke-width='2.2' stroke-linecap='round' fill='none'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6l12 12M18 6L6 18' stroke='black' stroke-width='2.2' stroke-linecap='round' fill='none'/></svg>") center / contain no-repeat;
}

/* =================================================================================================
   A STAGE SCREEN: the toast clears the bar the design floats over the picture (bottom 104), AND it
   clears the callout's band, which the bar's 104 does not.

   PLAN-180 pass three (D2, F2): THE TOAST AND THE CALLOUT ARE TWO SURFACES, NOT ONE BAND.

   MEASURED on 2026-09-15 at 1280 x 800, in one real call, with neither surface arranged: the join
   toast at y 638..696 and the information callout "Turning on cameras..." at y 612..700 - 367 x 58 px
   of one band, the toast's words drawn across the callout's sentence. The design's 104 clears the
   BAR; the callout stands above the bar, in the lower band, and 104 lands inside it.

   D2 and F2 give that band to one thing: "the lower band holds only the callout". So the toast takes
   its own band, 12 px above where the band's content starts.

   --stage-toast-floor IS MEASURED, NOT ASSUMED. wire.js writes it on the document root after every
   paint of the band (lowerBandHeight -> toastFloor): the distance up from the bottom of the window to
   the top of the topmost thing the band draws, with the More sheet left out of the sum for the same
   reason the band's height leaves it out. A callout that wraps to two lines, or to three in
   Lithuanian, moves the number with it.

   THE max() ONLY EVER LIFTS. With an empty band the floor is 0 and every one of the design's three
   numbers - 104 on a laptop, 244 on a phone, 160 with the bar collapsed - stands exactly as it was.
   ================================================================================================= */
.lh-toast-host[data-shell='stage'] {
  bottom: max(104px, calc(var(--stage-toast-floor, 0px) + 12px));
}

/* PLAN-221 T-4 (D9): while a panel is open ON A PHONE the toast is BEHIND the sheet, not over its
   rows. The panel lives inside the stage shell (z-index 5) and this host is a fixed body-level box
   at 35, so the panel cannot be lifted above it; the host goes under the shell instead, and the dim
   says the rest. The join toast at 244 px off the bottom of a phone was drawn over the sheet's third
   row.
   PLAN-221 FIX-1 (the landing review): PHONE ONLY, under 900 px. Above it the same panel is a 340 px
   COLUMN beside the picture with no dim, and the shell at z 5 is opaque and covers the whole
   viewport, so the unqualified rule put every laptop toast out of sight while a column was open. A
   laptop keeps its toasts at 35. */
@media (max-width: 899px) {
  body:has(#s-connected[data-more='open']) .lh-toast-host,
  body:has(#s-connected[data-chat='open']) .lh-toast-host { z-index: 4; }
}

@media (max-width: 719px) {
  /* A phone: full width minus 24, so the sentence is not a narrow column in the middle of a screen. */
  .lh-toast-host {
    left: 12px;
    right: 12px;
    width: auto;
    max-width: none;
    transform: none;
  }

  /* And the phone bar is two rows tall, or one when a person has collapsed it.
     THE COLLAPSED RULE HAS NO WRITER YET, and that is this plan's own split rather than an
     oversight: the phone bar and its swipe are PLAN-179's row (PLAN-178 D8), and data-bar is
     what that row will set. Until then a phone toast sits at the design's two-row height, which
     is where the bar really is. public/web/design/NOTES.md section 2.4 says so. */
  .lh-toast-host[data-shell='stage'] { bottom: max(244px, calc(var(--stage-toast-floor, 0px) + 12px)); }
  .lh-toast-host[data-shell='stage'][data-bar='collapsed'] { bottom: max(160px, calc(var(--stage-toast-floor, 0px) + 12px)); }
}

/* =================================================================================================
   PLAN-179 T-1 (D1, F1): THE PHONE HEADER, WHICH IS THE SWITCHER AND THE AVATAR AND NOTHING ELSE.

   "On phone the whole left group is hidden" is the design's own sentence (README, Screen 3), and it
   has to be written HERE rather than beside the group's other rules: .lh-stage-header-left is
   declared by the stage shell (PLAN-178 T-3) further up this file, and a rule of the same weight
   only wins where it is written after it. The clock and the meeting code are not lost to a phone -
   the code is in that person's own address bar, which is where the design leaves it.
   ================================================================================================= */
@media (max-width: 719px) {
  .lh-stage-header-left { display: none; }

  /* AND THE AVATAR STEPS OUT OF THE ROW SO THE SWITCHER CAN BE CENTRED. The design's own
     sentence: "on phone it is position:absolute right 16px so the switcher stays centred".
     Inside the row the two would share the space and the pill would sit left of centre, which
     is the one thing a person looks at on a phone header. The header is the positioned box
     (PLAN-178 T-3 made it relative), so 16 px is 16 px off the screen's own edge. */
  .lh-stage-header-right #stage-account-avatar {
    position: absolute;
    right: 16px;
  }
}

/* =================================================================================================
   PLAN-179 T-2 (D2, F2): THE LANGUAGE SWITCHER AND THE PICKER, BOTH READ OUT OF THE PROTOTYPE.

   The switcher is one pill with three controls in it: the language you SPEAK (a microphone and two
   letters), a round swap button, and the language you HEAR (two letters and a speaker). Each side is
   44 px tall, which is the design's own second exception to the 56 px law, and the pill itself is
   the panel surface at radius 999 with 4 px of padding.

   The picker is ONE box for all four lists (speak, hear, microphone, camera). The design draws them
   identically and places them differently, so the placement is what `data-place` decides and
   everything else is written once. Every value below is the prototype's; the shadow is its own .55
   rather than the token list's .5, which is NOTES.md 1.5.2 E-3.
   ================================================================================================= */

.lh-switcher {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border-radius: var(--r-pill);
  background: var(--stage-surface);
}

.lh-switcher[hidden] { display: none; }

.lh-switch-side {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 12px 0 10px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--stage-ink-panel);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

/* The hear side is the speak side's mirror: the design pads it the other way round, because its
   icon is on the right. */
.lh-switch-hear { padding: 0 10px 0 12px; }

.lh-switch-side:hover { background: #2a2b2e; }

.lh-switch-side svg {
  width: 22px;
  height: 22px;
  color: var(--stage-accent);
}

.lh-switch-side:focus-visible,
.lh-swap:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* PLAN-218 T-7 (D6, F6): 44 x 44. The record and the prototype draw this at 44 and the product drew
   a 40 circle inside a 44 pill (deploy-2 review, web-design reviewer, Important 85), so the
   PRESSABLE part was 40 - under the 44 floor every other control on this page is held to. The pill
   around it does not change; the button grows to fill it. */
.lh-swap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--stage-round);
  color: var(--stage-ink-panel);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-swap:hover { background: #414345; }
.lh-swap svg { width: 20px; height: 20px; }

/* ---- the picker ------------------------------------------------------------------------------- */

.lh-picker-catcher {
  position: fixed;
  inset: 0;
  z-index: 24;
  background: transparent;
}

.lh-picker-catcher[hidden],
.lh-picker[hidden] { display: none; }

.lh-picker {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  z-index: 25;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: min(520px, calc(100% - 24px));
  padding: 8px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-panel);
  background: var(--stage-surface);
  color: var(--stage-ink-panel);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  box-sizing: border-box;
}

/* The two language pickers hang under the header, which is the design's one fixed position for
   them. The device pickers stand on the bar and are placed by PLAN-179 T-7. */
.lh-picker[data-place='header'] { top: 72px; }

.lh-picker-title {
  margin: 6px 12px 8px;
  font-size: 18px;
  font-weight: 600;
  color: var(--stage-ink-muted);
}

.lh-picker-rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.lh-picker .lh-picker-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-menu-row);
  background: transparent;
  color: var(--stage-ink-panel);
  font-size: 19px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-picker .lh-picker-row:hover,
.lh-picker .lh-picker-row[aria-pressed='true'] { background: #2a2b2e; }

.lh-picker .lh-picker-row:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: -3px;
}

.lh-picker-tick {
  flex: 0 0 auto;
  width: 24px;
  color: var(--stage-accent);
  font-size: 22px;
  font-weight: 700;
}

.lh-picker-label {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The grab bar is the phone sheet's and nothing else's, so it is drawn nowhere until the sheet is. */
.lh-picker-grab { display: none; }

/* ---- the phone, where every picker is a bottom sheet -------------------------------------------- */
@media (max-width: 719px) {
  .lh-picker-catcher { background: var(--overlay-dim); }

  /* PLAN-207c T-6 (D7, F6): `[data-place='bar']` STANDS BESIDE `[data-place='header']` HERE, and the
     reason is specificity rather than taste. `.lh-picker[data-place='bar']` further down positions
     that box ABSOLUTELY above the bar, and (0,2,0) beats this block's bare `.lh-picker` (0,1,0)
     whatever the order they are written in - so on a phone the microphone and camera pickers, the
     two that stand on the bar, never became the bottom sheet every other picker becomes. Naming it
     here matches the specificity, and `position: fixed` is stated because the bar rule sets
     `position: absolute` and a sheet is fixed to the screen.
     AND THE PADDING NAMES THE SAFE AREA: a bare `24px` draws the sheet's last row under the home
     indicator on a phone that reserves that strip; nineteen other rules in this file already read
     `env(safe-area-inset-bottom)` for exactly this. */
  .lh-picker,
  .lh-picker[data-place='header'],
  .lh-picker[data-place='bar'] {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    transform: none;
    padding: 8px 12px calc(24px + env(safe-area-inset-bottom, 0px));
    border-radius: var(--r-panel) var(--r-panel) 0 0;
  }

  .lh-picker-grab {
    display: block;
    align-self: center;
    width: 40px;
    height: 4px;
    margin: 2px 0 6px;
    border-radius: 2px;
    background: var(--stage-hairline);
  }
}

/* =================================================================================================
   PLAN-179 T-3 (D3, F3): THE LINK SCREEN'S STAGE - THE PLACEHOLDER AND THE WAITING PILL.

   Every value is the prototype's own. The placeholder is the design's picture layer: the gradient,
   the glow over it, two 300 px rings on lhripple with the second delayed 1.5 s, and the host's own
   initial in a circle 34 per cent of the width and at most 180. It sits UNDER everything else on
   the stage, so a real picture covers it and a stage with no picture is the design's gradient
   rather than a black rectangle.

   The waiting pill is the design's own: top centre, the overlay pill ground, a 12 px dot on
   lhpulse, 18px/600. On a phone it is a static full-width block reading one word, which is
   README Screen 3's "Phone" line (and NOTES.md 1.5.2 E-2, where the prototype computes that layout
   and then never draws it).
   ================================================================================================= */

.lh-placeholder {
  position: absolute;
  inset: 0;
  background: var(--stage-placeholder);
}

.lh-placeholder[hidden] { display: none; }

.lh-placeholder-glow {
  position: absolute;
  inset: 0;
  background: var(--stage-placeholder-glow);
}

.lh-placeholder-ring {
  position: absolute;
  left: calc(50% - 150px);
  top: calc(50% - 150px);
  width: 300px;
  height: 300px;
  border: 2px solid var(--stage-own);
  border-radius: 50%;
  opacity: 0.35;
  animation: lhripple 3s ease-out infinite;
}

.lh-placeholder-ring:nth-of-type(3) { animation-delay: 1.5s; }

.lh-placeholder-initial {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(34%, 180px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--stage-own);
  color: #fff;
  font-size: clamp(40px, 8vw, 72px);
  font-weight: 600;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}

.lh-wait {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  max-width: calc(100% - 24px);
  padding: 10px 18px;
  border-radius: var(--r-pill);
  background: var(--overlay-pill);
  font-size: 18px;
  font-weight: 600;
  white-space: nowrap;
  box-sizing: border-box;
}

.lh-wait[hidden] { display: none; }

.lh-wait-dot {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--stage-accent);
  animation: lhpulse 1.4s ease-out infinite;
}

.lh-wait-text {
  margin: 0;
  color: var(--stage-ink);
  font-size: 18px;
  font-weight: 600;
  text-wrap: pretty;
}

/* The phone, where the design gives the link screen no picture at all: the pill is a static block
   above the card, full width, at the card's own radius, and it reads one word. */
@media (max-width: 719px) {
  .lh-placeholder { display: none; }

  .lh-wait {
    position: static;
    transform: none;
    max-width: none;
    margin: 0 0 12px;
    border-radius: var(--r-card);
  }
}

/* =================================================================================================
   PLAN-179 T-4 (D3, F3): THE ASK-ME SWITCH, AS THE DESIGN DRAWS IT.

   52 x 32 of track, a 24 px thumb 4 px in, and the thumb moves to 24 in the design's own 120 ms.
   The INPUT is still the control: it keeps every keyboard and screen-reader behaviour it had, and
   it is taken out of sight rather than replaced, because a drawn switch with no input behind it is
   a picture of a control. The focus ring lands on the track, which is what a person sees.
   ================================================================================================= */
.meet-card .switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.meet-card .switch-track {
  position: relative;
  flex: 0 0 auto;
  width: 52px;
  height: 32px;
  border-radius: 16px;
  background: var(--stage-hairline);
  transition: background-color var(--t-hover);
}

.meet-card .switch-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--stage-ink-panel);
  /* --t-switch-thumb carries its own property (`left 120ms ease`), which is how the README writes
     it, so it is used whole rather than after a property name. */
  transition: var(--t-switch-thumb), background-color var(--t-hover);
}

.meet-card .switch input:checked ~ .switch-track { background: var(--stage-accent); }
.meet-card .switch input:checked ~ .switch-track .switch-thumb {
  left: 24px;
  background: var(--stage-accent-ground);
}

.meet-card .switch input:focus-visible ~ .switch-track {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

.meet-card .switch:focus-within { outline: 0; }

/* =================================================================================================
   PLAN-179 T-5 (D3, F3): THE LINK SCREEN ON A PHONE, WHICH HAS NO PICTURE IN IT.

   README, Screen 3, "Phone": "no picture; header, then the card as a static block (radius 16), then
   the bar. Waiting pill on phone: static full width above the card". The prototype says the same
   thing three times over in its state map - stageBg transparent, stageMinH 0, and the picture layer
   itself inside an sc-if that a phone frame never enters - so a phone link screen is a COLUMN of
   things and not a picture with things floating on it.

   The stage keeps its own ground either way (#131314); what goes is the black picture box, its
   minimum height and everything that was drawn over it. `data-link` is set by app.js while the host
   is waiting, so this is the LINK screen's phone layout and never the call's.
   ================================================================================================= */
@media (max-width: 719px) {
  .lh-stage-shell[data-link='true'] .lh-stage-area { background: transparent; }

  .lh-stage-shell[data-link='true'] #s-connected:not([hidden]) { background: transparent; }

  /* The column: the pill, then the card, then whatever the bar is, with the design's own 12 px gap
     and 12 px of air off each edge. The stage stops being a picture frame and becomes a page. */
  .lh-stage-shell[data-link='true'] .stage {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    background: transparent;
    /* PLAN-179 T-13b (the gallery review): "at 390 with the QR open the card is 739 tall, the ask-me
       row cut and the bar below the fold". On a phone this screen is a COLUMN, and a column that is
       taller than the screen has to scroll or the controls under it cannot be reached. The bar is
       outside this box, so it stays where it is and the card scrolls under it. */
    overflow-y: auto;
  }

  /* The pill is first in the column and the card second, which is the prototype's own order:-1 on
     the pill. In the DOM the card is built before the pill (the card is built the moment the
     meeting exists and the pill when the screen is painted), and the design's order is a layout
     fact rather than a build order, so it is said here. */
  .lh-stage-shell[data-link='true'] .lh-wait { order: -1; }

  /* And nothing that belongs to a picture is drawn over the column: on a phone the link screen HAS
     no picture (the design's own layout), so the grid and the language box both go. At 1100 the grid
     stays, because that is where the host's own camera paints while they wait (T-16a). */
  .lh-stage-shell[data-link='true'] .video-tiles,
  .lh-stage-shell[data-link='true'] .stage-langs-row { display: none; }

  /* The callout on this screen is a block under the card rather than a banner over a picture,
     which is the design's "on phone static under the card". */
  .lh-stage-shell[data-link='true'] .stage-lower {
    position: static;
    padding: 12px 0 0;
    background: none;
  }
}

/* =================================================================================================
   PLAN-179 T-6 (D4, F4): THE BAR, AT THE DESIGN'S OWN NUMBERS.

   PLAN-159 T-1 made this bar a floating pill on the owner's Meet capture and it is already the
   design's colour, radius and padding. What this row changes is the two numbers the design writes
   differently and the one element it draws that was not there:

     the gap      10 on a laptop (it was 12). The phone's own gap is 8 and belongs to T-8, whose
                  row arithmetic depends on it, so it is not touched here.
     the rule     1 x 40 of the hairline, 2 px of margin each side, between the last round button
                  and the red one. Laptop only, as the design draws it.
   ================================================================================================= */
@media (min-width: 720px) {
  .talk-bar { gap: 10px; }
}

.bar-rule {
  flex: 0 0 auto;
  width: 1px;
  height: 40px;
  margin: 0 2px;
  background: var(--stage-hairline);
}

/* On a phone the design draws no rule at all: the band is two rows of controls and a line between
   two of them would be a line across a row. */
@media (max-width: 719px) {
  .bar-rule { display: none; }
}

/* =================================================================================================
   PLAN-179 T-6 (D3, F3): ONE NOTICE AT A TIME ON THE LINK SCREEN, AND IT SITS WHERE THE DESIGN PUTS IT.

   THE PLAN-178 GALLERY REVIEW, finding 1: the frame showed the design's sticky callout AND a
   separate "Setting up the call..." pill overlapping its bottom. They are the same box - the callout
   IS .stage-notices, which four modules and #connected-status all write into - so what the reviewer
   saw was the page's own status line standing beside a sentence a person had been asked to read.

   The README's must-not list says it plainly for the call screen ("No status pill"), and PLAN-180
   removes it there for good. On the LINK screen, which is this plan's, it is not drawn at all: there
   is no call to report the state of while a host is waiting for somebody to open a link.

   AND THE CALLOUT SITS AT TOP 72, which is README Screen 3's own position for it ("absolute,
   left/right 16, top 72 (laptop); on phone static under the card"). That is also what keeps it away
   from the toast, which lives at the bottom of the screen.
   ================================================================================================= */
.lh-stage-shell[data-link='true'] #connected-status { display: none; }

/*
  PLAN-179 T-13b (the gallery review): AND THE OTHER PERSON'S EMPTY TILE IS NOT DRAWN OVER THE
  LINK SCREEN'S OWN PICTURE.

  THE REVIEWER'S WORDS: "the stage is covered by a flat #0a2334 rectangle inset 16 px, so the
  README's gradient, glow and the two ripple rings are lost; the own initial circle is 132 px with NO
  letter, the prototype draws 180 px with the initial."

  TWO boxes were standing there, both of them a call's and neither of them this screen's.

    .stage-avatar   the tile a CALL draws when the other person's camera is off: an inset #0a2334
                    ground with their initial in it. On the link screen there is no other person, so
                    it was drawn empty - the flat rectangle the reviewer measured.
  ONLY .stage-avatar IS TAKEN OFF, AND ONLY IT. The first version of this rule took the picture grid
  off with it, and the full matrix answered for that too: D-04 ("New meeting: the host is let in at
  once, SEES THEMSELVES, and reads the link off the card") went red, because the grid is where the
  host's own camera paints while they wait. The prototype has no camera in it, so its Screen 3 draws
  the placeholder; the product has one, the owner's own PLAN-181 is called "the host sees themselves
  full screen until the other person arrives", and hiding the grid would have been this builder
  deciding against both. The gallery's grid is black because the harness's fake camera paints
  nothing, which is a fact about the harness and not about the screen.

  So the grid stays and the placeholder is UNDER it, which is what a placeholder is for: it is what a
  person sees when there is no picture, and the host's own face is what they see when there is one.
*/
.lh-stage-shell[data-link='true'] .stage-avatar { display: none; }

/*
  PLAN-179 T-13b (the gallery review) wrote `.stage-notices:empty { display: none; }` here, for a real
  reviewer finding: "an empty notice surface 681 x 32 sits under the waiting pill".

  PLAN-207c T-6 (D7, F6) REMOVES IT, because it can never match. `:empty` is true only of an element
  with NO children at all, and #stage-notices is a CONTAINER: index.html puts #connected-status,
  #connected-note, #call-state and #video-sheet inside it, and they are there whether or not any of
  them has a word in it. The rule has therefore drawn nothing since the day it was written, and the
  finding it was meant to answer was closed by the attribute hiding those four elements carry.

  THE TOAST HOST'S OWN `:empty` RULE IS UNTOUCHED and is not the same case: #toast-host really is
  emptied - showToast appends one box and hideToast removes it - so `:empty` is true of it exactly
  when there is no toast.
*/



/* PLAN-179 T-13b (the gallery review): "the surface runs the full stage width, 60 px tall, while
   index.html says 640 x 86". Sixteen pixels off each side of a 1076 px picture is a banner; the
   design's callout is at most 640 wide and centred, which is what the callout component itself is
   (PLAN-178 T-12). The design's top 72 for this screen stays. */
/* =================================================================================================
   PLAN-179 T-13c (the gallery review): THE CALLOUT IS ONE ROW, AND THE BOX IS THE WRAPPER.

   THE REVIEWER'S WORDS: the notice "runs the full stage width" and its X stands away from it.

   Measured, in a browser, with the notice standing (scratch probe, T-13c):

     div.lh-callout                     [12,64  640 x 86]     the design's box, static on the stage
       span.lh-callout-icon             [36,85   44 x 44]     the "!" - at the box's left
       div.stage-notices.lh-callout-body[230,136 640 x 90]    THE SENTENCE - somewhere else entirely
       button.callout-close             [96,79   56 x 56]     the X - back at the box's left

   The box PLAN-178 T-12 built (callout.js ensureBox) wraps the column the modules have always
   written into, and dresses the WRAPPER: one flex row of icon, sentence, X. But the column keeps its
   own `position: absolute` from the days when IT was the callout, so it is taken out of that row and
   floats wherever its own offsets put it, leaving the icon and the X sitting alone in an empty box.
   T-6a then moved the COLUMN to the design's top 72 and centred it, which moved the sentence and
   left the box behind - the exact picture the reviewer measured.

   So: inside the box the column is a plain child with no chrome of its own, and the LINK screen's
   own placing moves onto the box. A column with no box around it (a page where no callout has been
   built) keeps everything it had, which is why every rule here is scoped under .lh-callout.
   ================================================================================================= */
/*
  PLAN-179 T-16a: AND ONLY ON THE LINK SCREEN.

  The first version of this rule was unscoped, and the full matrix answered for it: U-05 measured the
  CALL screen's callout at [79,79] - the top left - where it belongs at the bottom of the picture, and
  U-04 measured its line at 1.09 to 1 because the ground it was read against had gone with the
  column's own chrome. Both are right: on the call screen the POSITION lives on the column, the
  wrapper is static, and taking the column's position away moved the sentence to the top of the
  stage.

  The call screen's callout is PLAN-180's row and this part does not touch it. So the neutralising is
  scoped to the screen this part owns: on the link screen the box is the positioned thing and the
  column inside it is a plain child; everywhere else both are exactly what they were.
*/
.lh-stage-shell[data-link='true'] .lh-callout > .stage-notices {
  position: static;
  transform: none;
  z-index: auto;
  gap: 2px;
  align-items: flex-start;
  width: auto;
  max-width: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
}

.lh-stage-shell[data-link='true'] .lh-callout {
  position: absolute;
  top: 72px;
  bottom: auto;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  z-index: 7;
  width: min(640px, calc(100% - 32px));
  max-width: none;
}

@media (max-width: 719px) {
  /* On a phone there is no picture to float over: the callout is a block under the card, in the
     column with everything else. The BOX stays a box - the design draws it there too - it simply
     stops floating. */
  .lh-stage-shell[data-link='true'] .lh-callout {
    position: static;
    transform: none;
    width: 100%;
  }

  .lh-stage-shell[data-link='true'] .stage-notices {
    position: static;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
  }
}

/* =================================================================================================
   PLAN-179 T-6b (D4, F4): THE LINK SCREEN'S BAR.

   The same row, the same pill, the same controls' sizes - what differs is which controls are in it
   and that the hold pill is disabled, because there is nobody to talk to yet. The design dims it to
   .55 and gives it the title "Nobody has joined yet", which is a sentence rather than a refusal.

   The fragment's status line and captions belong to a call and are hidden by wire.js on this screen;
   the row itself sits at the bottom of the stage, which is where the design draws it on both stage
   screens.
   ================================================================================================= */
.talk-bar .talk-hold[disabled] {
  opacity: 0.55;
  cursor: default;
}

/* Cancel is the red pill in the place End takes on a call, and it is the same pill: the design
   draws one red control on this bar at a time and never two. */
.talk-bar .link-cancel { min-width: 96px; }

@media (max-width: 719px) {
  /* PLAN-179 T-13b (the gallery review): "the red End is 94 px where the phone value is min-width
     80". The design gives the red pill 80 and 0 14px on a phone whether it says End or Cancel. */
  .talk-bar .link-cancel,
  .talk-bar .talk-end { min-width: 80px; padding: 0 14px; }
}

/* A bar control the page has hidden STAYS hidden: the rules that make these buttons round set
   `display: inline-flex` at a higher weight than the browser's own [hidden], so a control wire.js
   takes off the link screen would otherwise still be drawn. (PLAN-179 T-6b, measured: the
   microphone stood in the link bar with hidden=true on it.) */
.talk-bar .talk-mic[hidden],
.talk-bar .talk-camera[hidden],
.talk-bar .talk-chat[hidden],
.talk-bar .talk-more[hidden],
.talk-bar .mode-toggle[hidden],
.talk-bar .talk-hold[hidden],
.talk-bar .talk-end[hidden],
.talk-bar .direct-chip[hidden] { display: none; }

/* =================================================================================================
   PLAN-179 T-7 (D4, F4): THE SPLIT PILLS AND THE DEVICE PICKERS.

   One pill holding two controls: a 36 x 56 chevron that opens that device's list, and the 56 px
   round toggle that was already there. The wrapper carries the design's own two greys - #262729, and
   #4b4d4f while its picker is open - so a person can see WHICH list is open without reading a word.

   On a phone the design draws no chevrons: the wrapper is still the box around the toggle and the
   chevron inside it is not drawn, so a phone bar is the row of circles PLAN-156 measured.
   ================================================================================================= */
.talk-bar .bar-split {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--stage-chevron);
}

.talk-bar .bar-split[data-open='true'] { background: var(--stage-chevron-open); }

.talk-bar .bar-split .bar-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 56px;
  padding: 0 0 0 6px;
  border: 0;
  border-radius: var(--r-pill) 0 0 var(--r-pill);
  background: transparent;
  color: var(--stage-ink-panel);
  cursor: pointer;
  transition: filter var(--t-hover);
}

.talk-bar .bar-split .bar-chevron:hover { filter: brightness(1.2); }
.talk-bar .bar-split .bar-chevron svg { width: 20px; height: 20px; }

.talk-bar .bar-split .bar-chevron:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: -3px;
}

/* The picker when it stands on the bar: straight above it, centred on it, overlapping by the
   design's own 4 px so the two read as one control and its list. */
.lh-picker[data-place='bar'] {
  position: absolute;
  bottom: calc(100% - 4px);
  top: auto;
}

/* =================================================================================================
   PLAN-187 T-6 (D6, F8, R4): WHILE A PICKER STANDS ON THE BAR, IT IS THE TOP OF THE SCREEN.

   THE OWNER, 2026-09-14, finding 6, with a screenshot: the Microphone picker open and the language
   line "Now: you speak Lietuvių, you hear Lietuvių" drawn ACROSS its last row; and then "i cant ecen
   select anything too".

   TWO RULES, AND THE SECOND IS THE ONE HIS SECOND SENTENCE IS ABOUT.

   1. The BAR's stacking context is raised above the picker's own catcher. A picker standing on the
      bar is a child of `.talk-bar`, and `.talk-bar`'s `z-index: 5` makes a stacking context, so the
      picker's `z-index: 25` counted for nothing against the catcher's 24 OUTSIDE it. MEASURED at
      1100 (harness row PICKER-OVER): `document.elementFromPoint` at the centre of the picker's first
      row returned `lh-picker-catcher`. Every row he pressed closed the box instead of choosing.

   2. The LOWER BAND is not drawn while that picker is open. It is the one box that shares this corner
      of the screen - the language line, the captions, the status line - and the design's rule for it
      is one sentence at a time (PLAN-157 section 4). `display: none` rather than a transparency,
      because a box that is still there is still a box the picker's own rows have to fight.

   Both come back the instant the picker closes: wire.js sets these two attributes as it opens and
   takes them off as it closes, and nothing else writes them.
   ================================================================================================= */
.talk-bar[data-picker='open'] { z-index: 26; }
.lh-stage-shell[data-picker='bar'] .stage-lower { display: none; }

/* The level row: the analyser PLAN-160 T-3 built, at the design's size. */
.lh-picker-level {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 8px;
}

.lh-picker-level[hidden] { display: none; }

.lh-picker-level svg {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--stage-ink-muted);
}

.lh-picker-track {
  flex: 1;
  height: 8px;
  border-radius: 4px;
  background: var(--stage-hairline);
  overflow: hidden;
}

.lh-picker-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 4px;
  background: var(--stage-accent);
  transition: var(--t-mic-level);
}

.lh-picker-level-word {
  font-size: 18px;
  color: var(--stage-ink-muted);
  white-space: nowrap;
}

.lh-picker-rule {
  height: 1px;
  margin: 6px 12px;
  background: var(--stage-hairline);
}

.lh-picker-rule[hidden] { display: none; }

.lh-picker .lh-picker-settings {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 56px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-menu-row);
  background: transparent;
  color: var(--stage-ink-panel);
  font-size: 19px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-picker .lh-picker-settings[hidden] { display: none; }
.lh-picker .lh-picker-settings:hover { background: #2a2b2e; }

.lh-picker .lh-picker-settings:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: -3px;
}

.lh-picker-chevron {
  color: var(--stage-ink-muted);
  font-size: 22px;
}

@media (max-width: 719px) {
  .talk-bar .bar-split .bar-chevron { display: none; }
}

/* =================================================================================================
   PLAN-179 T-7 (D4, F4): THE HOLD PILL IS ONE LINE TALL, AT EVERY WIDTH.

   MEASURED at 1100 with the conversation panel open: the bar is capped at the width the panel
   leaves it (README, Panels: "the bar shifts left by 352px"), the pill shrinks below its 220 px
   basis, "Hold to talk" wraps onto two lines and the pill becomes 59 px - so the whole bar grows
   from 80 to 83 and every control in it sits three pixels lower than the design draws it.

   The design's pill is one line in every state it draws ("Hold to talk", "Speaking... 30s",
   "Talking directly"), so the label does not wrap: at a width that cannot hold the words the pill
   clips them with an ellipsis instead of growing. A clipped label on a control a person is holding
   is a smaller loss than a bar that changes height when a panel opens.
   ================================================================================================= */
.talk-bar .talk-hold {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* =================================================================================================
   PLAN-179 T-8 and T-9 (D5, F5): THE PHONE BAR, AND THE SWIPE.

   README, Screen 3, "Phone bar": a full-width band at radius 24 24 0 0, padding 12px 8px with 20 at
   the bottom for the safe area, gap 8, space-between, in three rows - the grab handle, then Hold to
   talk with the translation round beside it, then the collapsible row.

   The collapse is the design's own transition (max-height 80 to 0 in 260 ms on its curve, opacity in
   200 ms), and the drag is a transform on the whole band in the same 260 ms. Both are the tokens
   PLAN-178 T-1 put in :root, used whole.
   ================================================================================================= */
@media (max-width: 719px) {
  .talk-bar {
    width: 100%;
    /* PLAN-179 T-13b (the gallery review): "the phone bar is full bleed at 390 where the prototype
       insets it to 366". The prototype's band is width 100% AND max-width calc(100% - 24px), which
       NOTES.md 1.5.1 already recorded; this row had dropped the cap.

       PLAN-187 T-2 (D2, F2) - THE CAP IS MEASURED AGAINST THE PHONE, NOT AGAINST THE PICTURE, AND
       THAT IS THE OWNER'S FINDING 2: "Red stop button right side cropped on mobile".

       The prototype's 24 is the inset of the band INSIDE THE PHONE FRAME: 390 gives a 366 band. In
       this page the band's parent is the picture, `.lh-stage-area`, which already carries the
       design's own `margin: 0 12px` - so `calc(100% - 24px)` subtracted the same 24 a SECOND time
       and the band came out 342 wide. MEASURED at 390 x 844 before this line changed (harness row
       BAR-390): the band x 24 right 366, its second row 326 px of room for 4 x 56 rounds + 80 of
       End + 4 x 8 of gap = 336, `overflow: hidden` on `.bar-row2`, and End cut at 88 per cent, its
       right-hand 10 px gone. That is the crop he photographed.

       100vw is the phone, which is what the prototype's number is a fraction of: 366 at 390, the
       prototype's own band width, and 350 of room for a row that needs 336. Nothing else in the
       design moves - End keeps its 80 (D2: the red pill keeps its width) and the rounds keep the
       56 px touch target this file protects by name. */
    max-width: calc(100vw - 24px);
    margin: 0 auto;
    padding: 12px 8px 20px;
    gap: 8px;
    border-radius: 24px 24px 0 0;
    justify-content: space-between;
    transition: var(--t-bar-drag);
  }

  /* Row 0: the handle, full width, with the design's own negative margins so it steals no height
     from the rows under it. */
  .talk-bar .bar-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 100%;
    /* PLAN-207d T-8 (D9, F8): 44 px, and the comment this replaces was the defect.
       It read "36 px is the design's own number for this one control and the README's law 5 allows
       it where the document says so" - and law 5 says "every pressable target is at least 56 px
       tall (44 px only where this document says 44)". 44 is the ONLY exception the law names; 36 is
       not an exception it can grant, so a comment citing the law was breaking it. The handle is a
       pressable target (a tap toggles the band, a drag collapses it), so it takes the law's own
       exception and the README's Screen 3 line says 44 beside it.
       It is FULL WIDTH, so the target a thumb aims at is 350 x 44 on a 390 px phone rather than a
       44 px square. The minimum is said here because the module's own `.talk-actions button` rule
       sets 56.
       THE MARGINS ARE UNCHANGED, which is the plan's own L2 taken rather than avoided: the band
       grows by the 8 px the control grew, measured at 390 px in harness row PR-21 (188 -> 196), and
       the design's own `-10 0 -6` stays the number the README documents. */
    min-height: 44px;
    height: 44px;
    margin: -10px 0 -6px;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: grab;
    touch-action: none;
    user-select: none;
  }

  .talk-bar .bar-grip {
    width: 44px;
    height: 4px;
    border-radius: 2px;
    background: #5f6368;
  }

  .talk-bar .bar-handle:focus-visible {
    outline: 3px solid var(--stage-accent);
    outline-offset: -3px;
  }

  /* Row 1 is the hold pill and the translation round, and the pill's basis is the arithmetic above
     (the row minus the round and one gap). IT HAS TO BE AN EXPLICIT BASIS: talk/screens.js sets
     style.width = 100% on that element when it builds it, and an inline width beats every rule in
     this file, so a basis of auto reads 100 per cent and pushes the round onto a line of its own.
     Measured at 390 before this line was removed: the pill 374 px wide with the round under it.

     PLAN-179 T-20 (bugcheck round 1, codex on p12): THE RULE ITSELF IS NOT HERE, AND THIS COMMENT
     USED TO READ AS IF IT WERE. It is in the earlier `@media (max-width: 719px)` block of this same
     file, on `.talk-bar .talk-hold, .talk-bar .direct-chip` (flex: 1 1 calc(100% - 64px), width
     auto, min-width 0, max-width none), where the two numbers it depends on are written beside it.
     A reader of this block alone would have concluded the basis had been lost. It has not, and B-10
     measures it at this tip: at 390 the pill is 286 px and the round 56 px, side by side on one
     350 px row, which is the arithmetic doing its work. Nothing is declared here; only the note is
     corrected, because a duplicate rule in two blocks is how the next one gets changed alone. */

  /* The break that ends row 1, which is the prototype's own zero-height full-width span. */
  .talk-bar .bar-break {
    flex: 1 1 100%;
    height: 0;
  }

  /* Row 2: one element, because that is what the design collapses. */
  .talk-bar .bar-row2 {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex: 1 1 100%;
    max-height: 80px;
    opacity: 1;
    overflow: hidden;
    transition: var(--t-bar-collapse);
  }

  .talk-bar[data-bar='collapsed'] .bar-row2 {
    max-height: 0;
    opacity: 0;
  }
}

/* The handle, the grip and the break are a phone's alone: at 720 and up wire.js takes them out of
   the row, and these rules make sure a browser that has not re-laid the bar out yet draws none of
   them either. */
@media (min-width: 720px) {
  .talk-bar .bar-handle,
  .talk-bar .bar-break { display: none; }
}

/* =================================================================================================
   PLAN-179 T-10 (D6, F6): THE KNOCK CARD, AND THE SYSTEM LINE UNDER IT.

   README, Screen 5: "Not a separate page". The card is the design's own box - the field ground
   behind a hairline at radius 16, padded 14 in a 12 px column - with a 44 px circle, the name at
   19/600, one muted line, and two 56 px buttons side by side.

   WHERE IT SITS is the Conversation panel's body when a call has built one, and its own host when
   it has not: a knock arrives while a host is ALONE, which is the one screen with no panel on it.
   The host takes the panel's own place (the right column at 340, 12 px off the picture) so the card
   is where the design draws it, and PLAN-180 moves it into the real panel.
   ================================================================================================= */
.lh-knock-host {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 9;
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 340px;
  max-width: calc(100% - 24px);
  padding: 8px;
  border-radius: var(--r-panel);
  background: var(--stage-surface);
  box-shadow: var(--shadow-panel);
}

.lh-knock-host[hidden] { display: none; }

.lh-knock {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-card);
  background: var(--stage-field);
}

.lh-knock[hidden] { display: none; }

.lh-knock-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.lh-knock-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--stage-avatar);
  color: var(--stage-avatar-ink);
  font-size: 20px;
  font-weight: 600;
}

/* PLAN-207c T-6 (D7, F6): AND IT ANSWERS THE `hidden` ATTRIBUTE THE SCRIPT SETS ON IT. `showKnockCard`
   writes `circle.hidden = !letter` for a knocker whose name is empty, and the browser's own
   `[hidden] { display: none }` is the WEAKEST rule there is: any `display` in a stylesheet overrides
   it, and `display: inline-flex` above is one. So a 44 px empty circle was drawn beside the sentence
   for every nameless knocker, on the exact card the host is being asked to answer. `.lh-knock` has
   carried the same partner rule for the same reason since it was written. */
.lh-knock-circle[hidden] { display: none; }

.lh-knock-words { min-width: 0; }

.lh-knock-title {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  color: var(--stage-ink);
}

.lh-knock-body {
  margin: 0;
  font-size: 18px;
  color: var(--stage-ink-muted);
}

.lh-knock-buttons {
  display: flex;
  gap: 10px;
}

.lh-knock-yes,
.lh-knock-no {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* A SHARE EACH, from a zero base: flex:1 alone measured 141 and 143 px because each button asked
     for its own words first. The design draws two buttons of one width. */
  flex: 1 1 0;
  min-width: 0;
  min-height: 56px;
  padding: 0 14px;
  border-radius: var(--r-pill);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-knock-yes {
  border: 0;
  background: var(--stage-primary);
  color: #fff;
}

.lh-knock-yes:hover { background: var(--stage-primary-hover); }

.lh-knock-no {
  border: 1px solid var(--stage-hairline);
  background: transparent;
  color: var(--stage-ink-panel);
}

.lh-knock-no:hover { background: var(--stage-secondary-hover); }

.lh-knock-yes:focus-visible,
.lh-knock-no:focus-visible {
  outline: 3px solid var(--stage-accent);
  outline-offset: 2px;
}

/* The system line: a centred pill with a green dot, which is how the design says a thing HAPPENED
   rather than a thing somebody said. */
.lh-system-line {
  display: inline-flex;
  align-items: center;
  align-self: center;
  gap: 8px;
  margin: 0;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: var(--stage-field);
  color: var(--stage-ink-muted);
  font-size: 18px;
}

.lh-system-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--stage-success);
}

@media (max-width: 719px) {
  /* On a phone the panel is a bottom sheet, so the card's own host is one too.
     PLAN-179 T-13b (the gallery review): "at 390 the card floats mid screen over the ready card".
     It was absolute inside .stage, and on the link screen at 390 that box is a short static column,
     so its bottom is nowhere near the screen's. A sheet is fixed to the screen. */
  .lh-knock-host {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    width: auto;
    max-width: none;
    padding: 8px 12px calc(24px + env(safe-area-inset-bottom, 0px));
    border-radius: var(--r-panel) var(--r-panel) 0 0;
  }
}

/* =================================================================================================
   PLAN-179 T-11 (D7, F7): THE ENDED SCREEN, AS SCREEN 7 DRAWS IT.

   A column centred on the stage: a 96 px circle with the other person's initial, the heading at
   34/700 (28 on a phone), the reason at 20 px muted, then three 56 px pills in a 360 px column with
   a 12 px gap - "Start a new call" filled, "Send me what was said by email" outlined, "Home"
   outlined - and the design's own status line after the email pill has been pressed.

   The column's own gap is 16 and its padding 24px 20px 32px, which are the design's numbers, and
   nothing counts down: a person leaves this screen by pressing something (README Screen 7, and the
   product's own law 3.7).
   ================================================================================================= */
#s-connected[data-ended='true'] .talk-screen-ended {
  gap: 16px;
  max-width: 360px;
  padding: 24px 20px 32px;
}

#s-connected[data-ended='true'] .talk-ended-circle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--stage-avatar);
  color: var(--stage-avatar-ink);
  font-size: 40px;
  font-weight: 600;
  line-height: 1;
}

#s-connected[data-ended='true'] .talk-ended-title {
  font-size: 34px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--stage-ink);
}

#s-connected[data-ended='true'] .talk-ended-reason {
  font-size: 20px;
  color: var(--stage-ink-muted);
  text-wrap: pretty;
}

#s-connected[data-ended='true'] .talk-ended-again,
#s-connected[data-ended='true'] .talk-ended-email,
#s-connected[data-ended='true'] .talk-ended-home {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 360px;
  min-height: 56px;
  margin: 0;
  padding: 0 20px;
  border-radius: var(--r-pill);
  font: inherit;
  cursor: pointer;
  transition: background-color var(--t-hover), filter var(--t-hover);
}

#s-connected[data-ended='true'] .talk-ended-again {
  border: 0;
  background: var(--stage-primary);
  color: #fff;
  font-size: 19px;
  font-weight: 600;
}

#s-connected[data-ended='true'] .talk-ended-again:hover { filter: brightness(1.15); }

#s-connected[data-ended='true'] .talk-ended-email,
#s-connected[data-ended='true'] .talk-ended-home {
  border: 1px solid var(--stage-hairline);
  background: transparent;
  color: var(--stage-accent);
  font-size: 18px;
  font-weight: 600;
}

#s-connected[data-ended='true'] .talk-ended-email:hover,
#s-connected[data-ended='true'] .talk-ended-home:hover { background: var(--stage-secondary-hover); }

/* The line the email pill draws. It is a STATUS about a request, and NOTHING IS SENT until PLAN-174
   builds a sender: public/web/design/NOTES.md 2.11 tells the designer so. */
#s-connected[data-ended='true'] .talk-ended-sent {
  margin: 0;
  padding: 12px 20px;
  border-radius: var(--r-pill);
  background: var(--stage-bar);
  color: var(--stage-accent);
  font-size: 18px;
}

#s-connected[data-ended='true'] .talk-ended-sent[hidden] { display: none; }

/*
  PLAN-179 T-13b (the gallery review), corrected in T-13c AGAINST THE PROTOTYPE'S OWN FRAME.

  THE REVIEWER'S WORDS: "the build keeps the header's left group (clock, code, copy, info) where
  Screen 7 hides that group."

  T-13b hid the whole group. Then T-13c reached the prototype's Screen 7 for the first time (its
  navigator has no '12', so every earlier gallery had shot Screen 3 instead and nobody had seen the
  real frame) and the real frame is NOT an empty header: it reads "14:07 | Tomas and Simona", and
  the right side carries only the avatar. So the reviewer's list is right about three of its four
  items and the group itself stays:

    the time      STAYS      it is the only clock on the screen
    the rule      STAYS      it separates the time from the names
    the code      GOES       there is no meeting to join any more
    the copy      GOES       so does the link it copied
    the info      GOES       "about this call" is about a call that is running
    the switcher  GOES       nothing is being translated any more
    the names     ARRIVE     the design puts "Tomas and Simona" where the code was

  The names are the element the call has always written (#connected-names, "Tomas and Simona"), kept
  for a screen reader and never shown; on this one screen the design shows it, so it is taken out of
  .visually-hidden here and given the code's own type.
*/
.lh-stage-shell[data-ended='true'] .stage-code,
.lh-stage-shell[data-ended='true'] .stage-copy,
.lh-stage-shell[data-ended='true'] .stage-info,
.lh-stage-shell[data-ended='true'] #stage-switcher { display: none; }

.lh-stage-shell[data-ended='true'] #connected-names {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip: auto;
  clip-path: none;
  max-width: 40vw;
  color: var(--stage-ink);
  font-size: 20px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 719px) {
  #s-connected[data-ended='true'] .talk-ended-title { font-size: 28px; }

  /*
    PLAN-179 T-14d (the gallery review, the number that was left): AND THE PILLS ARE AS WIDE AS THE
    SCREEN LETS THEM BE, SO THE SENTENCE STAYS ON ONE LINE.

    Measured in the regenerated gallery: at 390 the email pill was 58 px where the other two were 56,
    because "Send me what was said by email" needs about 303 px at 18/600 and the pill was 302 - the
    column is 342 wide there and took 20 px off each side. It wrapped to two lines and the pill grew.
    The prototype's own Screen 7 at 390 draws that sentence on ONE line in a 56 px pill about 350 px
    wide, 20 px off each edge of the screen.

    So on a phone the column keeps its top and bottom air and gives its sides to the pills: 342 px of
    pill starting 24 px from the edge, which is the design's picture within four pixels and which
    puts the sentence back on one line. The laptop's 24px 20px 32px is untouched.
  */
  #s-connected[data-ended='true'] .talk-screen-ended { padding-left: 0; padding-right: 0; }
}

/* =================================================================================================
   PLAN-180 T-1 (D1, F1): THE CALL HEADER, WHICH IS THE SAME FOUR SLOTS WITH THE CALL'S OWN FOUR
   THINGS IN THEM.

   The design's Screen 6 header: the CALL LENGTH mm:ss in the time slot, the 1 x 24 rule, "{host}
   and {guest}" where the meeting code stands on Screen 3, and a 44 px info button. So the length
   and the names take the clock's and the code's own sizes - 20px/600, the length tabular so its
   digits do not dance - and app.js swaps which pair is drawn with the screen (paintStageHeader).

   The length is #c4c7c5 while it is clipped for a screen reader and the header's own ink when it is
   drawn: the design's time slot is the header ink, and a muted number beside a full-ink name reads
   as a footnote to it.
   ================================================================================================= */
.stage-chip .stage-timer:not(.visually-hidden) {
  color: var(--stage-ink);
  font-size: 20px;
  font-weight: 600;
}

.stage-chip .names:not(.visually-hidden) {
  max-width: 40vw;
  font-size: 20px;
}

.stage-chip .names[hidden],
.stage-chip .stage-timer[hidden] { display: none; }

/* PLAN-180 T-1 (D1, F1): THE INFO BUTTON AT THE DESIGN'S OWN SIZE, WHICH IS A 44 PX TARGET.

   The design: "info button 44x44 round transparent with bold 'i' 20px #c4c7c5 (hover #2a2b2e)". It
   was a 28 px circle with a 1 px border and an italic 18 px letter, which is PLAN-160's Meet capture
   and PLAN-169's floor argument (a 28 px circle round an 18 px character). Both of those answers go
   away at once here: 44 px is the design's target and 20 px is over the 18 px floor with room to
   spare, so U-07 and U-08 are satisfied by the design's own numbers rather than by a compromise.

   It is written AFTER the two blocks that size the button above (the T-6b/T-14 block and the
   PLAN-169 floor block), so at equal weight this is the rule that wins. */
.stage-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-muted);
  font-size: 20px;
  font-style: normal;
  font-weight: 700;
  line-height: 1;
  transition: background-color var(--t-hover), color var(--t-hover);
}

.stage-info:hover { border-color: transparent; background: #2a2b2e; color: var(--stage-ink-muted); }

/* =================================================================================================
   PLAN-180 T-2 (D2, F2): THE PICTURE, AND THE THREE THINGS THE DESIGN DRAWS IN IT.

   1. THE PICTURE IS THE STAGE AREA, NOT A BOX INSIDE IT. The gallery review of 2026-09-13 (its
      finding 1): "the stage at 1100 is a flat black box inset 16 px covering the README's gradient,
      rings and initial circle". That box is .video-tiles, which PLAN-159 T-1 gave Meet's own 16 px
      inset, 24 px clip and #000 ground out of the owner's capture. The design of record draws the
      picture as the stage area itself - margin 0 12, radius 20, #000, which .lh-stage-area already
      is - and puts the placeholder UNDER the picture rather than behind an opaque rectangle. So the
      tile box loses its inset, its radius and its ground, and becomes exactly what it is: the frame
      the two video elements sit in.

   2. THE CAMERA-OFF FACE is the design's: the placeholder gradient, a column centred with a 12 px
      gap and 140 px of padding under it (so the face sits above the band), the 112 px circle in the
      primary blue with their initial at 48px/600, their name at 20 px on the avatar ink, and
      "Camera off" at 18 px muted. It was a 132 px grey circle on a flat #0a2334 tile with no third
      line, which is PLAN-159's Meet capture.

   3. THE CONNECTING SCREEN and THE NAME CHIP are new, and every value in them is the prototype's.
   ================================================================================================= */

.video-tiles {
  inset: 0;
  border-radius: 0;
  background: transparent;
}

/* AND THE PICTURE ELEMENT ITSELF IS NOT A BLACK RECTANGLE EITHER. It is object-fit:cover, so a
   playing picture fills its box and the ground is never seen; an element with no stream yet, or one
   the page has hidden, must let the placeholder under it through. */
.video-remote { background: transparent; }

/* =================================================================================================
   PLAN-181 T-1 (D1, F1): THE HOST'S OWN PICTURE, AT THE SIZE OF THE PICTURE AREA.

   The big picture area IS the stage (PLAN-180 T-2 point 1 took .video-tiles' 16 px inset, its radius
   and its ground away), so the own picture takes the same box: inset 0, cover, and the mirror every
   self view on this page has - a person raising their right hand expects the hand on the right to
   move, and nothing about the transform reaches the track the other person receives.

   IT IS TRANSPARENT AND IT IS UNDER EVERYTHING. The ground under it is the design's placeholder
   gradient, which is what stands where there is no picture (F1); a black ground here would have
   covered the gradient with the letterbox bars of a 4:3 camera in a 16:9 area, which is exactly the
   black rectangle PLAN-180 T-2 removed. z-index is left alone so the DOM order decides: the
   placeholder is the stage's first child and is painted under this, and the tile column (z-index
   auto, later in the DOM), the connecting screen (1), the self tile (3) and the card are over it.
   ================================================================================================= */

.video-self-big {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  object-fit: cover;
  transform: scaleX(-1);
}

.video-self-big[hidden] { display: none; }

/* =================================================================================================
   PLAN-181 T-3 (D3, F3): AND NOBODY ELSE'S CAMERA-OFF FACE STANDS OVER YOUR OWN PICTURE.

   .stage-avatar is the OTHER person's face when they have no picture, and it covers the whole stage.
   While the big picture is your own it must not be drawn at all, and that has to hold in the windows
   where no repaint runs - MEASURED between the guest arriving (which ends the link screen's own rule
   hiding this element) and the first InCall that repaints the stage: the host's own full-screen
   picture was covered by an empty camera-off face for about two seconds.

   A SIBLING RULE RATHER THAN A FLAG, so it cannot race a repaint: #video-self-big is the stage's
   first element and #stage-avatar comes after it, so "the own picture is up" is a fact the
   stylesheet can read for itself.
   ================================================================================================= */

.video-self-big:not([hidden]) ~ .stage-avatar { display: none; }

/* =================================================================================================
   PLAN-181 T-3 (D4, F4): THE CONNECTING WORDS OVER A PICTURE THAT IS ALREADY THERE.

   D4: "before the host's first frame the guest sees themselves big (their preview) with the
   connecting words over it". The design's connecting picture stands on the placeholder gradient and
   is opaque, which is right when the stage under it is empty; over a person's own face it would be
   the page putting a grey rectangle where their picture is. wire.js writes data-over-picture
   whenever #video-self-big is really playing, and the ground becomes a scrim instead: dark enough
   for the white circles and the 24 px line to keep their contrast, thin enough that a person can see
   it is still their own camera underneath.
   ================================================================================================= */

.lh-connecting[data-over-picture='true'] { background: rgba(19, 19, 20, 0.62); }

.stage-avatar {
  inset: 0;
  border-radius: 0;
  gap: 12px;
  padding-bottom: 140px;
  background: var(--stage-placeholder);
}

.stage-initial {
  width: 112px;
  height: 112px;
  background: var(--stage-avatar);
  color: var(--stage-avatar-ink);
  font-size: 48px;
}

.stage-avatar-name { font-size: 20px; color: var(--stage-ink-avatar-name); }

.stage-avatar-off {
  margin: 0;
  color: var(--stage-ink-muted);
  font-size: 18px;
}

/* THE FIRST FOUR SECONDS (README Screen 6). Over the picture and under the chip and the self tile,
   which is the order the prototype draws them in. */
.lh-connecting {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  background: var(--stage-placeholder);
  pointer-events: none;
}

.lh-connecting[hidden] { display: none; }

.lh-connecting-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 22px;
}

/* The two rings are 220 px on lhripple, the second delayed 1.2 s over a 2.4 s cycle: the connecting
   screen's own tempo, which is faster than the link screen's 3 s wave because something is
   happening rather than nothing. */
.lh-connecting-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 220px;
  height: 220px;
  margin: -110px 0 0 -110px;
  border: 2px solid rgba(168, 199, 250, 0.35);
  border-radius: 50%;
  animation: lhripple 2.4s ease-out infinite;
}

.lh-connecting-ring:nth-of-type(2) { animation-delay: 1.2s; }

.lh-connecting-mine,
.lh-connecting-theirs {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  font-size: 32px;
  font-weight: 600;
}

.lh-connecting-mine { background: var(--stage-own); color: var(--stage-own-ink); }
.lh-connecting-theirs { background: var(--stage-avatar); color: var(--stage-avatar-ink); }

.lh-connecting-dots {
  position: relative;
  display: flex;
  gap: 8px;
}

.lh-connecting-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--stage-accent);
  animation: lhdot 1.2s ease-in-out infinite;
}

.lh-connecting-dots span:nth-child(2) { animation-delay: 0.2s; }
.lh-connecting-dots span:nth-child(3) { animation-delay: 0.4s; }

.lh-connecting-line {
  margin: 0;
  color: var(--stage-ink-avatar-name);
  font-size: 20px;
  text-align: center;
  text-wrap: pretty;
}

/* THE NAME CHIP. The one thing the design draws on the picture itself, and the place a phone reads
   the call length from (the phone header has no left group at all). */
.lh-name-chip {
  position: absolute;
  left: 16px;
  top: 16px;
  z-index: 2;
  margin: 0;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--overlay-name-chip);
  color: #fff;
  font-size: 18px;
  font-weight: 500;
}

.lh-name-chip[hidden] { display: none; }

/* The length is drawn on a phone and nowhere else, because on a laptop the header's own left group
   carries it and two clocks on one screen is one clock too many. */
.lh-name-chip-time { display: none; }

@media (max-width: 719px) {
  .lh-name-chip-time {
    display: inline;
    margin-left: 10px;
    color: var(--stage-ink-muted);
    font-variant-numeric: tabular-nums;
  }
}

/* =================================================================================================
   PLAN-180 T-2b (D2, F2): THE LOWER BAND IS THE DESIGN'S, AND IT HOLDS ONLY THE CALLOUT.

   README Screen 6: "Lower band: absolute bottom, column centred, gap 8, padding 36px 12px 12px,
   gradient to top. Contains only the callout (if any). No captions on the picture. No status pill."

   THE OWNER'S OWN ITEM 3 of 2026-09-13 is the defect this answers: the captions overlapped the
   camera on and off messages. Two things were being drawn in one strip over the bottom of the
   picture and they took each other's space. The design's answer is that only one of them belongs
   there: every spoken line now has a home in the Conversation panel (D5), out of the same store the
   band was reading.

   The caption box, the phone's one-line reading and the status line are not drawn ANYWHERE on the
   picture from here on. talk/captions.js still writes its own element and conversation.js is still
   told every line through the same onLine; what changed is where a person reads them. The elements
   stay in the call fragment talk/screens.js built them in, and the three rules below take them off
   the screen so a fragment that is laid out as a column cannot draw them under the picture either.

   THE BAND TAKES NO POINTER EVENTS and the callout inside it does, which is the prototype's own
   arrangement: a full-width gradient over the bottom third of the picture that swallowed presses
   would take the self tile's drag with it (NOTES.md 1.6.2 F-8).
   ================================================================================================= */

.stage-lower {
  gap: 8px;
  padding: 36px 12px 12px;
  background: var(--overlay-lower);
}

/* The captions, the phone's one line and the status pill: OFF THE PICTURE at every width, and kept
   for a screen reader rather than deleted.

   The design removes the PILL and the caption band, not the sentences. "You can talk now", "Your
   microphone is off" and the last thing that was said are exactly the sentences a person who cannot
   see the picture most needs, and talk/captions.js and talk/screens.js go on writing all three. So
   they are clipped the way every other screen-reader-only line on this page is (.visually-hidden's
   own rules), which is also what keeps thirteen harness rows that wait on "You can talk now" true:
   a clipped line is still rendered and still in innerText, and a display:none one is neither.

   The same treatment the header's names and length got at T-1, in the other direction. */
.stage-captions,
.conv-line,
.talk-fragment .talk-captions,
.talk-fragment .talk-status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  /* AND THEY KEEP THE FLOOR. The status line's own rule is 17 px and the band it used to stand in
     raised it; out of that band it fell back, and harness U-07 read "6 element(s) still render text
     under 18 px" over lines nobody can see. A clipped line has no size to a screen reader, so this
     costs nothing and keeps the floor's exception list empty, which is the whole point of it. */
  font-size: 18px;
}

/* THE CALL SCREEN'S CALLOUT, WHICH IS THE HALF PLAN-179 T-16a LEFT FOR THIS PART IN AS MANY WORDS
   ("The call screen's callout is PLAN-180's row and this part does not touch it").

   PLAN-178 T-12 built the design's box as a WRAPPER (.lh-callout: up to 640 wide, the 14/14/14/18
   padding, the hairline, the radius, the shadow) around the column four modules write into. The
   column still carried `position: absolute`, its own ground, border, radius, shadow and padding from
   the days when IT was the callout, which is why it floated out of its own box. On the link screen
   PLAN-179 neutralised it; on the call screen it is neutralised HERE, and the box simply stands in
   the band as one of its centred children, which is what the design draws.

   THIS IS ALSO THE END OF THE STRAY PILL the gallery review measured as finding 1 ("a stray empty
   42 x 31 callout-coloured pill at the stage's bottom edge"). A column with no chrome of its own and
   nothing visible in it draws nothing, whether or not a box has been built round it yet: the 42 x 31
   was the column's own border, ground and 16 px of padding round a set of hidden children. */
.stage-notices {
  position: static;
  left: auto;
  bottom: auto;
  transform: none;
  z-index: auto;
  gap: 2px;
  align-items: flex-start;
  width: auto;
  max-width: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
}

/* =================================================================================================
   PLAN-180 T-3 (D3, F3): THE SELF TILE, AT THE DESIGN'S SIZE, IN THE DESIGN'S CORNER, WITH NO WORD
   ON IT.

   The gallery review of 2026-09-13, finding 2: "the self tile is 190 x 253 at the bottom right with
   a 'You' label". Three things wrong with one element, and the design says all three: 22 per cent of
   the picture's width clamped between 96 and 190, 4/3 on a laptop and 3/4 on a phone, the DEFAULT
   corner bottom-LEFT, and no text of any kind on it.

   THE OFFSETS ARE THE DESIGN'S CONSTANTS, not a measurement of the band. PLAN-159 T-6 lifted the
   tile by --lower-band-h because the band held the captions and the status pill and grew with them;
   the band holds only the callout now (T-2b) and the design gives the tile a fixed 84 px of
   clearance (96 on a phone), which is what "so it clears the band" means when the band's height is
   known. The safe-area inset stays: a phone's own chin is not part of the design's arithmetic.

   THE TILE IS THE BOX AND THE PICTURE IS INSIDE IT, so the camera-off state can be the design's -
   #0a2334 with a 40 px circle carrying your own initial - rather than an element that goes away.
   ================================================================================================= */

.lh-self-tile {
  position: absolute;
  left: 12px;
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 22%;
  min-width: 96px;
  max-width: 190px;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--r-self-tile);
  /* The prototype draws a striped placeholder here because a drawing cannot hold a camera; the
     product has a real one, and the stripes are what stands under it until the first frame arrives.
     public/web/design/NOTES.md 2.13 says so for the designer. */
  background: repeating-linear-gradient(135deg, #1f2226 0 14px, #191c20 14px 28px);
  box-shadow: var(--shadow-self-tile);
  cursor: grab;
  touch-action: none;
  user-select: none;
  /* The token is the WHOLE transition value (all four offsets at 200 ms ease), not one duration, so
     it is used whole. Naming a property in front of it made an invalid list and the harness read the
     snap as 0s. */
  transition: var(--t-self-snap);
}

.lh-self-tile[hidden] { display: none; }

/* YOUR CAMERA IS OFF: the tile stays, and it says so with your own initial rather than by vanishing. */
.lh-self-tile[data-camera='off'] { background: #0a2334; }

.lh-self-initial {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--stage-own);
  color: var(--stage-own-ink);
  font-size: 18px;
  font-weight: 600;
  line-height: 1;
}

.lh-self-tile[data-camera='off'] .lh-self-initial { display: flex; }

/* The picture inside the box. MIRRORED, because a self view is a mirror: a person raising their
   right hand expects the hand on the right of the tile to move. The picture the OTHER person
   receives is not mirrored; this is a display transform and nothing about it reaches the track. */
.video-self {
  position: static;
  right: auto;
  bottom: auto;
  width: 100%;
  height: 100%;
  max-width: none;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  object-fit: cover;
  transform: scaleX(-1);
}

@media (max-width: 719px) {
  /* A phone's tile is 3/4, and it clears a taller bar. */
  .lh-self-tile {
    aspect-ratio: 3 / 4;
    bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  }
}

/* =================================================================================================
   PLAN-180 T-4 (D3, F3): THE FOUR CORNERS, AND THE SNAP BETWEEN THEM.

   The corner a person left the tile in is ONE attribute, and the offsets that place it are here
   rather than in wire.js, which is what keeps the phone's own 96 px and the safe-area inset in the
   stylesheet with every other size on this page. The 200 ms is the transition already declared on
   the tile's four offsets (--t-self-snap), so the snap is the browser's own animation and no timer
   in the page has to agree with it.

   WHILE A DRAG IS RUNNING the tile carries data-dragging and wire.js writes left and top in pixels;
   the transition is off for exactly that time, because a tile that eased towards the finger would
   lag behind it.
   ================================================================================================= */

.lh-self-tile[data-corner='bottom-left'] {
  left: 12px;
  right: auto;
  top: auto;
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
}

.lh-self-tile[data-corner='bottom-right'] {
  left: auto;
  right: 12px;
  top: auto;
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
}

.lh-self-tile[data-corner='top-left'] {
  left: 12px;
  right: auto;
  top: 12px;
  bottom: auto;
}

.lh-self-tile[data-corner='top-right'] {
  left: auto;
  right: 12px;
  top: 12px;
  bottom: auto;
}

.lh-self-tile[data-dragging='true'] {
  transition: none;
  cursor: grabbing;
}

@media (max-width: 719px) {
  .lh-self-tile[data-corner='bottom-left'],
  .lh-self-tile[data-corner='bottom-right'] {
    bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  }
}

/* =================================================================================================
   PLAN-180 T-5 (D4, F4): THE HELD PILL IS ONE COLOUR AND ONE SENTENCE.

   README, Screen 6: "mouse-down/touch-start -> holding: bg #154a9f, label 'Speaking... {n}s'". One
   darker blue over the whole pill for as long as a person is speaking, and nothing else drawn on it.

   TWO THINGS THE PHONE HAD GO, and they are named rather than dropped quietly. PLAN-159 T-3 drew the
   phone's own two decorations on this pill at the owner's word "the same like in mobile": a white
   wash whose WIDTH was the remaining time, and the phone's red #dc2626 over the last ten seconds.
   The design of record draws neither - it gives the held pill one colour and puts the remaining time
   in words - and "no changes to copy, order, sizes or colours" is the contract's own last line. The
   fact both of them carried, how much of this turn is left, is the sentence itself now, which is a
   thing a person can read rather than a length they have to judge.

   The count span stays and carries the whole held sentence; the pill's own resting word is put back
   the moment the hold stops (wire.js holdCountStop).
   ================================================================================================= */

.talk-bar .talk-hold[data-holding='true'] {
  background: #154a9f;
  color: #ffffff;
}

/* The wash and the last-ten-seconds red are not drawn at all. The elements stay: .hold-fill is the
   span wire.js appends and its rows still pin it, and a rule that removed it would mean a module
   change where a stylesheet change will do. */
.talk-bar .talk-hold .hold-fill { display: none; }

.talk-bar .talk-hold[data-warn='true'] {
  background: #154a9f;
  color: #ffffff;
}

/* The held sentence is the pill's whole label now, so it needs no separator from a resting word that
   is not being drawn beside it. */
.talk-bar .talk-hold .hold-count { margin-left: 0; }

/* =================================================================================================
   PLAN-180 T-5b (D4, F4): THE PILL SAYS THE CALL IS DIRECT, AND THE CHIP THAT USED TO IS NOT DRAWN.

   README, Screen 6: "When translation is off the pill reads 'Talking directly' with bg #333537 and
   is not pressable." One control in the middle of the bar in three states - blue at rest, darker
   blue while it is held, the round-button grey when there is no translation to hold for - rather
   than two elements swapping places.

   The chip is kept in the markup (talk/screens.js owns it and the next call_mode still finds it) and
   never drawn: a hidden element costs nothing and removing it would mean a module change.
   ================================================================================================= */

.talk-bar .talk-hold[data-direct='true'] {
  background: var(--stage-round);
  color: var(--stage-ink-panel);
  cursor: default;
}

.talk-bar .direct-chip { display: none; }

/* =================================================================================================
   PLAN-180 T-6 (D4, F4): THE UNREAD BADGE, AT THE DESIGN'S SIZE.

   README, Screen 6: "unread badge: absolute top 0, right 0, min-width 22, height 22, radius 11, 2px
   border #1e1f20, bg #db372d, white 14px/700, count."

   THE ONE VALUE THAT IS NOT TAKEN IS THE 14 PX, and it is named rather than quietly changed. This
   product has a text floor of 18 px (PLAN-157 section 6, the owner's own elderly-first rule, pinned
   by harness U-07 with an exceptions list that must stay empty), and a 14 px number on a control is
   exactly the kind of small text that floor exists for. Everything else is the design's: the 22 px
   box, the radius, the 2 px ring in the bar's own colour that separates the badge from the button
   under it, the red, the white and the 700. The count is one or two characters, so an 18 px number
   sits inside a 22 px circle with the padding growing it for a three-digit conversation.
   public/web/design/NOTES.md 1.6.2 F-12 says so for the designer.

   It is written after both earlier rules (PLAN-159's 22 px at 13 px, and PLAN-169's floor rule at
   26 px), so at equal weight this is the one that wins.
   ================================================================================================= */

.talk-bar .talk-chat-badge {
  top: 0;
  right: 0;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  box-sizing: border-box;
  border: 2px solid var(--stage-bar);
  border-radius: 11px;
  background: var(--stage-red);
  color: #ffffff;
  font-size: 18px;
  font-weight: 700;
  line-height: 18px;
}

/* =================================================================================================
   PLAN-180 T-6 (D4, F4): THE TWO PANEL BUTTONS SAY WHETHER THEIR PANEL IS OPEN.

   README, Screen 6: "Chat -> toggles Conversation panel; when open the button is #a8c7fa/#062e6f"
   and "More -> toggles More panel (button #a8c7fa/#062e6f while open)". The design's ON pair, the
   same one the language pickers and every other ON state on this page use.

   IT IS THE aria-pressed THE PAGE ALREADY WRITES. renderChat sets it on the chat button on every
   render, and talk/screens.js sets it on More when its panel opens, so the colour follows the state
   rather than a second flag that could disagree with it - which is the rule PLAN-155 T-3 wrote for
   the microphone and the camera and the reason their OFF colours have never drifted.
   ================================================================================================= */

.talk-bar .talk-chat[aria-pressed='true'],
.talk-bar .talk-more[aria-pressed='true'] {
  background: var(--stage-accent);
  color: var(--stage-accent-ground);
}

/* =================================================================================================
   PLAN-180 T-6b (D2, F2): THE PHONE'S LINK COLUMN SCROLLS.

   THE OWNER, on staging, 2026-09-13, his item 2: on the phone "Show QR code to connect" opens the
   code below the fold and the page will not scroll to it, so the QR and the Ask-me row cannot be
   reached at all.

   MEASURED ON THIS BUILD at 390 x 844 (harness PR-32): the code ends at 522 of 844, so it already
   fits here and the two items he photographed are STAGING's page, which serves PLAN-160's. That is
   written down rather than quietly claimed as a fix: the emulated frame is not his phone. A real
   phone gives the page less height than 844 - the browser's own chrome takes a bar at each end - and
   the card grows with the language, so the same card can still run past the bottom on his screen.

   So the column is made scrollable for the case, which is what he asked for and costs nothing when
   the content fits. It is scoped to the LINK screen on a phone, where the design draws no picture,
   no black ground and no radius (NOTES.md 1.5.2 E-12): there is nothing there for `overflow: hidden`
   to be clipping, which is the reason the stage area carries it everywhere else.
   ================================================================================================= */

@media (max-width: 719px) {
  .lh-stage-shell[data-link='true'] .lh-stage-area {
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* =============================================================================================
     PLAN-204 T-7 (A8, D9, F7): AND THE ENDED SCREEN SCROLLS FOR THE SAME REASON - AT EVERY WIDTH.

     PLAN-218 T-7 (D6, F6) MOVED THE TWO DECLARATIONS OUT OF THIS MEDIA QUERY, leaving the reasoning
     where it was written. The deploy-2 review (web-design reviewer, Important 75) found that the
     scroll path existed only under 719 px, while `.lh-stage-area { overflow: hidden }` still stood
     at 720 and above: so the 720 to 899 band, and a short desktop window at any width, kept the Copy
     pill below the fold with no way to reach it. The sentence below ("above it the column fits") is
     true of a TALL window and not of a short one, which is the half that was missed. The rule now
     stands at the top level, a few lines down, under the same selector.

     THE FINDING: when a call ends and the record could not be emailed, the ended column carries the
     sentence, a 200 px box with the whole conversation in it, the Copy pill and the "copy it now"
     line. MEASURED at 390 x 844 on this build before the rule: the column is 973 px inside a 788 px
     box, the Copy pill's own rectangle ends at 931, and ten wheel turns over the stage area moved it
     0 -> 0 because `.lh-stage-area` carries `overflow: hidden` for every screen but the link one.
     The one thing that screen exists to offer could not be reached at all.

     IT IS THE SAME RULE AS THE LINK SCREEN'S ABOVE, on the flag wire.js already mirrors onto the
     shell for exactly this kind of reach (`data-ended`, wire.js dropTheEndedScreen drops it again).
     IT USED TO BE SCOPED UNDER 719 because above it the column was taken to fit and the stage is a
     picture `overflow: hidden` is there to clip - and that reasoning holds for a TALL window only,
     which is what PLAN-218 T-7 corrected. When the ended column fits, `auto` shows nothing at all,
     so the wider scope costs the laptop nothing; and on the ended screen there is no picture, so
     there was nothing there for `hidden` to be clipping either.
     ============================================================================================= */
}

/* PLAN-218 T-7 (D6, F6): the ended screen's scroll, at EVERY width. The block inside the 719 media
   query above holds the reasoning and says why it moved. `auto` shows nothing at all when the
   column fits, which is the usual case on a laptop - what it buys is the short window, where the
   Copy pill the screen exists to offer was unreachable. */
.lh-stage-shell[data-ended='true'] .lh-stage-area {
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* =================================================================================================
   PLAN-180 T-7 (D5, F5): THE PANEL SHELL, AT THE DESIGN'S OWN TWO SHAPES.

   README "Panels": "laptop: right column 340px, radius 20, bg #202124, grid rows auto/1fr/auto, sits
   beside the picture with 12px gap; the bar shifts left by 352px. Narrow/phone: bottom sheet 76%
   tall, radius 20 20 0 0, dim rgba(0,0,0,.5), 40x4 grab bar, shadow 0 -8px 28px rgba(0,0,0,.45).
   Only one panel open at a time."

   IT HANGS FROM THE PICTURE'S BOX NOW (wire.js buildChat): `#stage-area` is the design's picture,
   it is already positioned, and everything a phone sheet has to cover is inside it. What that buys
   is that both shapes are one rule each instead of an arithmetic of header heights.

   THE 352 IS 340 PLUS THE 12 PX GAP, and it is the SAME number in both places: the picture gives up
   352 px of its own right side (`#s-connected` padding-right) and the panel is 340 wide against the
   picture box's right edge, so the gap between them is 12 by construction rather than by agreement
   between two numbers.
   ================================================================================================= */

.chat-panel {
  position: absolute;
  inset: auto 0 0 auto;
  top: 0;
  right: 0;
  bottom: 0;
  left: auto;
  width: 340px;
  max-width: 340px;
  height: auto;
  border-radius: var(--r-panel);
}

/* The dim is the phone sheet's, and it is drawn nowhere else: on a laptop the panel is a column
   beside the picture and there is nothing to dim. */
.lh-panel-dim {
  position: absolute;
  inset: 0;
  z-index: 7;
  display: none;
  background: var(--overlay-dim);
}

.lh-panel-dim[hidden] { display: none; }

/* The header is a COLUMN of two things at every width - the grab bar and the row the title and the X
   share - and the grab bar is drawn only where the panel is a sheet. */
.chat-panel .chat-head {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  /* The design's own 12 and 16. The safe-area top inset that used to be added here belonged to a
     sheet that filled the screen; this one is 76 per cent of the picture and is pinned to its BOTTOM
     edge, so there is no notch above it to clear. */
  padding: 12px 16px;
}

.chat-panel .chat-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
}

.chat-panel .chat-grab { display: none; }

/* THE HEADER'S X, AT THE DESIGN'S SIZE AND WITH NO WORD ON IT (the contract's own last law: "No text
   labels on icon buttons"). The word is kept, clipped, in the .bar-words span chat/panel.js appends,
   which is the same pattern every dressed button in the bottom bar uses. */
.chat-panel .chat-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: 56px;
  min-width: 56px;
  height: 56px;
  min-height: 56px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--panel-ink);
  transition: background-color var(--t-hover);
}

.chat-panel .chat-close:hover { background: rgba(168, 199, 250, 0.12); }
.chat-panel .chat-close-x { display: inline-flex; font-size: 0; }
.chat-panel .chat-close-x svg { width: 26px; height: 26px; }

@media (min-width: 900px) {
  /* The picture gives up the column's width AND the gap, in the one place the two are added up. */
  /* PLAN-219 T-4 (D4): and the same for the More panel, in the rule that actually wins at 900 and
     up. This block is the min-width one ONLY: the 720 to 899 band keeps its own rules untouched,
     where the panel is a sheet under the bar rather than a column beside it. */
  #s-connected[data-chat='open'] { padding-right: 352px; }
  #s-connected[data-more='open'] { padding-right: 352px; }
}

@media (max-width: 899px) {
  /* A SHEET, 76 per cent of the picture's own box, pinned to its bottom edge. It was a FULL screen
     (inset 0, 100dvh), which is PLAN-157's answer to "on mobile if i on messages to chat - it brakes
     screen and i cant of it"; the design's answer to the same thing is the grab bar, the 56 px X and
     the dim, with a quarter of the picture still visible above it so a person can see they are still
     in the call. */
  .chat-panel {
    inset: auto 0 0 0;
    top: auto;
    /* SEVENTY-SIX PER CENT OF THE FRAME, which is the design's own measure ("measured on the frame,
       not the window", README Breakpoints). The panel hangs from the picture box, and that box is
       the frame LESS the header, so a plain 76 per cent of it drew 70 per cent of the frame and the
       harness read it. dvh is the one that shrinks when a phone's keyboard comes up; vh is written
       first as the fallback, and max-height keeps the sheet inside the box it hangs from on a frame
       too short for either. */
    height: 76vh;
    height: 76dvh;
    max-height: 100%;
    width: auto;
    max-width: none;
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.45);
  }

  .lh-panel-dim { display: block; }

  .chat-panel .chat-head { padding: 10px 16px; }

  .chat-panel .chat-grab {
    display: block;
    align-self: center;
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: var(--stage-hairline);
  }
}

/* =================================================================================================
   PLAN-180 T-7b (D5, F5): EVERY PHONE PICKER IS THE DESIGN'S BOTTOM SHEET, AND THE KNOCK CARD DOES
   NOT STAND ON THE BAR.

   THE GALLERY REVIEW of 2026-09-13, finding 5: "the phone microphone picker floats 184 px above the
   bottom, 366 wide inset 12, while the language sheet is full bleed at the bottom". Two pickers,
   two shapes, one design: "Phone pickers: bottom sheet inside the frame: dim rgba(0,0,0,.5), sheet
   left/right/bottom 0, padding 8px 12px 24px, radius 20 20 0 0, 40x4 grab bar #444746 at top, same
   rows" (README, Screen 6). PLAN-179's rows are re-pinned onto this: the box, the rows, the tick,
   the level row and the settings row are all unchanged and are still theirs; where the box SITS on a
   phone is what this rule fixes, for all four of them at once rather than for the two that happened
   to be written that way.

   AND THE KNOCK CARD'S OWN HOST clears the bar. It is the host used only where there is no panel to
   put the card in - a host alone on the link screen - and it was pinned to the frame's bottom edge,
   over the one control that cancels the meeting. The card asks a question with two buttons on it;
   the bar underneath must still be reachable while it is being asked (finding 4's second half).
   ================================================================================================= */

@media (max-width: 719px) {
  .lh-picker {
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    transform: none;
    width: auto;
    max-width: none;
    padding: 8px 12px calc(24px + env(safe-area-inset-bottom, 0px));
    border-radius: var(--r-panel) var(--r-panel) 0 0;
  }

  /* The language pickers' fixed top is a laptop's rule; on a phone every picker is the same sheet.
     PLAN-207c T-6 (D7, F6): and so is the BAR's, for the same reason and with the same specificity
     problem - `.lh-picker[data-place='bar']` is (0,2,0) and beats the bare `.lh-picker` above
     whatever the order, so without this line the microphone and camera pickers kept the laptop's
     "stand above the bar" position on a phone while every other picker became a bottom sheet. */
  .lh-picker[data-place='header'],
  .lh-picker[data-place='bar'] {
    position: fixed;
    top: auto;
    bottom: 0;
  }

  /* THE CARD GOES TO THE TOP OF THE PICTURE ON A PHONE, which is where the laptop's host already
     puts it. A bottom sheet is the design's shape for the PANEL, and the panel is what this host
     stands in for while there is no call to build one; pinned to the bottom edge it covered the
     phone bar, whose two rows are about 190 px tall, and no constant above the bar is true for both
     of its states (harness PR-34 measured the host ending at 748 with the bar starting at 656). At
     the top it is fully visible and every control under it stays reachable, which is what the
     review's finding 4 is about. */
  .lh-knock-host {
    position: absolute;
    top: 12px;
    left: 12px;
    right: 12px;
    bottom: auto;
    width: auto;
    max-width: none;
    border-radius: var(--r-panel);
  }
}

/* =================================================================================================
   PLAN-180 T-8 (D5, F5): THE CONVERSATION BODY, AT THE DESIGN'S OWN VALUES.

   README "Conversation body": "Column gap 14, padding 8. Empty: 'Nothing has been said or written
   yet.' 19px #c4c7c5. Line: meta row 18px #c4c7c5 (name, optional Typed badge 26px round
   rgba(168,199,250,.16) with 16px keyboard icon #a8c7fa, time) then bubble padding 12px 16px,
   19px/1.45, pre-wrap: mine bg #5b93f0 ink #0d1117 radius 18 18 6 18 right-aligned; theirs spoken
   #303134 / typed #3c4043, ink #e3e3e3, radius 18 18 18 6 left-aligned; max-width 94%. System line
   as in Screen 5."

   THE ONE THING THE PAGE DID NOT HAVE IS THE THIRD SKIN. A thing somebody SAID and a thing somebody
   TYPED were one colour with a word beside them; the design gives them two grounds, #303134 and
   #3c4043, and keeps the badge as well. conversation.js already marks every entry `.conv-spoken` or
   `.conv-typed`, so this is a rule rather than a module change.

   THE SYSTEM LINE IS SCREEN 5's, which PLAN-179 T-10 built for the link screen: a centred pill on
   the field ground with an 8 px green dot and the text and the time joined by a middle dot. It was a
   full-width band on the hairline grey. One shape for one kind of line, on both screens.
   ================================================================================================= */

.chat-lines { padding: 8px; }

.chat-line { max-width: 94%; }

/* THEIRS, IN TWO SKINS: what they said, and what they typed. */
/* #3c4043, which the token set calls the own-initial ground, is the design's TYPED ground here. The
   field grey #2b2c2f is a shade lighter and is the system pill's; the first draft used it and the
   harness read rgb(43, 44, 47) against the design's rgb(60, 64, 67). */
.chat-theirs.conv-typed .chat-body { background: var(--stage-own); }

/* THE TYPED BADGE. A 26 px circle with a 16 px keyboard in it, and the word it used to draw is its
   accessible name (conversation.js). */
.conv-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  background: rgba(168, 199, 250, 0.16);
  color: var(--stage-accent);
  font-size: 0;
}

.conv-tag svg { width: 16px; height: 16px; }

/* THE SYSTEM LINE, WHICH IS SCREEN 5's PILL. Centred, on the field ground, with the green dot the
   link screen's own system line carries, and no bubble tail either way. */
.chat-line.chat-system { max-width: 100%; }

.chat-system .chat-body {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: var(--stage-field);
  color: var(--stage-ink-muted);
  font-size: 18px;
}

.chat-system .chat-body::before {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--stage-success);
}

/* =================================================================================================
   PLAN-180 T-9 (D5, F5): THE COMPOSER, WHICH IS ONE FIELD WITH THE PLANE INSIDE IT.

   README: "input type text 56 tall, padding 0 60px 0 20px, 1px #444746, radius 999, transparent,
   #e3e3e3 19px, placeholder 'Send a message', focus border #a8c7fa no outline, maxlength 2000; send
   button absolute right 6 centred 44x44 round transparent, paper-plane outline 26px, colour #9aa0a6
   when empty / #a8c7fa when text, hover rgba(168,199,250,.12)."

   THE PLANE MOVES INSIDE THE FIELD, which is why the field has 60 px of padding on its right: the
   two were a two-column grid with the button beside the box, and the design puts the button over the
   end of the box. So the composer becomes a relative wrapper with one absolutely placed child, and
   the field's own right padding is what keeps the words from running under it.

   THE COLOUR OF THE PLANE IS THE STATE OF THE DRAFT, and it is read from the field itself with
   `:placeholder-shown`, so no module has to tell the stylesheet whether anybody has typed anything:
   an empty field shows its placeholder and the plane is the muted grey; the first character hides
   the placeholder and the plane takes the accent.
   ================================================================================================= */

.chat-compose {
  position: relative;
  display: block;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
}

.chat-write {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 56px;
  max-height: none;
  padding: 0 60px 0 20px;
  line-height: 1.4;
}

.chat-write:focus {
  border-color: var(--stage-accent);
  outline: none;
}

/*
  PLAN-180 T-20 (bugcheck round 1, codex on p2, finding 1): MEASURED FROM THE FIELD'S OWN BOTTOM
  EDGE, NOT FROM THE MIDDLE OF A PADDED BOX.

  The composer's padding is not symmetrical - 12 at the top and 12 plus the phone's safe-area inset
  at the bottom, 24 plus it under 900 px - so `top: 50%` of the composer is NOT the middle of the
  input inside it: on a phone with a 34 px inset the button sat about 23 px low and hung below the
  field. The input is 56 tall and the button is 44, so the button's own bottom is exactly 6 px above
  the field's bottom, and the field's bottom is the composer's own bottom padding. Both numbers are
  the ones written right here, so there is nothing to keep in step.
*/
.chat-send {
  position: absolute;
  right: 22px;
  top: auto;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  transform: none;
  width: 44px;
  height: 44px;
  background: transparent;
  color: #9aa0a6;
  transition: background-color var(--t-hover), color var(--t-hover);
}

@media (max-width: 899px) {
  .chat-send { bottom: calc(30px + env(safe-area-inset-bottom, 0px)); }
}

.chat-send:hover { background: rgba(168, 199, 250, 0.12); }
.chat-send-glyph { display: inline-flex; font-size: 0; }
.chat-send-glyph svg { width: 26px; height: 26px; }

/* THE DRAFT'S OWN STATE, read off the field. */
.chat-compose:has(.chat-write:placeholder-shown) .chat-send { color: #9aa0a6; }
.chat-compose:has(.chat-write:not(:placeholder-shown)) .chat-send { color: var(--stage-accent); }

/* The phone keeps the design's deeper bottom padding (12 16 24). */
@media (max-width: 899px) {
  .chat-compose { padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }
}

/* =================================================================================================
   PLAN-180 T-10 (D5, F5): THE MORE BODY, IN THE PANEL THE CONVERSATION IS IN.

   README "More body": "Rows 64 tall, 19px, radius 12, hover #2a2b2e: switch row 'Read the
   translation aloud'; switch row 'Show their own words too'; (phone only) switch row 'Translation';
   row 'Language you hear / {English}' with the chevron; 1px rule; h3 'Sound check' 20px/700; the
   microphone line + 8px level bar; 'Their voice: ...'; 'Read aloud: ...'; rule; row 'Settings'."
   And the switch itself: "52x32, track #444746 / #a8c7fa, thumb 24 #e3e3e3 / #062e6f, left 4 / 24,
   120ms".

   THE SHEET IS THE SAME ELEMENT talk/screens.js has always built, moved into the panel shell by
   wire.js with its own title and Close taken up into the panel's header. Nothing in that module is
   edited: what changes here is the SHAPE of the rows it draws, which has been this stylesheet's half
   of that boundary since PLAN-153.

   THE TWO TOGGLES BECOME SWITCHES. They are buttons carrying `aria-pressed`, which is the state the
   design's switch draws, so the track and the thumb are drawn from that attribute with no second
   flag to disagree with it and no change to what the module writes.
   ================================================================================================= */

.lh-more-panel[hidden] { display: none; }

.lh-more-body { padding: 8px 8px 16px; gap: 2px; }

#more-panel .talk-sheet {
  position: static;
  inset: auto;
  width: auto;
  max-width: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Every row in the body is the design's row.
   PLAN-205 T-4 (D5, F4): .talk-sheet-noise joins them here and in every switch rule below. The
   "Reduce background noise" switch arrived with PLAN-187 T-11b and this stylesheet never heard of
   it (grep -c talk-sheet-noise app.css was 0), so it drew as a bare button between two rows drawn
   as switches - the owner's own Sound-sheet finding of 2026-09-14. It joins the SAME rules rather
   than getting copies of them, so the three switches cannot drift apart. */
#more-panel .talk-sheet-read,
#more-panel .talk-sheet-original,
#more-panel .talk-sheet-noise,
#more-panel .talk-sheet-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 64px;
  padding: 8px 12px;
  border: 0;
  border-radius: var(--r-menu-row);
  background: transparent;
  color: var(--stage-ink-panel);
  font: inherit;
  font-size: 19px;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-hover);
}

#more-panel .talk-sheet-read:hover,
#more-panel .talk-sheet-original:hover,
#more-panel .talk-sheet-noise:hover,
#more-panel .talk-sheet-row:hover { background: #2a2b2e; }

/* THE MODULE'S OWN CLOSE, ONCE IT IS IN THE PANEL'S HEADER, is the panel's X: 56 px round with the
   word clipped, exactly as the Conversation panel's is. It is NOT one of the body's rows - it was in
   that list in the first cut and the harness read it 308 x 64, the width of a row. */
#more-panel .chat-head-row .talk-sheet-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  min-width: 56px;
  height: 56px;
  min-height: 56px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--stage-ink-panel);
  transition: background-color var(--t-hover);
}

#more-panel .chat-head-row .talk-sheet-close:hover { background: rgba(168, 199, 250, 0.12); }

/* The X itself, drawn rather than written, because the module's word is a word. */
#more-panel .chat-head-row .talk-sheet-close::before {
  content: '';
  width: 26px;
  height: 26px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6l12 12M18 6L6 18' stroke='black' stroke-width='2.2' stroke-linecap='round' fill='none'/></svg>") center / 26px 26px no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6l12 12M18 6L6 18' stroke='black' stroke-width='2.2' stroke-linecap='round' fill='none'/></svg>") center / 26px 26px no-repeat;
}

/* THE SWITCH, drawn on the button's own aria-pressed. The track is the button's ::after and the
   thumb its ::before, so the module's text node stays exactly where it is. */
#more-panel .talk-sheet-read::after,
#more-panel .talk-sheet-original::after,
#more-panel .talk-sheet-noise::after {
  content: '';
  flex: 0 0 auto;
  order: 2;
  width: 52px;
  height: 32px;
  border-radius: 16px;
  background: var(--stage-hairline);
  transition: background-color var(--t-hover);
}

#more-panel .talk-sheet-read::before,
#more-panel .talk-sheet-original::before,
#more-panel .talk-sheet-noise::before {
  content: '';
  position: absolute;
  order: 3;
  width: 24px;
  height: 24px;
  margin: 4px 0 0 4px;
  border-radius: 50%;
  background: var(--stage-ink-panel);
  /* PLAN-180 T-20 (bugcheck round 1, codex on p2, finding 2): the thumb is placed from the RIGHT
     here (the track is an ::after at the end of the row), so `right` is the property that has to be
     animated. It transitioned `left`, which never changes, and the thumb jumped. */
  transition: right var(--t-switch-thumb), background-color var(--t-hover);
}

#more-panel .talk-sheet-read,
#more-panel .talk-sheet-original,
#more-panel .talk-sheet-noise { position: relative; }

#more-panel .talk-sheet-read::before { right: 36px; }
#more-panel .talk-sheet-original::before { right: 36px; }
#more-panel .talk-sheet-noise::before { right: 36px; }

#more-panel .talk-sheet-read[aria-pressed='true']::after,
#more-panel .talk-sheet-original[aria-pressed='true']::after,
#more-panel .talk-sheet-noise[aria-pressed='true']::after { background: var(--stage-accent); }

#more-panel .talk-sheet-read[aria-pressed='true']::before,
#more-panel .talk-sheet-original[aria-pressed='true']::before,
#more-panel .talk-sheet-noise[aria-pressed='true']::before {
  right: 16px;
  background: var(--stage-accent-ground);
}

/* The Sound check block: a heading at 20/700 and three lines a person READS. */
#more-panel .talk-sheet-sound { display: flex; flex-direction: column; gap: 6px; }

#more-panel .talk-sound-title {
  margin: 12px 0 8px;
  font-size: 20px;
  font-weight: 700;
  color: var(--stage-ink);
}

#more-panel .talk-sound-line {
  margin: 0;
  padding: 8px 12px;
  font-size: 18px;
  color: var(--stage-ink-panel);
}

/* A title left in the BODY is the one that is not drawn: wire.js takes the module's own title up
   into the panel's header, and a second one under it would be the same word twice. Scoped to the
   body, because the first cut was not and hid the header's title as well - the panel had no title at
   all, which is what the T-16 walk caught ("the title | 1100: not drawn | 390: not drawn") while
   PR-36 read its textContent and passed. */
#more-panel .lh-more-body .talk-sheet-title { display: none; }

/* =================================================================================================
   PLAN-180 T-11 (D6, F6): THE SETTINGS BODY.

   README "Settings body": the field "Your name" (an input like Register but on #2b2c2f behind
   #444746); h3 "Languages" 20px/700 margin 8 0 8 with the two selects and "The language of this
   page" with its help line 18px #c4c7c5; a 1 px #444746 separator at margin 20 0 0 with the next h3
   at margin 20 0 8; h3 "Sound" with the read-aloud switch and "Which microphone to use" plus the
   level bar; h3 "Camera" with "Which camera to use" and the "Start calls with my camera on" switch.
   Every control is 56 px tall, every select carries the design's own 24 px chevron, and there is no
   Save button anywhere.

   THE HEAR SELECT'S WARNING IS A BORDER AND NOTHING ELSE: "hear border 2px #ff9b7d when equal to
   speak, NO error text here". The Register screen keeps its sentence, because there a person is
   choosing for the first time; here they are changing one thing and the border is the whole message.
   ================================================================================================= */

.lh-set-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 0;
}

.lh-set-label { font-size: 18px; font-weight: 600; color: var(--stage-ink-panel); }

.lh-set-help { margin: 0; font-size: 18px; color: var(--stage-ink-muted); }

.lh-set-heading {
  margin: 8px 0 8px;
  font-size: 20px;
  font-weight: 700;
  color: var(--stage-ink);
}

.lh-set-rule {
  display: block;
  height: 1px;
  margin: 20px 0 0;
  background: var(--stage-hairline);
}

.lh-set-rule + .lh-set-heading { margin: 20px 0 8px; }

.lh-set-input,
.lh-set-select {
  width: 100%;
  box-sizing: border-box;
  min-height: 56px;
  padding: 12px 14px;
  border: 1px solid var(--stage-hairline);
  border-radius: var(--r-field);
  background: var(--stage-field);
  color: var(--stage-ink-panel);
  font: inherit;
  font-size: 18px;
}

/* The design's own chevron, drawn rather than the browser's, at the right of every select. */
.lh-set-select {
  padding-right: 52px;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 9l6 6 6-6' stroke='%23a5aebd' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 24px 24px;
}

/* THE ONE WARNING IN THIS BODY, and it is a border. */
.lh-set-select[data-same='true'] { border: 2px solid var(--stage-warn); }

.lh-set-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 64px;
  padding: 8px 0;
  border-radius: var(--r-menu-row);
  font-size: 19px;
  cursor: pointer;
}

.lh-set-switch {
  position: relative;
  flex: 0 0 auto;
  width: 52px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 16px;
  background: var(--stage-hairline);
  cursor: pointer;
  transition: background-color var(--t-hover);
}

.lh-set-switch[aria-checked='true'] { background: var(--stage-accent); }

.lh-set-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--stage-ink-panel);
  transition: left var(--t-switch-thumb), background-color var(--t-hover);
}

.lh-set-switch[aria-checked='true'] .lh-set-thumb { left: 24px; background: var(--stage-accent-ground); }

/* The level bar under the microphone select, which is PLAN-160's own meter at the design's size. */
.lh-set-level {
  display: block;
  height: 8px;
  border-radius: 4px;
  background: var(--stage-hairline);
  overflow: hidden;
}

.lh-set-level-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 4px;
  background: var(--stage-accent);
  transition: width var(--t-mic-level);
}

/* =================================================================================================
   PLAN-180 T-13 (D7, F8): THE ENDED SCREEN'S PILLS ARE THE PROTOTYPE'S 360 AND 12.

   THE GALLERY REVIEW of 2026-09-13, its finding 6: "the ended screen's pills are 320 wide with a
   16 px gap against the prototype's 360 and 12 (and 342 against 350 at 390); the reason sentence
   wraps to two lines where the prototype keeps one".

   MEASURED CAUSE: the ended column carries `max-width: 360` AND `padding: 24px 20px 32px`, so the
   pills inside it can only ever be 320. The prototype has TWO columns - the page's own, padded, and
   a button column of max-width 360 inside it - and this page draws the pills as siblings of the
   title, so the outer column takes the button column's width PLUS its own padding: 400.

   The gap is the other half. The prototype's page column is 16 and its button column is 12, and one
   flex column cannot be both; the 12 is put between the PILLS, where the design puts it, by giving
   each pill after the first a negative top margin of the difference. That is the whole of it: the
   reason sentence keeps the 16 above the first pill and the three pills sit 12 apart.
   ================================================================================================= */

#s-connected[data-ended='true'] .talk-screen-ended { max-width: 400px; }

#s-connected[data-ended='true'] .talk-ended-email,
#s-connected[data-ended='true'] .talk-ended-home { margin-top: -4px; }

/* =================================================================================================
   PLAN-174 T-8 - THE RECORD: the two switches in the More sheet, and the private Copy block on the
   ended screen.

   The switches borrow the sheet's own row shape, so they look like the two switches above them and
   nobody has to learn a new control. The Copy block is DELIBERATELY PLAIN: a read-only textarea in
   the stage's own colours, a filled Copy button, and one quiet line under it. It is the last place a
   person can get the words of their call, so it must be readable before it is pretty.
   ================================================================================================= */

.talk-sheet-record {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}

/* PLAN-218 T-7 (D6, F6): 18px, the floor the same pass applied to this rule's two neighbours
   (.talk-sheet-record-summary and -script, both 18 above) while these two stayed at 15 (deploy-2
   review, web-design reviewer, Important 75). */
.talk-sheet-record-title {
  margin: 4px 0 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--stage-ink-muted);
  text-transform: none;
}

.talk-sheet-record-summary,
.talk-sheet-record-script {
  min-height: 56px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--r-pill, 28px);
  background: var(--stage-bar, #26282c);
  color: var(--stage-ink-panel);
  font: inherit;
  font-size: 18px;
  text-align: left;
  cursor: pointer;
}

.talk-sheet-record-summary[aria-pressed='true'],
.talk-sheet-record-script[aria-pressed='true'] {
  background: var(--stage-accent, #8ab4f8);
  color: var(--stage-accent-ground);
  font-weight: 600;
}

.talk-sheet-record-summary[disabled],
.talk-sheet-record-script[disabled] { opacity: 0.45; cursor: default; }

/* PLAN-218 T-7 (D6, F6): 18px, with its title above. This is the line that says WHERE the record
   goes - the address a person checks before pressing - so it is not the line to shrink. */
.talk-sheet-record-to {
  margin: 0 0 4px;
  padding: 0 4px;
  font-size: 18px;
  color: var(--stage-ink-muted);
  word-break: break-word;
}

#s-connected[data-ended='true'] .talk-ended-record {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  margin-top: 4px;
  text-align: left;
}

#s-connected[data-ended='true'] .talk-ended-record[hidden] { display: none; }

#s-connected[data-ended='true'] .talk-ended-record-why {
  margin: 0;
  font-size: 18px;
  color: var(--stage-accent, #8ab4f8);
}

#s-connected[data-ended='true'] .talk-ended-record-text {
  width: 100%;
  min-height: 200px;
  padding: 12px;
  box-sizing: border-box;
  border: 1px solid var(--stage-hairline);
  border-radius: 12px;
  background: var(--stage-bar, #26282c);
  color: var(--stage-ink-panel);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* PLAN-204 T-7 (D9, F7): 14 px was the smallest type on any screen of this product, in the ONE box
     a person has to read their whole conversation out of. 18 px is the floor this design sets. */
  font-size: 18px;
  line-height: 1.5;
  resize: vertical;
}

#s-connected[data-ended='true'] .talk-ended-record-copy {
  min-height: 56px;
  border: 0;
  border-radius: var(--r-pill, 28px);
  background: var(--stage-accent, #8ab4f8);
  color: var(--stage-accent-ground);
  font: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

#s-connected[data-ended='true'] .talk-ended-record-keep {
  margin: 0;
  /* PLAN-204 T-7 (D9, F7): the line that says to copy it NOW, at the same 18 px floor. */
  font-size: 18px;
  color: var(--stage-ink-muted);
}
