/* =====================================================
   🫧 Bubble Pop Counting — counting 1-10 by MAKING the number.

   Loaded after css/style.css (tokens, .game-area, .kg-target's shared
   sizing), css/kid-games.css and css/kid-motion.css (the particle layer).
   Nothing here restyles a shared class on its own: every selector either
   introduces a kg-puppy-count- class or qualifies a shared one with it.

   THE ONE MEASUREMENT THE WHOLE SHEET IS BUILT AROUND
   Three bubbles across, >=76 CSS px each, >=30 px apart, on a 360 px phone.
   That is the tightest case the brief allows and it does not fit inside
   .game-area's padding: 360 - 24 (page gutters) - 36 (card padding) leaves
   300 px, and 3x76 + 2x30 is 288 with 12 px to spare — before a scrollbar.
   So the field takes the card's padding back with a negative inline margin
   (--kg-card-pad exists in css/kid-games.css for exactly this) and runs edge
   to edge as a band of sky. That buys ~36 px, which is the difference
   between a comfortable 86 px bubble and a 73 px one that breaks the floor.

   WHY THE BUBBLES DO NOT ADD COLUMNS ON A BIG SCREEN
   Three across everywhere. A tablet gets BIGGER bubbles, not more of them,
   so the shape of a round is the same object on every device and the layout
   the rules module lays out (rows of FIELD_COLS) is the layout that renders.

   TWO STATES THAT MUST NEVER BE CONFUSED
     .kg-hint (kid-games.css) is the one reserved "this one" highlight and is
     used here only for the scaffold's level-3 reveal — exactly as many
     glowing bubbles as she still needs.
     .kg-puppy-count-wake is a WASH ON THE FIELD, never a glow on a bubble.
     It is the level-2 "there are still some to pop" and it carries a static
     ring as well as its bob, so the signal survives when a child who asked
     for reduced motion has the animation flattened out from under it.

   prefers-reduced-motion is already handled globally at style.css:559-562
   and JS-driven motion is gated on ctx.reducedMotion in the game file, so
   there is deliberately no reduced-motion block here.
   ===================================================== */

/* ---------------- The spoken line ---------------- */
.kg-puppy-count-line {
  /* Two lines' worth, reserved: the round opens on one line and the payoff
     runs to two, and a line that grows would push the whole field down under
     her finger at the exact moment she is aiming at it. */
  min-height: 2.2em;
  font-weight: 700;
}

/* ---------------- Counters ----------------
   The goal and the tally, side by side, above the field. Above and not below
   because that is where her eyes already are when the round starts, and a
   tally she has to look DOWN for after every pop is a tally she stops
   checking. Each panel carries a numeral AND a dot group: the numeral for a
   grown-up and for the day she can read it, the dots for now. */
.kg-puppy-count-counters {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: clamp(10px, 3vw, 20px);
}

.kg-puppy-count-panel {
  flex: 1 1 0;
  max-width: 260px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 8px 12px;
  border-radius: var(--radius);
  background: #fff;
  border: 3px solid #f0ecfa;
  box-shadow: var(--shadow);
  transition: border-color .25s var(--ease), background .25s var(--ease),
              transform .25s var(--ease);
}

.kg-puppy-count-cap {
  font-size: .82rem;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-soft);
  line-height: 1;
}

.kg-puppy-count-num {
  font-size: clamp(1.9rem, 8vw, 2.5rem);
  font-weight: 800;
  line-height: 1;
  color: var(--ink);
}

/* The ten-frame. Rows of up to five, filled left to right, so "five and two
   more" is a shape before it is a count. */
.kg-puppy-count-dots {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  min-height: 14px;
}
.kg-puppy-count-dotrow { display: flex; gap: 6px; }
.kg-puppy-count-dot {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: #fff;
  border: 2.5px solid var(--ink-soft);
  opacity: .38;
  transition: background .2s var(--ease), opacity .2s var(--ease),
              border-color .2s var(--ease), transform .2s var(--ease);
}
/* Filled is a SOLID dot with an edge, never a faded one: "not yet" and
   "broken" have to look different to someone who cannot read the caption. */
.kg-puppy-count-dot-on {
  background: var(--accent);
  border-color: var(--accent);
  opacity: 1;
}
/* One too many. Amber, the site's own "look at this" colour, and only ever
   on screen for the half second before the extra bubble comes back. */
.kg-puppy-count-dot-over {
  background: var(--amber);
  border-color: var(--amber);
  opacity: 1;
}

.kg-puppy-count-goal .kg-puppy-count-num { color: var(--accent); }

/* The tally has landed on the number. Green, because it means the same thing
   .kg-correct means everywhere else on these pages. */
.kg-puppy-count-tally.kg-puppy-count-hit {
  border-color: var(--teal);
  background: #e9fbf7;
}
.kg-puppy-count-tally.kg-puppy-count-hit .kg-puppy-count-num { color: var(--teal); }
.kg-puppy-count-tally.kg-puppy-count-over { border-color: var(--amber); }
.kg-puppy-count-tally.kg-puppy-count-over .kg-puppy-count-num { color: var(--amber); }

/* The replay's wash, and the scaffold's "here is the number again". A ring
   and a tint on the GOAL panel — never a glow on a bubble. The ring is a
   plain state change, so it is still there for a child whose animations have
   been flattened; the little swell on top of it is the part that is allowed
   to disappear. */
.kg-puppy-count-pulse .kg-puppy-count-goal {
  border-color: var(--accent);
  background: var(--kg-tint, #fff0f6);
  animation: kg-puppy-count-swell .7s var(--ease);
}
@keyframes kg-puppy-count-swell {
  0%, 100% { transform: scale(1); }
  45% { transform: scale(1.06); }
}

/* Screen-reader only, for the one live region on this screen. The visible
   numerals and dots beside it are aria-hidden, so the tally announces one
   clean sentence instead of a string of loose digits. */
.kg-puppy-count-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
}

/* ---------------- The field ----------------
   A band of sky across the whole card. The negative inline margin takes back
   .game-area's own padding, which is what makes three >=76px bubbles with
   >=30px gutters fit a 360px phone with room over. */
.kg-puppy-count-field {
  --pc-gap: 30px;                          /* the brief's floor, never less */
  --pc-size: clamp(76px, 22vw, 108px);

  position: relative;                      /* the particle layer's origin */
  width: calc(100% + 2 * var(--kg-card-pad, 20px));
  margin-inline: calc(-1 * var(--kg-card-pad, 20px));
  padding: 14px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--pc-gap);
  background:
    radial-gradient(120% 80% at 50% 0%, #ffffff 0%, rgba(255, 255, 255, 0) 60%),
    linear-gradient(170deg, #f3fbff, var(--kg-tint, #fff0f6));
  box-shadow: inset 0 3px 0 rgba(255, 255, 255, .9),
              inset 0 -3px 0 rgba(53, 49, 94, .06);
  transition: background .25s var(--ease), box-shadow .25s var(--ease);
}

/* css/kid-motion.css leaves the particle layer overflow: visible, which is
   right for a host that is already clipped. This one is not: a twelve-sprite
   puff thrown at 400px/s off the bottom row grew documentElement.scrollHeight
   from 847 to 1386 and scrollWidth from 390 to 455 about a second in, so a
   scrollbar appeared and the page could be dragged mid-round — once per pop,
   ten times a round. Clipped to the band, which is where the popping happens
   and where the confetti belongs. */
.kg-puppy-count-field .kg-particle-layer { overflow: hidden; }

.kg-puppy-count-row {
  display: flex;
  width: 100%;
  justify-content: center;
  gap: var(--pc-gap);
}

/* THE TARGET. .kg-target already carries the 76px minimum, the :active
   touchdown, the focus ring and the correct/dim/hint states; this only makes
   it round, takes the shared 18px inset padding down to 4px so the drawing
   fills the box it is measured at, and caps the width so three across can
   never overflow the band whatever the viewport does.

   The 18px of slop the brief asks for beyond the artwork lives in the 30px
   gutter here rather than inside the button: with a circular target, inset
   padding would shrink the visible bubble to something noticeably smaller
   than the thing being measured, and a bubble that LOOKS small gets aimed at
   carefully — which is the one behaviour this verb exists to avoid. */
.kg-puppy-count-bubble {
  flex: 0 0 auto;
  /* block, not the shared .kg-target's grid: the drawing is sized off the
     button rather than the button off the drawing, so the measured target
     and the visible bubble are the same circle. */
  display: block;
  width: min(var(--pc-size), calc((100% - 2 * var(--pc-gap)) / 3));
  height: min(var(--pc-size), calc((100% - 2 * var(--pc-gap)) / 3));
  /* 2px, not the shared .kg-target's 18px inset: with a circular target the
     visible bubble is already ~7px inside the measured box (the drawing's own
     circle sits inside its viewBox), and every pixel of inset on top of that
     makes the bubble look smaller than the thing being measured. A bubble
     that LOOKS small gets aimed at carefully, which is the one behaviour this
     verb exists to remove. */
  padding: 2px;
  border-width: 3px;
  border-radius: 50%;
  background: transparent;
  box-shadow: none;
  overflow: visible;
}
.kg-puppy-count-bubble:focus-visible { border-radius: 50%; }
.kg-puppy-count-bubble[disabled] { cursor: default; }

/* The drift. One inner span so the rAF loop's translate and the button's own
   :active scale never fight over the same transform. */
.kg-puppy-count-bob {
  display: block;
  width: 100%; height: 100%;
  will-change: transform;
}
.kg-puppy-count-art {
  width: 100%; height: 100%; display: block;
  transition: opacity .18s var(--ease), transform .18s var(--ease);
}

/* ---------------- The creature ----------------
   Soft round bubble, a rounded shape floating inside it, two stubby nubs and
   a heart-ish belly mark. No eyes, no face, nothing that could look
   frightened. Four tints so a field reads as a group of individuals; the
   tint never changes the SHAPE or the size, so counting is unaffected. */
.kg-puppy-count-skin {
  fill: var(--pc-skin, #cfeaff);
  fill-opacity: .8;
  stroke: #fff;
  stroke-width: 2.5;
}
.kg-puppy-count-body { fill: var(--pc-body, #ffffff); fill-opacity: .96; }
.kg-puppy-count-nub { fill: var(--pc-body, #ffffff); fill-opacity: .96; }
.kg-puppy-count-mark { fill: var(--pc-mark, #ff9ec4); }
.kg-puppy-count-sheen {
  fill: none; stroke: #fff; stroke-width: 5; stroke-linecap: round; opacity: .9;
}
.kg-puppy-count-glint { fill: #fff; opacity: .85; }

.kg-puppy-count-tint-0 { --pc-skin: #cfeaff; --pc-body: #ffffff; --pc-mark: #ff9ec4; }
.kg-puppy-count-tint-1 { --pc-skin: #ffd9ec; --pc-body: #fffdff; --pc-mark: #7fc9e8; }
.kg-puppy-count-tint-2 { --pc-skin: #d9f7e6; --pc-body: #ffffff; --pc-mark: #ffb05c; }
.kg-puppy-count-tint-3 { --pc-skin: #fff0c2; --pc-body: #fffefa; --pc-mark: #9d8bd8; }

/* ---------------- Popped ----------------
   The bubble goes, a dashed ring stays. The field NEVER reflows: a popped
   bubble keeps its place, so no target moves under her finger mid-round, and
   the ring is a countable record of what she has already done. */
.kg-puppy-count-ghost {
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  border: 3px dashed var(--accent-2);
  opacity: 0;
  transform: scale(.82);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
  pointer-events: none;
}
.kg-puppy-count-popped .kg-puppy-count-ghost { opacity: .75; transform: scale(1); }
.kg-puppy-count-popped .kg-puppy-count-art { opacity: 0; transform: scale(.55); }

/* Coming back after an over-pop. A re-inflate, not a rewind: it is a thing
   arriving, because nothing here was taken away from her. */
@keyframes kg-puppy-count-inflate {
  0% { transform: scale(.5); opacity: 0; }
  70% { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.kg-puppy-count-back .kg-puppy-count-art {
  animation: kg-puppy-count-inflate .5s var(--ease) both;
}

/* ---------------- Scaffold level 2 ----------------
   A wash on the FIELD, plus a slow bob on everything still poppable. The
   wash is a plain state change and survives a flattened animation; the bob
   is the part that is allowed to vanish. Never a per-bubble glow — that is
   .kg-hint's job and .kg-hint's alone. */
.kg-puppy-count-field.kg-puppy-count-wake {
  background:
    radial-gradient(120% 80% at 50% 0%, #ffffff 0%, rgba(255, 255, 255, 0) 55%),
    linear-gradient(170deg, #ffffff, var(--kg-tint, #fff0f6));
  box-shadow: inset 0 0 0 4px var(--accent-2);
}
.kg-puppy-count-wake .kg-puppy-count-bubble:not(.kg-puppy-count-popped) .kg-puppy-count-art {
  animation: kg-puppy-count-wake 1.5s var(--ease) 2;
}
@keyframes kg-puppy-count-wake {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.09); }
}

/* ---------------- Round meter ----------------
   Six beads, one per round. Countable, nothing to read, drawn rather than set
   in the device's emoji font — and riding IN the toolbar rather than on a row
   of its own, because on the ten-bubble round every vertical pixel spent
   above or below the field is a pixel of scroll between her and the last row
   of bubbles. */
.game-toolbar.kg-puppy-count-bar { align-items: center; gap: 16px; }
.kg-puppy-count-meter {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.kg-puppy-count-bead {
  width: 13px; height: 13px;
  border-radius: 50%;
  background: #fff;
  border: 2.5px solid var(--ink-soft);
  opacity: .34;
  transition: background .25s var(--ease), opacity .25s var(--ease),
              border-color .25s var(--ease);
}
.kg-puppy-count-bead-on {
  background: var(--accent);
  border-color: var(--accent);
  opacity: 1;
}

/* ---------------- Breakpoints (only those style.css already uses) ------- */
@media (hover: hover) {
  .kg-puppy-count-bubble:hover { border-color: var(--accent-2); }
}

@media (max-width: 560px) {
  .kg-puppy-count-panel { padding: 8px 6px 10px; }
  .kg-puppy-count-dot { width: 12px; height: 12px; border-width: 2px; }
  .kg-puppy-count-dotrow { gap: 5px; }
}

/* The tightest case in the brief. Everything the band can give back to the
   bubbles, it gives back: the field loses its own side padding entirely so
   the 300px of card interior is spent on three targets and two gutters and
   nothing else. */
@media (max-width: 360px) {
  .kg-puppy-count-field { padding: 14px 0; }
  .kg-puppy-count-meter { gap: 8px; }
  .kg-puppy-count-counters { gap: 8px; }
}

@media (min-width: 700px) {
  .kg-puppy-count-field { --pc-gap: 36px; padding: 24px 8px; }
  .kg-puppy-count-line { min-height: 1.6em; }
}
