/* deploy/pet.css — pet.html only.
   Everything here rides on site.css's tokens (--line, --paper, --shadow-hard, --bw …) so the
   page inherits the site's look and its dark theme for free. Kept out of site.css on purpose:
   no other page loads a byte of it. The seal sprite itself is styled by site.css (.tank-seal)
   and seals.css (.seal-N) — see paintPet() in pet.js. */

/* Text sizes for this page, one --fs-* per admin slider (PET_FONT_VARS in render.js).
   Every one is written as var(--fs-x, <what it was>) so an untouched site renders byte-identical
   to before the sliders existed, and clearing a slider restores exactly that number.

   The two .page-hero rules are overrides, not new rules: site.css sizes .page-hero h1 and
   .subtitle from --fs-rankTitle/--fs-rankSubtitle, which are the ranking page's sliders. This
   file only loads on pet.html, so re-pointing them here gives the pet page its own controls
   without touching any other page. Same specificity, later stylesheet, so these win. */
.page-hero h1{font-size:var(--fs-petTitle, 2.3rem);}
.page-hero .subtitle{font-size:var(--fs-petSubtitle, 1.5rem);}

.pet-layout{
  display:grid; gap:18px; margin:20px auto 0; max-width:640px;
}

/* The generous top padding is headroom for the petting hand: .pet-stage clips its children
   (overflow:hidden keeps the sea floor inside the rounded border), and the hand starts its
   swing about 30px above the seal's head. */
/* The water changes with the seal's age — shallow and clear at แรกเกิด, deeper every stage, night
   sky at ในตำนาน. paintPet() writes the colours as inline custom properties from PET_STAGE_DEFS.

   The two themes read two *different* variables (--sky-* vs --dsky-*) rather than sharing one,
   because an inline style always beats a stylesheet rule: if both rules said var(--sky-a), the
   dark-theme rule below could never override what pet.js had already put on the element. Every
   var keeps the colour this shipped with as its fallback, so the stage still looks right in the
   moment before /api/content lands, and with JS off entirely. */
.pet-stage{
  display:flex; flex-direction:column; align-items:center; gap:10px;
  padding:58px 22px 22px;
  background:linear-gradient(var(--sky-a,#eaf7ff) 0%, var(--sky-b,#cfeaf8) 62%, var(--sky-b,#b6dff2) 100%);
  border:var(--bw) solid var(--line); border-radius:22px;
  box-shadow:var(--shadow-hard);
  position:relative; overflow:hidden;
}
/* Any hand reaching in — to pick the seal up, to pat it, to rub it — needs headroom that scales
   with the seal itself, and at the larger growth stages hand.png/hand-hold.png's own reach is
   taller than this tank's fixed top padding could ever budget for on its own (PET_HAND_TIP
   sits deep inside both hands, so most of each one's height falls *above* the point that
   actually touches the head). Rather than clip it, the tank's border stops containing anything
   for as long as some hand is on screen — petHoldLift()/petHoldEnd() toggle `.holding` for the
   pick-up gesture, petHandAnim() and petRubEnter()/petRubLeave() toggle `.petting` for a swing
   or the mouse-tracking rub — so the hand can spill above the rounded top edge, which reads as
   reaching in from outside the tank rather than as a bug. The floor/veil (::after/::before
   below) carry their own matching border-radius for exactly this — they used to lean on this
   overflow staying hidden to get their rounded corners, and turning it off used to put their
   square corners on display right where a hand was trying to look like it belonged outside the
   tank. */
.pet-stage.holding, .pet-stage.petting{overflow:visible;}
:root[data-theme="dark"] .pet-stage{
  background:linear-gradient(var(--dsky-a,#16324d) 0%, var(--dsky-b,#1c4463) 62%, var(--dsky-b,#163a58) 100%);
}
/* Sun shafts / aurora on the stages whose row in PET_STAGE_DEFS carries a `veil`. Painted before
   the sea floor and the props (tree order decides among z-index:0/auto), so it reads as being in
   the water rather than in front of everything in it. */
.pet-stage::before{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:var(--veil,none);
  /* Matches .pet-stage's own border-radius (kept as a literal, since that's a literal too) —
     see the note on .pet-stage::after below for why this can't just rely on the parent's
     overflow:hidden any more. */
  border-radius:22px;
}
/* The same tiled sea floor the participants-page tank stands on, so the two read as one world.

   Rounded on its own bottom corners rather than leaning on .pet-stage's overflow:hidden to clip
   them: .pet-stage.holding/.petting turn that off on purpose (see the comment there) so a hand
   reaching in for a pick-up/pat/rub isn't cut off, and this pseudo-element spans the exact same
   box as .pet-stage — full width, flush against the bottom edge — so the instant overflow
   stops being hidden, its own square corners would poke out past the tank's rounded ones
   exactly where the hand is trying to look like it's reaching in from *outside* the tank. */
.pet-stage::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:26px;
  background:repeating-linear-gradient(90deg,var(--floor-a,#a9d8ee) 0 14px,var(--floor-b,#bde3f4) 14px 28px);
  border-radius:0 0 22px 22px;
}
:root[data-theme="dark"] .pet-stage::after{
  background:repeating-linear-gradient(90deg,var(--dfloor-a,#123049) 0 14px,var(--dfloor-b,#17395c) 14px 28px);
}

/* Whatever is standing in the tank with the seal. z-index:1 lifts the whole layer above the sea
   floor (::after, z-index auto) so a rock or a starfish can sit *on* the floor rather than behind
   it; the sprite is z-index:1 as well but comes later in the document, so the seal still passes in
   front of every prop. pointer-events:none keeps the click target for petting the seal alone. */
.pet-props{position:absolute; inset:0; z-index:1; pointer-events:none;}
/* Drawn as <img>: width is set inline as a % of the stage and the height follows from the art
   itself, so a grid out of PET_PROP_DEFS and a PNG somebody uploaded are placed by the same two
   numbers without either side knowing the other's shape.

   left/top address the item's *bottom centre*, not its middle. Most of what stands in here is
   scenery resting on something — seaweed, a rock, a treasure chest — and with a centred anchor
   the pinned point moves as soon as the art gets taller, so anything sitting on the sea floor
   drifts up off it the moment its size changes. Pinning the base keeps "put it here" meaning
   that at every size. */
.pet-prop{
  position:absolute; transform:translate(-50%,-100%);
  height:auto; display:block;
  image-rendering:pixelated;
}

/* The art is one square of a 4x4 mood sheet, not one of the ten .seal-N pictures: 400% 400%
   blows the sheet up so exactly one cell fills the box, and pet.js moves background-position
   to whichever mood the seal is in (see petMoodIndex()). Both overrides matter — .tank-seal
   sets background-size:contain and image-rendering:pixelated, and this art is a soft pastel
   render that is being scaled to a non-integer size, where nearest-neighbour would chew the
   faces up and smooth scaling does not. */
.pet-sprite{
  cursor:pointer; position:relative; z-index:1;
  /* On a mouse (touch has no :hover), the rubbing hand takes over as the pointer — showing the
     system cursor as well underneath it would read as two things touching the head at once. */
  /* Must match PET_SHEET_URL in pet.js exactly (one download) — webp through Vercel's image
     optimizer; see the note there. */
  background-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90");
  /* Which mood square, and how far the sheet is blown up. Written by paintPet() as custom
     properties rather than straight onto background-position/size, because the tint layer below
     has to address exactly the same square through its mask and two properties set from one
     variable can never drift apart. The fallbacks are the no-JS values (406% = PET_ZOOM in pet.js). */
  background-position:var(--mood-pos, 0% 0%);
  background-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
  background-repeat:no-repeat;
  image-rendering:auto;
  /* The age's colour, as light spilling off the seal. drop-shadow follows the sprite's own alpha,
     so it hugs the pixel silhouette instead of sitting behind it as a blob — which is the whole
     difference between this and the soft background auras that were tried and rejected first. */
  filter:var(--seal-glow,none);
  /* Leaning toward the pointer (petLookPaint() in pet.js). The individual rotate/translate
     properties, not transform: seal-bob, the pat squish and the drag all own `transform`, and
     these compose on top of it instead of overwriting it. */
  rotate:var(--look-rot,0deg);
  translate:var(--look-x,0px) var(--look-y,0px);
  transition:width .35s ease, height .35s ease,   /* growing up should be visible, not a jump */
             rotate .35s ease-out, translate .35s ease-out;
}
/* Held, it hangs straight from the hand; the lean would only tip the swing off-centre. */
.pet-sprite.held{rotate:0deg; translate:none;}
/* Recolours the seal's line art, muzzle and cheeks to the age's colour without touching the white
   body. mix-blend-mode:color keeps the backdrop's brightness and takes only hue+saturation from
   this layer, and white has nowhere to go — so the body stays white while everything that was
   actually drawn picks the colour up. The mask is the sheet itself at the same square, so the
   colour stops exactly at the seal's outline rather than filling the box.

   Blending is contained by .pet-sprite's own stacking context (position+z-index above), so this
   never reaches the page behind it. --seal-ink is unset on แรกเกิด, and a transparent source
   leaves the backdrop untouched — the art exactly as drawn, with no special-casing. */
.pet-sprite::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:var(--seal-ink,transparent);
  mix-blend-mode:color;
  -webkit-mask-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90"); mask-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90");
  -webkit-mask-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
          mask-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
  -webkit-mask-position:var(--mood-pos, 0% 0%); mask-position:var(--mood-pos, 0% 0%);
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
}
.pet-sprite:focus-visible{outline:2px solid var(--grape-deep); outline-offset:4px;}
/* The squish under a hand. Deliberately not one of the poke animations: a poke is a poke
   (bounce/spin/wiggle), a pat presses down and springs back. .petted is excluded from nothing
   because it sets `animation` outright, the same way .poked does. */
.pet-sprite.petted{animation:pet-squish .45s cubic-bezier(.3,1.5,.5,1);}
@keyframes pet-squish{
  0%  { transform:translateY(0) scale(1,1); }
  30% { transform:translateY(4px) scale(1.1,.86); }
  60% { transform:translateY(-2px) scale(.97,1.04); }
  100%{ transform:translateY(0) scale(1,1); }
}

/* ---- Picked up ----

   touch-action:none is what makes a lift possible on a phone at all: without it the browser
   claims the gesture as a page scroll before the drag ever starts. It costs a swipe that begins
   on the seal itself, which is the trade every draggable thing on a touch screen makes. */
.pet-sprite{touch-action:none;}
/* Held, the bob has to stop: it animates `transform`, and an animation outranks the inline
   transform the drag writes, so the two would flicker against each other every frame. The seal
   also rides above the props while it is off the floor.

   The art itself swaps to held-seal.png — a seal hanging upright is a genuinely different
   drawing, not a mood square, so this doesn't touch --mood-pos/--mood-zoom at all; it just
   points the same background-image property at a plain image instead of a sheet, at whatever
   box pet.js has already sized in --seal-w/--seal-h for this stage's held aspect. Specificity
   (two classes beats one) is what lets this win over .pet-sprite's own background-image without
   needing !important, both here and on ::after below. */
.pet-sprite.held{
  /* transition:none matters for more than looks: petHoldLift() sets --seal-h to the held
     aspect and reads getBoundingClientRect() right after, in the same tick, to place the hand
     and shadow. .pet-sprite's own width/height transition would otherwise still be mid-flight
     from the lying size at that read, so the hand would be placed for a box that isn't on
     screen yet. */
  animation:none; transition:none; z-index:3;
  background-image:url("/_vercel/image?url=%2Fpet%2Fheld-seal.png%3Fv%3D1&w=1200&q=90");
  background-position:0 0; background-size:100% 100%;
}
/* The tint-by-age layer (see .pet-sprite::after above) has to mask the same picture, or it goes
   on recolouring the outline of a lying seal that is not there any more. */
.pet-sprite.held::after{
  -webkit-mask-image:url("/_vercel/image?url=%2Fpet%2Fheld-seal.png%3Fv%3D1&w=1200&q=90"); mask-image:url("/_vercel/image?url=%2Fpet%2Fheld-seal.png%3Fv%3D1&w=1200&q=90");
  -webkit-mask-position:0 0; mask-position:0 0;
  -webkit-mask-size:100% 100%; mask-size:100% 100%;
}
/* Let go: the same transform property transitions from wherever it was dropped back to nothing,
   which is the resting spot, with an overshoot so it lands rather than glides. */
.pet-sprite.dropping{animation:none; transition:transform .42s cubic-bezier(.34,1.56,.64,1);}
/* What it left on the sea floor. Sized and placed inline from the sprite's own box, so it fits
   the seal at every growth stage; petHoldPaint() shrinks and fades it as the seal goes up. */
.pet-hold-shadow{
  position:absolute; z-index:0; pointer-events:none;
  border-radius:50%; background:rgba(24,48,68,.26);
  transition:opacity .26s ease;
}
:root[data-theme="dark"] .pet-hold-shadow{background:rgba(0,0,0,.34);}
/* The pinching hand parks on the head and stays there — petHandAnim()'s swing would pull it
   off the head the moment the seal starts moving. */
.pet-hand.holding{animation:none; opacity:1;}
/* The rubbing hand tracks the mouse frame by frame (petRubPosition() in pet.js) — the swing-in
   keyframe would fight that positioning every time it replayed, so it's off entirely, the same
   way .holding turns it off for the pinch. */
.pet-hand.rubbing{animation:none; opacity:1;}
/* Scoped to actual mice (not just "supports :hover"), so a touchscreen that happens to satisfy
   a looser hover query never gets stuck showing no cursor after a tap. */
@media (hover:hover) and (pointer:fine){
  .pet-sprite:hover{cursor:none;}
}
@media (prefers-reduced-motion:reduce){
  .pet-sprite.dropping{transition:transform .12s linear;}
}

/* The hand that comes down on its head — /pet/hand.png, positioned inside .pet-stage (which is
   position:relative) from the sprite's own box by petHandAnim() (a fixed swing-down) or
   petRubPosition() (tracking the mouse, via .rubbing above), so it lands on the head at every
   growth size either way. Width is set inline for the same reason. */
.pet-hand{
  position:absolute; z-index:2; pointer-events:none;
  height:auto; display:block;
  filter:drop-shadow(0 3px 4px rgba(20,20,20,.22));
  animation:pet-hand-down .7s ease-out forwards;
}
/* petHandAnim() parks the element exactly where the fingertips meet the head, so 0 here is
   "resting on the head" and the keyframes only move around that: down from above, a small
   press, then lifted away again. */
@keyframes pet-hand-down{
  0%  { opacity:0; transform:translateY(-30px) rotate(-7deg); }
  25% { opacity:1; transform:translateY(0) rotate(-2deg); }
  45% { opacity:1; transform:translateY(5px) rotate(1deg); }
  70% { opacity:1; transform:translateY(-1px) rotate(-2deg); }
  100%{ opacity:0; transform:translateY(-22px) rotate(0deg); }
}

/* ---- Dozing ----
   petDozeCheck() adds .dozing after a while with nobody moving: the sleepy face (from pet.js), a
   bob slowed right down to breathing pace, and three z's drifting up off the head. */
.pet-stage.dozing .pet-sprite:not(.petted):not(.poked):not(.held):not(.dropping){animation-duration:4.8s;}
.pet-zzz{
  position:absolute; z-index:2; pointer-events:none; display:none;
  font-weight:800; color:var(--grape-deep); line-height:1;
}
.pet-stage.dozing .pet-zzz{display:block;}
.pet-zzz span{
  position:absolute; left:0; top:0; opacity:0;
  font-size:1.05rem; text-shadow:0 0 3px rgba(255,255,255,.8);
  animation:pet-zzz 3.6s ease-in-out infinite;
}
.pet-zzz span:nth-child(2){animation-delay:1.2s; font-size:1.3rem;}
.pet-zzz span:nth-child(3){animation-delay:2.4s; font-size:1.6rem;}
@keyframes pet-zzz{
  0%  { opacity:0; transform:translate(0,0) rotate(-10deg); }
  20% { opacity:1; }
  100%{ opacity:0; transform:translate(22px,-44px) rotate(12deg); }
}
:root[data-theme="dark"] .pet-zzz{color:#e9dcff;}
:root[data-theme="dark"] .pet-zzz span{text-shadow:0 0 4px rgba(0,0,0,.6);}

/* ---- Toys ----
   Positioned entirely by transform from petToysTick() (top-left corner of the stage is 0,0), so
   left/top stay pinned at zero. The ball rides above the seal so it can be seen landing on its
   head; the duck floats along the top edge. */
.pet-toy{
  position:absolute; left:0; top:0; z-index:2; display:block; height:auto;
  image-rendering:pixelated; user-select:none; -webkit-user-drag:none;
  filter:drop-shadow(1px 2px 0 rgba(20,20,20,.18));
}
.pet-ball{cursor:grab; touch-action:none;}
.pet-ball.held{cursor:grabbing; filter:drop-shadow(2px 6px 2px rgba(20,20,20,.25));}
.pet-duck{cursor:var(--cursor-pointer-url), pointer;}
/* The hop rides on the separate `translate` property so it can't knock out the transform the
   tick writes every frame. */
.pet-duck.hop{animation:pet-duck-hop .45s cubic-bezier(.3,1.6,.5,1);}
@keyframes pet-duck-hop{
  0%,100%{ translate:0 0; }
  40%    { translate:0 -12px; }
}
.pet-toy-poof{font-weight:800; font-size:.95rem; color:var(--grape-deep);
  text-shadow:0 0 3px #fff, 0 0 6px #fff;}
:root[data-theme="dark"] .pet-toy-poof{color:#ffe066; text-shadow:0 0 4px rgba(0,0,0,.7);}

/* ---- The growth album ----
   A row of framed portraits, one per stage (paintAlbum() in pet.js). Wraps into a grid where
   there is room and scrolls sideways on a phone, snapping one card at a time. Each frame is
   painted in its own stage's water colours, and the face inside is the same mood-sheet square
   and ink tint the big sprite uses, sized to that stage's growth step. */
.pet-album{
  list-style:none; margin:0; padding:4px 2px 8px;
  display:grid; grid-auto-flow:column; grid-auto-columns:minmax(76px,1fr); gap:8px;
  overflow-x:auto; scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain;
}
.pet-album-item{
  display:flex; flex-direction:column; align-items:center; gap:3px; text-align:center;
  scroll-snap-align:center; min-width:0;
}
.pet-album-frame{
  position:relative; width:100%; height:92px;
  display:flex; align-items:center; justify-content:center;
  border:2px solid var(--line); border-radius:16px;
  background:linear-gradient(var(--sky-a,#eaf7ff), var(--sky-b,#cfeaf8));
  box-shadow:2px 3px 0 var(--line);
}
:root[data-theme="dark"] .pet-album-frame{
  background:linear-gradient(var(--dsky-a,#16324d), var(--dsky-b,#1c4463));
}
.pet-album-face{
  position:relative; isolation:isolate;
  width:var(--face-w); height:var(--face-h);
  background-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90");
  background-position:var(--mood-pos,0% 0%);
  background-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
  background-repeat:no-repeat;
}
/* Same recolour as .pet-sprite::after — see the note there. */
.pet-album-face::after{
  content:""; position:absolute; inset:0;
  background:var(--seal-ink,transparent); mix-blend-mode:color;
  -webkit-mask-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90"); mask-image:url("/_vercel/image?url=%2Fpet%2Fmoods.png%3Fv%3D5&w=1200&q=90");
  -webkit-mask-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
          mask-size:var(--mood-zoom,406%) var(--mood-zoom,406%);
  -webkit-mask-position:var(--mood-pos,0% 0%); mask-position:var(--mood-pos,0% 0%);
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
}
.pet-album-no{
  position:absolute; left:6px; top:5px;
  font-size:.7rem; font-weight:800; color:var(--line); opacity:.55;
}
:root[data-theme="dark"] .pet-album-no{color:var(--ink);}
.pet-album-name{font-size:.8rem; line-height:1.25;}
.pet-album-cap{font-size:.72rem; color:var(--ink-soft); line-height:1.25;}

/* Where it is now: a bigger frame edge, a ribbon, and a slow happy wobble. */
.pet-album-item.now .pet-album-frame{border-width:3px; box-shadow:3px 4px 0 var(--grape-deep);}
.pet-album-item.now .pet-album-face{animation:pet-album-wobble 2.4s ease-in-out infinite;}
@keyframes pet-album-wobble{
  0%,100%{ transform:rotate(-4deg); }
  50%    { transform:rotate(4deg) translateY(-2px); }
}
.pet-album-now{
  position:absolute; right:-4px; top:-9px; z-index:1;
  background:var(--pink); color:#141414; border:2px solid var(--line); border-radius:999px;
  padding:0 8px; font-size:.68rem; font-weight:800; transform:rotate(6deg);
}
/* Not reached yet: a flat shadow of the seal (brightness 0 keeps the outline shape, nothing
   else), the frame greyed out. The next one along gets a dashed "coming soon" edge. */
.pet-album-item.next .pet-album-face,
.pet-album-item.locked .pet-album-face{filter:brightness(0); opacity:.28;}
.pet-album-item.next .pet-album-face::after,
.pet-album-item.locked .pet-album-face::after{display:none;}
.pet-album-item.next .pet-album-frame{border-style:dashed;}
.pet-album-item.locked .pet-album-frame{filter:grayscale(.75); opacity:.8;}
.pet-album-item.next .pet-album-cap{color:var(--grape-deep); font-weight:800;}
:root[data-theme="dark"] .pet-album-item.next .pet-album-cap{color:#d8c2ff;}
:root[data-theme="dark"] .pet-album-item.next .pet-album-face,
:root[data-theme="dark"] .pet-album-item.locked .pet-album-face{filter:brightness(0) invert(1); opacity:.3;}
.pet-album-q{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:1.6rem; font-weight:800; color:var(--line); opacity:.55;
}
:root[data-theme="dark"] .pet-album-q{color:var(--ink);}

@media (prefers-reduced-motion:reduce){
  .pet-zzz span, .pet-album-item.now .pet-album-face, .pet-duck.hop{animation:none;}
  .pet-zzz span{opacity:.8;}
  .pet-zzz span:nth-child(2){transform:translate(10px,-16px);}
  .pet-zzz span:nth-child(3){transform:translate(20px,-34px);}
}

.pet-stage-label{
  font-weight:700; color:var(--line); z-index:1;
  background:rgba(255,255,255,.86); border:2px solid var(--line);
  border-radius:999px; padding:2px 16px;
  font-size:var(--fs-petStageLabel, 1rem);
}
:root[data-theme="dark"] .pet-stage-label{background:rgba(26,36,47,.86); color:var(--ink);}

.pet-meta{display:flex; flex-wrap:wrap; gap:10px; justify-content:center; z-index:1;}
.pet-chip{
  background:var(--grape-soft); color:var(--ink);
  border:2px solid var(--line); border-radius:999px;
  padding:3px 14px; font-weight:700; font-size:var(--fs-petChip, .95rem);
}
/* "อีก N มื้อจะโตเป็น…" — the donation call to action, so it gets its own colour rather than
   sitting in the row looking like another stat. Its own line because the label runs long. */
/* The text colour is a literal, not var(--line) or var(--ink): both of those flip to near-white
   under [data-theme="dark"] while --mint stays the same pastel green, which would leave this
   at about 1.8:1 against its own background. Pinning the light theme's ink keeps it readable
   in both. flex-basis puts it on its own line — the label runs long enough in Thai that
   sharing a row with the other two chips wraps it awkwardly. */
.pet-chip.next{
  background:var(--mint); color:#141414; flex-basis:100%; text-align:center;
  font-size:var(--fs-petNextChip, .95rem);
}

.pet-bars{display:grid; gap:12px;}
.pet-bar-row{display:grid; grid-template-columns:auto 1fr auto; gap:10px; align-items:center;}
.pet-bar-name{font-weight:700; min-width:6em; font-size:var(--fs-petBarName, 1rem);}
.pet-bar-value{
  color:var(--ink-soft); font-size:var(--fs-petBarValue, .95rem);
  min-width:4.2em; text-align:right;
}
.pet-bar{
  height:18px; background:var(--paper-2);
  border:2px solid var(--line); border-radius:999px; overflow:hidden;
}
.pet-bar-fill{
  height:100%; width:0;
  background:var(--mint);
  transition:width .3s ease, background-color .3s ease;
}
.pet-bar-fill.happy{background:var(--pink);}
.pet-bar-fill.meal{background:var(--orange);}
/* Under a third full turns red-ish, so "needs a pat" is legible without reading the number. */
.pet-bar-fill.low{background:#e2685f;}

.pet-counts{
  display:flex; flex-wrap:wrap; gap:6px 22px; justify-content:center;
  margin-top:14px; color:var(--ink-soft); font-weight:700;
  font-size:var(--fs-petCounts, .95rem);
}
.pet-counts b{color:var(--grape-deep);}

.pet-actions{display:flex; flex-wrap:wrap; gap:12px; justify-content:center;}
.pet-btn{
  font-family:inherit; font-weight:700; font-size:var(--fs-petBtn, 1.15rem); cursor:pointer;
  display:inline-flex; align-items:center; gap:10px;
  padding:14px 34px;
  background:var(--pink-soft); color:var(--ink);
  border:var(--bw) solid var(--line); border-radius:999px;
  box-shadow:3px 3px 0 var(--line);
  transition:transform .12s ease, box-shadow .12s ease, opacity .12s ease;
}
.pet-btn:hover{transform:translate(-2px,-2px); box-shadow:5px 5px 0 var(--line);}
.pet-btn:active{transform:translate(2px,2px); box-shadow:1px 1px 0 var(--line);}

.pet-feed-title{margin:0 0 4px; font-size:var(--fs-petFeedTitle, 1.25rem);}
.hintline{color:var(--ink-soft); font-size:var(--fs-petFeedHint, .95rem); margin-bottom:12px;}
.pet-feed-empty{color:var(--ink-soft); margin:0; font-size:var(--fs-petFeedEmpty, 1rem);}
/* Full log renders now (pet.js no longer slices to the top 8), so this scrolls in place
   instead of pushing the rest of the page down as more people feed the seal — a fixed
   height plus touch-scrolling makes the overflow a swipe-to-browse list on mobile. */
#petFeedLog{max-height:340px; overflow-y:auto; -webkit-overflow-scrolling:touch; overscroll-behavior:contain;}
/* pet.html reuses .rank-note for its closing line, which site.css sizes from the Ranking page's
   --fs-rankNote. Re-pointed here (pet-only stylesheet) so the two pages get separate sliders. */
.rank-note{font-size:var(--fs-petNote, .98rem);}
/* One slider for a whole feed row: the name, the note and the timestamp are set in `em` off it
   so the badge and the "เมื่อครู่นี้" stay in proportion as the row grows. */
.pet-feed-row{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px;
  padding:9px 0; border-bottom:2px dashed var(--line-soft);
  font-size:var(--fs-petFeedRow, 1rem);
}
.pet-feed-row:last-child{border-bottom:0;}
/* Which food tier bought this meal — real art if the admin has uploaded it, otherwise the
   tier's own emoji (petFoodIconFallback() in pet-labels.js swaps a 404'd <img> for this span).
   Round coin treatment on both because the art (pixel food on a white square, no alpha) would
   otherwise show as a stray white box on the tank's blue gradient or in dark mode — a solid
   badge behind it reads as deliberate in both themes instead, matching how .pet-stage-label
   already badges itself against the same background. */
.pet-feed-icon, .pet-feed-icon-emoji{
  width:1.7em; height:1.7em; flex:0 0 auto;
  border-radius:50%; border:2px solid var(--line); background:#fff;
}
.pet-feed-icon{object-fit:cover;}
.pet-feed-icon-emoji{
  font-size:1.1em; line-height:1; display:inline-flex;
  align-items:center; justify-content:center;
}
.pet-feed-who{font-weight:700;}
.pet-feed-meals{
  background:var(--yellow); color:var(--line);
  border:2px solid var(--line); border-radius:999px;
  padding:1px 10px; font-weight:700; font-size:.85em;
}
.pet-feed-note{color:var(--ink-soft);}
.pet-feed-when{margin-left:auto; color:var(--ink-soft); font-size:.9em;}

.pet-toast{
  position:fixed; left:50%; bottom:26px; transform:translate(-50%,20px);
  z-index:98; pointer-events:none;
  background:var(--line); color:var(--paper);
  border-radius:999px; padding:10px 22px; font-weight:700;
  opacity:0; transition:opacity .2s ease, transform .2s ease;
  max-width:calc(100vw - 32px); text-align:center;
}
.pet-toast.show{opacity:1; transform:translate(-50%,0);}

@media (prefers-reduced-motion:reduce){
  .pet-sprite{transition:none;}
  .pet-sprite.petted{animation:none;}
}

@media (max-width:520px){
  .pet-bar-row{grid-template-columns:auto 1fr; grid-template-areas:'name value' 'bar bar';}
  .pet-bar-name{grid-area:name;}
  .pet-bar-value{grid-area:value;}
  .pet-bar{grid-area:bar;}
  .pet-feed-when{margin-left:0; width:100%;}
}
