/* Live, his side: the ring and chip on her face, the banner, the player
   pinned on her thread, the Tonight row and the public teaser.
   docs/internal/specs/uptoyouka-live.md. */
:root { --ukl-red: #ff2d55; --ukl-ink: #fff; --ukl-shade: rgba(0, 0, 0, .55); }

/* THE RING on any face while she is live, and the chip that says so. */
.uk-live-ring { position: relative; display: inline-block; border-radius: 50%;
  box-shadow: 0 0 0 2px var(--utyk-bg, #fff), 0 0 0 4px var(--ukl-red); }
.uk-live-pill { display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px;
  border-radius: 999px; background: var(--ukl-red); color: #fff; font-size: 11px;
  font-weight: 800; letter-spacing: .04em; text-decoration: none; line-height: 1.5; }
.uk-live-pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #fff;
  animation: ukl-blink 1.4s ease-in-out infinite; }
@keyframes ukl-blink { 50% { opacity: .25; } }
/* Spin (docs/internal/specs/uptoyouka-live-spin.md): a Spin live's badge. */
.uk-spin-badge { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 999px;
  background: #ff4f8b; color: #fff; font-size: 11px; font-weight: 800; letter-spacing: .04em; line-height: 1.5; }
.tn-livehero .uk-spin-badge { position: absolute; left: 64px; top: 10px; font-size: 12px; padding: 3px 9px; }
@media (prefers-reduced-motion: reduce) { .uk-live-pill::before { animation: none; } }

/* THE BANNER, top of every page, tappable. */
.ukl-banner { position: fixed; z-index: 9700; left: 50%; top: max(10px, env(safe-area-inset-top, 0px));
  transform: translate(-50%, -140%); transition: transform .28s ease; width: min(440px, calc(100vw - 24px));
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 16px;
  background: #16121a; color: #fff; box-shadow: 0 10px 30px rgba(0, 0, 0, .35); text-decoration: none; }
.ukl-banner.is-in { transform: translate(-50%, 0); }
.ukl-banner-faces { display: flex; flex-shrink: 0; }
.ukl-banner-faces img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--ukl-red); background: #333; }
.ukl-banner-faces img + img { margin-left: -14px; }
.ukl-banner-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 14px; }
.ukl-banner-txt b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ukl-banner-txt small { opacity: .75; font-size: 12px; }
.ukl-banner-x { flex-shrink: 0; width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .12); color: #fff; font-size: 18px; line-height: 1; cursor: pointer; }


/* THE PLAYER. Her stream is portrait, 540x960, so the stage is a 9:16 box,
   never a wide box that crops her face. Contain by default; an upright
   picture fills a phone's screen and a desktop's 9:16 box (cover, below). */
.ukl { background: #000; color: var(--ukl-ink); display: flex; flex-direction: column; }
/* Only her picture gives way when the column is short: a row with its own
   sideways scroll (the openers, the bar strip) would otherwise shrink to a
   sliver (owner, 2026-10-20: the chips under Say hi cut off). */
.ukl > :not(.ukl-stage) { flex-shrink: 0; }
/* `display` above beats the [hidden] the end puts on it: say it again. */
.ukl[hidden] { display: none !important; }
/* And every part of it: several parts set `display`, which beat `hidden`
   (the Ask chips and the openers showed while she was live). */
.ukl [hidden] { display: none !important; }
.ukl-stage { position: relative; overflow: hidden; background: #000; }
.ukl video { width: 100%; height: 100%; object-fit: contain; background: #000; display: block; }
/* A 9:16 stage is narrow: the place and bar get their own line under the
   pill and the button rather than being squeezed to nothing. */
.ukl-top { position: absolute; inset: 0 0 auto 0; display: flex; flex-wrap: wrap; row-gap: 4px; align-items: center;
  gap: 5px; padding: 8px; background: linear-gradient(rgba(0, 0, 0, .55), transparent); font-size: 12px; }
.ukl-top .uk-live-pill { margin-right: auto; }
.ukl-where { order: 9; flex: 1 0 100%; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ukl-btn { border: 0; border-radius: 999px; padding: 4px 9px; background: var(--ukl-shade);
  color: #fff; font: inherit; font-weight: 700; cursor: pointer; }
.ukl-btn[aria-pressed="true"] { background: #fff; color: #000; }
/* The subtitles hint: a bubble hanging under the button, once (live-player.js). */
.ukl-ccwrap { position: relative; display: inline-flex; }
.ukl-cchint { position: absolute; top: calc(100% + 8px); left: 0; z-index: 5; width: max-content; max-width: 210px;
  padding: 8px 11px; border: 0; border-radius: 10px; background: #fff; color: #000; font: inherit; font-weight: 700;
  text-align: left; line-height: 1.3; cursor: pointer; box-shadow: 0 4px 14px rgba(0, 0, 0, .4); }
.ukl-cchint::before { content: ""; position: absolute; top: -5px; left: 16px; width: 10px; height: 10px;
  background: #fff; transform: rotate(45deg); }
/* HIS VOLUME (LivePlayer.volume): the toggle never turns white like CC, and
   it stays away while "Tap to hear her" says the same thing. The slider is
   there only where the browser lets a page set the volume (never iOS), and
   only with a mouse or trackpad: a phone has its volume buttons, and no
   room in this row. It drops down under the toggle on hover or focus, so
   the narrow row never wraps for it. */
.ukl-vol { position: relative; display: inline-flex; }
.ukl-vol .ukl-btn[aria-pressed] { background: var(--ukl-shade); color: #fff; }
.ukl-vol input { position: absolute; top: 100%; right: 0; z-index: 4; width: 96px; height: 28px; margin: 0;
  accent-color: #fff; filter: drop-shadow(0 0 3px rgba(0, 0, 0, .9)); cursor: pointer; opacity: 0; pointer-events: none; }
.ukl-vol:hover input, .ukl-vol:focus-within input { opacity: 1; pointer-events: auto; }
.ukl-stage:has(> .ukl-sound:not(.is-small):not([hidden])) .ukl-vol { display: none; }
@media (hover: none), (pointer: coarse) { .ukl-vol input { display: none; } }
.ukl-also { position: absolute; left: 8px; top: 62px; display: flex; gap: 6px; }
.ukl-also a img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; }
/* HIS FIRST TAP brings her sound: big in the middle at first; after 4 s
   (`.is-small`, live-player.js) it goes, and the muted sound button in the
   top row pulses gently in its place until he hears her (owner, 2026-10-22). */
.ukl-sound { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  padding: 14px 22px; font-size: 17px; background: rgba(0, 0, 0, .7); box-shadow: 0 4px 18px rgba(0, 0, 0, .4);
  transition: all .3s ease; z-index: 3; white-space: nowrap; }
.ukl-sound.is-small { display: none; }
.ukl-stage:has(> .ukl-sound.is-small:not([hidden])) .ukl-vol .ukl-btn { animation: ukl-pulse 1.8s ease-in-out infinite;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .35); }
/* Transform only: a moving box-shadow repaints the button every frame. */
@keyframes ukl-pulse { 50% { transform: scale(1.12); } }
@media (prefers-reduced-motion: reduce) {
  .ukl-stage:has(> .ukl-sound.is-small:not([hidden])) .ukl-vol .ukl-btn { animation: none; box-shadow: 0 0 0 2px #fff; } }
/* The room's heart meter, along the bottom of her picture. */
.ukl-meter { position: absolute; left: 8px; right: 8px; bottom: 8px; display: flex; align-items: center; gap: 6px;
  font-size: 12px; pointer-events: none; z-index: 3; }
.ukl-meter i { flex: 1; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, .25); overflow: hidden; }
.ukl-meter b { display: block; height: 100%; width: 0; background: var(--ukl-red); transition: width .4s ease; }
.ukl:not([data-state="live"]):not([data-state="weak"]) .ukl-meter { display: none; }
.ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-meter { right: calc(min(96px, 22%) + 16px); }
/* FREE TAPS under her picture: Say hi, then the reactions. */
.ukl-acts { display: flex; align-items: center; gap: 8px; padding: 8px 12px 4px; background: #111; }
.ukl-hi { flex: none; border: 0; border-radius: 999px; padding: 8px 14px; background: #fff; color: #000;
  font: inherit; font-size: 14px; font-weight: 800; cursor: pointer; white-space: nowrap; }
.ukl-hi:disabled { background: #2c2c2e; color: #fff; cursor: default; }
.ukl-rxrow { flex: 1; display: flex; justify-content: space-around; gap: 2px; min-width: 0; }
.ukl-rxrow button { border: 0; background: none; font-size: 22px; line-height: 1; padding: 6px; cursor: pointer;
  border-radius: 50%; touch-action: manipulation; }
.ukl-rxrow button:active { transform: scale(1.25); }
.ukl-openers { display: flex; gap: 6px; overflow-x: auto; padding: 4px 12px 6px; background: #111; }
.ukl-openers button { flex: none; border: 1px solid #444; border-radius: 999px; padding: 5px 12px; background: none;
  color: #fff; font: inherit; font-size: 13px; cursor: pointer; white-space: nowrap; }
/* RELEASES 2 AND 3 (engagement spec): Ask her… beside Say hi, its two
   chips in the openers' row style; the reactions close up to make room. */
.ukl-acts .ukl-hi { padding: 8px 12px; }
.ukl-hi.ukl-askbtn { background: #2c2c2e; color: #fff; font-variant-numeric: tabular-nums; }
.ukl-hi.ukl-askbtn:disabled { opacity: .75; }
.ukl-rxrow button { padding: 6px 1px; }
/* A narrow column (a longer language, a short desktop) wraps the reactions
   under the two buttons rather than squeezing them or widening the column. */
.ukl-acts { flex-wrap: wrap; }
.ukl-acts .ukl-rxrow { flex: 1 0 auto; }
@media (min-width: 900px) { .tp-card.ukl-on > #ukLive .ukl-acts { width: 0; min-width: 100%; } }
/* The honest counter: a chip beside the LIVE pill, the real numbers, never
   cut short (a longer language wraps the buttons after it instead). */
.ukl-watching { padding: 2px 8px; border-radius: 999px; background: var(--ukl-shade); font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.ukl-top .uk-live-pill:has(+ .ukl-watching:not([hidden])) { margin-right: 0; }
.ukl-top .ukl-watching { margin-right: auto; }
/* The drink moment, big in the middle of her picture for 4 s; somebody's
   request, a smaller line above it for 3 s. Neither takes a tap. */
.ukl-moment { position: absolute; left: 6%; right: 6%; top: 50%; transform: translateY(-50%); margin: 0; z-index: 5;
  text-align: center; font-size: 26px; font-weight: 800; line-height: 1.2; text-shadow: 0 2px 8px rgba(0, 0, 0, .85);
  pointer-events: none; animation: ukl-pop .35s ease-out; }
@keyframes ukl-pop { from { transform: translateY(-50%) scale(.6); opacity: 0; } }
.ukl-asked { position: absolute; left: 50%; top: 28%; transform: translateX(-50%); margin: 0; z-index: 5; max-width: 86%;
  padding: 6px 12px; border-radius: 999px; background: rgba(0, 0, 0, .72); font-size: 13px; font-weight: 700;
  text-align: center; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .ukl-moment { animation: none; } }
/* Her Thai quiz, under her picture: about 80px, so his thread stays. */
.ukl-quiz { flex: none; padding: 6px 12px 0; background: #111; }
.ukl-q-head { display: flex; align-items: baseline; gap: 6px; min-width: 0; margin: 0 0 5px; font-size: 13px; }
.ukl-q-head b { font-size: 20px; line-height: 1.1; }
.ukl-q-head span { opacity: .8; font-style: italic; }
.ukl-q-head small { margin-left: auto; color: #ffd23f; font-size: 12px; font-weight: 700; text-align: right; }
.ukl-quiz[data-q="result"] .ukl-q-head :is(b, span) { display: none; }
.ukl-quiz[data-q="result"] .ukl-q-head small { margin-left: 0; color: #fff; font-size: 13px; text-align: left; }
.ukl-q-choices { display: flex; gap: 6px; }
.ukl-q-choices button { flex: 1 1 0; min-width: 0; min-height: 36px; padding: 4px 6px; border: 1px solid #444;
  border-radius: 10px; background: #1c1c1e; color: #fff; font: inherit; font-size: 13px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; touch-action: manipulation; }
.ukl-q-choices button:disabled { cursor: default; }
.ukl-q-choices button.mine { border-color: #fff; background: #3a3a3c; }
.ukl-q-choices button.right { border-color: #30d158; background: #1f5f2e; }
.ukl-q-choices button.right::after { content: " ✓"; }
.ukl-q-choices button.wrong { border-color: #ff453a; background: #5f1f1f; }
.ukl-q-choices button.wrong::after { content: " ✗"; }
.ukl-q-bar { display: block; height: 4px; margin: 6px -12px 0; background: rgba(255, 255, 255, .12); }
.ukl-q-bar b { display: block; width: 100%; height: 100%; background: #ffd23f; }
.ukl-quiz[data-q="result"] .ukl-q-bar b { visibility: hidden; }
.ukl-sayname { display: inline-flex; align-items: center; gap: 4px; margin-left: 4px; white-space: nowrap; cursor: pointer; }
.ukl-sayname input { margin: 0; }
/* Before she is live the free taps keep their place, unseen, so his thread
   does not jump at her first frame. */
.ukl:not([data-state="live"]):not([data-state="weak"]):not([data-state="paused"]) .ukl-acts { visibility: hidden; }
.ukl:not([data-state="live"]):not([data-state="weak"]):not([data-state="paused"]) .ukl-openers { display: none; }
/* His camera: himself, small and mirrored, in the corner; the ask over the
   middle of her video. */
.ukl video.ukl-self { position: absolute; right: 8px; bottom: 8px; width: 22%; max-width: 96px; height: auto;
  aspect-ratio: 3 / 4; object-fit: cover; border-radius: 10px; border: 2px solid #fff; transform: scaleX(-1); }
.ukl video.ukl-self[hidden] { display: none; }
.ukl-camask { position: absolute; left: 8px; right: 8px; top: 50%; transform: translateY(-50%); padding: 12px;
  border-radius: 14px; background: rgba(0, 0, 0, .85); text-align: center; font-size: 14px; }
.ukl-camask p { margin: 0 0 4px; font-weight: 700; }
.ukl-camask small { display: block; opacity: .8; }
.ukl-camask-row { display: flex; gap: 8px; justify-content: center; margin-top: 10px; }
.ukl-camask .ukl-btn { padding: 8px 14px; }
.ukl-camask .ukl-btn.go { background: #fff; color: #000; }
.ukl-cap { position: absolute; left: 8%; right: 8%; bottom: 12%; text-align: center; font-size: 15px;
  font-weight: 600; text-shadow: 0 1px 3px #000; }
.ukl-cap span { background: rgba(0, 0, 0, .6); padding: 2px 8px; border-radius: 6px;
  -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.ukl-veil { position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
  flex-direction: column; gap: 8px; padding: 20px; text-align: center; background: rgba(0, 0, 0, .7); }
.ukl-veil p { margin: 0; font-size: 15px; font-weight: 700; }
.ukl-veil small { opacity: .75; }
.ukl[data-state="connecting"] .ukl-veil, .ukl[data-state="paused"] .ukl-veil,
.ukl[data-state="ended"] .ukl-veil, .ukl[data-state="removed"] .ukl-veil { display: flex; }
.ukl[data-state="weak"] .ukl-veil { display: flex; inset: auto 0 0 0; background: var(--ukl-shade); padding: 8px; }
.ukl-veil [data-for] { display: none; }
.ukl[data-state="connecting"] [data-for="connecting"], .ukl[data-state="paused"] [data-for="paused"],
.ukl[data-state="weak"] [data-for="weak"], .ukl[data-state="ended"] [data-for="ended"],
.ukl[data-state="removed"] [data-for="removed"] { display: block; }
.ukl:not([data-state="live"]):not([data-state="weak"]) .ukl-sound,
.ukl:not([data-state="live"]):not([data-state="weak"]) .ukl-cap { display: none; }
.ukl-note { margin: 0; padding: 8px 12px; font-size: 13px; background: #111; color: #ddd; }
.ukl-barbox { background: #111; border-top: 1px solid #222; }
.ukl-strip { display: flex; gap: 10px; overflow-x: auto; padding: 4px 12px 12px; scroll-snap-type: x proximity; }
.ukl-lady { flex: 0 0 auto; width: 92px; display: flex; flex-direction: column; align-items: center; gap: 4px;
  font-size: 12px; text-align: center; scroll-snap-align: start; }
.ukl-lady img { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; background: #333; }
.ukl-lady b { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ukl-lady .ukl-act { width: 100%; padding: 4px 0; border: 0; border-radius: 999px; background: #2c2c2e;
  color: #fff; font: inherit; font-weight: 700; text-decoration: none; cursor: pointer; }
.ukl-lady .ukl-act.drink { background: var(--ukl-red); }
.ukl-cast-h { margin: 0; padding: 6px 12px 0; font-size: 12px; font-weight: 700; }
.ukl-cast .ukl-strip { padding-top: 6px; padding-bottom: 8px; }
.ukl-cast .ukl-lady { width: 88px; }
.ukl-cast .ukl-lady .ukl-act { white-space: nowrap; font-size: 12px; }
.ukl-cast .ukl-lady img { width: 48px; height: 48px; }
.ukl-moretile { border: 0; background: none; color: inherit; font: inherit; cursor: pointer; }
.ukl-moretile b { white-space: normal; font-size: 12px; line-height: 1.2; }
.ukl-moreico { width: 48px; height: 48px; border-radius: 50%; background: #2c2c2e; display: flex;
  align-items: center; justify-content: center; font-size: 26px; font-weight: 700; }

/* INSTANT START (owner, 2026-10-21): her picture over the stage from the
   first paint, a moving bar and "Joining Mint's live…", until her first
   frame (#ukLive[data-ff], live-player.js), then a fade to her video. It
   sits under the veil, so "She stepped away" and the end read over it; the
   connecting veil and "Tap to hear her" wait for the frame. */
.ukl-start { position: absolute; inset: 0; display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: 12px; background: #111; pointer-events: none; transition: opacity .5s ease, visibility .5s; }
.ukl-start img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; }
.ukl-start-say { position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 0;
  max-width: calc(100% - 32px); padding: 6px 12px; border-radius: 12px; background: rgba(0, 0, 0, .5);
  font-size: 14px; text-align: center; text-shadow: 0 1px 3px #000; }
.ukl-start-bar { display: block; width: 140px; max-width: 100%; height: 4px; border-radius: 2px;
  background: rgba(255, 255, 255, .25); overflow: hidden; }
.ukl-start-bar b { display: block; width: 40%; height: 100%; border-radius: 2px; background: var(--ukl-red);
  animation: ukl-slide 1.1s ease-in-out infinite; }
@keyframes ukl-slide { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
#ukLive[data-ff] .ukl-start { opacity: 0; visibility: hidden; }
.ukl:is([data-state="paused"], [data-state="ended"], [data-state="removed"]) .ukl-start-say { display: none; }
.ukl:not([data-ff])[data-state="connecting"] .ukl-veil, .ukl:not([data-ff]) .ukl-sound { display: none; }
/* Her browser refused even a muted start (`data-tap`, live-player.js): no
   moving bar, and "Tap to hear her" big over her picture, since his tap is
   what starts her. */
.ukl[data-tap] .ukl-start-say { display: none; }
.ukl[data-tap]:is([data-state="live"], [data-state="weak"]) .ukl-sound { display: block; }
@media (prefers-reduced-motion: reduce) {
  .ukl-start { transition: none; }
  .ukl-start-bar b { width: 100%; opacity: .7; animation: none; } }

/* THE ROOM'S CHAT (owner, 2026-10-21; js/live-chat.js): over the lower part
   of her picture, never her face: the last 6, newest at the bottom, older
   fading, at most 30% of the stage. Above the meter, and above the bar chip
   or the small sound chip when either shows. Taps go through to her video,
   but for "Original". Her lines, and her bar's ladies', in her red. */
.ukl-chat { position: absolute; left: 8px; bottom: 28px; z-index: 2; width: min(72%, 340px); max-height: 30%;
  display: flex; flex-direction: column; justify-content: flex-end; overflow: hidden; pointer-events: none;
  -webkit-mask-image: linear-gradient(transparent, #000 16px); mask-image: linear-gradient(transparent, #000 16px); }
.ukl-stage:has(> .ukl-barchip:not([hidden])) .ukl-chat { bottom: 46px; }
#ukLive .ukl-stage.is-big .ukl-chat { bottom: max(76px, calc(env(safe-area-inset-bottom, 0px) + 64px)); left: 16px; }
.ukrc-list { display: flex; flex-direction: column; gap: 3px; margin: 0; padding: 0; list-style: none; }
.ukrc-line { align-self: flex-start; max-width: 100%; padding: 3px 8px; border-radius: 10px; background: rgba(0, 0, 0, .45);
  font-size: 13px; line-height: 1.3; text-shadow: 0 1px 2px rgba(0, 0, 0, .6); overflow-wrap: anywhere;
  animation: ukrc-in .25s ease-out; }
.ukrc-line b { font-weight: 700; color: #c9d4ff; }
.ukrc-her { background: rgba(255, 45, 85, .45); }
.ukrc-lady { background: rgba(255, 45, 85, .28); }
.ukrc-her b, .ukrc-lady b { color: #fff; }
.ukrc-pending { font-style: italic; }
.ukrc-list > :nth-last-child(4) { opacity: .85; }
.ukrc-list > :nth-last-child(5) { opacity: .65; }
.ukrc-list > :nth-last-child(6) { opacity: .45; }
.ukrc-orig { margin-left: 6px; padding: 0; border: 0; background: none; color: rgba(255, 255, 255, .7); font: inherit;
  font-size: 11px; text-decoration: underline; cursor: pointer; pointer-events: auto; }
.ukrc-orig[aria-pressed="true"] { color: #fff; }
/* One small line (owner, 2026-10-22), cut short rather than wrapped. */
.ukrc-hint { align-self: flex-start; box-sizing: border-box; max-width: 100%; margin: 3px 0 0; padding: 3px 9px;
  border-radius: 10px; background: rgba(0, 0, 0, .55); font-size: 11.5px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
/* Not while "Tap to hear her" is big in the middle: they would collide. */
.ukl-stage:has(> .ukl-sound:not(.is-small):not([hidden])) .ukrc-hint { visibility: hidden; }
@keyframes ukrc-in { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .ukrc-line { animation: none; } }
/* Her captions step above the chat while it has lines. */
#ukLive .ukl-stage:has(.ukrc-list > li) .ukl-cap { bottom: calc(30% + 34px); }
/* THE BOX under her video: "Chat with everyone". 16px, or iOS zooms in. */
.ukl-chatbox { position: relative; display: flex; gap: 6px; margin: 0; padding: 8px 12px 4px; background: #111; }
.ukl-chatbox input { flex: 1; min-width: 0; height: 36px; padding: 0 12px; border: 1px solid #333; border-radius: 18px;
  background: #1c1c1e; color: #fff; font: inherit; font-size: 16px; text-overflow: ellipsis; }
.ukl-chatbox input:disabled { opacity: .6; }
.ukl-chatbox button { flex: none; display: grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 0;
  border-radius: 50%; background: var(--ukl-red); color: #fff; cursor: pointer; }
.ukrc-status { position: absolute; left: 20px; bottom: 100%; z-index: 3; padding: 3px 9px; border-radius: 8px;
  background: rgba(0, 0, 0, .85); color: #fff; font-size: 12px; }
@media (min-width: 900px) { .tp-card.ukl-on > #ukLive .ukl-chatbox { width: 0; min-width: 100%; } }
/* "Private" over his own composer, so the two boxes are never mixed up. */
.ukl-private { display: flex; align-items: center; gap: 5px; margin: 0; padding: 5px 14px 0; font-size: 11.5px;
  color: var(--t2, #9faac0); }
.ukl-private[hidden] { display: none; }

/* LIVE MODE, ONE TO ONE (owner, 2026-10-18): her video and HIS PRIVATE
   THREAD together. live-player.js gathers the thread's nodes (her messages,
   his composer, the wall) into `.ukl-conv`, which has no box at all until
   the card is in live mode, so the plain thread lays out as it always has.
   A desktop puts the video on the left and the thread on the right; a
   phone has the video on top, the full width, and the thread under it.
   The header stays; Video call goes while she is live. */
.ukl-conv { display: contents; }
.tp-card.ukl-on .tp-head-act[data-onclick="tp-call"], .tp-card.ukl-on #tpActCall { display: none !important; }
.tp-card.ukl-on > #ukLive { flex: none; }
.tp-card.ukl-on .ukl-stage { height: 44vh; }
/* A PHONE (owner, 2026-10-19: "can't scroll", her messages squeezed to a
   sliver): the video fills a box sized to its shape, the line about who
   sees what is one small line, the Play row is compact, and her bar's other
   ladies are a chip over the video, so his thread keeps most of the screen. */
/* WHO IS ON CAMERA (owner, 2026-10-21): her and the ladies with her, a
   face each down the right edge of the video, each a tap to buy HER a
   drink. Above his own camera (bottom right), clear of the top bar. */
.ukl-oncam { position: absolute; right: 8px; top: 56px; z-index: 3; display: flex; flex-direction: column;
  gap: 8px; max-height: calc(100% - 96px); overflow-y: auto; }
.ukl-oncam[hidden] { display: none; }
.ukl-oc { position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; width: 58px;
  padding: 0; border: 0; background: none; color: #fff; cursor: pointer; }
.ukl-oc img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; background: #333;
  border: 2px solid var(--ukl-red); }
.ukl-oc i { position: absolute; top: 26px; right: 0; width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: 50%; background: #fff; font-style: normal; font-size: 13px; line-height: 1; }
.ukl-oc b { max-width: 100%; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .8); }
.ukl-barchip { position: absolute; right: 8px; bottom: 8px; max-width: 70%; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis; padding: 6px 12px; font-size: 13px; }
/* Beside his own camera (the corner picture, `.ukl-self`), never over it;
   gone over the big picture, whose strip it would open out of sight; and
   her captions sit above it. */
.ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-barchip { right: calc(min(96px, 22%) + 16px); max-width: 50%; }
#ukLive .ukl-stage.is-big .ukl-barchip { display: none; }
.ukl-stage:not(.is-big):has(> .ukl-barchip:not([hidden])) .ukl-cap { bottom: calc(12% + 32px); }
.ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-cap { right: calc(min(96px, 22%) + 16px); }
@media (max-width: 899px) {
  /* 4vh each went to the chat box under her picture (2026-10-21), so his
     thread keeps its share. */
  .tp-card.ukl-on .ukl-stage { height: 25vh; }
  .tp-card.ukl-on > #ukLive[data-shape="tall"] .ukl-stage { height: 37vh; }
  .tp-card.ukl-on > #ukLive:has(#ukLiveCast:not([hidden])) .ukl-stage { height: 21vh; }
  /* THE ROOM'S CHAT UNDER HER PICTURE (owner, 2026-10-21: over her face,
     two lines showed): a strip of about four lines between her video and
     the box, newest at the bottom, the older fading out at its top. The
     stage keeps the strip's room below itself (the margin) and lets the
     strip hang into it. Over her picture again when bigger, and in a game,
     whose board needs the height. */
  .tp-card.ukl-on > #ukLive:not([data-game]) .ukl-stage:not(.is-big) { overflow: visible; margin-bottom: 86px; }
  .tp-card.ukl-on > #ukLive:not([data-game]) .ukl-stage:not(.is-big) > .ukl-chat { top: 100%; bottom: auto; left: 0;
    width: auto; right: 0; height: 86px; max-height: none; padding: 4px 12px 2px; }
  .tp-card.ukl-on > #ukLive:not([data-game]) .ukl-stage:not(.is-big) .ukrc-line { padding: 1px 8px; }
  #ukLive:not([data-game]) .ukl-stage:not(.is-big):has(.ukrc-list > li) .ukl-cap { bottom: calc(12% + 32px); }
  /* In a game the board needs the room: the chat stays over her picture,
     its box steps aside until the game is done. */
  .tp-card.ukl-on > #ukLive[data-game] .ukl-chatbox { display: none; }
  /* Cover, biased high so her face stays in; whole (contain) where the box
     is far from her picture's shape: during a game, with the strip open,
     and for an upright picture, whose bottom fifth the near-square box cut
     off (MattHam, 2026-10-20: "couldn't see Ice's bikini"). */
  .tp-card.ukl-on .ukl video { object-fit: cover; object-position: 50% 20%; }
  .tp-card.ukl-on > #ukLive[data-shape="tall"] .ukl-stage > video:not(.ukl-self),
  .tp-card.ukl-on > #ukLive[data-game] .ukl-stage > video:not(.ukl-self),
  .tp-card.ukl-on > #ukLive:has(#ukLiveCast:not([hidden])) .ukl-stage > video:not(.ukl-self) { object-fit: contain; }
  /* In a game the strip is put away, so the chip that opens it goes too. */
  .tp-card.ukl-on > #ukLive[data-game] .ukl-barchip { display: none; }
  .tp-card.ukl-on .ukl-note { padding: 4px 12px; font-size: 11px; line-height: 1.35; color: #aab; }
  .tp-card.ukl-on .ukl-game { padding: 6px 12px; }
  .tp-card.ukl-on .ukl-g-row[data-for="ask"] small { display: none; }
  .tp-card.ukl-on .ukl-g-row[data-for="ask"] .ukl-g-btn { flex: 1 1 auto; min-height: 42px; }
}
.tp-card.ukl-on > .ukl-conv { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
@media (min-width: 900px) {
  /* The video's column is as wide as the 9:16 box at its full height,
     said outright: WebKit sized an `auto` column from the box after the
     column had squeezed it (117px, its buttons wrapping word by word). */
  .tp-card.ukl-on { display: grid; grid-template-columns: minmax(calc(min(75vh, 100vh - 190px) * 9 / 16), auto) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr); }
  .tp-card.ukl-on > .tp-head { grid-column: 1 / -1; }
  .tp-card.ukl-on > #ukLive { grid-column: 1; grid-row: 2; min-height: 0; overflow-y: auto;
    border-right: 1px solid #222; }
  .tp-card.ukl-on .ukl-stage { height: min(75vh, calc(100vh - 190px)); aspect-ratio: 9 / 16; }
  /* An upright picture fills the 9:16 box (cover, trimmed at the sides
     only), as it fills a phone. */
  .tp-card.ukl-on > #ukLive[data-shape="tall"] .ukl-stage:not(.is-big) > video:not(.ukl-self) { object-fit: cover; }
  /* A WIDE PICTURE (owner, 2026-10-19: "wide and not very tall, hard to
     see"): a 9:16 box showed a 4:3 picture as a strip a third of its
     height. The box takes the picture's shape, never narrower than the tall
     box was (nor than the 344px game panel), so nothing gets smaller. `data-shape` is live-player.js's, from the video itself. */
  .tp-card.ukl-on:has(> #ukLive[data-shape="wide"]) { grid-template-columns: clamp(calc(min(75vh, 100vh - 190px) * 9 / 16), 58%, 640px) minmax(0, 1fr); }
  .tp-card.ukl-on:has(> #ukLive[data-shape="wide"][data-game]) { grid-template-columns: clamp(max(345px, calc(min(75vh, 100vh - 190px) * 9 / 16)), 58%, 640px) minmax(0, 1fr); }
  /* WITH A SIDE PANEL FOLDED (owner, 2026-10-21: the inbox or her details
     on /chat) the conversation is far wider, so a wide picture's 640px cap
     goes to 960px; 58% still leaves his thread the rest. An upright one is
     already as tall as the column allows. */
  :is(body.uk-ctx-off, body.uk-inbox-off) .tp-card.ukl-on:has(> #ukLive[data-shape="wide"]) { grid-template-columns: clamp(calc(min(75vh, 100vh - 190px) * 9 / 16), 58%, 960px) minmax(0, 1fr); }
  :is(body.uk-ctx-off, body.uk-inbox-off) .tp-card.ukl-on:has(> #ukLive[data-shape="wide"][data-game]) { grid-template-columns: clamp(max(345px, calc(min(75vh, 100vh - 190px) * 9 / 16)), 58%, 960px) minmax(0, 1fr); }
  /* FOUR IN A ROW STAYS 2.1.564's (owner, 2026-10-21: the 344px panel
     spread its columns apart): its 320px panel, in the column it had then. */
  .tp-card.ukl-on:has(> #ukLive[data-game][data-kind="four"]:not([data-shape="wide"])) { grid-template-columns: auto minmax(0, 1fr); }
  .tp-card.ukl-on:has(> #ukLive[data-shape="wide"][data-game][data-kind="four"]) { grid-template-columns: clamp(max(321px, calc(min(75vh, 100vh - 190px) * 9 / 16)), 58%, 640px) minmax(0, 1fr); }
  :is(body.uk-ctx-off, body.uk-inbox-off) .tp-card.ukl-on:has(> #ukLive[data-shape="wide"][data-game][data-kind="four"]) { grid-template-columns: clamp(max(321px, calc(min(75vh, 100vh - 190px) * 9 / 16)), 58%, 960px) minmax(0, 1fr); }
  .tp-card.ukl-on > #ukLive[data-shape="wide"] .ukl-stage { width: 100%; height: auto; aspect-ratio: 4 / 3;
    max-height: calc(100vh - 190px); }
  .tp-card.ukl-on > #ukLive .ukl-note, .tp-card.ukl-on > #ukLive .ukl-barbox,
  .tp-card.ukl-on > #ukLive .ukl-quiz { width: 0; min-width: 100%; }
  .tp-card.ukl-on > .ukl-conv { grid-column: 2; grid-row: 2; }
  /* NO HOLE UNDER THE STRIP (owner, 2026-10-19): the column is as tall as
     his thread and the 4:3 box is not, so the box takes whatever height is
     spare. The picture stays whole (contain) in the middle of it, and the
     game, the note and the bar strip sit at the bottom, level with his
     composer. NOTHING UNDER THE FOLD EITHER (owner, 2026-10-20): the box
     also gives way, down to 200px, so Say hi, its row and the strip stay
     on screen on a short desktop; only below that does the column scroll. */
  .tp-card.ukl-on > #ukLive .ukl-stage { flex: 1 1 auto; min-height: 200px; }
}

/* FOUR IN A ROW (owner, 2026-10-19): his board, right under her video. An
   ink plate, her discs red, his warm yellow. One row says whose turn it is
   (or the result) with its buttons, the board under it at the full width,
   so every column is at least 44px wide on a 390px phone. The discs size to
   the screen's height so his thread and composer stay on it. */
:root { --ukl-him: #ffc93c; }
.ukl-game { flex: none; padding: 8px 12px 10px; background: var(--p1, #0f131c); color: var(--t1, #edf0f6);
  border-bottom: 1px solid var(--ln, rgba(255, 255, 255, .07)); }
.ukl-game[hidden], .ukl-game [hidden] { display: none !important; }
.ukl-g-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ukl-g-row p { margin: 0; flex: 1 1 auto; font-weight: 700; }
.ukl-g-row small { flex: 1 0 100%; color: var(--t2, #9faac0); font-size: 13px; }
/* The ask is one row where it fits: the button, its one line beside it. */
.ukl-g-row[data-for="ask"] small { flex: 1 1 140px; }
.ukl-g-btn { min-height: 44px; padding: 0 16px; border: 1px solid var(--ln2, rgba(255, 255, 255, .13));
  border-radius: 999px; background: var(--p2, #141926); color: var(--t1, #edf0f6); font: inherit;
  font-weight: 700; cursor: pointer; }
/* Waiting on her: a status card with a moving dot. Yes: lit. Cancel is a
   small link at the row's end, never where Play was. */
.ukl-g-wait p, .ukl-g-yes p { display: flex; align-items: center; gap: 8px; }
.ukl-g-dot { width: 10px; height: 10px; flex: none; border-radius: 50%; background: var(--ac, #ffae35);
             animation: ukl-blink 1s ease-in-out infinite; }
.ukl-g-yes p { color: var(--ac, #ffae35); font-size: 17px; }
.ukl-g-link { margin-left: 6px; padding: 6px 2px; border: 0; background: none; color: var(--t2, #9faac0);
              font: inherit; font-size: 13px; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.ukl-g-btn[disabled] { opacity: .7; }
@media (prefers-reduced-motion: reduce) { .ukl-g-dot { animation: none; } }
.ukl-g-btn.go { border-color: transparent; background: var(--ac, #ffae35); color: var(--aci, #0a0d13); }
.ukl-g-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.ukl-g-says { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.ukl-g-bar .ukl-g-btn { flex: none; min-height: 40px; padding: 0 10px; }
.ukl-g-turn { margin: 0; font-size: 15px; font-weight: 800; line-height: 1.25; }
.ukl-g-turn.mine { color: var(--ac, #ffae35); }
.ukl-g-sub { color: var(--t2, #9faac0); font-size: 12px; line-height: 1.3; }
.ukl-g-sub:empty { display: none; }

/* --ukl-d is the disc: at most 44px, never wider than a seventh of the
   screen, and a twelfth of what is left of the height once the fixed parts
   are taken (about 470px: the header, the panel's own row, the line with
   the name she knows him by, his thread's floor, the composer, and a
   slack for a longer composer or a result that wraps). The stage takes the other half. */
.ukl-g-board { --ukl-d: min(44px, calc((100vw - 54px) / 7), max(24px, calc((100vh - 470px) / 12)));
  display: flex; gap: 3px; padding: 6px; border-radius: 14px; background: var(--p3, #1b2231);
  box-shadow: inset 0 0 0 1px var(--ln2, rgba(255, 255, 255, .13)); }
.ukl-g-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column-reverse; align-items: center;
  gap: 3px; min-height: 44px; padding: 0; border: 0; border-radius: 8px; background: none; cursor: default; }
.ukl-g-col:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; }
/* A phone (owner, 2026-10-23: "feel like Connect Four"): each column one
   disc wide, so the discs sit as close across as they do down (3px) and the
   frame hugs them, centred. A desktop keeps its 320px board. */
@media (max-width: 899px) {
  .ukl-g-board { width: max-content; max-width: 100%; margin-inline: auto; }
  .ukl-g-col { flex: 0 0 var(--ukl-d); }
}
/* His turn, on a touch screen too: every open column washed, his disc
   waiting half-seen where it would land; firmer under his finger. */
.ukl-g-col:not(:disabled) { cursor: pointer; background: color-mix(in srgb, var(--ukl-him) 9%, transparent); }
.ukl-g-cell { position: relative; flex: none; width: var(--ukl-d); height: var(--ukl-d); border-radius: 50%;
  background: var(--bg, #0a0d13); box-shadow: inset 0 2px 3px rgba(0, 0, 0, .6); }
.ukl-g-cell::after { content: ""; position: absolute; inset: 2px; border-radius: 50%; display: none; }
.ukl-g-cell[data-d="h"]::after { display: block; background: var(--ukl-red);
  box-shadow: inset 0 -3px 0 rgba(0, 0, 0, .25); }
.ukl-g-cell[data-d="m"]::after { display: block; background: var(--ukl-him);
  box-shadow: inset 0 -3px 0 rgba(0, 0, 0, .2); }
.ukl-g-col:not(:disabled) .ukl-g-cell.next::after { display: block; background: var(--ukl-him); opacity: .3; }
.ukl-g-col:not(:disabled):active .ukl-g-cell.next::after,
.ukl-g-col:not(:disabled):focus-visible .ukl-g-cell.next::after { opacity: .8; }
@media (hover: hover) { .ukl-g-col:not(:disabled):hover .ukl-g-cell.next::after { opacity: .8; } }
/* Her last disc ringed; the winning four pulse. */
.ukl-g-cell.last::after { outline: 2px solid #fff; outline-offset: 1px; }
.ukl-g-cell.win::after { animation: ukl-win .9s ease-in-out infinite alternate; }
@keyframes ukl-win { to { transform: scale(.82); filter: brightness(1.35); } }
/* A new disc falls from above the board (--fall is rows to fall), with a tiny bounce. */
.ukl-g-cell.drop { z-index: 1; }
.ukl-g-cell.drop::after { animation: ukl-drop .25s ease-in; }
@keyframes ukl-drop {
  0% { transform: translateY(calc(var(--fall, 6) * -112%)); }
  80% { transform: translateY(0); }
  90% { transform: translateY(-7%); }
  100% { transform: translateY(0); } }
/* A refused drop: the board shakes once as his disc goes back. */
.ukl-g-board.shake { animation: ukl-shake .15s linear; }
@keyframes ukl-shake { 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
@media (prefers-reduced-motion: reduce) {
  .ukl-g-cell.drop::after, .ukl-g-cell.win::after, .ukl-g-board.shake { animation: none; }
  .ukl-g-cell.win::after { outline: 3px solid #fff; outline-offset: -3px; } }

/* THE OTHER THREE GAMES (owner, 2026-10-21). Play opens the four as cards,
   a name and one line each, two to a row. A card he tapped says Asking…
   (its data-busy, set by live-player.js) over its line. */
.ukl-g-pick { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 8px; }
.ukl-g-kind { position: relative; min-height: 56px; padding: 8px 10px; border: 1px solid var(--ln2, rgba(255, 255, 255, .13));
  border-radius: 12px; background: var(--p2, #141926); color: var(--t1, #edf0f6); font: inherit; text-align: left;
  display: flex; flex-direction: column; justify-content: center; gap: 2px; cursor: pointer; }
.ukl-g-kind b { font-size: 15px; }
.ukl-g-kind span { color: var(--t2, #9faac0); font-size: 12px; line-height: 1.3; }
.ukl-g-kind:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; }
.ukl-g-kind[data-busy] span { visibility: hidden; }
.ukl-g-kind[data-busy]::after { content: attr(data-busy); position: absolute; left: 10px; bottom: 8px;
  color: var(--ac, #ffae35); font-size: 12px; }
/* Who he plays: her and the ladies on camera, one ticked, above the cards. */
.ukl-g-who { grid-column: 1 / -1; }
.ukl-g-who p { margin: 0 0 4px; color: var(--t2, #9faac0); font-size: 12px; font-weight: 700; }
.ukl-g-faces { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; }
.ukl-g-faces::-webkit-scrollbar { display: none; }
.ukl-g-face { flex: 0 0 60px; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 2px 0; border: 0; background: none; color: var(--t2, #9faac0); font: inherit; cursor: pointer; }
.ukl-g-face img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; opacity: .55;
  box-shadow: 0 0 0 2px var(--ln2, rgba(255, 255, 255, .13)); }
.ukl-g-face b { max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; }
.ukl-g-face[aria-pressed="true"] { color: var(--t1, #edf0f6); }
.ukl-g-face[aria-pressed="true"] img { opacity: 1; box-shadow: 0 0 0 2px var(--ac, #ffae35); }
.ukl-g-face:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; border-radius: 8px; }
.ukl-game .shake { animation: ukl-shake .15s linear; }
/* Picking his next game while he watches hers: the picker in the board's place. */
.ukl-game[data-picking] [data-board] { display: none !important; }

/* Five in a Row: 7 x 7 squares, her red O, his yellow X, her last ringed,
   the five lit. A square is at most 44px and a seventh of the width; on a
   phone it takes the height first (36px on a 375x812 phone, never under
   28px) and the stage gives way to it (below). The size is #ukLive's, as
   the Memory card's is, so the stage's height can be worked out from it. */
.ukl { --ukl-x: clamp(28px, calc((100vh - 560px) / 7), min(44px, calc((100vw - 52px) / 7)));
  --ukl-c: min(64px, calc((100vw - 60px) / 4), max(40px, calc((100vh - 470px) / 7))); }
.ukl-g-five { display: grid; grid-template-columns: repeat(7, var(--ukl-x)); gap: 2px; justify-content: center;
  padding: 6px; border-radius: 14px; background: var(--p3, #1b2231);
  box-shadow: inset 0 0 0 1px var(--ln2, rgba(255, 255, 255, .13)); }
.ukl-g-x { position: relative; width: var(--ukl-x); height: var(--ukl-x); padding: 0; border: 0; border-radius: 5px;
  background: var(--bg, #0a0d13); cursor: default; }
.ukl-g-x:not(:disabled) { cursor: pointer; background: color-mix(in srgb, var(--ukl-him) 9%, var(--bg, #0a0d13)); }
.ukl-g-x:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; z-index: 1; }
.ukl-g-x::after { position: absolute; inset: 0; display: grid; place-items: center;
  font-size: calc(var(--ukl-x) * .68); font-weight: 900; line-height: 1; }
.ukl-g-x[data-d="h"]::after { content: "O"; color: var(--ukl-red); animation: ukl-pop .18s ease-out; }
.ukl-g-x[data-d="m"]::after { content: "X"; color: var(--ukl-him); animation: ukl-pop .18s ease-out; }
.ukl-g-x.last { box-shadow: inset 0 0 0 2px #fff; }
.ukl-g-x.win { background: color-mix(in srgb, #fff 22%, var(--bg, #0a0d13)); }
.ukl-g-x.win::after { animation: ukl-win .9s ease-in-out infinite alternate; }
@keyframes ukl-pop { from { transform: scale(.4); opacity: 0; } }

/* High or Low: his number picker (every target 44px), then her guesses as
   chips, Higher green-ish, Lower red-ish, found lit, and the range left. */
.ukl-g-num { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; margin-bottom: 8px; }
.ukl-g-step { min-width: 44px; min-height: 44px; padding: 0 8px; border: 1px solid var(--ln2, rgba(255, 255, 255, .13));
  border-radius: 12px; background: var(--p2, #141926); color: var(--t1, #edf0f6); font: inherit; font-weight: 800; cursor: pointer; }
.ukl-g-num input { width: 84px; min-height: 48px; border: 1px solid var(--ln2, rgba(255, 255, 255, .13)); border-radius: 12px;
  background: var(--bg, #0a0d13); color: var(--ukl-him); font: inherit; font-size: 26px; font-weight: 900; text-align: center;
  font-variant-numeric: tabular-nums; -moz-appearance: textfield; appearance: textfield; }
/* No spinner arrows: his ±1 and ±10 keys do that. */
.ukl-g-num input::-webkit-inner-spin-button, .ukl-g-num input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.ukl-g-num .ukl-g-btn { flex: 1 0 100%; }
.ukl-g-secret { margin: 0 0 6px; font-size: 17px; font-weight: 800; color: var(--ukl-him); font-variant-numeric: tabular-nums; }
.ukl-g-secret:empty, .ukl-g-range:empty { display: none; }
.ukl-g-guesses { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.ukl-g-guesses li { padding: 6px 10px; border-radius: 999px; background: var(--p3, #1b2231); font-weight: 700;
  font-size: 14px; font-variant-numeric: tabular-nums; animation: ukl-pop .18s ease-out; }
.ukl-g-guesses li[data-a="+"] { box-shadow: inset 0 0 0 1px #4cd38a; }
.ukl-g-guesses li[data-a="-"] { box-shadow: inset 0 0 0 1px var(--ukl-red); }
.ukl-g-guesses li[data-a="="] { background: var(--ac, #ffae35); color: var(--aci, #0a0d13); }
.ukl-g-range { margin: 8px 0 0; color: var(--t2, #9faac0); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Memory: 4 x 4 cards; face down a plain back, up its fruit; a pair taken
   in its owner's colour (her red, him yellow), a card up and not taken a
   neutral grey; the card he flipped spins until the server says its face. */
.ukl-g-score { margin: 0 0 6px; font-weight: 800; font-size: 14px; font-variant-numeric: tabular-nums; }
.ukl-g-cards { display: grid; grid-template-columns: repeat(4, var(--ukl-c)); gap: 6px; justify-content: center;
  padding: 6px; border-radius: 14px; background: var(--p3, #1b2231);
  box-shadow: inset 0 0 0 1px var(--ln2, rgba(255, 255, 255, .13)); }
.ukl-g-card { width: var(--ukl-c); height: var(--ukl-c); padding: 0; border: 0; border-radius: 10px;
  background: repeating-linear-gradient(45deg, #2a3550 0 6px, #232c43 6px 12px); color: inherit;
  font-size: calc(var(--ukl-c) * .55); line-height: 1; cursor: default; transition: transform .2s; }
.ukl-g-card:not(:disabled) { cursor: pointer; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ukl-him) 45%, transparent); }
.ukl-g-card:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; }
.ukl-g-card[data-up="1"] { background: #dfe3ea; }
.ukl-g-card[data-d="h"] { background: color-mix(in srgb, var(--ukl-red) 75%, #fff); box-shadow: inset 0 0 0 3px var(--ukl-red); }
.ukl-g-card[data-d="m"] { background: var(--ukl-him); box-shadow: inset 0 0 0 3px #d99a00; }
.ukl-g-card.flip { animation: ukl-flip .5s ease-in-out infinite alternate; }
@keyframes ukl-flip { to { transform: scaleX(.1); } }
/* A desktop: the squares share the column's height too (40px at 800px,
   42px at most, which is what the 344px panel holds). */
@media (min-width: 900px) { .ukl { --ukl-x: clamp(36px, calc((100vh - 520px) / 7), 42px); --ukl-c: 62px; } }
@media (prefers-reduced-motion: reduce) {
  .ukl-g-x::after, .ukl-g-x.win::after, .ukl-g-guesses li, .ukl-game .shake, .ukl-g-card.flip { animation: none !important; }
  .ukl-g-card.flip { opacity: .6; } }

/* THE HEAD ROW (owner, 2026-10-22: "anybody, at any time, should be able to
   minimise it"): the game's name and Hide while it is open; folded, the
   panel is this one row, saying where the game is, and a tap opens it
   (live-player.js folded()). */
.ukl-g-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 40px; margin: 0 0 6px;
  padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.ukl-g-head b { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font-size: 15px; font-weight: 800; }
.ukl-g-hide { flex: none; display: inline-flex; align-items: center; gap: 4px; min-height: 34px; padding: 0 12px;
  border: 1px solid var(--ln2, rgba(255, 255, 255, .13)); border-radius: 999px; background: var(--p2, #141926);
  font-size: 13px; font-weight: 700; }
.ukl-g-show { display: none; }
.ukl-game[data-fold] { padding-top: 4px; padding-bottom: 4px; }
.ukl-game[data-fold] .ukl-g-head { margin: 0; }
.ukl-game[data-fold] .ukl-g-hide { display: none; }
.ukl-game[data-fold] .ukl-g-show { flex: none; display: inline-grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; background: var(--p2, #141926); }
.ukl-game[data-fold] > :not(.ukl-g-head) { display: none !important; }
.ukl-g-head:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 2px; border-radius: 10px; }

/* A PHONE (owner, 2026-10-22: "it should just replace half the screen with
   the options to play a game, and then ... the board"; "if people do want
   to message her privately, they should be away"). Her live is the bigger
   picture. Her games there are a sheet over its lower half
   (`#ukLive[data-sheet]`, live-player.js), the dock stepping aside under
   it, the squares sized to the sheet. Folded, or never opened, the sheet
   is gone and Play is in the bigger picture's own row. His private thread
   is his own screen, away from it: her video small on top, the one way
   back to her live under it, a game in play as its head row (a tap goes
   back to her live, the game open), and nothing else of the live. */
.ukl-tolive { display: none; }
@media (max-width: 599px), (pointer: coarse) and (max-height: 500px) {
  #ukLive[data-big]:not([data-sheet]) > .ukl-game { display: none !important; }
  .tp-card.ukl-on > #ukLive[data-sheet] > .ukl-game { position: fixed; left: 0; right: 0; bottom: 0; z-index: 9652;
    max-height: 62vh; overflow-y: auto; overscroll-behavior: contain; margin: 0; border: 0;
    padding: 10px max(14px, env(safe-area-inset-right, 0px)) max(12px, env(safe-area-inset-bottom, 0px)) max(14px, env(safe-area-inset-left, 0px));
    border-radius: 18px 18px 0 0; background: rgba(15, 19, 28, .97); box-shadow: 0 -10px 30px rgba(0, 0, 0, .45); }
  .tp-card.ukl-on > #ukLive[data-sheet] > :is(.ukl-chatbox, .ukl-acts, #ukLiveAskRow, .ukl-fullrow) { display: none !important; }
  .tp-card.ukl-on > #ukLive[data-sheet][data-side] > .ukl-game { left: 50%; top: 0; max-height: none; border-radius: 0; }
  #ukLive[data-sheet] { --ukl-x: min(44px, calc((100vw - 52px) / 7), max(26px, calc((62vh - 150px) / 7.4)));
    --ukl-c: min(64px, calc((100vw - 60px) / 4), max(40px, calc((62vh - 170px) / 4.4))); }
  #ukLive[data-sheet] .ukl-g-board { --ukl-d: min(44px, calc((100vw - 54px) / 7), max(24px, calc((62vh - 150px) / 6.6))); }
  #ukLive[data-sheet][data-side] { --ukl-x: min(44px, calc((50vw - 52px) / 7), max(24px, calc((100vh - 150px) / 7.4)));
    --ukl-c: min(64px, calc((50vw - 60px) / 4), max(36px, calc((100vh - 170px) / 4.4))); }
  #ukLive[data-sheet][data-side] .ukl-g-board { --ukl-d: min(44px, calc((50vw - 54px) / 7), max(22px, calc((100vh - 150px) / 6.6))); }

  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) > :not(.ukl-stage, .ukl-game, .ukl-tolive) { display: none !important; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) > .ukl-game[data-g="ask"] { display: none !important; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) > .ukl-tolive { order: 1; display: flex; align-items: center;
    justify-content: center; gap: 6px; min-height: 44px; margin: 0; padding: 8px 14px; border: 0;
    background: var(--ukl-red); color: #fff; font: inherit; font-size: 14.5px; font-weight: 800; cursor: pointer; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) > .ukl-game { order: 2; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) .ukl-stage { height: 26vh !important; margin-bottom: 0 !important; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) .ukl-stage > video:not(.ukl-self) { object-fit: cover !important; object-position: 50% 25%; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) .ukl-stage > :is(.ukl-chat, .ukl-meter, .ukl-oncam, .ukl-barchip, .ukl-also,
    .ukl-moment, .ukl-asked, .ukl-camask) { display: none !important; }
  .tp-card.ukl-on:not(.ukl-desk) > #ukLive:not([data-big]) .ukl-top > :not(.uk-live-pill, .ukl-watching, .ukl-vol) { display: none !important; }
}

/* FROM HIS ASK ON (#ukLive[data-game], set by live-player.js) the page
   takes its game layout once and keeps it until he is done: the line about
   who sees what steps aside, and on a phone the video gives way to half of
   what is left (about 22vh on a 390x844 phone), the bar strip goes, and his
   thread keeps a floor so he can read her during play. The !important beats
   the bar strip's own 36vh rule, whose :has() argument carries an id.
   Before that, the Play button shares a phone's height like the bar strip
   does: the video gives way to 36vh. */
.tp-card.ukl-on > #ukLive[data-game] .ukl-note { display: none; }
@media (max-width: 899px) {
  .tp-card.ukl-on > #ukLive[data-game] .ukl-stage { height: max(100px, calc((100vh - 470px) / 2)) !important; }
  /* The two taller boards (#ukLive[data-kind], live-player.js): the stage
     is what is left once the header, the board, the free taps, his thread's
     floor and his composer are on screen (456px and 498px are those parts
     beside the board, with 12px to spare for a line that wraps), so his
     composer stays on a 375x812 phone. */
  .tp-card.ukl-on > #ukLive[data-game][data-kind="five"] .ukl-stage { height: max(90px, calc(100vh - 456px - 7 * var(--ukl-x))) !important; }
  .tp-card.ukl-on > #ukLive[data-game][data-kind="pairs"] .ukl-stage { height: max(90px, calc(100vh - 498px - 4 * var(--ukl-c))) !important; }
  .tp-card.ukl-on > #ukLive[data-game] .ukl-barbox { display: none; }
  /* And the reactions stay in the one row beside Say hi in every language
     (a longer Say hi wrapped them, about 40px), scrolling sideways if they
     must. Auto margins spread them while they fit and start them at the
     left when they do not. */
  .tp-card.ukl-on > #ukLive[data-game] .ukl-acts { flex-wrap: nowrap; }
  .tp-card.ukl-on > #ukLive[data-game] .ukl-rxrow { flex: 1 1 0; justify-content: flex-start; overflow-x: auto;
    scrollbar-width: none; }
  .tp-card.ukl-on > #ukLive[data-game] .ukl-rxrow button { flex: none; margin: 0 auto; }
  .tp-card.ukl-on:has(> #ukLive[data-game]) #tpBody { min-height: min(120px, 12vh); }
}
/* A desktop: the panel sits under the video in the video's column, at the
   video's width until a game, then 344px wide (seven 42px squares; Four in a Row's 320px) with the video shortened so
   the board is on screen without scrolling the column. */
@media (min-width: 900px) {
  .tp-card.ukl-on > #ukLive .ukl-game { width: 0; min-width: 100%; }
  .tp-card.ukl-on > #ukLive[data-game] .ukl-game { width: 344px; }
  .tp-card.ukl-on > #ukLive[data-game][data-kind="four"] .ukl-game:not([data-picking]) { width: 320px; }
  .tp-card.ukl-on > #ukLive[data-game] .ukl-stage { height: max(200px, calc(100vh - 540px)); }
  /* The two taller boards: the stage gives way a little more, so Say hi
     stays on a 1280x800 screen under the board. */
  .tp-card.ukl-on > #ukLive[data-game]:is([data-kind="five"], [data-kind="pairs"]) .ukl-stage { min-height: 150px; }
  .ukl-g-board { --ukl-d: 34px; }
}

/* TONIGHT: each live stream is an event-sized card at the front of the
   night's cards (_uk_live_row.html), its picture the latest still shown
   whole like a poster, the LIVE pill over it. */
.tn-cards[hidden] { display: none; }
.tn-bar .tn-hero.tn-livehero { position: relative; background: #000; }
/* A wide still in the 4:5 box: whole, over a blurred copy that fills it,
   never between black bars. */
.tn-livehero img[data-live-pic] { position: relative; }
.tn-livehero .tn-liveback { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: blur(22px) brightness(.65) saturate(1.2); transform: scale(1.2); }
.tn-livehero .uk-live-pill { position: absolute; left: 10px; top: 10px; font-size: 12px; padding: 3px 9px; }
/* The honest counter: wraps inside the picture rather than run off it. */
.tn-livehero .tn-livewatch { position: absolute; left: 10px; top: 40px; max-width: calc(100% - 20px); padding: 3px 9px;
  border-radius: 12px; background: rgba(0, 0, 0, .62); color: #fff; font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.35; }
.tn-livehero .tn-livewatch[hidden] { display: none; }
.tn-bar .tn-kind.tn-kind-live { background: color-mix(in srgb, var(--ukl-red) 28%, transparent); }
.tn-livecard .tn-night { color: var(--ukl-red); font-weight: 700; text-decoration: none; }

/* THE PUBLIC TEASER: blurred faces only. */
.ukl-teaser { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 14px; margin: 12px 0;
  border-radius: 16px; background: #16121a; color: #fff; }
.ukl-teaser-faces { display: flex; }
.ukl-teaser-faces span { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; border: 2px solid var(--ukl-red);
  background: #444; }
.ukl-teaser-faces span + span { margin-left: -12px; }
.ukl-teaser-faces img { width: 100%; height: 100%; object-fit: cover; filter: blur(6px); transform: scale(1.2); }
.ukl-teaser p { flex: 1; min-width: 160px; margin: 0; font-size: 14px; }
.ukl-teaser a { padding: 8px 14px; border-radius: 999px; background: var(--ukl-red); color: #fff;
  font-weight: 700; text-decoration: none; }
.ukd-live { position: absolute; left: 11px; bottom: 11px; z-index: 3; }
/* The whole live card taps through to her live; the bar's name keeps its
   own link above that. */
.tn-bar.tn-livecard { position: relative; }
.tn-livecard .tn-night::after { content: ""; position: absolute; inset: 0; border-radius: 16px; }
.tn-livecard .tn-barhead a { position: relative; z-index: 1; }
/* LIVE NOW at the top of Tonight: on a phone the cards scroll sideways, two
   in view, so the first ones sit above the fold however many are live. */
.tn-livenow > h2::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 7px;
  border-radius: 50%; background: var(--ukl-red); vertical-align: 2px; }
/* On a desktop a band that hugs its tiles, each stream a short tile: the
   picture on the left, her details beside it, so a single live does not
   stand alone as a page-tall poster; several wrap across the page. */
@media (min-width: 1000px) {
  .tn-livenow { align-self: flex-start; max-width: 100%; padding: 14px 16px 16px; border-radius: 18px;
    border: 1px solid color-mix(in srgb, var(--ukl-red) 35%, var(--ln));
    background: color-mix(in srgb, var(--ukl-red) 7%, var(--p1)); }
  .tn-livenow .tn-bars { display: flex; flex-wrap: wrap; gap: 12px; }
  .tn-livenow .tn-bar { width: 320px; display: grid; grid-template-columns: 104px minmax(0, 1fr); column-gap: 14px;
    row-gap: 2px; align-content: start; padding: 12px; }
  .tn-livenow .tn-bar > * { grid-column: 2; }
  .tn-livenow .tn-bar > .tn-hero { grid-column: 1; grid-row: 1 / span 7; align-self: start; }
  .tn-livenow .tn-barhead { margin: 0; }
  .tn-livenow .tn-barhead h3 { font-size: 14px; }
  .tn-livenow .tn-blurb { height: auto; }
  .tn-livenow .tn-livehero .uk-live-pill { left: 6px; top: 6px; font-size: 10px; padding: 2px 6px; }
  .tn-livenow .tn-livehero .tn-livewatch { left: 6px; top: 30px; max-width: calc(100% - 12px); font-size: 10px; padding: 2px 6px; }
}
@media (max-width: 999px) {
  .tn-livenow { margin: 0 -16px; }
  .tn-livenow.tn-sec > h2 { margin: 0 16px; }
  .tn-livenow .tn-bars { display: grid; grid-auto-flow: column; grid-template-columns: none;
    grid-auto-columns: calc((100% - 42px) / 2); gap: 10px; overflow-x: auto; padding: 0 16px;
    scroll-snap-type: x mandatory; scroll-padding: 0 16px; scrollbar-width: none; }
  .tn-livenow .tn-bars::-webkit-scrollbar { display: none; }
  .tn-livenow .tn-bar { scroll-snap-align: start; padding: 10px 10px 12px; gap: 6px; }
  .tn-livenow .tn-barhead h3 { font-size: 14px; }
}


/* TONIGHT'S DOT while anybody is live: on the rail item and the phone tab,
   from the first paint and then the shell's poll (js/uk-live-banner.js). */
.ukl-navdot { width: 9px; height: 9px; border-radius: 50%; background: var(--ukl-red);
  box-shadow: 0 0 0 2px var(--bg, #000); animation: ukl-blink 1.4s ease-in-out infinite; }
.ukl-navdot[hidden] { display: none; }
.r-tab-ic .ukl-navdot { position: absolute; top: -2px; left: -4px; }
.r-navitem .ukl-navdot { margin-left: 6px; }
@media (prefers-reduced-motion: reduce) { .ukl-navdot { animation: none; } }

/* BIGGER (owner, 2026-10-19): her stage over the whole page, the picture
   whole (contain, never cropped), her captions and controls still on it,
   and one way back. Above the shell and the tab bar, under the banner.
   `#ukLive` and !important beat the stage heights set per layout above. */
.ukl-small { display: none; }
#ukLive .ukl-stage.is-big { position: fixed; inset: 0; z-index: 9650; width: auto !important; max-height: none !important;
  height: auto !important; aspect-ratio: auto !important; }
#ukLive .ukl-stage.is-big video { object-fit: contain !important; }
/* Over the game layout's own !important height on a phone, too. */
.tp-card.ukl-on > #ukLive[data-game] .ukl-stage.is-big { height: auto !important; }
#ukLive .ukl-stage.is-big .ukl-top { padding: var(--ukl-pad, max(12px, env(safe-area-inset-top, 0px))) 12px 14px; font-size: 13px; row-gap: 8px;
  background: linear-gradient(rgba(0, 0, 0, .55), rgba(0, 0, 0, .25) 70%, transparent); }
#ukLive .ukl-stage.is-big .ukl-where { font-size: 12.5px; opacity: .85; text-shadow: 0 1px 2px rgba(0, 0, 0, .7); }
#ukLive .ukl-stage.is-big .ukl-cap { font-size: 20px; }
#ukLive .ukl-stage.is-big .ukl-small:not([hidden]) { display: inline-grid; place-items: center; padding: 6px 8px; }
.ukl-stage:not(.is-big) video { cursor: zoom-in; }
.ukl-bigbtn { display: inline-grid; place-items: center; padding: 5px 7px; }
/* THE BIGGER PICTURE (TheGhost2, 2026-10-21: no chat in full screen; owner,
   2026-10-22: "fill the entire screen ... neat and tidy and professional").
   Her picture under everything. Along the top, on a fade: LIVE and the
   counter with the cross, her controls, where she is; under them the other
   lives at her bar, her private reply and the ladies on camera, placed by
   the top's real height (`--ukl-top`, live-player.js dock()). Down the right
   above the dock, the free reactions. Along the bottom, the dock: her games
   when open, then Say hi, Ask her and a drink for her, then the room's box,
   each stacked by its real height (`--ukl-dock`). On her picture above the
   dock: the room's chat and the meter. */
.tp-card.ukl-on > #ukLive[data-big] { --ukl-dock: calc(100px + env(safe-area-inset-bottom, 0px)); --ukl-top: 120px; }
.tp-card.ukl-on > #ukLive[data-big] .ukl-stage > video:not(.ukl-self) { object-position: 50% 35%; }
/* A PHONE HELD UPRIGHT: an upright picture fills it; a wide one is whole
   over the blurred backdrop (`data-backdrop`, below), never cropped. */
@media (max-width: 599px) and (orientation: portrait) {
  .tp-card.ukl-on > #ukLive[data-big] .ukl-stage > video:not(.ukl-self) { object-fit: cover !important; object-position: 50% 30%; }
}
.tp-card.ukl-on > #ukLive[data-big] > :is(.ukl-chatbox, .ukl-acts, #ukLiveAskRow, .ukl-fullrow) { position: fixed; left: 0; right: 0;
  z-index: 9651; width: auto; min-width: 0; margin: 0; border: 0; background: transparent;
  padding-left: max(12px, env(safe-area-inset-left, 0px)); padding-right: max(12px, env(safe-area-inset-right, 0px)); }
/* The box sits low: the home bar's inset less what its own padding gives. */
.tp-card.ukl-on > #ukLive[data-big] > .ukl-chatbox { display: flex; bottom: 0; padding-top: 4px;
  padding-bottom: max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px)); background: linear-gradient(transparent, rgba(0, 0, 0, .55)); }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-chatbox input { height: 40px; border-color: rgba(255, 255, 255, .22);
  background: rgba(0, 0, 0, .45); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-chatbox button { width: 40px; height: 40px; }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-acts { flex-wrap: nowrap; gap: 6px; padding-top: 0; padding-bottom: 6px; }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-acts .ukl-hi { padding: 7px 12px; font-size: 13.5px; }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-acts .ukl-askbtn { background: rgba(0, 0, 0, .5); }
.tp-card.ukl-on > #ukLive[data-big] > #ukLiveAskRow { padding-top: 0; padding-bottom: 6px; }
/* The free reactions: a column down the right, above the dock. */
.tp-card.ukl-on > #ukLive[data-big]:not([data-side]) .ukl-rxrow { position: fixed; z-index: 9651; flex: none;
  right: max(8px, env(safe-area-inset-right, 0px)); bottom: calc(var(--ukl-dock) + 22px);
  flex-direction: column; justify-content: flex-end; gap: 6px; overflow: visible; }
.tp-card.ukl-on > #ukLive[data-big] .ukl-rxrow button { flex: none; margin: 0; text-shadow: 0 1px 3px #000; }
.tp-card.ukl-on > #ukLive[data-big]:not([data-side]) .ukl-rxrow button { width: 42px; height: 42px; padding: 0;
  font-size: 21px; background: rgba(0, 0, 0, .32); }
/* A drink for her, beside Say hi, on the bigger picture only. */
.ukl-fdrink { display: none; }
.tp-card.ukl-on > #ukLive[data-big] .ukl-fdrink { display: block; flex: 0 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; background: var(--ukl-red); color: #fff; }
/* Her games, when open (her panel's `data-g`, gRender), above the taps. */
.ukl-fullrow { display: none; }
.tp-card.ukl-on > #ukLive[data-big] > .ukl-fullrow { display: flex; gap: 6px; padding-top: 0; padding-bottom: 6px; }
#ukLive > .ukl-fullrow [hidden] { display: none !important; }
.ukl-fullrow .ukl-hi { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; padding: 7px 14px; font-size: 13.5px; }
.ukl-fullrow .ukl-fgame { background: #f5b942; color: #1c1a22; }
.ukl-fullrow .ukl-fpm { background: rgba(0, 0, 0, .5); color: #fff; }
/* The openers only fill his private box, which is under the picture. */
.tp-card.ukl-on > #ukLive[data-big] > #ukLiveOpeners { display: none !important; }
.tp-card.ukl-on > #ukLive[data-big] .ukl-meter { left: 12px; right: 12px; bottom: calc(var(--ukl-dock) + 4px); }
.tp-card.ukl-on > #ukLive[data-big] .ukl-chat { bottom: calc(var(--ukl-dock) + 22px); left: 12px; max-height: 28%;
  width: min(calc(100% - 84px), 340px); }
.tp-card.ukl-on > #ukLive[data-big] video.ukl-self { top: calc(var(--ukl-top) + 6px); bottom: auto; right: 12px; }
.tp-card.ukl-on > #ukLive[data-big][data-state="weak"] .ukl-veil { bottom: var(--ukl-dock); }
.tp-card.ukl-on > #ukLive[data-big] .ukl-cap { right: 64px; left: 12px; bottom: calc(var(--ukl-dock) + 30px); }
.tp-card.ukl-on > #ukLive[data-big] .ukl-stage:has(.ukrc-list > li) .ukl-cap { bottom: calc(28% + var(--ukl-dock) + 30px); }
/* Under her controls: the other lives at her bar on the left, her private
   reply under them; the ladies on camera down the right, above the
   reactions; his own camera's corner picture top right. */
.tp-card.ukl-on > #ukLive[data-big] .ukl-also { left: 12px; top: calc(var(--ukl-top) + 6px); }
.tp-card.ukl-on > #ukLive[data-big] .ukl-oncam { right: 8px; top: calc(var(--ukl-top) + 6px);
  max-height: calc(100% - var(--ukl-top) - var(--ukl-dock) - 290px); }
.tp-card.ukl-on > #ukLive[data-big] .ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-oncam { top: calc(var(--ukl-top) + 142px);
  max-height: calc(100% - var(--ukl-top) - var(--ukl-dock) - 426px); }
/* HER PRIVATE REPLY (live-player.js), 6 s. */
.ukl-dm { display: none; }
#ukLive .ukl-stage.is-big .ukl-dm:not([hidden]) { display: block; position: absolute; z-index: 6; left: 12px;
  top: calc(var(--ukl-top) + 6px); max-width: min(calc(100% - 96px), 340px); padding: 8px 12px;
  border: 0; border-radius: 14px; background: rgba(255, 255, 255, .95); color: #1c1a22; font: inherit; font-size: 14px;
  line-height: 1.35; text-align: left; cursor: pointer; box-shadow: 0 6px 20px rgba(0, 0, 0, .45);
  animation: ukrc-in .25s ease-out; overflow-wrap: anywhere; }
#ukLive .ukl-stage.is-big:has(> .ukl-also) .ukl-dm:not([hidden]) { top: calc(var(--ukl-top) + 50px); }
.ukl-dm b { font-weight: 800; }
/* SIDEWAYS ON A PHONE (owner, 2026-10-22): a wide picture fills the screen
   (an upright one is whole over the blurred backdrop, below),
   the box takes the left of the bottom line, the taps the right (the
   reactions a column down the right edge, below), and the room's chat sits
   above the box. */
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-stage > video:not(.ukl-self) { object-fit: cover !important; object-position: 50% 30%; }
.tp-card.ukl-on > #ukLive[data-big][data-side] > #ukLiveChatForm { right: 50%; }
.tp-card.ukl-on > #ukLive[data-big][data-side] > :is(.ukl-acts, #ukLiveAskRow, .ukl-fullrow) { left: 50%; }
.tp-card.ukl-on > #ukLive[data-big][data-side] > .ukl-acts { padding-bottom: max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px)); }
/* A short desktop window; a phone has the column (the phone block, below). */
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-rxrow { flex: 1 1 0; justify-content: flex-start; overflow-x: auto; scrollbar-width: none; }
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-chat { width: calc(50% - 24px); max-height: 40%; }
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-meter { display: none; }
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-oncam { max-height: calc(100% - var(--ukl-top) - 80px); }
/* With his camera on, the ladies on camera stand to the left of his corner
   picture: under it, a sideways screen had no room left and they vanished. */
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-oncam {
  top: calc(var(--ukl-top) + 6px); right: calc(min(96px, 22%) + 20px); max-height: calc(100% - var(--ukl-top) - 80px); }
.tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-cap { right: 8%; }
/* iPHONE SAFARI (iOS 26) softly blurs whatever sits under its status bar,
   about 100pt from the top, and paints its toolbar from the fixed bar at
   the bottom of the page (2026-10-22 screenshots: LIVE and the counter
   smeared, a navy band under the box, the tab bar's colour through the
   picture). On an iPhone's Safari her controls start below the blur (40px
   was still inside it); on every phone the shell's tab bar and its button
   go while the picture is bigger, and the page and its theme colour
   (live-player.js) are black. */
@media (display-mode: browser) and (pointer: coarse) and (orientation: portrait) {
  #ukLive .ukl-stage.is-big { --ukl-pad: max(40px, calc(env(safe-area-inset-top, 0px) + 12px)); }
}
/* The blur is Safari's own, not the page's: nothing of ours blurs the
   counter. 66px still sat inside it (owner, 2026-10-22), so the row starts
   below its ~100pt. */
@supports (-webkit-touch-callout: none) {
  @media (display-mode: browser) and (pointer: coarse) and (orientation: portrait) {
    #ukLive .ukl-stage.is-big { --ukl-pad: max(104px, calc(env(safe-area-inset-top, 0px) + 44px)); }
  }
}
html:has(#ukLive[data-big]), html:has(#ukLive[data-big]) body { background: #000; }
html:has(#ukLive[data-big]) :is(.r-tabs, .uk-tabs, .r-fab, .uk-fab) { display: none !important; }
/* A desktop: the dock under the chat, at the chat's side, not a bar across the screen. */
@media (min-width: 600px) and (min-height: 501px) {
  .tp-card.ukl-on > #ukLive[data-big] > :is(.ukl-chatbox, .ukl-acts, #ukLiveAskRow, .ukl-fullrow) { right: auto; width: min(440px, 100vw); }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-meter { right: auto; width: min(416px, calc(100vw - 24px)); }
}
/* A desktop's full window shows the room's newest 6; the column keeps the rest. */
#ukLive[data-dbig] .ukrc-list > :nth-last-child(n+7) { display: none; }
/* Tell me when she's live: the one-tap offer when her live ends (live_push.py). */
/* Low, just above his composer (`bottom` is set by the page when it shows),
   never over her name in the header: the width of the screen less its
   gutters on a phone, its own width in the middle on a desktop. */
.ukl-pushask { position: fixed; left: 16px; right: 16px; bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  z-index: 9998; display: flex; gap: 6px; align-items: center; justify-content: space-between; padding: 6px; border-radius: 999px; background: #1c1a22;
  border: 1px solid #3a3644; box-shadow: 0 12px 40px rgba(0, 0, 0, .45); }
.ukl-pushask[hidden] { display: none; }
.ukl-pushask button { border: 0; border-radius: 999px; padding: 8px 12px; background: transparent;
  color: #f4f1ec; font: 600 14px/1.2 Inter, system-ui, sans-serif; cursor: pointer; }
.ukl-pushask .go { flex: 1; background: #f4f1ec; color: #1c1a22; }
@media (min-width: 600px) {
  .ukl-pushask { left: 50%; right: auto; width: max-content; max-width: calc(100vw - 32px); transform: translateX(-50%); }
  .ukl-pushask .go { flex: none; } }

/* ==== DISCOVERY OUTSIDE THE PLAYER (2026-10-21) =========================
   Wherever her face is, she reads as live: `is-live` on a `[data-live-slug]`
   container, set at paint and kept true by the shell's poll
   (js/uk-live-banner.js), which also shows and hides its `.uk-live-tag`. */
.is-live .ukc-face { box-shadow: 0 0 0 2px var(--bg, #000), 0 0 0 4px var(--ukl-red); }
.ukc-name .uk-live-pill { margin-left: 6px; vertical-align: 1px; }
.ukd-card[data-live="1"] { box-shadow: 0 0 0 3px var(--ukl-red); }
.ukv-card { position: relative; }
.ukv-card.is-live { border-color: var(--ukl-red); box-shadow: 0 0 0 2px var(--ukl-red); }
.ukv-live { position: absolute; left: 10px; top: 10px; z-index: 1; }
.ukp-live { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 0 0 14px;
  padding: 12px 16px; border-radius: 14px; background: var(--ukl-red); color: #fff; font-weight: 800;
  font-size: 15px; text-decoration: none; }
.uk-live-tag[hidden] { display: none !important; }
.ukp-live .uk-live-pill { background: #fff; color: var(--ukl-red); }
.ukp-live .uk-live-pill::before { background: var(--ukl-red); }

/* THE BLURRED BACKDROP (owner, 2026-10-22; live-player.js backdrop(), which
   says where). `#ukLive[data-backdrop]`: her picture whole (contain,
   centred), and under it, "blur", the same stream (#ukLiveBack) filling the
   stage, blurred and darkened, instead of black bands; "plain", the black
   bands (reduced motion, Save-Data, a phone dropping frames). Two ids, so
   it wins over every fill rule above; the stage isolates so the copy sits
   above its black and under everything else. */
#ukLive #ukLiveBack { display: none; position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1;
  object-fit: cover !important; object-position: 50% 40% !important; background: #000; pointer-events: none;
  filter: blur(28px) brightness(.5) saturate(1.15); transform: scale(1.15); }
#ukLive[data-backdrop] .ukl-stage { isolation: isolate; }
#ukLive[data-backdrop="blur"] #ukLiveBack { display: block; }
#ukLive[data-backdrop] #ukLiveVideo { object-fit: contain !important; object-position: 50% 50% !important; }
#ukLive[data-backdrop="blur"] #ukLiveVideo { background: transparent; }

/* HER CONTROLS FADE on a phone's bigger picture (live-player.js calm()):
   the top row only; the chat and the dock stay. No double-tap zoom on her
   picture, whose double tap is a heart. Over the veil, so the cross and
   her controls still work while she has stepped away. */
#ukLive .ukl-stage.is-big .ukl-top { z-index: 3; }
#ukLive .ukl-stage.is-big .ukl-top > * { transition: opacity .3s ease; }
#ukLive[data-calm] .ukl-stage.is-big .ukl-top { pointer-events: none; }
/* THE HONEST COUNTER NEVER FADES (owner, 2026-10-22), nor LIVE beside it:
   only her other controls do. */
#ukLive[data-calm] .ukl-stage.is-big .ukl-top > :not(.uk-live-pill, .ukl-watching) { opacity: 0; }
#ukLive .ukl-stage.is-big video { touch-action: manipulation; }

/* THE ROOM'S CHAT ON A PHONE'S BIGGER PICTURE (owner, 2026-10-22): the last
   4, the older two fading. A desktop keeps 6. */
@media (max-width: 599px), (pointer: coarse) and (max-height: 500px) {
  #ukLive[data-big] .ukrc-list > :nth-last-child(n+5) { display: none; }
  #ukLive[data-big] .ukrc-list > :nth-last-child(3) { opacity: .8; }
  #ukLive[data-big] .ukrc-list > :nth-last-child(4) { opacity: .55; }
}

/* JOINING, PAUSED AND ENDED (owner, 2026-10-22). Joining: her latest still
   (or photograph) softly blurred, the moving bar in the middle of the
   bigger picture, her controls and the dock already in place. Paused: her
   last frame blurred under "She stepped away", the chat still working.
   Ended on the bigger picture: the end card (the veil's `ended` lines and
   buttons) over her last frame (#ukLiveStill, live-player.js snap()),
   blurred, and nothing else on it. */
.ukl-start img { filter: blur(10px) brightness(.8); transform: scale(1.06); }
#ukLive .ukl-stage.is-big .ukl-start, .tp-card.ukl-desk .ukl-stage .ukl-start { align-items: center; padding-bottom: 0; }
.tp-card.ukl-on > #ukLive[data-big][data-state="connecting"] > .ukl-acts { visibility: visible; }
#ukLive .ukl-still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#ukLive[data-state="paused"] #ukLiveVideo,
#ukLive[data-state="ended"] :is(#ukLiveVideo, #ukLiveStill, .ukl-start img) {
  filter: blur(18px) brightness(.65); transform: scale(1.08); }
#ukLive:is([data-state="paused"], [data-state="ended"]) .ukl-veil { background: rgba(0, 0, 0, .3); text-shadow: 0 1px 4px rgba(0, 0, 0, .8); }
#ukLive .ukl-stage.is-big .ukl-veil p { font-size: 20px; }
#ukLive .ukl-stage.is-big .ukl-veil small { font-size: 14px; }
#ukLive[data-state="ended"] .ukl-stage > :not(video, .ukl-still, .ukl-start, .ukl-veil) { display: none !important; }
#ukLive[data-state="ended"] > :is(.ukl-chatbox, .ukl-acts, #ukLiveAskRow, .ukl-fullrow, #ukLiveOpeners, .ukl-quiz, .ukl-game) { display: none !important; }
#ukLive[data-state="ended"] .ukl-veil .ukl-endrow { display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  width: min(300px, 100%); margin-top: 16px; }
.ukl-endrow .ukl-hi { padding: 12px 18px; font-size: 15px; text-align: center; overflow: hidden; text-overflow: ellipsis; }
.ukl-endrow #ukLiveEndPush { background: rgba(255, 255, 255, .16); color: #fff; }

/* ==== A DESKTOP, DIRECTION A (owner, 2026-10-22) =========================
   900px and up, while she is live and the stage is not the full window
   (live-player.js deskIn(): `.ukl-desk` on the card, `ukl-desk-on` on the
   body). The card is two columns: her STAGE, her picture whole in its own
   shape over a blurred, darkened copy of itself, with her controls on it;
   and a PANEL, 384px (340px under 1180px): her header, the two tabs, then
   the room's chat (`.ukl-room`, Everyone) or his own thread (`.ukl-conv`,
   Only her). Every rule here names `.ukl-desk` or a node that exists only
   on it, so a phone and the full window are exactly as they were. */
:root {
  --ukl-i-globe: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18'/%3E%3C/svg%3E");
  --ukl-i-mute: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 5 6 9H3v6h3l5 4z'/%3E%3Cpath d='m17 9 4 6M21 9l-4 6'/%3E%3C/svg%3E");
  --ukl-i-sound: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 5 6 9H3v6h3l5 4z'/%3E%3Cpath d='M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13'/%3E%3C/svg%3E");
  --ukl-i-cam: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round'%3E%3Cpath d='M3 8h4l2-3h6l2 3h4v11H3z'/%3E%3Ccircle cx='12' cy='13' r='3.5'/%3E%3C/svg%3E");
  --ukl-i-share: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v13M7 8l5-5 5 5M5 14v6h14v-6'/%3E%3C/svg%3E");
}
.ukl-tabs[hidden], .ukl-room[hidden], .ukl-tabs [hidden], .ukl-room [hidden] { display: none !important; }
.ukl-oc-d { display: none; }

/* The card: the stage on the left, down its whole height; the panel's
   header, tabs and pane on the right. !important over the split view's
   own columns per game and shape, whose :has() carries an id. */
.tp-card.ukl-on.ukl-desk { --ukl-side: 384px; display: grid; grid-template-columns: minmax(0, 1fr) var(--ukl-side) !important;
  grid-template-rows: auto auto minmax(0, 1fr); background: var(--p1, #0f131c); }
@media (max-width: 1179px) { .tp-card.ukl-on.ukl-desk { --ukl-side: 340px; } }
.tp-card.ukl-on.ukl-desk.ukl-desk > .tp-head { grid-column: 2; grid-row: 1; min-width: 0; gap: 12px; padding: 14px 16px 14px 18px; }
.tp-card.ukl-on.ukl-desk > .ukl-tabs { grid-column: 2; grid-row: 2; }
.tp-card.ukl-on.ukl-desk > :is(.ukl-room, .ukl-conv) { grid-column: 2; grid-row: 3; min-width: 0; min-height: 0; }
.tp-card.ukl-on.ukl-desk[data-tab="her"] > .ukl-room,
.tp-card.ukl-on.ukl-desk:not([data-tab="her"]) > .ukl-conv { display: none !important; }
/* Her live over: his plain thread beside the end card. */
.tp-card.ukl-on.ukl-desk:has(> #ukLive[data-state="ended"]) > :is(.ukl-tabs, .ukl-room) { display: none !important; }
.tp-card.ukl-on.ukl-desk:has(> #ukLive[data-state="ended"]) > .ukl-conv { display: flex !important; grid-row: 2 / -1; }
.tp-card.ukl-on.ukl-desk.ukl-desk .ukl-private { color: var(--t2, #9faac0); text-shadow: none; }

/* HER HEADER, at the top of the panel: her face ringed red while she is
   live, her name, bar and Thai time, then her drink button (round here, its
   words its tooltip and its name) and the more button, at every width. */
.tp-card.ukl-desk > .tp-head .tp-avatar { width: 44px; height: 44px; box-shadow: 0 0 0 2px var(--p1, #0f131c), 0 0 0 4px var(--ukl-red); }
.tp-card.ukl-on.ukl-desk.ukl-desk > .tp-head .tp-head-act[data-onclick="tp-drink"] { width: 38px; height: 38px; padding: 0; justify-content: center; }
.tp-card.ukl-desk > .tp-head .tp-head-act[data-onclick="tp-drink"] > span { position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.tp-card.ukl-on.ukl-desk.ukl-desk > .tp-head .tp-head-more { display: inline-flex; width: 38px; height: 38px; }
/* Under 1000px her profile's button is its chevron alone: the panel is narrow. */
.tp-card.ukl-desk > .tp-head .tp-head-go-t { display: none; }
.tp-card.ukl-on.ukl-desk.ukl-desk > .tp-head .tp-head-go { padding: 0 12px; }
/* Her details folded at every desktop width while she is live (below 1400px
   they are a row over the conversation, not a column). */
@media (min-width: 1000px) { body.ukl-desk-on.uk-ctx-off .ukc-ctx { display: none; } }

/* THE STAGE. Her picture is as tall as the stage less 20px, in its own
   shape (`--ukl-ar`, live-player.js shape(); 3:4 until it is known), never
   wider than the stage; behind it the blurred copy fills the stage
   (`data-backdrop`, plain dark under reduced motion, Save-Data or dropped
   frames). The inbox's chevron, folded, sits in the gutter her picture
   leaves at the side or above it. */
.tp-card.ukl-on.ukl-desk > #ukLive { grid-column: 1; grid-row: 1 / -1; position: relative; display: flex; flex-direction: row;
  align-items: center; justify-content: center; min-width: 0; min-height: 0; padding: 20px; overflow: clip;
  isolation: isolate; container-type: size; background: var(--bg, #0a0d13); border-right: 1px solid var(--ln, rgba(255, 255, 255, .07)); }
.tp-card.ukl-on.ukl-desk > #ukLive > :not(.ukl-stage, #ukLiveBack) { display: none !important; }
.tp-card.ukl-desk > #ukLive > #ukLiveBack { inset: -60px; width: calc(100% + 120px); height: calc(100% + 120px); transform: none;
  filter: blur(48px) brightness(.42) saturate(1.25); }
.tp-card.ukl-on.ukl-desk > #ukLive .ukl-stage { flex: none; width: min(100cqw, 100cqh * var(--ukl-ar, .75)); height: auto;
  max-height: none; min-height: 0; aspect-ratio: var(--ukl-ar, .75); margin: 0; border-radius: 20px; overflow: hidden;
  background: #000; box-shadow: 0 30px 80px rgba(0, 0, 0, .55); }
.tp-card.ukl-on.ukl-desk > #ukLive .ukl-stage > video:not(.ukl-self) { object-fit: cover; object-position: 50% 50%; }

/* ON HER PICTURE, along the top: LIVE and the honest counter, and under
   them where she is, on the left (always shown, never cut: where the row
   is too narrow for all of it, `data-dtight` from deskMeasure(), the counter
   takes a line of its own); her buttons on the right, round, which fade
   after 4 s without the mouse (`data-dcalm`) unless her sound is still off. */
.tp-card.ukl-desk .ukl-stage:not(.is-big) .ukl-top { z-index: 3; display: grid; padding: 18px 18px 44px; font-size: 13px;
  grid-template-columns: auto auto minmax(0, 1fr) repeat(5, auto); align-items: center; gap: 8px 6px;
  background: linear-gradient(rgba(0, 0, 0, .6), rgba(0, 0, 0, .22) 65%, transparent); }
.tp-card.ukl-desk .ukl-top > * { transition: opacity .3s ease; }
.tp-card.ukl-desk .ukl-top > .uk-live-pill { grid-area: 1 / 1; height: 26px; margin: 0; padding: 0 10px; gap: 6px; font-size: 12px; }
.tp-card.ukl-desk .ukl-top > .uk-live-pill::before { width: 7px; height: 7px; }
.tp-card.ukl-desk .ukl-top > .ukl-watching { grid-area: 1 / 2; display: inline-flex; align-items: center; height: 26px; margin: 0;
  padding: 0 11px; border-radius: 13px; background: rgba(0, 0, 0, .5); font-size: 13px; font-weight: 600; }
.tp-card.ukl-desk .ukl-top > .ukl-where { grid-area: 2 / 1 / 3 / 4; font-size: 13px; color: rgba(255, 255, 255, .85);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6); }
.tp-card.ukl-desk > #ukLive[data-dtight] .ukl-top > .ukl-watching { grid-area: 2 / 1 / 3 / -1; justify-self: start; }
.tp-card.ukl-desk > #ukLive[data-dtight] .ukl-top > .ukl-where { grid-area: 3 / 1 / 4 / -1; }
.tp-card.ukl-desk .ukl-top > .ukl-ccwrap { grid-area: 1 / 4; }
.tp-card.ukl-desk .ukl-top > .ukl-vol { grid-area: 1 / 5; }
.tp-card.ukl-desk .ukl-top > #ukLiveMyCam { grid-area: 1 / 6; }
.tp-card.ukl-desk .ukl-top > #ukLiveShare { grid-area: 1 / 7; }
.tp-card.ukl-desk .ukl-top > .ukl-bigbtn { grid-area: 1 / 8; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top .ukl-btn { display: inline-grid; place-items: center; width: auto; min-width: 34px;
  height: 34px; padding: 0; border-radius: 17px; background: rgba(0, 0, 0, .5); color: #fff; font-size: 0; line-height: 1; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top .ukl-btn:hover { background: rgba(0, 0, 0, .72); }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top .ukl-btn[aria-pressed="true"]:not(#ukLiveMute) { background: #fff; color: #111; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top :is(#ukLiveCC, #ukLiveMute, #ukLiveMyCam, #ukLiveShare)::before { content: ""; width: 16px; height: 16px;
  background: currentColor; -webkit-mask: var(--ukl-i) center / contain no-repeat; mask: var(--ukl-i) center / contain no-repeat; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveCC { --ukl-i: var(--ukl-i-globe); display: inline-flex; gap: 6px; padding: 0 12px; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveCC::after { content: attr(data-lang); font: 600 13px/1 Inter, system-ui, sans-serif; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveMute { --ukl-i: var(--ukl-i-mute); }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveMute[aria-pressed="true"] { --ukl-i: var(--ukl-i-sound); }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveMyCam { --ukl-i: var(--ukl-i-cam); }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveShare { --ukl-i: var(--ukl-i-share); }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveShare[data-copied] { padding: 0 12px; font: 600 13px/1 Inter, system-ui, sans-serif; }
:is(.tp-card.ukl-desk .ukl-stage:not(.is-big), #ukLive[data-dbig] .ukl-stage.is-big) .ukl-top #ukLiveShare[data-copied]::before { display: none; }
/* A desktop's full window keeps the same round buttons; its cross where
   the full window button was. */
#ukLive[data-dbig] .ukl-stage.is-big .ukl-top { gap: 6px; }
#ukLive[data-dbig] .ukl-stage.is-big .ukl-top .ukl-small { order: 8; }
.tp-card.ukl-desk > #ukLive[data-dcalm] .ukl-top > :is(.ukl-ccwrap, .ukl-vol, #ukLiveMyCam, #ukLiveShare, .ukl-bigbtn) { opacity: 0; pointer-events: none; }
.tp-card.ukl-desk > #ukLive[data-dcalm] .ukl-stage:has(> .ukl-sound.is-small:not([hidden])) .ukl-top > .ukl-vol { opacity: 1; pointer-events: auto; }
/* Its full window fades the same buttons, its cross with them. */
#ukLive[data-dbig][data-dcalm] .ukl-stage.is-big .ukl-top > :is(.ukl-ccwrap, .ukl-vol, #ukLiveMyCam, #ukLiveShare, .ukl-small) { opacity: 0; pointer-events: none; }
#ukLive[data-dbig][data-dcalm] .ukl-stage.is-big:has(> .ukl-sound.is-small:not([hidden])) .ukl-top > .ukl-vol { opacity: 1; pointer-events: auto; }

/* Under her controls: the other lives at her bar on the left, and the
   ladies on camera down the right edge, a Drink on each, between the top
   and the stack at the bottom (`--ukl-dtop`, `--ukl-dstack`, deskMeasure()). */
.tp-card.ukl-desk .ukl-stage:not(.is-big) .ukl-also { left: 18px; top: var(--ukl-dtop, 96px); }
.tp-card.ukl-desk .ukl-stage:not(.is-big) .ukl-oncam { right: 14px; top: var(--ukl-dtop, 96px); gap: 12px; padding-bottom: 6px;
  max-height: calc(100% - var(--ukl-dtop, 96px) - var(--ukl-dstack, 150px) - 8px); }
.tp-card.ukl-desk .ukl-stage:not(.is-big):has(> video.ukl-self:not([hidden])) .ukl-oncam { top: calc(var(--ukl-dtop, 96px) + 140px);
  max-height: calc(100% - var(--ukl-dtop, 96px) - var(--ukl-dstack, 150px) - 148px); }
.tp-card.ukl-desk .ukl-stage:not(.is-big) video.ukl-self { top: var(--ukl-dtop, 96px); right: 16px; bottom: auto; }
.tp-card.ukl-desk .ukl-oc { width: 64px; gap: 4px; }
.tp-card.ukl-desk .ukl-oc img { width: 52px; height: 52px; }
.tp-card.ukl-desk .ukl-oc i { display: none; }
.tp-card.ukl-desk .ukl-oc .ukl-oc-d { position: absolute; top: 36px; right: -2px; display: grid; place-items: center; height: 20px;
  padding: 0 6px; border-radius: 10px; background: #fff; color: #1c1a22; font-size: 10px; font-weight: 800; }
.tp-card.ukl-desk .ukl-oc b { font-size: 12px; font-weight: 600; }
/* Too short a picture for them down the edge (`data-drow`): a row under
   her buttons, from the right. */
.tp-card.ukl-desk > #ukLive[data-drow] .ukl-stage:not(.is-big) .ukl-oncam { flex-direction: row-reverse; max-height: none;
  max-width: calc(100% - 28px); overflow: visible; }
.tp-card.ukl-desk .ukl-stage:not(.is-big) .ukl-camask { left: 50%; right: auto; width: min(360px, calc(100% - 36px));
  transform: translate(-50%, -50%); }
.tp-card.ukl-desk > #ukLive[data-state="weak"] .ukl-veil { inset: auto 0 var(--ukl-dstack, 150px) 0; z-index: 2; background: none; }

/* ALONG THE BOTTOM, on a fade, one stack from the bottom up (deskIn() puts
   them in this order): the free taps, Say hi, Ask her…, a drink for her and,
   while her games are open, Play a game, with the reactions at the right
   end; the room's heart meter; the openers and Ask her's chips; her
   captions, centred. */
.tp-card.ukl-on.ukl-desk > #ukLive .ukl-stage:not(.is-big) > .ukl-acts { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  width: auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 80px 18px 18px;
  background: linear-gradient(transparent, rgba(0, 0, 0, .45) 45%, rgba(0, 0, 0, .78)); pointer-events: none; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > * { pointer-events: auto; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > :is(.ukl-cap, #ukLiveAskRow, #ukLiveOpeners, .ukl-meter) { flex: 1 0 100%; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > .ukl-cap { position: static; margin: 0 0 6px; padding: 0 48px; font-size: 20px;
  font-weight: 600; line-height: 1.45; pointer-events: none; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > .ukl-cap span { padding: 3px 10px; border-radius: 8px; background: rgba(0, 0, 0, .62); }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > :is(#ukLiveAskRow, #ukLiveOpeners) { padding: 0; background: none; gap: 6px; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > :is(#ukLiveAskRow, #ukLiveOpeners) button { height: 34px; padding: 0 14px;
  border: 1px solid rgba(255, 255, 255, .28); border-radius: 17px; background: rgba(0, 0, 0, .5); font-size: 13px; font-weight: 600; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts > .ukl-meter { position: static; margin: 4px 0 4px; gap: 8px; font-size: 13px; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-hi { display: inline-flex; align-items: center; height: 40px; padding: 0 16px;
  border-radius: 20px; font-size: 14px; font-weight: 700; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-askbtn { background: rgba(0, 0, 0, .55); }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-fdrink { display: inline-flex; background: var(--ukl-red); color: #fff; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-fgame { background: #f5b942; color: #1c1a22; }
.tp-card.ukl-desk:not(:has(#ukLiveGame:not([hidden]))) #ukLiveFullGame,
.tp-card.ukl-desk:has(#ukLiveGame[data-g="watch"]:not([data-open])) #ukLiveFullGame { display: none !important; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-rxrow { flex: none; margin-left: auto; justify-content: flex-end; gap: 2px; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-rxrow button { width: 40px; height: 40px; padding: 0; border-radius: 50%;
  background: rgba(0, 0, 0, .4); font-size: 19px; }
.tp-card.ukl-desk .ukl-stage > .ukl-acts .ukl-rxrow button:hover { background: rgba(0, 0, 0, .62); }
/* Too narrow for the taps beside the buttons (`data-dwrap`, deskMeasure()):
   they end the meter's line instead, and the buttons have a line of their own. */
.tp-card.ukl-desk > #ukLive[data-dwrap] .ukl-stage > .ukl-acts > .ukl-meter { order: 1; flex: 1 1 calc(100% - 226px); min-width: 0; }
.tp-card.ukl-desk > #ukLive[data-dwrap] .ukl-stage > .ukl-acts > .ukl-rxrow { order: 2; }
.tp-card.ukl-desk > #ukLive[data-dwrap] .ukl-stage > .ukl-acts > .ukl-hi { order: 3; }
/* Joining or away, the meter keeps its line, so the stack does not reflow. */
.tp-card.ukl-desk > #ukLive:is([data-state="connecting"], [data-state="paused"]) .ukl-stage > .ukl-acts > .ukl-meter { display: flex; visibility: hidden; }

/* THE TWO TABS: Everyone · how many are here, and Only her with a lock and
   a count of her lines he has not seen. */
.tp-card.ukl-on.ukl-desk > .ukl-tabs { display: flex; gap: 4px; margin: 14px 18px 6px; padding: 4px; border-radius: 14px;
  background: var(--bg, #0a0d13); }
.ukl-tabs > button { flex: 1 1 0; min-width: 0; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; padding: 0 8px; border: 0; border-radius: 10px; background: none; color: var(--t2, #9faac0);
  font: 600 13.5px/1 Inter, system-ui, sans-serif; white-space: nowrap; cursor: pointer; }
.ukl-tabs > button:hover { color: var(--t1, #edf0f6); }
.ukl-tabs > button[aria-selected="true"] { background: var(--p3, #1b2231); color: #fff; }
.ukl-tabs > button:focus-visible { outline: 2px solid var(--ac, #ffae35); outline-offset: 1px; }
.ukl-tabs .uv-ic { flex: none; }
.ukl-tabn { color: var(--t2, #9faac0); font-variant-numeric: tabular-nums; }
.ukl-tabname { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ukl-tabdot { flex: none; display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--ukl-red); color: #fff; font-size: 11px; font-weight: 800; }

/* EVERYONE: her games or the quiz on top when there is one, then the room's
   chat as a full column (newest at the bottom; her lines and her bar's
   ladies' in her red; the drink moment a quiet line), her private line as
   a card, the Tell me offer, the box and one line about who reads it. */
.tp-card.ukl-on.ukl-desk > .ukl-room { display: flex; flex-direction: column; overflow: clip; color: var(--t1, #edf0f6);
  --ukl-x: 40px; --ukl-c: 62px; }
@media (max-width: 1179px) { .tp-card.ukl-on.ukl-desk > .ukl-room { --ukl-x: 37px; --ukl-c: 58px; } }
.ukl-room > .ukl-game { flex: none; margin: 8px 18px 0; padding: 12px; border: 1px solid var(--ln, rgba(255, 255, 255, .07));
  border-radius: 16px; background: var(--p2, #141926); }
.tp-card.ukl-desk:not(:has(> #ukLive[data-game])) > .ukl-room > .ukl-game:not([data-fold]),
.ukl-room > .ukl-game .ukl-g-row[data-for="ask"] { display: none !important; }
.ukl-room > .ukl-game .ukl-g-pick { margin-top: 0; }
.ukl-room > .ukl-game .ukl-g-board { --ukl-d: 34px; justify-content: center; }
.ukl-room > .ukl-quiz { flex: none; margin: 8px 18px 0; padding: 10px 12px 0; border-radius: 16px; overflow: hidden;
  background: var(--p2, #141926); }
.ukl-room > .ukl-chat { position: static; z-index: auto; flex: 1 1 auto; min-height: 0; width: auto; max-height: none;
  display: flex; flex-direction: column; overflow-y: auto; padding: 10px 18px; pointer-events: auto;
  -webkit-mask-image: linear-gradient(transparent, #000 14px); mask-image: linear-gradient(transparent, #000 14px);
  scrollbar-width: thin; }
.ukl-room .ukrc-list { margin-top: auto; gap: 12px; }
.ukl-room .ukrc-list > li { opacity: 1; }
.ukl-room .ukrc-line { align-self: stretch; padding: 0; border-radius: 0; background: none; color: var(--t1, #edf0f6);
  font-size: 14px; line-height: 1.4; text-shadow: none; }
.ukl-room .ukrc-line b { color: #b9c3ff; }
.ukl-room :is(.ukrc-her, .ukrc-lady) { padding: 8px 10px; border-radius: 12px; background: rgba(255, 45, 85, .16); }
.ukl-room .ukrc-lady { background: rgba(255, 45, 85, .1); }
.ukl-room :is(.ukrc-her, .ukrc-lady) b { color: #ff8fa6; }
.ukl-room .ukrc-note { align-self: center; color: var(--t2, #9faac0); font-size: 13px; text-align: center; }
.ukl-room .ukrc-orig { color: var(--t2, #9faac0); }
.ukl-room .ukrc-hint { visibility: visible; white-space: normal; margin-top: 10px; padding: 8px 12px; border-radius: 12px;
  background: var(--p2, #141926); color: var(--t2, #9faac0); font-size: 13px; }
.ukl-rdm { flex: none; display: flex; align-items: center; gap: 10px; margin: 0 18px 10px; padding: 10px 12px;
  border: 1px solid var(--ln2, rgba(255, 255, 255, .13)); border-radius: 14px; background: var(--p2, #141926);
  color: var(--t1, #edf0f6); font: 14px/1.35 Inter, system-ui, sans-serif; text-align: left; cursor: pointer;
  animation: ukrc-in .25s ease-out; }
.ukl-rdm:hover { border-color: #f5b942; }
.ukl-rdm > .uv-ic { flex: none; color: #f5b942; }
.ukl-rdm-t { flex: 1; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  overflow-wrap: anywhere; }
.ukl-rdm-go { flex: none; color: #f5b942; font-size: 13px; font-weight: 700; }
.ukl-room > .ukl-pushask { position: static; z-index: auto; width: auto; max-width: none; margin: 0 18px 10px; transform: none;
  box-shadow: none; }
.ukl-room > .ukl-pushask .go { flex: 1; }
.ukl-room > .ukl-chatbox { flex: none; width: auto; gap: 8px; padding: 0 18px 8px; background: none; }
.ukl-room > .ukl-chatbox input { height: 46px; padding: 0 16px; border: 1px solid var(--ln2, rgba(255, 255, 255, .13)); border-radius: 23px;
  background: var(--bg, #0a0d13); font-size: 15px; }
.ukl-room > .ukl-chatbox input:focus { outline: none; border-color: color-mix(in srgb, var(--ukl-red) 60%, transparent); }
.ukl-room > .ukl-chatbox button { width: 46px; height: 46px; }
.ukl-room .ukrc-status { left: 22px; }
.ukl-roomnote { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 0; padding: 0 18px 16px;
  color: var(--t2, #9faac0); font-size: 12px; }
.ukl-roomnote .ukl-sayname { margin: 0 0 0 auto; }
@media (prefers-reduced-motion: reduce) { .ukl-rdm { animation: none; } }
/* THE BIGGER PICTURE ON A PHONE, TIDIED (owner, 2026-10-22: "neat and tidy
   and professional"). Phones only (live-player.js's `phone` query): a
   desktop's bigger picture is being redesigned on its own.
   - One scrim up from the bottom and a firmer fade at the top, so the
     chat, the place line and the dock read over a bright picture. The
     scrim is the stage's first box: over her video, under all the rest.
   - The cross pinned top right, wherever the row wraps; the row, the chat,
     her reply and the meter clear of the notch when sideways.
   - The drink whole in every language (a short label), Ask her the one
     that gives way.
   - "Her connection is weak" a small pill under her controls, not a band
     over the chat; her captions just above the chat's real height
     (`--ukl-chath`, live-player.js dock()), not its 28% ceiling.
   - The ladies on camera clear of the reactions, beside his camera when
     it is on, and smaller on a short phone.
   - Sideways, the reactions are the same column down the right. */
.ukl-fd-short { display: none; }
@media (max-width: 599px), (pointer: coarse) and (max-height: 500px) {
  #ukLive .ukl-stage.is-big::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; pointer-events: none;
    height: calc(var(--ukl-dock, 100px) + 34%); background: linear-gradient(transparent, rgba(0, 0, 0, .5)); }
  /* Sideways with her games' sheet on the right half: her picture, its
     overlays and the room's chat keep the left half, whole. */
  .tp-card.ukl-on > #ukLive[data-sheet][data-side] .ukl-stage.is-big { right: 50%; }
  .tp-card.ukl-on > #ukLive[data-sheet][data-side] .ukl-chat { width: auto; right: 12px; }
  /* Tap to hear her: in the middle of the free picture, between her
     controls and the chat over the dock (the sheet's height under a game). */
  #ukLive .ukl-stage.is-big .ukl-sound { top: calc((var(--ukl-top, 120px) + 100% - var(--ukl-dock, 100px) - var(--ukl-chath, 0px) - 22px) / 2); }
  #ukLive .ukl-stage.is-big .ukl-top { background: none;
    padding-left: max(12px, env(safe-area-inset-left, 0px)); padding-right: calc(max(12px, env(safe-area-inset-right, 0px)) + 44px); }
  #ukLive .ukl-stage.is-big .ukl-top::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: linear-gradient(rgba(0, 0, 0, .6), rgba(0, 0, 0, .35) 75%, transparent); transition: opacity .3s ease; }
  #ukLive[data-calm] .ukl-stage.is-big .ukl-top::before { opacity: 0; }
  #ukLive .ukl-stage.is-big .ukl-small:not([hidden]) { position: absolute; z-index: 1;
    right: max(12px, env(safe-area-inset-right, 0px)); top: var(--ukl-pad, max(12px, env(safe-area-inset-top, 0px))); }
  #ukLive .ukl-stage.is-big .ukl-where { opacity: .9; text-shadow: 0 1px 3px #000, 0 0 8px rgba(0, 0, 0, .6); }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-chat,
  .tp-card.ukl-on > #ukLive[data-big] .ukl-also { left: max(12px, env(safe-area-inset-left, 0px)); }
  #ukLive .ukl-stage.is-big .ukl-dm:not([hidden]) { left: max(12px, env(safe-area-inset-left, 0px)); }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-meter { left: max(12px, env(safe-area-inset-left, 0px));
    right: max(12px, env(safe-area-inset-right, 0px)); }
  .tp-card.ukl-on > #ukLive[data-big] video.ukl-self { right: max(12px, env(safe-area-inset-right, 0px)); }
  .tp-card.ukl-on > #ukLive[data-big] > #ukLiveAskRow button { background: rgba(0, 0, 0, .5); border-color: rgba(255, 255, 255, .3); }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-hi { box-shadow: 0 1px 6px rgba(0, 0, 0, .35); }
  /* The drink never gives way: Ask her does. */
  .tp-card.ukl-on > #ukLive[data-big] > .ukl-acts .ukl-askbtn { flex: 0 1 auto; min-width: 48px; overflow: hidden; text-overflow: ellipsis; }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-fdrink { flex: none; }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-fd-long { display: none; }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-fd-short { display: inline; }
  .tp-card.ukl-on > #ukLive[data-big][data-state="weak"] .ukl-veil { top: calc(var(--ukl-top) + 6px); bottom: auto; left: 50%; right: auto;
    transform: translateX(-50%); width: max-content; max-width: calc(100% - 24px); padding: 6px 14px; border-radius: 999px; }
  .tp-card.ukl-on > #ukLive[data-big][data-state="weak"] .ukl-veil p { font-size: 14px; }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-stage:has(.ukrc-list > li) .ukl-cap {
    bottom: calc(var(--ukl-dock) + 32px + var(--ukl-chath, 28%)); }
  /* The faces stop above the reactions (5 x 42 + 4 x 6 + 22, and a little). */
  .tp-card.ukl-on > #ukLive[data-big] .ukl-oncam { right: max(8px, env(safe-area-inset-right, 0px));
    max-height: calc(100% - var(--ukl-top) - var(--ukl-dock) - 270px); }
  .tp-card.ukl-on > #ukLive[data-big] .ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-oncam { top: calc(var(--ukl-top) + 6px);
    right: calc(min(96px, 22%) + 20px); max-height: calc(100% - var(--ukl-top) - var(--ukl-dock) - 270px); }
  /* Sideways: the column again, smaller, with the faces to its left. */
  .tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-rxrow { position: fixed; z-index: 9651; flex: none;
    right: max(8px, env(safe-area-inset-right, 0px)); bottom: calc(var(--ukl-dock) + 16px);
    flex-direction: column; justify-content: flex-end; gap: 4px; overflow: visible; }
  .tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-rxrow button { width: 36px; height: 36px; padding: 0;
    font-size: 18px; background: rgba(0, 0, 0, .32); }
  .tp-card.ukl-on > #ukLive[data-big][data-side]:has(video.ukl-self:not([hidden])) .ukl-rxrow { right: calc(min(96px, 22%) + 20px); }
  .tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-oncam { right: calc(max(8px, env(safe-area-inset-right, 0px)) + 46px); }
  .tp-card.ukl-on > #ukLive[data-big][data-side] .ukl-stage:has(> video.ukl-self:not([hidden])) .ukl-oncam { right: calc(min(96px, 22%) + 66px); }
  /* The dock's rows stop short of the reactions' column (fixed, so the
     padding leaves it where it is); a row too long for one line wraps. */
  .tp-card.ukl-on > #ukLive[data-big][data-side] > :is(.ukl-acts, #ukLiveAskRow, .ukl-fullrow) {
    padding-right: calc(max(8px, env(safe-area-inset-right, 0px)) + 48px); }
  .tp-card.ukl-on > #ukLive[data-big][data-side]:has(video.ukl-self:not([hidden])) > :is(.ukl-acts, #ukLiveAskRow, .ukl-fullrow) {
    padding-right: calc(min(96px, 22%) + 68px); }
  .tp-card.ukl-on > #ukLive[data-big] > .ukl-fullrow { flex-wrap: wrap; }
  /* Away: her veil's lines clear of the reactions down the right. */
  .tp-card.ukl-on > #ukLive[data-big][data-state="paused"]:not([data-side]) .ukl-veil { padding-left: 64px; padding-right: 64px; }
}
@media (max-width: 599px) and (max-height: 700px), (pointer: coarse) and (max-height: 500px) {
  #ukLive[data-big] .ukl-oc img { width: 36px; height: 36px; }
  #ukLive[data-big] .ukl-oc i { top: 20px; }
  #ukLive[data-big] .ukl-oncam { gap: 4px; }
  /* A face cut by the column's end fades, so it reads as a column that
     scrolls. The fade is mostly its 8px of padding below the faces, which
     is empty when nothing is cut and fits the 8px the column keeps above
     the reactions (its top is 6px below --ukl-top's line). */
  #ukLive[data-big] .ukl-oncam { box-sizing: content-box; padding-bottom: 8px;
    -webkit-mask-image: linear-gradient(#000 calc(100% - 12px), transparent); mask-image: linear-gradient(#000 calc(100% - 12px), transparent); }
}
/* HIS NAME IN THE ROOM'S BOX (owner, 2026-10-23): a quiet chip before the
   input, the name she and the room know him by; a tap opens the persona
   sheet (uk-persona.js). Listed twice to outrank both boxes' round red
   button rules: the phone's bigger picture and the desktop's room column. */
.tp-card.ukl-on > #ukLive > .ukl-chatbox > button.ukl-asname, .ukl-chatbox > button.ukl-asname {
  display: inline-flex; align-items: center; gap: 3px; width: auto; max-width: 34%; height: auto; align-self: stretch;
  padding: 0 9px 0 11px; border: 1px solid rgba(255, 255, 255, .22); border-radius: 999px;
  background: rgba(0, 0, 0, .45); color: #fff; font: inherit; font-size: 13px; font-weight: 700; }
.ukl-asname > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ukl-asname > svg { flex: none; opacity: .75; }
