/* ===== v91 — LAYOUT CHUẨN: một rule stage theo đơn vị stage =====
   Bi chốt 2026-10-28 (layout-standard.md): khu bé portrait-only,
   thiết kế cho phone rồi scale lên tablet. Mọi chiều cao stage cũ
   theo dvh / max-height từng mode (v17/v79 + các dải 840/760/680)
   bị XÓA — thay bằng MỘT rule cho mỗi mode: height =
   var(--stage-w) × tỉ lệ đo thật tại F2 (390×844, stage-w 366px).
   --stage-w do init.js syncStage() đo từ .pet-panel thật (fallback
   366px). Stage co lại (flex-shrink) khi panel cần chỗ, sàn
   min-height 150px giữ thú luôn thấy được. Bong bóng top 58px duy
   nhất (các top 54/52/50/48/40 theo dải đã xóa). Nền chung = nền
   stage của home (trời/cỏ, xem layout.css .pet-stage). */
:root { --stage-w: 366px; }
#screen-pet .pet-stage {
  /* v91 fix (v78 win-drift, found 2026-10-28): the stage MUST be
     rigid — flex: 0 1 auto let panel pressure shrink it at deal
     (race 296 vs ratio 354) and grow back at win when choices
     clear (panelSH 517 -> 390), a 58-90px frame jump that breaks
     the absolute fixed-frame rule. Rigid = v90's F2 frame exactly
     (ratios were measured from v90), panels scroll internally
     when their content exceeds the leftover. */
  flex: 0 0 auto; min-height: 150px;
  height: calc(var(--stage-w) * 1.06);
}
/* v101: #mode-feed leaves this 0.877 group — feed's stage is the
   strip layout (count-panel-round) for the WHOLE session now, set
   once by setMode; its only stage rule is the round one below. */
#screen-pet .pet-panel:not(.count-panel-round):has(#mode-count.active) .pet-stage { height: calc(var(--stage-w) * 0.877); }
#screen-pet .pet-panel:has(#mode-listen.active) .pet-stage { height: calc(var(--stage-w) * 0.762); }
/* v99 (bi photo QA 2026-10-29 14:35 — race "vẫn cuộn trong khi
   bên trên trống nhiều"): the 0.967 ratio was measured at F2 in
   the v90 layout, when the race track still lived in the stage
   family; since v87 the track + question + answers all live in
   the PANEL, and the stage is bubble + pet + scenery only — yet
   at stage-w 620 it still claimed 600px, leaving the panel
   68-100px of box for ~330px of content at 1024x768/1280x800
   (measured: cards at y792-860, score/msg below the viewport,
   the panel scrolling internally under a mostly empty stage).
   Race joins the sentence/house stage family at 0.56: the
   default pet rule (min(192px, 100% - 132px)) keeps a 192px pet
   on wide frames and ~100-125px on phones, the bubble keeps its
   132px sky, and the panel gains the ~240px it needed — no
   scroll at any target frame (verified by probe, see v99). */
#screen-pet .pet-panel:has(#mode-race.active) .pet-stage { height: calc(var(--stage-w) * 0.56); }
#screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: calc(var(--stage-w) * 0.831); }
#screen-pet .pet-panel:has(#mode-cook.active) .pet-stage { height: calc(var(--stage-w) * 0.784); }
#screen-pet .pet-panel:has(#mode-garden.active) .pet-stage { height: calc(var(--stage-w) * 0.716); }
#screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { height: calc(var(--stage-w) * 0.59); }
/* v93: on short portrait frames the sentence builder needs every
   pixel below (see the layout.css bands) — the speech strip gives
   back 6px there; bubble + pet still fit (strip floor rules in
   layout.css keep the pet whole). */
@media (orientation: portrait) and (max-height: 760px) {
  #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { height: calc(var(--stage-w) * 0.575); }
}
#screen-pet .pet-panel:has(#mode-trace.active) .pet-stage,
#screen-pet .pet-panel:has(#mode-dots.active) .pet-stage,
#screen-pet .pet-panel:has(#mode-shapes.active) .pet-stage,
#screen-pet .pet-panel:has(#mode-clock.active) .pet-stage { height: calc(var(--stage-w) * 0.546); }
/* v99 (bi photo QA 2026-10-29 14:35 — trace must prioritise the
   drawing board): on wide-but-short windows (desktop 1280x800 /
   1024x768) the 0.546 stage still took 339px, leaving the trace
   panel 339-371px, of which the control stack ate 258 — the
   board measured 81-113px, smaller than the buttons under it.
   In this band only (stage-w is the 620 cap there, so the pet
   rule min(148px, 100% - 128px) still yields a 132px pet and
   the one-line bubble keeps its sky) the trace stage trims to
   the yard-strip family 0.42 and hands ~79px to the board.
   Phones and tall tablets keep 0.546 untouched. */
@media (min-width: 620px) and (max-height: 860px) {
  #screen-pet .pet-panel:has(#mode-trace.active) .pet-stage { height: calc(var(--stage-w) * 0.42); }
}
/* v100 (bi QA 2026-10-29 15:54 — "sửa đua thú thì cũng phải rà lại
   hết các trò, tất cả chung một cách thiết kế"): the v99 race fix
   was audited against EVERY mode (zz-v100audit, 18 modes x 3 frames
   + 864x768 + tall frames). Root cause family: stage height was a
   ratio of stage WIDTH only (cap 620), blind to viewport height —
   at 1024x768 the leftover panel measured 88-234px against
   335-573px of content (fish 309 / house 281 / word 247 / cook 214
   / garden 211 / listen 173 / number 134 / letter 124 / count 55 /
   shapes 40 panel overflow). Three shared moves, no per-game
   patching: (1) word/number/letter leave the 1.06 default and join
   the sentence stage family (0.59) at ALL frames — that default was
   a leftover, their panels are word/letter stacks like sentence;
   (2) every heavy mode's stage becomes height-aware — min(v91
   ratio, 100dvh - K) with K sized from its measured panel content
   (trace's band trim was the first instance of this idea); (3) the
   heaviest panel stacks compact in matching height bands. Tall frames keep
   the v91 ratios and the 192px pet; phones keep theirs except the
   portrait band further down. Clean modes (dots/clock/race/chase/
   bath/maze) are untouched and must stay 0/0. */
#screen-pet .pet-panel:has(#mode-word.active) .pet-stage,
#screen-pet .pet-panel:has(#mode-number.active) .pet-stage,
#screen-pet .pet-panel:has(#mode-letter.active) .pet-stage { height: calc(var(--stage-w) * 0.59); }
/* v100 stage caps (the height-aware half of the fix): on wide
   screens the stage height becomes min(v91 ratio, 100dvh - K),
   where K = that mode's measured panel content + the 90px chrome
   + ~14px slack. The stage yields exactly what the panel needs at
   EVERY height — at 768 the panel gains 100-260px, at 1080+ the
   ratio wins untouched and the pet stays 192px. Contents (after
   the compaction bands below): fish 424, cook 405, listen 335,
   garden 403, house 416, sentence 404, word 362, shapes 356,
   count/feed rounds 390. */
@media (min-width: 620px) {
  #screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: min(calc(var(--stage-w) * 0.831), calc(100vh - 520px)); height: min(calc(var(--stage-w) * 0.831), calc(100dvh - 520px)); }
  #screen-pet .pet-panel:has(#mode-cook.active) .pet-stage { height: min(calc(var(--stage-w) * 0.784), calc(100vh - 509px)); height: min(calc(var(--stage-w) * 0.784), calc(100dvh - 509px)); }
  #screen-pet .pet-panel:has(#mode-listen.active) .pet-stage { height: min(calc(var(--stage-w) * 0.762), calc(100vh - 439px)); height: min(calc(var(--stage-w) * 0.762), calc(100dvh - 439px)); }
  #screen-pet .pet-panel:has(#mode-garden.active) .pet-stage { height: min(calc(var(--stage-w) * 0.716), calc(100vh - 507px)); height: min(calc(var(--stage-w) * 0.716), calc(100dvh - 507px)); }
  #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { height: min(calc(var(--stage-w) * 0.59), calc(100vh - 508px)); height: min(calc(var(--stage-w) * 0.59), calc(100dvh - 508px)); }
  #screen-pet .pet-panel:has(#mode-word.active) .pet-stage { height: min(calc(var(--stage-w) * 0.59), calc(100vh - 458px)); height: min(calc(var(--stage-w) * 0.59), calc(100dvh - 458px)); }
  #screen-pet .pet-panel:has(#mode-shapes.active) .pet-stage { height: min(calc(var(--stage-w) * 0.546), calc(100vh - 460px)); height: min(calc(var(--stage-w) * 0.546), calc(100dvh - 460px)); }
  #screen-pet .pet-panel:not(.count-panel-round):has(#mode-count.active) .pet-stage { height: min(calc(var(--stage-w) * 0.877), calc(100vh - 494px)); height: min(calc(var(--stage-w) * 0.877), calc(100dvh - 494px)); }
}
/* --- v100 panel stack compactions (wide screens). Each band
   reaches exactly as far as that mode's stage cap can bind, so a
   capped stage always meets the compacted stack it was sized
   for. The 84/88px win-banner reserve is NOT touched (v79/v86:
   it keeps the win bar off the score at the win moment). --- */
@media (min-width: 620px) and (max-height: 1030px) {
  /* fish: pond 196->116 (still 3 fish rows); the fish-show card
     keeps its v78/v88 frame-stability reserve. */
  #mode-fish .fish-pond { height: 116px; }
  #mode-fish .msg { height: 34px; }
}
@media (min-width: 620px) and (max-height: 960px) {
  /* garden: plots 76->64 (two rows -24), show/choices/count trim;
     the harvest counter ends directly under the choices instead
     of 116px below the board inside a scroller (bi 15:53). */
  #mode-garden .g-plot { min-height: 64px; }
  #mode-garden .garden-show { min-height: 30px; margin-top: 2px; }
  #mode-garden .garden-choices { min-height: 60px; }
  #mode-garden .garden-choice { min-height: 58px; }
  #mode-garden .garden-count { margin-top: 3px; }
}
@media (min-width: 620px) and (max-height: 920px) {
  /* listen: replay + show strip slim; cards keep tap size. */
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-replay { min-height: 48px; padding: 6px 26px; font-size: 21px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-replay-row { margin-top: 4px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-show { min-height: 52px; margin-top: 4px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-card { min-height: 68px; }
}
@media (min-width: 620px) and (max-height: 880px) {
  /* sentence: pick cards 46->38 in this band (fitSentence steps
     the fonts inside; card heights are the frame contract). */
  #mode-sentence #sentPicks:not(.d4-picks) .pick-opt { height: 38px; min-height: 38px; }
  #mode-sentence .speaker-btn.huge { min-height: 46px; }
  /* word: the picture + target line slim a touch so long-word
     rounds keep a margin under the stage cap. */
  #mode-word .word-pic { font-size: 52px; }
  #mode-word .word-target { min-height: 34px; }
}
@media (min-width: 620px) and (max-height: 860px) {
  /* shapes: sample + grid trim (the 88px win reserve stays). */
  #screen-pet #mode-shapes.mode-panel:has(> .win-banner) .shapes-sample { min-height: 44px; }
  #mode-shapes .shapes-grid { margin-top: 2px; }
}
/* v100 garden: in the plant/water phases the show + choices
   strips render EMPTY but kept their min-heights (36/68), which
   left the harvest counter floating ~97px under the board in
   empty green — the detached look from bi's photo. Same :empty
   collapse the race/house choices already use; when a phase
   deals choices the strip takes its natural height again and
   the counter stays directly underneath either way. */
#mode-garden .garden-show:empty { min-height: 0; margin-top: 0; }
#mode-garden .garden-choices:empty { min-height: 0; margin-top: 0; }
/* v100 portrait phones (<=760px tall): the same family showed up
   on 414x736 — garden stage .716 of a 414 stage-w plus a 445px
   stack, listen .762, cook .784 (18px over), sentence picks need
   the room the un-clipped #sentPicks now takes. Trim only the
   modes that measured over; fish/bath/chase/maze phones were 0. */
@media (orientation: portrait) and (max-height: 760px) {
  #screen-pet .pet-panel:has(#mode-garden.active) .pet-stage { height: calc(var(--stage-w) * 0.58); }
  #screen-pet .pet-panel:has(#mode-listen.active) .pet-stage { height: calc(var(--stage-w) * 0.66); }
  #screen-pet .pet-panel:has(#mode-cook.active) .pet-stage { height: calc(var(--stage-w) * 0.60); }
  #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { height: calc(var(--stage-w) * 0.52); }
  /* v100 phone round 2 (membercheck seed states are the heavy
     ones): fish/cook/house stacks measure the same 422-573px on
     phones as on desktop, against a 646px stage+panel budget —
     they get the same treatment in miniature: stage trims to the
     sentence/race phone family and the stacks compact (fish pond
     to the desktop band's 116, cook tray/menu/pot slim, house
     scene + model shrink with parts rescaled). Pets land at
     92-129px, inside the phone family (race 86-100, sentence 83). */
  #screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: calc(var(--stage-w) * 0.60); }
  #mode-fish .fish-pond { height: 116px; }
  #mode-cook .cook-tray { min-height: 0; }
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-card { min-height: 48px; }
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-pot .ck-pot { font-size: 34px; }
  /* Cook phone round 3: tray cards are content-height (pic + cap),
     so the pics and paddings slim instead of min-heights. (The pic
     span's class is .cc-pic — measured on the live DOM.) */
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-card .cc-pic { font-size: 23px; }
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-card .cc-cap { font-size: 11.5px; }
  #mode-cook .cook-card { padding: 5px 3px; }
  #mode-cook .cook-tray { gap: 4px; margin-top: 0; }
  #mode-cook .cook-menu { margin-top: 4px; }
  #mode-cook .cook-score, #mode-cook .game-score { margin-top: 2px; }
  #mode-cook .cook-msg, #mode-cook .msg { margin-top: 4px; }
  /* House phone round 4 (card internals measured): the choice
     cards' 78px is the base min-height 76, not the glyph sizes —
     min-height and the top row's pills slim on phones. */
  /* Listen phone round 3: the <=920 compaction band is desktop-
     only (min-width 620); phones get their own plain-selector set
     (2-line card names pushed listen 1-6px over). */
  #mode-listen .listen-replay { min-height: 44px; }
  #mode-listen .listen-show { min-height: 56px; }
  #mode-listen .listen-show .ls-pic { font-size: 30px; }
  #screen-pet #mode-listen.mode-panel .listen-card { min-height: 68px; }
  #mode-garden .g-plot { min-height: 64px; }
  #mode-garden .garden-show { min-height: 30px; margin-top: 2px; }
  #mode-garden .garden-choices { min-height: 60px; }
  #mode-garden .garden-choice { min-height: 58px; }
  #mode-garden .garden-count { margin-top: 3px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-replay { min-height: 48px; padding: 6px 26px; font-size: 21px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-show { min-height: 52px; margin-top: 4px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-card { min-height: 68px; }
}
#screen-pet .pet-panel:has(> #gameYard:not([hidden])) .pet-stage { height: calc(var(--stage-w) * 0.404); }
#screen-pet .pet-panel.count-panel-round:has(#mode-count.active) .pet-stage,
#screen-pet .pet-panel.count-panel-round:has(#mode-feed.active) .pet-stage { height: calc(var(--stage-w) * 0.459); }
/* v101 (feed unification): feed's strip stage gets the v100
   height-aware treatment too — min(0.459 ratio, 100dvh - K_feed).
   K_feed = 584, sized from the UNIFIED feed stack measured on the
   harness (zz-v101measure, all values after the compaction band
   below): meter 25 + eq 34 + groups 46 + pond window 114 +
   bowl-count 42 + dots 16 + ask choices 64 + msg 22 + win reserve
   84 = ~449px of content; at any capped frame the panel is a
   constant K - 118 (top/bottom chrome) = ~466, so the stack fits
   with slack and the stage never moves mid-session. Tall frames:
   the 0.459 ratio wins and the uncompacted stack (~569 worst,
   mul ask with the pond kept visible) still fits the panel it
   leaves (800x950: 547 panel vs 569 — the band below covers
   heights <=1030 for exactly this reason). Count legacy keeps
   its plain 0.459 — its own deals still toggle the class. */
@media (min-width: 620px) {
  #screen-pet .pet-panel.count-panel-round:has(#mode-feed.active) .pet-stage { height: min(calc(var(--stage-w) * 0.459), calc(100vh - 584px)); height: min(calc(var(--stage-w) * 0.459), calc(100dvh - 584px)); }
}
/* v101, 414x628 frame (bi's iPhone 6s Plus in Safari, toolbars
   visible — added to the matrix 2026-10-29): in short portrait
   the width-driven 0.459 strip (190px at 414 wide) leaves only
   ~348px of panel, and the mul/div phases overflow it (measured:
   div-ask +93, mul-ask +79 at 414x628). The same dvh-cap idea as
   the desktop K_feed, with K = 510 sized so the panel holds at
   ~420px whenever the cap binds: at 628 the stage is 118, and
   the cap releases exactly where the uncapped panel reaches
   420 again (700px tall), so 414x736 keeps its 190px strip.
   Because 100dvh tracks Safari's toolbar, the stage breathes
   with the toolbar instead of overflowing behind it. The extra
   stack tightening for this band is in the <=700px block after
   the phone band below. Feed only (the :has keys on mode-feed);
   legacy count rounds keep the plain 0.459 here too. */
@media (orientation: portrait) and (max-height: 700px) {
  /* the v91 shell floor (min-height 150 on .pet-stage, "the pet
     always stays visible") clamps the cap — feed's strip may dip
     to 132 in this band only: the pet is ~74px there, still the
     stage's clear subject, and every other mode keeps the 150
     floor. Net at 628: stage 132, panel 406. */
  #screen-pet .pet-panel.count-panel-round:has(#mode-feed.active) .pet-stage { height: min(calc(var(--stage-w) * 0.459), calc(100vh - 510px)); height: min(calc(var(--stage-w) * 0.459), calc(100dvh - 510px)); min-height: 132px; }
}
/* v101 feed stack compaction (the band the K_feed arithmetic
   above is sized with): the unified session's tallest stacks —
   mul/div ask phases, which since v101 keep the pond visible
   under the choices — measure ~569px uncompacted, more than any
   short frame's panel can hold under a 0.459 stage. Like the
   v100 bands for fish/cook/house, the FEED stack slims exactly
   in the frames where the stage cap binds (wide-short) and on
   short portrait phones. #mode-feed selectors only: the legacy
   count panel, which shares most of these classes, is untouched. */
@media (min-width: 620px) and (max-height: 1030px), (orientation: portrait) and (max-height: 860px) {
  #screen-pet #mode-feed .pond.heap .food-btn { min-height: 34px; padding: 2px; }
  #screen-pet #mode-feed .pond.heap .food-btn svg { max-width: 30px; }
  #screen-pet #mode-feed .bowl-count { padding: 0 12px 2px; }
  #screen-pet #mode-feed .bowl-count b { font-size: 20px; vertical-align: -2px; }
  #screen-pet #mode-feed .choices { margin-top: 4px; }
  #screen-pet #mode-feed .choices .choice-btn { min-height: 50px; font-size: 30px; }
  #screen-pet #mode-feed .add-eq { font-size: 20px; min-height: 22px; margin: 2px auto; }
  #screen-pet #mode-feed .feed-meter { margin-bottom: 4px; }
  #screen-pet #mode-feed .progress-dots { margin-top: 2px; }
  #screen-pet #mode-feed .md-mini { width: 12px; height: 12px; }
  #screen-pet #mode-feed .md-mini svg { width: 11px; }
  #screen-pet #mode-feed .md-mini.empty { width: 10px; height: 10px; }
  #screen-pet #mode-feed .md-group-items, #screen-pet #mode-feed .md-bowl-items { min-height: 13px; }
  #screen-pet #mode-feed .md-reset { min-height: 32px; margin-top: 2px; }
  #screen-pet #mode-feed.mode-panel:has(> .win-banner) { padding-bottom: 78px; }
  /* v101 ask-phase tightening (harness-measured: div-ask with the
     pond kept visible overflowed 34px at 1024x768 with a 2-row
     grid pond; mul-ask had only ~6px spare). The mul/div group
     cards and the base-density grid pond slim a notch further in
     the same band — internal section sizes only, the stage/panel
     geometry above is untouched. Denser ponds keep their own
     sizing (their layout.css rules are tighter already). */
  #screen-pet #mode-feed .md-groups, #screen-pet #mode-feed .md-bowls { gap: 5px; }
  #screen-pet #mode-feed .md-group, #screen-pet #mode-feed .md-bowl { padding: 2px 4px; border-width: 2px; border-radius: 12px; }
  #screen-pet #mode-feed .md-group-label, #screen-pet #mode-feed .md-bowl-label { font-size: 10px; margin-top: 1px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn { min-height: 44px; padding: 2px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn svg { max-width: 34px; }
}
@media (orientation: portrait) and (max-height: 860px) {
  /* phones are the tightest panel (414x736 leaves ~456): the
     heap window slims one more notch there. */
  #screen-pet #mode-feed .pond.heap .food-btn { min-height: 32px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn { min-height: 38px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn svg { max-width: 30px; }
  #screen-pet #mode-feed .choices .choice-btn { min-height: 46px; }
}
@media (orientation: portrait) and (max-height: 700px) {
  /* v101, 414x628 Safari-toolbar band: the stage cap above holds
     the panel at ~420px here; the mul/div stacks slim one more
     notch so they fit it with margin (div-ask measured 441px of
     content at 628 before this block). */
  #screen-pet #mode-feed .pond.heap .food-btn { min-height: 28px; }
  #screen-pet #mode-feed .pond.heap .food-btn svg { max-width: 25px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn { min-height: 30px; }
  #screen-pet #mode-feed .pond:not(.heap):not(.dense):not(.dense2) .food-btn svg { max-width: 24px; }
  #screen-pet #mode-feed .choices { margin-top: 2px; }
  #screen-pet #mode-feed .choices .choice-btn { min-height: 40px; font-size: 26px; }
  #screen-pet #mode-feed .add-eq { font-size: 18px; min-height: 20px; margin: 1px auto; }
  #screen-pet #mode-feed .md-mini { width: 11px; height: 11px; }
  #screen-pet #mode-feed .md-mini svg { width: 10px; }
  #screen-pet #mode-feed .md-reset { min-height: 26px; }
  #screen-pet #mode-feed .md-group-items, #screen-pet #mode-feed .md-bowl-items { min-height: 11px; }
  #screen-pet #mode-feed .bowl-count { padding: 0 12px 0; }
  #screen-pet #mode-feed .bowl-count b { font-size: 18px; }
  #screen-pet #mode-feed .feed-meter { margin-bottom: 2px; }
  #screen-pet #mode-feed .progress-dots { margin-top: 0; }
  #screen-pet #mode-feed .progress-dots span { width: 7px; height: 7px; }
  #screen-pet #mode-feed.mode-panel:has(> .win-banner) { padding-bottom: 62px; }
}
/* ===== v107 — KHUNG THẤP (portrait ≤700px): VÙNG CHƠI ƯU TIÊN =====
   Bi QA 2026-10-30 trên iPhone 6s Plus thật (Safari hiện thanh
   công cụ, cao khả kiến 628px): "chỗ vẽ quá bé, đồng hồ quá bé".
   Lượt rà v106 (zz-v106audit, 20 trò × 414×628) đo được: trace
   board 72px, clock face 114px, count msgrow NGOÀI màn hình,
   msg của cook/listen/sentence/fish/house bị pill che — trong
   khi stage vẫn tính theo bề ngang (0.546 × stage-w) mù chiều
   cao, và các stack nội dung cố định không có cơ chế co.
   Ba nước đi, đúng họ v100/v101, CHỈ ở dải portrait ≤700px
   (khung cao giữ nguyên từng pixel):
   (1) stage cap theo chiều cao: height = min(tỉ lệ v91,
       100dvh − K) với K đo từ stack thật của từng trò — stage
       nhường đúng phần panel thiếu, thú co theo công thức
       reserve sẵn có nên bong bóng không bao giờ đè thú.
   (2) trace + clock: stack điều khiển dạt sang CỘT BÊN — bảng
       tô / mặt đồng hồ chiếm trọn cột chính (mẫu khung cao:
       điều khiển không ăn diện tích vùng chơi).
   (3) nén nhẹ stack của cook/listen/sentence/house trong dải.
   Sàn đo @414×628: trace ≥240 (đạt 248), clock ≥200 (đạt 232),
   count msgrow trong màn hình, msg mọi trò hết bị pill che. */
@media (orientation: portrait) and (max-height: 700px) {
  /* (1) stage caps — K: trace/clock 428, cook 426, listen 396,
     sentence 440, fish 404, house 442 (panel cần = stack đo
     được + slack; cap chỉ bind khi dvh < ~660). */
  #screen-pet .pet-panel:has(#mode-trace.active) .pet-stage { height: min(calc(var(--stage-w) * 0.546), calc(100vh - 428px)); height: min(calc(var(--stage-w) * 0.546), calc(100dvh - 428px)); }
  #screen-pet .pet-panel:has(#mode-clock.active) .pet-stage { height: min(calc(var(--stage-w) * 0.546), calc(100vh - 428px)); height: min(calc(var(--stage-w) * 0.546), calc(100dvh - 428px)); }
  #screen-pet .pet-panel:has(#mode-cook.active) .pet-stage { height: min(calc(var(--stage-w) * 0.60), calc(100vh - 426px)); height: min(calc(var(--stage-w) * 0.60), calc(100dvh - 426px)); }
  #screen-pet .pet-panel:has(#mode-listen.active) .pet-stage { height: min(calc(var(--stage-w) * 0.66), calc(100vh - 396px)); height: min(calc(var(--stage-w) * 0.66), calc(100dvh - 396px)); }
  #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { height: min(calc(var(--stage-w) * 0.52), calc(100vh - 440px)); height: min(calc(var(--stage-w) * 0.52), calc(100dvh - 440px)); }
  #screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: min(calc(var(--stage-w) * 0.60), calc(100vh - 404px)); height: min(calc(var(--stage-w) * 0.60), calc(100dvh - 404px)); }
  /* (2a) TRACE: --trace-w thôi trừ 234px của stack dọc; ở dải
     này stack nằm ở cột bên nên chỉ trừ phần còn xếp dọc thật
     (thanh % + msg + đệm = 90). Panel thành lưới: bảng ở cột
     chính (rộng đúng --trace-w), ghost/check/pick xếp dọc ở
     cột bên ~126px, msg nằm dưới cùng cả hai cột. */
  #screen-pet #mode-trace { --trace-w: min(calc(var(--stage-w) - 152px), calc(var(--panel-h) - 90px)); }
  #screen-pet .mode-panel#mode-trace.active {
    display: grid; column-gap: 10px; align-content: start;
    grid-template-columns: var(--trace-w) minmax(0, 1fr);
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas: "board ghost" "board check" "board pick" "msg msg";
  }
  #screen-pet #mode-trace .trace-wrap { grid-area: board; margin: 0; }
  #screen-pet #mode-trace .trace-bar-row { margin-top: 4px; }
  #screen-pet #mode-trace #traceGhostRow {
    grid-area: ghost; width: 100%; margin: 0;
    flex-direction: column; gap: 8px; align-items: stretch;
  }
  #screen-pet #mode-trace #traceGhostRow .ghost-btn { flex: 0 0 auto; width: 100%; }
  #screen-pet #mode-trace .trace-actions { grid-area: check; width: 100%; margin: 8px 0 0; }
  #screen-pet #mode-trace .trace-pick-row { grid-area: pick; width: 100%; margin: 8px 0 0; }
  #screen-pet #mode-trace .trace-pick-row .ghost-btn { font-size: 14.5px; line-height: 1.25; white-space: normal; min-height: 48px; }
  #screen-pet #mode-trace .msg { grid-area: msg; margin-top: 6px; }
  /* (2b) CLOCK: mặt đồng hồ ở cột chính; cột bên 148px chứa
     nút ván mới (SET) hoặc 3 thẻ giờ xếp dọc (READ) + dòng msg
     gói gọn dưới chúng; hàng trên cùng: cảnh bên trái, số
     digital bên phải. Mặt = min(cột 232, trần 272 sẵn có). */
  #screen-pet .mode-panel#mode-clock.active {
    display: grid; column-gap: 10px; align-content: start;
    grid-template-columns: minmax(0, 1fr) 148px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas: "scene digital" "face side" "face msg";
  }
  #screen-pet #mode-clock .clock-scene { grid-area: scene; margin-top: 0; }
  #screen-pet #mode-clock .clock-digital { grid-area: digital; min-height: 42px; font-size: 34px; }
  /* wrap phải bị khóa vào track của nó: rule win-form ở dots.css
     đặt width tường minh min(0.74·stage-w, 272px) (đặc tả 2,3,0)
     → wrap phình 272px khỏi cột 232px, svg theo đó tràn vành sang
     cột msg đè nét chữ đầu dòng (bắt bằng ảnh live v107). Selector
     :has ở đây ngang đặc tả và responsive nạp sau dots nên thắng;
     width:auto + min-width:0 → wrap = đúng track, max-width:100%
     của svg mới có nghĩa. */
  #screen-pet #mode-clock .clock-wrap,
  #screen-pet #mode-clock.mode-panel:has(> .win-banner) .clock-wrap { grid-area: face; height: 100%; max-height: none; margin: 0; min-width: 0; width: auto; }
  #screen-pet #mode-clock .clock-svg { max-width: 100%; }
  #screen-pet #mode-clock .clock-actions { grid-area: side; margin-top: 0; align-self: start; display: block; }
  #screen-pet #mode-clock .clock-actions .ghost-btn { width: 100%; }
  #screen-pet #mode-clock .clock-choices { grid-area: side; flex-direction: column; margin-top: 0; gap: 8px; }
  #screen-pet #mode-clock .clock-card { min-width: 0; width: 100%; min-height: 54px; }
  #screen-pet #mode-clock .msg { grid-area: msg; margin-top: 4px; }
  /* (3) nén stack trong dải cho các trò còn lại */
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-card { min-height: 50px; }
  #screen-pet #mode-cook.mode-panel:has(> .win-banner) .cook-card .cc-pic { font-size: 26px; }
  #mode-cook .cook-tray { min-height: 108px; }
  #mode-cook .cook-menu { min-height: 0; margin-top: 4px; }
  #mode-cook .cook-menu-item { padding: 3px 2px; }
  #mode-cook .cook-menu-item .cm-pic { font-size: 24px; }
  #screen-pet #mode-listen.mode-panel:has(> .win-banner) .listen-show { min-height: 52px; margin-top: 4px; }
  #mode-sentence .sentence-text { margin-bottom: 0; }
  #mode-sentence .sentence-slots { margin-top: 2px; }
  #mode-sentence .speaker-btn.huge { min-height: 40px; }
  /* count panel-round (more/missing/div): badge số đếm 30px
     làm stack vượt panel 3px — nén như feed đã làm ở cùng dải. */
  #mode-count .bowl-count { padding: 0 12px 0; }
  #mode-count .bowl-count b { font-size: 20px; vertical-align: -2px; }
  #mode-cook .game-score { margin-top: 0; min-height: 22px; }
  #mode-cook .msg { margin-top: 2px; }
}
/* v107: count legacy ván "feed" (không phải panel-round) giữ
   stage 0.877 ở mọi khung cao — ở 414×628 stage ngốn 363px,
   panel còn 175px cho stack 327px, msgrow rơi khỏi màn hình.
   Cap cùng họ như trên nhưng bind ở cả dải ≤860px (ở 414×736
   msgrow vẫn bị pill che 30px): stage = min(0.877, dvh − 423);
   ở 736 stage còn 313, panel đủ 327; khung ≥844 tỉ lệ gốc thắng. */
@media (orientation: portrait) and (max-height: 860px) {
  #screen-pet .pet-panel:not(.count-panel-round):has(#mode-count.active) .pet-stage { height: min(calc(var(--stage-w) * 0.877), calc(100vh - 423px)); height: min(calc(var(--stage-w) * 0.877), calc(100dvh - 423px)); }
}

/* Panel claims the leftover (v79, giữ nguyên): yard games keep yard priority. */
#screen-pet .pet-panel:not(:has(> #gameYard:not([hidden]))) .mode-panel.active { flex-grow: 1; }
#screen-pet .pet-panel:has(> #gameYard:not([hidden])) .mode-panel.active { flex-grow: 0; }
/* v91: kid-area column cap 620px (parent zone keeps its 760px .wrap). */
body.on-home .wrap, body.on-pet .wrap { max-width: 620px; }
/* v91 fix (v84 regression, found 2026-10-28): the v88 core-sentence
   pick system is FLEX (basis 30% + wrap + third-cap), NOT the
   games.css grid. The v91 surgery dropped the display:flex override
   for #sentPicks, so grid + the flex-basis/max-width leftovers
   crushed every card to ~30px wide (scrollWidth 51 > clientWidth 24)
   at every frame — v90 computed parent display:flex gap 8px, card
   display:flex. Restored here (no padding/height touched, so the
   v88 46px card + 2px 4px padding cascade is unchanged; D4 picks
   keep their own grid via the :not exclusion). */
#mode-sentence #sentPicks:not(.d4-picks) .pick-opts { display: flex; flex-wrap: wrap; gap: 8px; }
#mode-sentence #sentPicks:not(.d4-picks) .pick-opt { display: flex; align-items: center; justify-content: center; gap: 6px; }
/* v91 E1: rotate reminder — touch devices in landscape ONLY (phone
   and tablet); mouse devices keep the centred portrait column. */
#rotateOverlay { display: none; }
@media (hover: none) and (orientation: landscape) {
  body.on-home #rotateOverlay, body.on-pet #rotateOverlay {
    display: flex; position: fixed; inset: 0; z-index: 200;
    flex-direction: column; align-items: center; justify-content: center; gap: 12px;
    background: linear-gradient(180deg, #8fd8ff 0%, #c8f2ff 55%, #93e77e 56%, #63d64f 100%);
    text-align: center; padding: 24px;
  }
}
#rotateOverlay .ro-ico { font-size: 64px; line-height: 1; }
#rotateOverlay .ro-text { font-size: 24px; font-weight: 800; color: #26436b; line-height: 1.4; }

#screen-pet .pet-panel:has(> #gameYard:not([hidden])) .pet-stage { flex-grow: 0; }
    /* v21 (feedback #15): in dots mode the board — not the stage —
       claims the leftover column space, so it can grow until the
       number badges stay readable at the smallest screens. */
    #screen-pet .pet-panel:has(#mode-dots.active) .pet-stage { flex-grow: 0; }
    /* v21: shapes at 6-7 deals 12 cards — the panel, not the stage,
       claims the leftover, and the 12-card grid goes 4-across so the
       taller deal still fits one screen. */
    #screen-pet .pet-panel:has(#mode-shapes.active) .pet-stage { flex-grow: 0; }
    /* v75: sentence — the panel, not the stage, claims the leftover (its pick rows flex inside) */
    #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage { flex-grow: 0; }
    #screen-pet .pet-panel:has(#mode-sentence.active) .pet-stage > .pet-face { height: min(148px, calc(100% - 120px)); }
    .shapes-grid.g12 { grid-template-columns: repeat(4, minmax(0, 1fr)); width: min(92vw, 320px); gap: 7px; }
    /* v79 (frame stability): the shapes panel reserve is PERMANENT
       like the dots panel's (see layout.css) — the win moment must
       not change any geometry, so the old play-only shrink is gone. */
    #screen-pet #gameYard { flex: 1 1 auto; min-height: 190px; }
    /* slim-stage modes: smaller sky reserve, pet stays clearly visible
       (v78: reserve 120px — the bubble sits lower under the name pill
       and carries the target row; the reserve keeps its tail off the
       pet's ears — verified against the feedback-suite geometry) */
    #screen-pet .pet-panel:has(#mode-trace.active) .pet-stage > .pet-face { height: min(148px, calc(100% - 120px)); }
    /* v78: 52px (was 36) — the trace bubble slid under the pet's
       name/hearts pill at every frame size; keep the pill clear. */
    #screen-pet .pet-panel:has(#mode-dots.active) .pet-stage > .pet-face { height: min(132px, calc(100% - 120px)); }
    #screen-pet .pet-panel:has(#mode-clock.active) .pet-stage > .pet-face { height: min(132px, calc(100% - 120px)); }
    #screen-pet .pet-panel:has(#mode-shapes.active) .pet-stage > .pet-face { height: min(132px, calc(100% - 120px)); }
    #screen-pet .pet-panel:has(#mode-shapes.active) .bubble .b-text { }
    /* v78: the shapes glyph rides a touch smaller in the bubble —
       the sample card below keeps the full-size sample + name. */
    #screen-pet .pet-panel:has(#mode-shapes.active) .bubble .b-big { font-size: 30px; }
    /* v78: same for the dots hunted number — a 30px target digit
       keeps the slim-stage bubble off the pet at short frames. */
    #screen-pet .pet-panel:has(#mode-dots.active) .bubble .b-big { font-size: 30px; }
    /* v78: on narrow frames the shape's name label yields its
       width to the question text (the glyph stays in the bubble;
       the name stays on the panel's sample card) so the line
       keeps its two-line fit instead of growing a third line. */
    @media (max-width: 380px) {
      #screen-pet .pet-panel:has(#mode-shapes.active) .bubble .b-big-label { display: none; }
    }
    
    
/* v91: panel count rounds — pet stands left in the strip, bubble beside it.
   Stage height = stage-unit ratio (was 208/192/168/152px by height band);
   bubble offset scales with --stage-w (was 154px left at F2). */
#screen-pet .pet-panel.count-panel-round .pet-stage > .pet-face {
  display: block; left: 10px; right: auto; transform: none; bottom: 6px;
  height: min(148px, calc(100% - 58px)); width: auto; aspect-ratio: 1 / 1;
}
#screen-pet .pet-panel.count-panel-round .pet-head { display: flex; top: 6px; bottom: auto; left: 12px; z-index: 7; }
#screen-pet .pet-panel.count-panel-round .pet-colors { display: none; }
#screen-pet .pet-panel.count-panel-round .bubble { top: 56%; transform: translateY(-50%); left: calc(var(--stage-w) * 0.42); right: 12px; flex-wrap: wrap; row-gap: 2px; align-content: center; }
/* v67: same comic bubble, tail pointing left at the pet beside it */
#screen-pet .pet-panel.count-panel-round .bubble::before {
  left: -15px; top: 50%; bottom: auto; margin: 0; transform: translateY(-50%);
  border: 10px solid transparent; border-right-color: var(--ink); border-left: 0;
}
#screen-pet .pet-panel.count-panel-round .bubble::after {
  left: -8px; top: 50%; bottom: auto; margin: 0; transform: translateY(-50%);
  border: 7px solid transparent; border-right-color: #fffdf4; border-left: 0;
}
#screen-pet .pet-panel.count-panel-round .bubble .b-text { font-size: 15.5px; flex: 1 1 100%; order: 2; }
#screen-pet .pet-panel.count-panel-round .bubble .b-big { font-size: 24px; order: 1; line-height: 1.1; }
/* v94 (bi photo QA 2026-10-29 06:33 — the pet is covered while it
   eats): in count rounds the pet stands at the tray from the deal
   (nav's spec.pet === "tray"), and syncBubbleDock does narrow the
   bubble to the free side space — but the dock's own left/right
   (layout.css #screen-pet .bubble.dock-l/r, specificity (1,2,0))
   lose the cascade to the count-round bubble rule above
   ((1,3,1)), so the bubble stayed parked at left:42% on top of
   the eating pet (measured on a 414x736 missing round: a 128x104
   bubble over the pet's 121x121 box — 83% of the pet covered, at
   idle and while eating alike). These rules give the dock its
   authority back inside count rounds: side docks pin to the free
   side (the JS still sets the width from the live free space),
   dock-up spans the stage under the top the JS lifts it to. */
#screen-pet .pet-panel.count-panel-round .bubble.dock-l { left: 8px; right: auto; }
#screen-pet .pet-panel.count-panel-round .bubble.dock-r { left: auto; right: 8px; }
#screen-pet .pet-panel.count-panel-round .bubble.dock-up { left: 10px; right: 10px; transform: none; }
/* v95 (bi photo QA 2026-10-29 08:20 — "the speech bubble's arrow
   is wrong"): a side-docked bubble kept the BASE left-pointing
   tail (care.css) in its narrow docked phase — docked on the
   LEFT with the pet eating on the RIGHT, the arrow pointed away
   from the pet into empty space. The dock tail now mirrors the
   dock: dock-l points RIGHT toward the pet, dock-r points LEFT,
   both vertically centred on the bubble's side edge. dock-up
   keeps the standard down tail. */
#screen-pet .pet-panel.count-panel-round .bubble.dock-l::before { left: auto; right: -15px; top: 50%; bottom: auto; transform: translateY(-50%); border: 10px solid transparent; border-left-color: var(--ink); border-right: 0; }
#screen-pet .pet-panel.count-panel-round .bubble.dock-l::after { left: auto; right: -8px; top: 50%; bottom: auto; transform: translateY(-50%); border: 7px solid transparent; border-left-color: #fffdf4; border-right: 0; }
#screen-pet .pet-panel.count-panel-round .bubble.dock-r::before { left: -15px; right: auto; top: 50%; bottom: auto; transform: translateY(-50%); border: 10px solid transparent; border-right-color: var(--ink); border-left: 0; }
#screen-pet .pet-panel.count-panel-round .bubble.dock-r::after { left: -8px; right: auto; top: 50%; bottom: auto; transform: translateY(-50%); border: 7px solid transparent; border-right-color: #fffdf4; border-left: 0; }
    /* (B1) one slim top row on phones */
    @media (max-width: 600px) {
      .topbar { flex-wrap: nowrap; gap: 6px; margin-bottom: 6px; }
      .home-btn.show { white-space: nowrap; font-size: 14.5px; padding: 6px 10px; min-height: 44px; gap: 5px; flex: 0 1 auto; }
      .sticker-box { padding: 4px 10px 4px 6px; gap: 6px; flex: 0 0 auto; }
      .sticker-box .s-label { display: none; }
      .sticker-box .s-ico { width: 28px; height: 28px; }
      .sticker-box .s-num { font-size: 21px; }
      .lang-pop-btn { min-height: 44px; padding: 6px 10px; }
      body.on-pet .icon-btn { min-height: 44px; min-width: 44px; }
    }
    /* (B2) phone panel/banner reserves — v22: the fixed tab toolbar is
       gone (pet pill + full-screen menu instead), so panels no longer
       pad past a bottom bar; banners sit at the panel's own edge. */
    @media (max-width: 600px) {
      #screen-pet .mode-panel.active { padding-bottom: 14px; }
      #screen-pet .win-banner.show { bottom: 12px; }
    }


/* ===== v81 — ONE UNIFIED SCENE for the game screen (owner QA
   2026-10-27 21:51/21:52) =======================================
   Before: every game screen was TWO/THREE bordered boxes stacked —
   a decorated stage box on top (in bath/chase a 148px strip that
   measured 85% empty scenery: name pill + big gold speaker + sun,
   while the pet and the bubble played in the yard box below), the
   yard as its own bordered box, and the mode panel as a white card.
   The owner: "many games have this top frame — it no longer makes
   sense; restructure the game screen."
   Now: the whole pet screen is ONE scene. The stage keeps its
   sky->grass gradient (the scene's sky), the pet panel carries the
   scene's ground, the yard and the mode panel lose their borders /
   radii / shadows and the panel becomes a soft light clearing that
   fades in from the grass — no box edges anywhere, play content
   sits IN the scene. Geometry is untouched (every height/top pin
   from v74/v78/v79 stands; the frame-stability standard is about
   boxes not moving, and none move). The name/hearts pill and the
   replay button form one slim HUD row pinned to the scene's top
   edge (the bubble already starts below it at 58px): the big gold
   in-stage speaker is gone — the replay is a small white round
   button in the same language as the pill and the colour button.
   Its handler and DOM place are unchanged (yard.js inserts the
   bubble before it inside the stage), so v80-audio semantics hold. */
#screen-pet .pet-panel {
  background: linear-gradient(180deg, #63d64f 0%, #4cc24a 100%);
}
#screen-pet .pet-stage {
  border: none; border-radius: 0; box-shadow: none;
}
#screen-pet .game-yard {
  border: none; border-radius: 0; box-shadow: none;
}
#screen-pet .mode-panel.active {
  border: none; border-radius: 0; box-shadow: none;
  /* v93 (bi's layout verdict on v92, dots 1280x800 = the standard):
     the v80 "soft light clearing" — a gradient washing to
     near-white 64px down — is RETIRED. Every mode panel now
     carries the yard's grass, opaque, top to bottom, so game
     content sits ON the scene like the dots board does. This one
     shared rule is also the scene guarantee member panels
     inherit on integration. (The dots.css per-mode copies of
     this recipe predate it and agree with it.) */
  /* v99 (bi photo QA 2026-10-29 14:33 — "vườn và trò chơi vẫn
     lệch màu và có kẻ tách"): the v93 recipe still restarted the
     grass at the panel's top edge — its first stop #5ec94d plus
     the .35 sunlit wash at the top centre met the ground above
     (stage/yard rendered bottom = the hills' composite
     rgb(92,202,82), pixel-measured at every seam) as a bright
     patch under a straight line, and the 10px margin-top opened
     a third band between them. The panel is now a true
     CONTINUATION of the ground: margin closed, no wash, first
     stop exactly the ground's rendered bottom colour #5cca52,
     last stop the pet-panel family's own end #4cc24a — so the
     panel's bottom also meets the bottom-bar zone (painted by
     the panel ::before, which ends at #4cc24a) with no step.
     Outside the column the seam is closed by the pet-panel
     ::before's hard-stop segment (see the v99 note there): a
     ::before bleed on the mode panel itself cannot work — the
     panel scrolls internally (overflow-y: auto), which clips
     any child that reaches past its box sideways. */
  margin-top: 0;
  background: linear-gradient(180deg, #5cca52 0%, #4cc24a 100%);
}
/* HUD replay: small, round, quiet — no more gold slab in the scene */
#screen-pet #bubbleSpeak {
  background: rgba(255, 255, 255, .94);
  border: 2.5px solid rgba(255, 255, 255, .95);
  color: var(--ink);
  box-shadow: 0 3px 0 rgba(35, 50, 70, .14);
}
#screen-pet #bubbleSpeak:active { transform: translateY(2px); box-shadow: none; }
/* ==== SW v81 addendum (bi QA photo 00:12, bath): the stage strip
   still read as its own decorated scene in the yard games because
   its ground layer (hills + fence + stone path + tree) painted a
   complete empty landscape above the yard's own sky. While the
   yard is open the strip becomes SKY ONLY — one sky gradient —
   keeping the sun, the clouds and the flowers at the seam
   (ambient bees target stage flowers; hiding the flowers too
   would park bees at 0,0). One sky now runs strip -> yard; the
   yard's fence is the only horizon. Paint-only: no box moves. == */
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .scene-bg {
  background: linear-gradient(180deg, #8fd8ff 0%, #c8f2ff 100%);
}
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .sc-ground > path,
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .sc-ground .sc-fence,
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .sc-ground .sc-path,
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .sc-treew {
  display: none;
}
/* ==== SW v87 addendum 2 (bi photo QA 07:15): the v82 rule above
   kept the strip's FLOWERS "at the seam" for the ambient bees —
   with the hills/fence hidden they hung in pure sky, stems ending
   in air, a flower row floating under the bubble while the yard's
   own ground sat far below (bi: "hoa lơ lửng giữa trời"). The
   strip is now sky-only INCLUDING its flowers; the planted flowers
   live in the yard's ground. The bees skip zero-size (hidden)
   flowers when picking a target — see js/pets/ambient.js. == */
#screen-pet .pet-panel:has(#gameYard:not([hidden])) .pet-stage .sc-ground .sc-flower {
  display: none;
}
/* ==== SW v88 addendum (bi QA 08:53): a bright green band still cut
   the sky at the strip/yard seam. It was NOT scenery: the pet-panel
   itself paints a green gradient (#63d64f -> #4cc24a, v81 block
   below), and #gameYard's margin-top: 10px opened a 10px window
   onto that green between the sky-only strip (bottom) and the yard
   (top) — measured on the harness at 390x844: a full-width green
   band at y158-167, rgb(94,210,78), elementFromPoint = the panel.
   Both boxes are already borderless/square (v81), so closing the
   margin joins strip sky -> yard sky into ONE continuous sky; the
   yard simply grows the 10px it used to waste. Bath shares the
   same seam and is fixed by the same rule. == */
#screen-pet .pet-panel:has(#gameYard:not([hidden])) > #gameYard {
  margin-top: 0;
}
/* ==== SW v87 addendum 2 (bi photo QA 07:15, menu/care at wide
   frames): the care panel was the one pale clearing column beside
   the stage's full scene — two disconnected blocks, the panel
   ~90% empty. At wide frames the care panel now paints the
   stage's own sky->grass gradient, so stage + panel read as ONE
   panorama with a single horizon. Paint-only. == */
/* ==== SW v88 addendum 3 (bi photo QA 2026-10-28 09:21): the v87
   gradient above gave the care panel its OWN horizon at 54%, and
   anim.js injected a second full scenery (second fence) into it —
   but the panel stacks BELOW the stage, so the yard rendered as
   TWO scenes: stage scene, a sky strip carrying the hint, then a
   second fence + empty grass. Fix: no injected scenery in
   #mode-care (anim.js), no sky in the panel at all — at >=600px
   the panel is a GRASS CONTINUATION of the stage's ground (top
   colour = the stage's rendered bottom-edge grass, deepening to
   the panel green), and the 10px panel margin closes so grass
   meets grass. ONE fence, ONE horizon, the hint sits inside the
   scene on the grass. Portrait (<600px) is untouched. == */
/* v93 addendum 3 (bi 23:00, phone photo): the v88 grass
   continuation above was gated to >=600px-wide frames, so on
   PHONES the care strip under the stage stayed pale — the exact
   "yard band + dead pale zone" photo bi sent. The continuation
   now applies at EVERY width: grass meets grass on phones too. */
#screen-pet .mode-panel#mode-care.active {
  background: linear-gradient(180deg, #59ca4e 0%, #4cc24a 100%);
}
#screen-pet .pet-panel:has(> #mode-care.active) > #mode-care {
  margin-top: 0;
}
/* The care panel carries no scenery layer any more (v88); the
   hint stays above the panel's own background. */
#mode-care { position: relative; }
#mode-care .care-hint { position: relative; z-index: 2; }

/* ==== SW v83 (PLAY1 addendum to the v82 round): the shared
   .modes-hint line under the pet panel carries the FEED game's
   instruction text, but in the wide regimes it rendered under
   EVERY mode — PLAY1 photographed it at the bottom of the Bath
   screen on desktop (1280x800, all modes: display block, 40px).
   The line only describes feeding/counting, so it now shows
   only while the feed or count panel is active; every other
   mode already has its own task line and speech bubble. == */
#screen-pet .pet-panel:not(:has(> #mode-feed.active, > #mode-count.active)) > .modes-hint {
  display: none;
}

/* v91 (farmLand regression guard): the v74 landscape block carried the
   v76 sun cap (height min(45%, 118px)) that kept the farm sun's disc
   clear of the shop button at 844x390. Deleting the landscape grid
   removed the cap too, and the probe measures geometry under the
   rotate overlay — so the cap is restored as ONE landscape-scoped
   scenery rule (not a layout regime): portrait suns are untouched. */
@media (orientation: landscape) {
  .farm-scene .sc-sunw { width: auto; height: min(45%, 118px); }
}

/* ==== SW v96 (bi 2026-10-29 11:43): borderless, full-bleed yard ====
   The scene box now runs edge to edge (layout.css .farm-scene); the
   rules below keep everything that must NOT follow it to the edge
   inside the logical <=620px yard column, and keep the scenery
   ornaments at their design size on wide screens — the sky grows,
   the sun does not. */
/* Shop button: bottom-right of the LOGICAL yard, not of the screen. */
.farm-scene .shop-btn { right: max(10px, calc(50% - 300px)); }
/* Scenery ornaments: design sizes, however wide the bleed gets. */
.farm-scene .sc-sunw { width: min(25%, 150px); }
.farm-scene .sc-cw1 { width: min(31%, 250px); }
.farm-scene .sc-cw2 { width: min(22%, 180px); }
.farm-scene .sc-treew { width: min(23%, 185px); }
/* Pet screen: stage and panel have worn no borders since v81 — now
   they also touch the screen's edges on phones (the wrap's side
   padding is gone there); the 620px column cap on wide screens and
   every inner layout rule stand. */
body.on-pet .wrap { padding-left: 0; padding-right: 0; }

/* ==== SW v98 (bi photo QA 2026-10-29 13:36-13:38): the pet
   screen bleeds too ====
   Home went borderless in v96/v97; the pet screen still ended
   its painting at the 620px column, leaving a pale washed void
   on both sides at wide frames. Every painted layer of the pet
   screen now runs edge to edge while every box stays in the
   column: the stage's scenery (layout.css), the game yard's
   backdrop (care.css) — and here the panel's own grass, bled on
   a ::before behind the whole panel so the strips no stage or
   mode covers (the care footer's band, the seams between mode
   panels) continue the meadow across the screen. The panel's
   gradient is the flat grass family every mode panel already
   sits on, so the joins read as one field. */
#screen-pet .pet-panel { position: relative; isolation: isolate; }
#screen-pet .pet-panel::before {
  content: ""; position: absolute; top: 0; bottom: 0;
  left: calc(50% - 50vw); width: 100vw; z-index: -1;
  /* v99: inside the active mode's vertical span this bleed wears
     the MODE's own continuation gradient (#5cca52 -> #4cc24a,
     phased over exactly the mode's span), so outside the column
     the ground also meets the stage/yard at rgb(92,202,82) with
     no step — the v98 single gradient phased over the whole
     panel cut the seam at rgb(81,198,75) there (pixel-measured).
     syncStage (init.js) publishes the span as --pm-top/--pm-bot
     (px within the panel); the hard stops sit exactly under the
     stage/yard bleeds' bottom edges, so the jump itself is never
     the visible row. Outside the span the v98 family gradient
     stands. Fallbacks (no vars yet) keep the v98 painting. */
  /* The segment starts a few px ABOVE --pm-top: that strip is
     always covered by the stage/yard bleed (which ends at the
     seam in the ground's own colour), so a few px of measure
     staleness can never expose the jump as a row of its own. */
  background: linear-gradient(180deg,
    #63d64f 0px,
    #4cc24a calc(var(--pm-top, 100%) - 6px),
    #5cca52 calc(var(--pm-top, 100%) - 6px),
    #4cc24a var(--pm-bot, 100%),
    #4cc24a 100%);
}

/* ===== v109 — S107E/#340 FIXES: fish fit, clock READ msg, house 761–860 =====
   Three frame classes the earlier bands missed:
   (a) portrait 761–860px tall (375×812, 390×844): the ≤760 phone
       compactions switch off but the dvh is still too short for the
       uncompacted fish/house stacks — the fish panel overflowed its
       box by 62px at 375×812 so the absolute win bar landed ON the
       caught-fish line (+10px, Issue #340), and the house msg row
       ended under the pet pill (elementFromPoint = petPill).
   (b) portrait ≤700 (414×628): the v107 fish stage cap (K=404)
       still left the fish stack ~40px taller than its panel, and
       the compacted 116px pond broke the lane math (see fish.js
       fishLayoutLanes — lanes are now derived in JS; the pond here
       is sized so the derived tiles stay tappable).
   (c) clock READ rounds at ≤700: the v107 side-column grid left
       the msg a 148px-wide box that clipped its content
       (scrollH 160 > clientH 66 measured in all 3 languages). */
@media (orientation: portrait) and (max-width: 619px) and (min-height: 761px) and (max-height: 860px) {
  /* fish: stage yields the panel's missing ~62px (cap sized from
     the measured 472px stack + reserve at 812; the ratio wins again
     on taller frames inside the band). */
  #screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: min(calc(var(--stage-w) * 0.831), calc(100vh - 582px)); height: min(calc(var(--stage-w) * 0.831), calc(100dvh - 582px)); }
}
@media (orientation: portrait) and (max-width: 619px) and (max-height: 700px) {
  /* fish: stage cap tightened (v107 K=404 -> 478) and the pond
     grows 116 -> 146 so the JS-derived lanes keep a tappable tile
     height (~29px); the target card slims to match (its v88 worst
     case is re-derived at these sizes: pic 30 + caption 17px). */
  #screen-pet .pet-panel:has(#mode-fish.active) .pet-stage { height: min(calc(var(--stage-w) * 0.60), calc(100vh - 478px)); height: min(calc(var(--stage-w) * 0.60), calc(100dvh - 478px)); }
  #mode-fish .fish-pond { height: 146px; }
  #mode-fish .task-sub { margin-top: 4px !important; }
  #mode-fish .fish-show { min-height: 68px; }
  #mode-fish .fish-show .fs-pic { font-size: 30px; }
  #mode-fish .fish-show .fs-big { font-size: 34px; }
  #mode-fish .fish-show .fs-cap { font-size: 17px; }
  #mode-fish .fish-show .fs-cap ruby rt { font-size: 9px; }
  /* clock READ: msg leaves the 148px side column and spans the
     full panel width under the face + cards; the face keeps the
     main column (v107 floor: >= 200px), the play area keeps
     priority. SET rounds keep the v107 layout untouched. */
  #screen-pet .mode-panel#mode-clock.read.active {
    grid-template-areas: "scene digital" "face side" "msg msg";
    /* face row pinned: the JA read hint needs a 3-line msg (80px
       at the base font); an auto face row left the msg only 66px.
       216px keeps the face >= 200 and frees the msg row; the
       slightly smaller msg font is the second half of the fit. */
    grid-template-rows: auto 216px auto;
  }
  #screen-pet #mode-clock.read .msg { font-size: 15px; }
  /* the side cell stacks .clock-actions over .clock-choices (both
     in grid-area "side" — a v107 arrangement): the "Giờ khác"
     button (45px, cell top) covered the first card's digits.
     Anchor the choices to the cell top, start them below the
     button, and slim the READ cards so all three fit the row. */
  #screen-pet #mode-clock.read .clock-choices { align-self: start; padding-top: 52px; }
  #screen-pet #mode-clock.read .clock-card { min-height: 44px; font-size: 22px; padding: 4px 10px; }
}

/* ===== v110 — HOUSE REBUILT: the ONE house band =====
   Every pre-v110 house rule (v91 ratio copy, v100/v107/v109
   compaction sets for the old emoji-part scene) is deleted; this
   band is the whole house layout law now. The stage keeps the
   standing 0.623 ratio (spec); the panel is a flex column
   (games.css) whose scene flex-grows into whatever the panel
   leaves, so the SVG house is as tall as the frame allows. Only
   the <=700px portrait class needs help: there the stage caps by
   height (the v100/v107 dvh-cap pattern).
   Round 2 (lead eye-check): the first cap (dvh-474) left the
   stage 154px at 414x628, so the shared pet-face rule (stage
   height - 132px of bubble headroom) squeezed the pet canvas to
   150x22 and the pet drew ~17px tall — invisible. The cap is
   raised to dvh-418 (stage 210px, face 78px, pet drawn ~69px)
   and the panel pays for it: no task-sub line, score+msg on one
   row, 96px cards, tighter panel padding (games.css). The old
   .pet-face width override is GONE: it broke the face's 1:1
   aspect (150 wide x 22 tall); the face is square again, sized
   by height like every other game. Scene floors (probe-
   measured): >=180px @414x628 (lowered from 190 in round 2 —
   the 10px bought pet visibility), >=240px @375x812,
   >=260px @412x915, >=300px @768x1024; cards >=88x96 @414x628. */
#screen-pet .pet-panel:has(#mode-house.active) .pet-stage { height: calc(var(--stage-w) * 0.623); }
@media (min-width: 620px) {
  #screen-pet .pet-panel:has(#mode-house.active) .pet-stage { height: min(calc(var(--stage-w) * 0.623), calc(100vh - 524px)); height: min(calc(var(--stage-w) * 0.623), calc(100dvh - 524px)); }
}
@media (min-width: 620px) and (min-height: 1000px) {
  /* Tall tablets (768x1024): the 0.623 ratio alone leaves the
     scene at 265px, under its 300px floor — the stage yields
     ~22px more here (this band cannot bind on short desktops). */
  #screen-pet .pet-panel:has(#mode-house.active) .pet-stage { height: min(calc(var(--stage-w) * 0.623), calc(100vh - 660px)); height: min(calc(var(--stage-w) * 0.623), calc(100dvh - 660px)); }
}
@media (orientation: portrait) and (max-height: 700px) {
  #screen-pet .pet-panel:has(#mode-house.active) .pet-stage { height: min(calc(var(--stage-w) * 0.52), calc(100vh - 418px)); height: min(calc(var(--stage-w) * 0.52), calc(100dvh - 418px)); }
  #mode-house .house-card { min-height: 96px; }
}
