/* ============================================================
   kids-kit · components.css · v1.4.0
   The shared components, styled only from tokens.css.
   Consume after tokens.css. No per-app forks — world flavor
   enters through the --world-* tokens alone.
   ============================================================ */

/* ---- Kit-level rules ---- */
.kk, .kk * { box-sizing: border-box; }
.kk button, .kk a, .kk [role="button"], .kk input, .kk select, .kk label {
  touch-action: manipulation; /* double-tap zoom off, suite-wide */
}
.kk {
  font-family: var(--font-text);
  color: var(--color-ink);
  background: var(--color-bg);
  -webkit-tap-highlight-color: transparent;
}

/* ---- Button ----
   Primary: the only filled button in any bar. Quiet: hairline,
   never filled. Icon: 48×48. Labels in Josefin Sans (--font-label).
   FIT RULE (v1.4.0): a button label never ellipsizes. The height
   is a MINIMUM — a label the shell fit (shell.js) wraps to two
   lines grows the button, and the bar it sits in grows with it. */
.kk-btn {
  font-family: var(--font-label);
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  letter-spacing: 0.04em;
  min-height: var(--btn-height);
  min-width: var(--target-min);
  padding: var(--space-1) var(--space-6);
  white-space: normal;
  text-align: center;
  line-height: var(--leading-tight);
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  cursor: pointer;
  background: none;
  color: var(--color-ink);
  transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
  user-select: none;
  -webkit-user-select: none;
}
.kk-btn:active { transform: scale(0.97); }
.kk-btn--primary {
  background: var(--world-accent);
  border-color: var(--world-accent);
  color: #FFFFFF;
}
.kk-btn--primary:active { background: var(--world-deep); border-color: var(--world-deep); }
.kk-btn--quiet {
  background: var(--color-bg);
  border-color: var(--color-hairline);
  color: var(--color-ink);
}
.kk-btn--quiet:active { background: var(--world-tint); }
.kk-btn[disabled], .kk-btn--disabled {
  background: var(--color-disabled-bg);
  border-color: var(--color-disabled-bg);
  color: var(--color-disabled-text);
  cursor: default;
  pointer-events: none;
}
.kk-btn--icon {
  width: var(--btn-icon-size);
  height: var(--btn-icon-size);
  min-height: var(--btn-icon-size);
  min-width: var(--btn-icon-size);
  padding: 0;
  border-radius: 50%;
  font-size: 20px;
}
.kk-btn--icon.kk-btn--quiet { border-color: var(--color-hairline); }
.kk-btn svg { width: 20px; height: 20px; flex: none; }

/* ---- Chip ----
   36px label chip; 52px when it is an answer option.
   Selected = progress tint + progress border (state, not world). */
.kk-chip {
  font-family: var(--font-label);
  font-size: var(--type-chip-size);
  font-weight: var(--type-chip-weight);
  letter-spacing: 0.03em;
  height: var(--chip-height);
  min-width: var(--target-min);
  padding: 0 var(--space-4);
  border-radius: var(--radius-chip);
  border: 1.5px solid var(--color-hairline);
  background: var(--color-bg);
  color: var(--color-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.kk-chip--answer {
  height: var(--chip-answer-height);
  font-size: var(--type-button-size);
  padding: 0 var(--space-5);
}
.kk-chip[aria-pressed="true"], .kk-chip--selected {
  background: var(--color-selected-bg);
  border-color: var(--color-selected-border);
  color: var(--world-deep);
}
.kk-chip[disabled] {
  background: var(--color-disabled-bg);
  border-color: var(--color-disabled-bg);
  color: var(--color-disabled-text);
  cursor: default;
}

/* ---- ProgressDots / Stars / ProgressBar ---- */
.kk-dots { display: inline-flex; gap: var(--dot-gap); align-items: center; }
.kk-dot {
  width: var(--dot-size); height: var(--dot-size);
  border-radius: 50%;
  background: var(--color-hairline);
}
.kk-dot--done { background: var(--color-progress); }
.kk-dot--now { background: var(--color-progress); box-shadow: 0 0 0 3px var(--color-progress-tint); }

.kk-stars { display: inline-flex; gap: var(--space-1); align-items: center; }
.kk-star { width: 22px; height: 22px; color: var(--color-hairline); }
.kk-star--earned { color: var(--color-star); } /* gold is for stars only */
.kk-star svg { width: 100%; height: 100%; display: block; }

.kk-progressbar {
  height: var(--progress-bar-height);
  border-radius: var(--radius-pill);
  background: var(--color-progress-tint);
  overflow: hidden;
}
.kk-progressbar > i {
  display: block; height: 100%;
  background: var(--color-progress);
  border-radius: var(--radius-pill);
  transition: width 300ms ease;
}

/* ---- Cards ----
   Card titles: GameCard names use the text face (Quicksand) —
   card titles in lists and grids are text-face, always. The
   header serif is used sparingly, for headers and identity
   moments only; its one card use is the WorldCard name (a world
   name is an identity moment).
   WorldCard: radius 18, hairline border, no shadow, art tile on
   the world tint, name in the header serif. The text block is
   FIXED SLOTS: the title zone always reserves two lines
   (--wc-title-height), and the description sits in a fixed
   two-line slot (--wc-desc-height) — the text WRAPS inside the
   slot and ellipsis applies only after the second line — so the
   progress row lands at the same offset on every card whatever
   the title or description length, and cards in a row come out
   equal height.
   GameCard: radius 16, name 16/700 in the text face, description
   in the same fixed two-line wrapped slot (--gc-desc-height),
   progress. The art tile is CHARACTER-LED: 84×84 at radius 16 —
   the style guide's settled size (88 in the kit's v1.1.0 build,
   60×60 in v1.0.0) — so it carries the world's featured character
   large, with the game's symbol as a small corner badge — never
   a bare icon. Same tile geometry in every state, locked too. */
.kk-worldcard, .kk-gamecard {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  background: var(--color-bg);
  border: 1px solid var(--color-hairline);
  text-align: left;
  width: 100%;
  cursor: pointer;
  font-family: var(--font-text);
  color: var(--color-ink);
  min-height: var(--target-min);
}
.kk-worldcard { border-radius: var(--radius-world-card); padding: var(--space-3); flex-direction: column; align-items: stretch; gap: var(--space-2); }
.kk-worldcard__art {
  height: 84px;
  border-radius: var(--radius-tile);
  background: var(--world-tint);
  display: flex; align-items: center; justify-content: center;
  font-size: 40px;
}
.kk-worldcard__name {
  display: block;
  height: var(--wc-title-height); /* fixed slot: two lines reserved, one- or two-line titles alike */
  overflow: hidden;
  font-family: var(--font-header);
  font-size: var(--type-title-size);
  line-height: var(--leading-tight);
}
.kk-worldcard__desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  height: var(--wc-desc-height); /* fixed slot: two lines reserved, one-line descriptions alike */
  overflow: hidden;
  font-size: var(--type-small-size);
  font-weight: 600;
  line-height: var(--leading-body);
  color: var(--color-ink-secondary);
}
.kk-worldcard__progress {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--type-small-size);
  font-weight: 700;
  color: var(--color-ink-secondary);
}
.kk-gamecard { border-radius: var(--radius-card); padding: var(--space-3); }
.kk-gamecard__tile {
  width: var(--card-tile-size); height: var(--card-tile-size);
  border-radius: var(--radius-tile);
  background: var(--world-tint);
  display: flex; align-items: center; justify-content: center;
  font-size: 40px;
  flex: none;
  position: relative;
}
.kk-gamecard__tile-char { font-size: 46px; line-height: 1; }
.kk-gamecard__tile-badge {
  position: absolute; right: 5px; bottom: 5px;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--color-bg);
  border: 1px solid var(--color-hairline);
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1;
}
.kk-gamecard--locked .kk-gamecard__tile-char { filter: grayscale(1); opacity: 0.55; }
.kk-gamecard--locked .kk-gamecard__name { color: var(--color-disabled-text); }
.kk-gamecard__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.kk-gamecard__name { font-size: 16px; font-weight: 700; line-height: var(--leading-tight); }
.kk-gamecard__desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  height: var(--gc-desc-height); /* fixed slot: two lines reserved, one-line descriptions alike — star rows align across cards */
  overflow: hidden;
  font-size: 13.5px;
  font-weight: 600;
  line-height: var(--leading-body);
  color: var(--color-ink-secondary);
}
.kk-gamecard__progress { display: flex; align-items: center; gap: var(--space-2); margin-top: 2px; }

/* ---- GameShell ----
   The game-mode takeover. Top bar → prompt → stage → feedback
   line (fixed height, inset to the content padding, with a
   clear gap above the bar) → pinned bottom bar with fixed
   slots: [Hint] [Undo/Clear] … [Answer] [Primary].
   Shell text never truncates (v1.4.0): the header title and
   the primary CTA label always render in full — shell.js steps
   their size down to the 13px floor, then wraps them to two
   lines; the top bar and the pinned bottom bar grow to fit and
   the bottom bar stays pinned. No ellipsis at any width. */
.kk-shell {
  display: flex; flex-direction: column;
  height: 100%;
  background: var(--color-bg);
  font-family: var(--font-text);
  color: var(--color-ink);
}
.kk-shell__topbar {
  min-height: var(--shell-topbar-height); /* a minimum: the bar grows when a long title wraps to two lines */
  flex: none;
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-bottom: 1px solid var(--color-hairline);
}
.kk-shell__exit {
  width: var(--btn-icon-size); height: var(--btn-icon-size);
  border: none; background: none; cursor: pointer;
  font-size: 20px; color: var(--color-ink-secondary);
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
}
.kk-shell__title {
  font-family: var(--font-header);
  font-size: 17px;
  flex: 1; min-width: 0;
  line-height: var(--leading-tight);
  /* FIT RULE (v1.4.0): the title never ellipsizes. shell.js steps
     its size down until it fits; if it still cannot fit on one
     line it wraps to two lines inside the bar and the bar grows. */
  overflow-wrap: break-word;
}
.kk-shell__set-progress {
  font-size: var(--type-small-size);
  font-weight: 600;
  color: var(--color-ink-secondary);
  white-space: nowrap;
}
.kk-shell__help {
  width: var(--btn-icon-size); height: var(--btn-icon-size);
  border: 1.5px solid var(--color-hairline); background: var(--color-bg);
  border-radius: 50%; cursor: pointer;
  font-family: var(--font-label); font-weight: 700; font-size: 17px;
  color: var(--color-ink);
  display: flex; align-items: center; justify-content: center;
}
.kk-shell__prompt {
  flex: none;
  padding: var(--space-3) var(--space-4) var(--space-1);
  font-size: var(--type-body-large-size);
  font-weight: 600;
  line-height: var(--leading-body);
}
.kk-shell__stage { flex: 1; min-height: 0; padding: var(--space-3) var(--space-4); overflow: hidden; }
.kk-shell__feedback {
  flex: none;
  height: var(--feedback-height);
  /* v1.1.0: inset to the shell's content padding — never
     full-bleed — with a guaranteed gap (--feedback-gap) between
     the line and the pinned bottom bar, in every state. */
  margin: 0 var(--space-4) var(--feedback-gap);
  display: flex; align-items: center;
  font-size: var(--type-body-size);
  font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kk-shell__feedback--success { color: var(--color-success); }
.kk-shell__feedback--try { color: var(--color-try-again); }
.kk-shell__feedback--hint { color: var(--color-hint); }
.kk-shell__bottombar {
  flex: none;
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--color-hairline);
  background: var(--color-bg);
}
.kk-shell__spacer { flex: 1; }
.kk-shell__bottombar .kk-btn { padding: var(--space-1) var(--space-4); }
.kk-shell__bottombar .kk-btn--primary { padding: var(--space-1) var(--space-6); }
.kk-btn--hint { color: var(--color-hint); border-color: var(--color-hint); background: var(--color-bg); }
.kk-btn--hint:active { background: var(--color-hint-tint); }

/* Wrong-answer shake — applied to the stage by shell.js */
@keyframes kk-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(calc(var(--shake-distance) * -1)); }
  40% { transform: translateX(var(--shake-distance)); }
  60% { transform: translateX(calc(var(--shake-distance) * -0.6)); }
  80% { transform: translateX(calc(var(--shake-distance) * 0.6)); }
}
.kk-shake { animation: kk-shake 380ms ease; }
@media (prefers-reduced-motion: reduce) {
  .kk-shake { animation: none; }
  .kk-btn { transition: none; }
}

/* ---- Celebration ----
   A full-screen takeover on the shell's layout law (v1.1.0):
   a fixed-height asset slot (--celebration-asset-height) for
   the world's celebration character art sits above the stars
   and headline in the content area, and the two actions —
   Next (filled primary) + Back to list (quiet) — render in the
   standard pinned bottom bar, never stacked in the flow. */
.kk-celebration {
  display: flex; flex-direction: column;
  height: 100%;
  background: var(--color-bg);
  font-family: var(--font-text);
  color: var(--color-ink);
}
.kk-celebration__main {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-5);
  text-align: center;
  overflow-y: auto;
}
.kk-celebration__asset {
  height: var(--celebration-asset-height);
  display: flex; align-items: flex-end; justify-content: center;
  font-size: 96px; line-height: 1;
}
.kk-celebration__asset img { height: 100%; width: auto; display: block; }
.kk-celebration .kk-star { width: 44px; height: 44px; }
.kk-celebration__praise {
  font-family: var(--font-header);
  font-size: var(--type-display-size);
  line-height: var(--leading-tight);
}
.kk-celebration__note { font-size: var(--type-body-size); color: var(--color-ink-secondary); font-weight: 600; }
.kk-celebration__bar {
  flex: none;
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--color-hairline);
  background: var(--color-bg);
}
.kk-celebration__bar .kk-btn { padding: var(--space-1) var(--space-4); }
.kk-celebration__bar .kk-btn--primary { padding: var(--space-1) var(--space-6); }
@keyframes kk-star-pop {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.15); }
  100% { transform: scale(1); opacity: 1; }
}
.kk-celebration .kk-star--earned { animation: kk-star-pop 450ms ease both; }
.kk-celebration .kk-star--earned:nth-child(2) { animation-delay: 140ms; }
.kk-celebration .kk-star--earned:nth-child(3) { animation-delay: 280ms; }
@media (prefers-reduced-motion: reduce) {
  .kk-celebration .kk-star--earned { animation: none; }
}

/* ---- HelpModal ---- */
.kk-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(34, 34, 34, 0.45);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  z-index: 40;
}
.kk-modal {
  background: var(--color-bg);
  border-radius: var(--radius-bubble);
  border: 1px solid var(--color-hairline);
  max-width: 340px; width: 100%;
  padding: var(--space-5);
  font-family: var(--font-text);
}
.kk-modal__title { font-family: var(--font-header); font-size: var(--type-title-size); margin-bottom: var(--space-2); }
.kk-modal__body { font-size: var(--type-body-size); line-height: var(--leading-body); }
.kk-modal__credit { font-size: var(--type-small-size); color: var(--color-ink-secondary); margin-top: var(--space-3); font-weight: 600; }
.kk-modal__actions { margin-top: var(--space-4); display: flex; }
.kk-modal__actions .kk-btn { flex: 1; }
[hidden] { display: none !important; }

/* ---- CharacterHead ----
   TOP-ALIGNMENT RULE: in BOTH variants the bubble's top edge
   sits flush with the top edge of the head circle. The speaker
   name rides on the bubble's top edge — absolutely positioned,
   straddling it — so it never takes a row of its own and never
   pushes the bubble down.
   Hint variant: 56px head + hint-tinted bubble, sits BESIDE the
   stage, never over the board. Name in Quicksand 700 sentence case.
   Dialogue variant: 64px head, name label, speech bubble —
   one speaker per screen. */
.kk-character { display: flex; gap: var(--space-3); align-items: flex-start; font-family: var(--font-text); }
.kk-character__head {
  border-radius: 50%;
  background: var(--world-tint);
  border: 2px solid var(--world-accent);
  display: flex; align-items: center; justify-content: center;
  flex: none; overflow: hidden;
}
.kk-character--hint .kk-character__head { width: var(--head-hint-size); height: var(--head-hint-size); font-size: 30px; }
.kk-character--dialogue .kk-character__head { width: var(--head-dialogue-size); height: var(--head-dialogue-size); font-size: 36px; }
.kk-character__main { flex: 1; min-width: 0; position: relative; }
.kk-character__name {
  position: absolute; top: 0; left: var(--space-3);
  transform: translateY(-50%);
  padding: 1px var(--space-2);
  background: var(--color-bg);
  border-radius: var(--radius-pill);
  font-weight: 700; font-size: var(--type-body-size); line-height: 1.25;
  white-space: nowrap;
  z-index: 1;
}
.kk-character--dialogue .kk-character__name {
  font-family: var(--font-label); /* dialogue variant: Josefin Sans name label */
  letter-spacing: 0.04em;
  font-size: var(--type-body-size);
  color: var(--world-deep);
}
.kk-character__bubble {
  border-radius: var(--radius-bubble);
  /* extra top padding clears the name riding on the top edge */
  padding: var(--space-4) var(--space-4) var(--space-3);
  font-size: var(--type-body-size);
  line-height: var(--leading-body);
}
.kk-character--hint .kk-character__bubble { background: var(--color-hint-tint); }
.kk-character--dialogue .kk-character__bubble {
  background: var(--color-bg);
  border: 1px solid var(--color-hairline);
  font-size: 16.5px;
}
