/* Roberta's and Brodie's TVs (lib/tvSet.mjs). Copied from hippochattie's chattie/styles.css TV rules (#21) via its
   roberta-tv-kit (PR #31), renamed rtv* so nothing clashes with this page. Their stills only; nothing calibrated. */
.rtv { margin: 0; display: grid; justify-items: center; transition: opacity .3s, filter .3s; }
.rtvClip { width: 100%; aspect-ratio: 900 / 810; overflow: hidden; border-radius: 12px; }
.rtvArt { position: relative; width: 100%; aspect-ratio: 1 / 1; margin-top: -5%; }
.rtvGlass { position: absolute; border-radius: 12%; }
.rtvFrame { position: absolute; inset: 0; width: 100%; height: 100%; user-select: none; -webkit-user-drag: none; }
/* The artwork has its own pale studio backdrop, so the TV sits on a rounded tile, as in HippoChattie and the kit. */
.rtvScreen { position: absolute; overflow: hidden; transition: box-shadow .25s; }
.rtv.talking .rtvScreen { box-shadow: inset 0 0 0 3px rgba(217,169,58,.9), inset 0 0 18px rgba(255,214,150,.5); }
/* Whoever is not speaking dims slightly; their TV stays on (f7e6ab01). */
.rtv.dim { opacity: .72; filter: saturate(.8); }
.rtvPicture { position: absolute; inset: 0; }
.rtvPortrait { width: 100%; height: 100%; object-fit: cover; display: block; user-select: none; -webkit-user-drag: none; }
.rtvFace { position: absolute; inset: 0; pointer-events: none; }   /* their eyes and mouth layers (lib/faces.mjs) */
.rtvFace[hidden] { display: none; }
.rtvKnob { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 50%; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvKnob:focus-visible { outline: 3px solid #d9a93a; outline-offset: -3px; }
/* THE TV'S OWN MUTE (e605ddaf): a real tap target over the painted Mute, with its state drawn OVER the art, never in it.
   Muted ("Sound off"): a grey ring. Sound on: a warm gold ring. The wee label sits just above the painted button. */
.rtvMute { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
/* THE RING SITS ON THE PAINTED BUTTON (Amanda 13 Oct): the tap area stays finger-sized, but every state ring is drawn
   round the painted button inside it (lib/tvSet.mjs ringInArea sets --ringL/T/W/H), so it never spills off the button
   or below the TV when the TV is small. */
:is(.rtvMute, .rtvReplay, .rtvVolume, .rtvPause)::after { content: ''; position: absolute; pointer-events: none;
  left: var(--ringL, 0%); top: var(--ringT, 0%); width: var(--ringW, 100%); height: var(--ringH, 100%);
  border-radius: 12px; transition: box-shadow .2s; }
.rtvMute::after { box-shadow: 0 0 0 3px rgba(60,60,70,.55); }
.rtvMute[data-muted="false"]::after { box-shadow: 0 0 0 3px #d9a93a, 0 0 14px 4px rgba(217,169,58,.55); }
.rtvMute:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
.rtvMuteState { position: absolute; left: calc(var(--ringL, 0%) + var(--ringW, 100%) / 2); bottom: calc(100% - var(--ringT, 0%) + 4px); transform: translateX(-50%); white-space: nowrap;
  font: 700 12px/1 system-ui, sans-serif; padding: 4px 7px; border-radius: 999px; background: rgba(40,40,48,.85); color: #fff; pointer-events: none; }
.rtvMute[data-muted="false"] .rtvMuteState { background: #d9a93a; color: rgb(20,40,75); }
/* THE TV'S OWN REPLAY (df0880a3): a real tap target over the painted "Replay 10s", its thin ring drawn OVER the art,
   never in it, so it reads as live. A tap glows gold for a moment, as the Mute does when her sound is on. */
.rtvReplay { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvReplay::after { box-shadow: 0 0 0 2px rgba(217,169,58,.7); }
.rtvReplay.went::after { box-shadow: 0 0 0 3px #d9a93a, 0 0 14px 4px rgba(217,169,58,.55); }
.rtvReplay:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
/* THE TV'S OWN VOLUME (db5cba2e): a real tap target over the painted Volume; for about two seconds after a tap, a gold
   ring and a wee "Quiet" / "Normal" / "Loud" label above it, drawn OVER the art like Mute's. */
.rtvVolume { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvVolume.shown::after { box-shadow: 0 0 0 3px #d9a93a, 0 0 14px 4px rgba(217,169,58,.55); }
.rtvVolume:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
/* It sits a step higher than Mute's "Sound off", which is always up beside it, so the two never cover each other. */
.rtvVolumeState { position: absolute; left: calc(var(--ringL, 0%) + var(--ringW, 100%) / 2); bottom: calc(100% - var(--ringT, 0%) + 28px); transform: translateX(-50%); white-space: nowrap;
  font: 700 12px/1 system-ui, sans-serif; padding: 4px 7px; border-radius: 999px; background: #d9a93a; color: rgb(20,40,75);
  pointer-events: none; display: none; }
.rtvVolume.shown .rtvVolumeState { display: block; }
/* THE TV'S OWN PAUSE (49146fb8): a real tap target over the painted Pause, its state drawn OVER the art like Mute's:
   while she is paused, a gold ring and a wee "Paused" label above the button. */
.rtvPause { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvPause[data-paused="true"]::after { box-shadow: 0 0 0 3px #d9a93a, 0 0 14px 4px rgba(217,169,58,.55); }
.rtvPause:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
.rtvPauseState { position: absolute; left: calc(var(--ringL, 0%) + var(--ringW, 100%) / 2); bottom: calc(100% - var(--ringT, 0%) + 4px); transform: translateX(-50%); white-space: nowrap;
  font: 700 12px/1 system-ui, sans-serif; padding: 4px 7px; border-radius: 999px; background: #d9a93a; color: rgb(20,40,75);
  pointer-events: none; display: none; }
.rtvPause[data-paused="true"] .rtvPauseState { display: block; }
/* THE LOVE BUTTON (61fc9ecf; moved by b7985828): the button is an invisible tap target; the ❤️ is drawn next to it, OVER
   the art, at a painted button's size, as a pink round button with a gold ring like the painted ones. */
.rtvLove { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvLove:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
.rtvLove:active + .rtvLoveBadge { transform: scale(.9); }
/* The heart is an SVG whose box is the heart itself (e98a2f3b), 55% of the circle, centred by the grid: no emoji. */
.rtvHeart { display: block; width: 55%; height: auto; aspect-ratio: 20 / 18.35; fill: #dd2e44; filter: drop-shadow(0 .5px .5px rgba(120,20,30,.35)); }
.rtvLoveBadge { position: absolute; box-sizing: border-box; display: grid; place-items: center; border-radius: 50%; line-height: 1;
  background: radial-gradient(circle at 42% 36%, #fde6e8 0%, #f8c9cd 55%, #f1b3b9 100%);
  box-shadow: inset 0 0 0 2px #e4b97f, inset 0 0 0 3px #8c4c4c, 0 1px 3px rgba(0,0,0,.25);
  pointer-events: none; transition: transform .1s; }
/* The painted Speed is covered by the bar's own cream (b7985828), so the bottom row reads as four buttons. */
.rtvRowCover { position: absolute; border-radius: 6px; pointer-events: none; }
/* THE LANGUAGE BUTTON (b93c37b1): the button is an invisible tap target; the disc ("EN", "GD", ...) is drawn OVER the
   painted Speed circle at a painted button's size, in the same pink and gold, and the wee "Language" caption covers the
   word Speed in the bar's own cream and the painted labels' dark type. Neither takes a tap. */
.rtvLang { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; border-radius: 12px; cursor: pointer;
  -webkit-tap-highlight-color: rgba(217,169,58,.35); }
.rtvLang:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 3px; }
.rtvLang:active + .rtvLangDisc { transform: scale(.9); }
.rtvLangDisc { position: absolute; box-sizing: border-box; display: grid; place-items: center; border-radius: 50%; line-height: 1;
  font-family: system-ui, sans-serif; font-weight: 800; letter-spacing: .02em; color: #8c4c5a;
  background: radial-gradient(circle at 42% 36%, #fde6e8 0%, #f8c9cd 55%, #f1b3b9 100%);
  box-shadow: inset 0 0 0 2px #e4b97f, inset 0 0 0 3px #8c4c4c, 0 1px 3px rgba(0,0,0,.25);
  pointer-events: none; transition: transform .1s, box-shadow .2s; }
.rtvLang.went + .rtvLangDisc { box-shadow: inset 0 0 0 2px #e4b97f, inset 0 0 0 3px #8c4c4c, 0 0 10px 3px rgba(217,169,58,.6); }
.rtvLangCap { position: absolute; display: grid; place-items: center; white-space: nowrap; line-height: 1; border-radius: 4px;
  font-family: system-ui, sans-serif; font-weight: 700; color: #2b2626; pointer-events: none; }
/* The shower: a copy of hippochattie's .tvShower/.tvDrop (912d2718). Inside the screen mask; it never takes a tap. */
.rtvShower { position: absolute; inset: 0; pointer-events: none; --dropSize: clamp(18px, 7vw, 32px); }
.rtvDrop { position: absolute; top: 0; height: 100%; display: flex; align-items: flex-start; transform: translate(-50%, -12%); opacity: 0;
  will-change: transform, opacity; animation: rtvFall 2.4s linear both; pointer-events: none; }
.rtvDrop i { font-style: normal; line-height: 1; filter: drop-shadow(0 2px 2px rgba(0,0,0,.2)); }
@keyframes rtvFall { 0% { opacity: 0; transform: translate(-50%, -12%); } 8% { opacity: 1; } 78% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, 96%); } }
@keyframes rtvDropFade { 0% { opacity: 0; } 15% { opacity: 1; } 70% { opacity: 1; } 100% { opacity: 0; } }
/* Off: the picture shrinks to a line, then a dot, and the screen stays dark. On, and as it first appears: a warm-up. */
.rtvScreen.off { background-color: #050607 !important; }
.rtvScreen.off .rtvPicture { animation: rtvOff .45s ease-in forwards; }
.rtvScreen.warm .rtvPicture { animation: rtvOn .7s ease-out; }
.rtvDot { position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%; background: #fff;
  box-shadow: 0 0 8px 3px rgba(220,235,255,.8); opacity: 0; display: none; }
.rtvScreen.off .rtvDot { display: block; animation: rtvDot .9s ease-out .3s; }
@keyframes rtvOff { 0% { transform: none; filter: none; } 55% { transform: scale(1, .015); filter: brightness(3); } 100% { transform: scale(0, .015); filter: brightness(3); opacity: 0; } }
@keyframes rtvOn { 0% { transform: scale(0, .015); filter: brightness(3); } 40% { transform: scale(1, .015); filter: brightness(2.4); } 100% { transform: none; filter: none; } }
@keyframes rtvDot { 0% { opacity: 1; } 100% { opacity: 0; } }
.rtvOffNote { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
  .rtv, .rtvScreen { transition: none; }
  /* "Turn on the TV" (09d2bf99): the hand and the glow hold still; earlier lines simply go. */
  .tviHand, .tviGlow, .tviHand.own[data-point] { animation: none; transition: none; }
  .tviGlow { box-shadow: 0 0 0 3px #d9a93a, 0 0 12px 4px rgba(217,169,58,.6); }
  .rconvo .rline { transition: none; }
  .rconvo .rline.past { display: none; }
  .rtvScreen.off .rtvPicture { animation: none; opacity: 0; }
  .rtvScreen.warm .rtvPicture, .rtvScreen.off .rtvDot { animation: none; }
  /* A few emojis fade in and out where they are, instead of falling. */
  .rtvDrop { display: none; }
  .rtvDrop:nth-child(-n+3) { display: flex; top: 38%; height: auto; transform: translateX(-50%); animation-name: rtvDropFade !important; }
  .rtvLoveBadge { transition: none; }
  .rconvo .rline:not([hidden]) { animation: none; }
  .rtvLove:active + .rtvLoveBadge { transform: none; }
  .rtvLangDisc { transition: none; }
  .rtvLang:active + .rtvLangDisc { transform: none; }
}

/* THE WEE TASTER (aaeeba2e, 7728ab82): Roberta's pink TV at the top, with one "Listen again" under it. */
/* THE ROOM HER ROUND PICTURE FREED GOES TO THE TV (Steward 4ca9fbcf, 13 Oct): the TV runs to 6px from the panel's edges;
   the start rows keep the bubbles' 16px margins (10px of their own). */
.rtvTaster { flex: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 12px; padding: 0 6px 6px; }
/* THE WAY IN, FROM THE START (53442408): one row per taster under her TV, outside the scroll, full width of the panel's
   16px margins. Her words are plain text and WRAP (never cut, never pushed off the edge, whatever the text size); the
   button beside them is a solid, rounded button in Roberta's soft blue (9f343d31), 44px tall: every pixel here is
   taken from her bubble box, so the rows are as compact as a good tap target allows. */
.rtvStarts { flex: 1 0 100%; min-width: 0; max-width: 100%; display: grid; gap: 4px; padding: 0 10px; }
.rtvStarts[hidden] { display: none; }
.rtvStart { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; min-width: 0; }
.rtvStart p { margin: 0; min-width: 0; overflow-wrap: break-word; font-size: 15px; line-height: 1.25; font-weight: 600; color: rgb(20,40,75); }
.rtvStartGo { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 84px; padding: 0 18px;
  text-decoration: none; font-size: 17px; font-weight: 700; color: rgb(20,40,75); white-space: nowrap;
  background: var(--start, #cfe2f9); border: 1.5px solid var(--startEdge, #92bcf0); border-radius: 12px;
  box-shadow: 0 4px 14px rgba(37,122,226,.22); -webkit-tap-highlight-color: transparent; }
.rtvStartGo:active { transform: translateY(1px); box-shadow: 0 2px 8px rgba(37,122,226,.22); }
.rtvStartGo:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 2px; }
.rtvTaster .rtv { width: min(100%, 440px, calc((88vh - 330px) * 0.97), var(--rtvFit, 440px)); }   /* BIGGER (e605ddaf): the full width of the panel on a phone;
   --rtvFit is set only when the newest bubble would not fit whole under it (9f343d31, lib/bubbleScroll.mjs tvFit) */
/* THE PINK TV CAN BE BIGGER (Amanda via Steward a078fc08: "I can see the white / cream area around the TV image"):
   in the Wee Taster the art's own pale backdrop is cropped to TASTER_CROP (lib/tvSet.mjs, x 72-828, y 60-838 of the
   900 art), so the TV itself fills the panel. Her picture is untouched; every control is placed in % of .rtvArt, so
   each hit area stays on its painted button. The width cap keeps her words and both Start rows on one screen
   (88% of the screen is the panel's tallest; 330px is its header, the room under the TV and the Start rows). */
.rtvTaster { overflow-x: clip; }   /* a hand reaching in from beyond the edge never makes the panel scroll sideways */
.rtvTaster .rtvClip { aspect-ratio: 756 / 778; }
.rtvTaster .rtvArt { width: 119.048%; margin-left: -9.524%; margin-top: -7.937%; }
/* THE START ROWS AT THE BOTTOM (Steward 09d2bf99): her words go directly under the TV, the rows under them. The
   wrapper keeps the 6px the TV slot gave them, so they still sit on the bubbles' 16px margins. */
.rtvFoot { flex: none; display: flex; padding: 4px 6px 6px; }
.rtvFoot:has(> .rtvStarts[hidden]) { display: none; }
/* ONLY THE LINE BEING SAID, PLUS AT MOST THE ONE BEFORE (09d2bf99): earlier lines roll up and out of sight. */
.rconvo .rline { transition: max-height .45s ease, opacity .35s ease, margin .45s ease, transform .45s ease; max-height: 80em; }
.rconvo .rline.past { max-height: 0; opacity: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; transform: translateY(-40%); pointer-events: none; }
.rline .rtvAgain { margin-top: 8px; }   /* under the last bubble of each page (e605ddaf) */
/* LISTEN AGAIN BELONGS TO THE TV (df0880a3; Amanda: "at the moment its looks intrusive"): no navy pill. A small pill in
   the TV's pink and cream with a thin gold ring, a small ▶, and the Sound on label's rounded type. The BUTTON is the
   44px-tall tap target; the pill drawn inside it is small. */
.rtvAgain { flex: none; min-height: 44px; padding: 0 2px; border: 0; background: transparent; cursor: pointer;
  display: inline-flex; align-items: center; -webkit-tap-highlight-color: transparent; }
.rtvAgainPill { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px 5px 5px; border-radius: 999px;
  background: #fdf3e6; color: #7a3a46; box-shadow: 0 0 0 1.5px #d9a93a; font: 700 13px/1 system-ui, sans-serif; }
.rtvAgain .ic { display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: #f7c2c7; color: #7a3a46; font-size: 9px; }
.rtvAgain:active .rtvAgainPill { background: #f9e3e0; }
.rtvAgain:focus-visible { outline: none; }
.rtvAgain:focus-visible .rtvAgainPill { box-shadow: 0 0 0 1.5px #d9a93a, 0 0 0 4px rgb(20,40,75); }
.rconvo .rline.now p { background: #fff6d8; box-shadow: 0 0 0 2px #d9a93a; }

/* WHAT WE DO (f7e6ab01, 4a6fccd1): side by side, never stacked. Whoever is speaking has the BIG TV (lib/whatTvs.mjs sets
   data-big); the other is a small TV beside it, bottoms lined up. The big one is as wide as the row allows after the
   small one, at most 300px, at most 40% of the screen's height, and smaller still if the line being said needs the
   room (--whatFit). */
.whatTvs { flex: none; display: flex; justify-content: center; align-items: flex-end; gap: 10px; padding: 0 16px 4px; --whatSmall: 104px; }
.whatTvs .rtv { flex: none; min-width: 0; width: var(--whatSmall); }
.whatTvs[data-big="Roberta"] .rtv[data-who="Roberta"], .whatTvs[data-big="Brodie"] .rtv[data-who="Brodie"] {
  width: min(calc(100% - var(--whatSmall) - 10px), 300px, 40vh, var(--whatFit, 300px)); }
/* THE SMALL TV KEEPS ITS CONTROLS BUT NOT THEIR LABELS (Steward 0898c01e): at ~104px wide the "Sound on" / "Paused" /
   "Loud" labels and the gold rings would pile up over the picture. Both TVs share one state, and the big TV shows it. */
.whatTvs[data-big="Roberta"] .rtv[data-who="Brodie"] :is(.rtvMuteState, .rtvPauseState, .rtvVolumeState),
.whatTvs[data-big="Brodie"] .rtv[data-who="Roberta"] :is(.rtvMuteState, .rtvPauseState, .rtvVolumeState) { display: none !important; }
.whatTvs[data-big="Roberta"] .rtv[data-who="Brodie"] :is(.rtvMute, .rtvPause, .rtvVolume, .rtvReplay)::after,
.whatTvs[data-big="Brodie"] .rtv[data-who="Roberta"] :is(.rtvMute, .rtvPause, .rtvVolume, .rtvReplay)::after { box-shadow: none !important; }

/* HER WORDS APPEAR AS SHE SAYS THEM (f7196bb4): each bubble fades in as she starts it; under reduced motion it simply
   appears, at the same pace (in the reduced-motion block above). */
.rconvo .rline:not([hidden]) { animation: rlineIn .35s ease-out; }
@keyframes rlineIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* THE PLAY/PAUSE TOGGLE (09d2bf99): while she waits for Play, a ▶ disc in the painted buttons' pink and gold and a wee
   "Play" caption in the bar's cream are drawn OVER the painted Pause; playing, the painted Pause shows. No tap of its own. */
.rtvPlayDisc { position: absolute; box-sizing: border-box; display: grid; place-items: center; border-radius: 50%; line-height: 1;
  color: #8c4c5a; background: radial-gradient(circle at 42% 36%, #fde6e8 0%, #f8c9cd 55%, #f1b3b9 100%);
  box-shadow: inset 0 0 0 2px #e4b97f, inset 0 0 0 3px #8c4c4c, 0 1px 3px rgba(0,0,0,.25); pointer-events: none; }
.rtvPlayIc { display: block; transform: translateX(8%); }
.rtvPlayCap { position: absolute; display: grid; place-items: center; white-space: nowrap; line-height: 1; border-radius: 4px;
  font-family: system-ui, sans-serif; font-weight: 700; color: #2b2626; pointer-events: none; }
.rtvPlayDisc[hidden], .rtvPlayCap[hidden] { display: none; }
.rtvPause.rtvToggle .rtvPauseState { display: none !important; }   /* the ▶ says it; no "Paused" label on a toggle */
.rtvPause.rtvToggle[data-paused="true"]::after { box-shadow: none; }
/* A TV that starts OFF (09d2bf99) is dark from its first frame: no switch-off animation as it appears. */
.rtvScreen.off.still .rtvPicture { animation: none; opacity: 0; }
.rtvScreen.off.still .rtvDot { display: none; }

/* "TURN ON THE TV" (lib/tvIntro.mjs, Steward 09d2bf99): the hand, its words, Skip, the glow and the zoom's blur. */
.rtv.tviHost { position: relative; }
.tviLayer { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.tviLayer[hidden] { display: none; }
.tviHand { position: absolute; width: 13%; transform: translate(-50%, 0); filter: drop-shadow(0 2px 3px rgba(60,30,30,.3));
  animation: tviBob 1.1s ease-in-out infinite; transition: left .5s ease, top .5s ease; }
.tviLayer.still .tviHand, .tviLayer.still .tviHand.own[data-point] { animation: none; transition: none; }
.tviHandArt { display: block; width: 100%; height: auto; }
/* THE CHARACTER'S OWN HAND (Amanda's art, 69a4e534): its fingertip sits on the spot (--tipX/--tipY, measured on the
   picture), and the wee nudge goes along the way it points. A painted button's height, about. */
.tviHand.own { width: 17%; transform: translate(var(--tipX, -100%), var(--tipY, -15%)); animation-name: tviNudge; }
.tviHand.own[data-point="left"] { animation-name: tviNudgeL; }
.tviHandPic { display: block; width: 100%; height: auto; user-select: none; -webkit-user-drag: none; }
.tviHandPic[hidden] { display: none; }
@keyframes tviNudge { 0%, 100% { transform: translate(var(--tipX), var(--tipY)); } 50% { transform: translate(calc(var(--tipX) - 8%), var(--tipY)); } }
@keyframes tviNudgeL { 0%, 100% { transform: translate(var(--tipX), var(--tipY)); } 50% { transform: translate(calc(var(--tipX) + 8%), var(--tipY)); } }
@keyframes tviBob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 10%); } }
/* UP FROM BELOW (Play, a078fc08): her right-pointing hand turned a quarter about its own fingertip, so it points up
   from under the TV. Turned, never flipped or retouched; the nudge goes up and down. */
.tviHand.own[data-point="up"] { transform-origin: var(--tipOX) var(--tipOY); transform: translate(var(--tipX), var(--tipY)) rotate(-90deg);
  animation-name: tviNudgeU; }
@keyframes tviNudgeU { 0%, 100% { transform: translate(var(--tipX), var(--tipY)) rotate(-90deg); }
  50% { transform: translate(var(--tipX), calc(var(--tipY) + 12%)) rotate(-90deg); } }
/* THE WEE MESSAGES GO UNDER THE TV, NOT INSIDE IT (Amanda via Steward a078fc08: "that's where all the wee messages
   should be.. not inside the TV"; "Turn me on" was too big): in the room just below the TV, at a calm reading size,
   never over the screen or the controls. Two lines' room is kept, so the zoom measures the same block every step. */
.tviTip { position: absolute; left: 4%; right: 4%; top: calc(100% + 16px); min-height: calc(2 * 1.35em); margin: 0;
  text-align: center; font: 600 16px/1.35 system-ui, sans-serif; color: rgb(20,40,75); }
.tviSkip { pointer-events: auto; position: absolute; top: 6px; right: 6px; min-height: 44px; min-width: 64px; padding: 0 14px;
  border: 0; border-radius: 999px; background: rgba(253,243,230,.92); color: #7a3a46; box-shadow: 0 0 0 1.5px #d9a93a;
  font: 700 14px/1 system-ui, sans-serif; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tviSkip:focus-visible { outline: 3px solid rgb(20,40,75); outline-offset: 2px; }
/* The glow on whichever control the hand is on. */
.tviGlow { animation: tviGlow 1.4s ease-in-out infinite; }
@keyframes tviGlow { 0%, 100% { box-shadow: 0 0 0 3px #d9a93a, 0 0 10px 3px rgba(217,169,58,.55); }
  50% { box-shadow: 0 0 0 3px #f1c75b, 0 0 22px 9px rgba(241,199,91,.75); } }
/* The zoom: everything in the stage but the TV is blurred, and so is the page behind it. */
.tviBlur { filter: blur(6px); transition: filter .6s ease; pointer-events: none; }
.tviBackdrop { position: fixed; inset: 0; background: rgba(244,241,234,.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .6s ease; }
.tviBackdrop.on { opacity: 1; }
/* "TURN ON THE TVs" ON WHAT WE DO (lib/whatIntro.mjs, Steward 0c832eb7): the same hand, words, Skip and glow, laid over
   BOTH TVs. While it runs the big TV is a little smaller (as fit() may make it) so each hand has room to reach in from
   outside its TV; the words sit under the TVs. Brodie's own step gives him the big place, and the row moves left, so his
   hand reaches his knob from the right with room to spare. The TVs keep their bottoms lined up and are never stacked. */
.whatTvs.wti { position: relative; --whatFit: min(196px, calc(100vw - 190px)); }   /* 170px on a 360 phone: his hand still fits */
.whatTvs.wti[data-wti="brodieKnob"] { justify-content: flex-start; }
.wtiLayer .tviHand.own { width: 54px; }
.wtiLayer .tviTip { top: calc(100% + 10px); }
.wtiLayer.wtiLow .tviTip { left: 50%; right: 2%; top: calc(100% + 2px); }   /* the Play step: beside the hand that comes up from under her TV (Steward 4fc535bf) */
.wtiLayer .tviSkip { top: 0; right: 10px; }
/* The page's own "Show me how again" link. */
.tviAgain { margin-left: 6px; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-decoration: underline; cursor: pointer;
  min-height: 24px; }
