/* Nemo's World — UI styling. Cozy Nintendo-adjacent pastel look. */

@font-face {
  font-family: 'Baloo 2';
  src: url('/fonts/baloo2.woff2') format('woff2');
  font-weight: 400 800;
  font-display: swap;
}

:root {
  --font: 'Baloo 2', 'Comic Sans MS', 'Segoe UI Rounded', system-ui, sans-serif;
  --ink: #4a3f56;
  --ink-soft: #7a6f8a;
  --card: rgba(255, 255, 255, 0.72);
  --card-border: rgba(255, 255, 255, 0.9);
  --shadow: 0 10px 30px rgba(90, 60, 120, 0.18), 0 2px 8px rgba(90, 60, 120, 0.10);
  --hunger: linear-gradient(90deg, #ffb15e, #ff8a5c);
  --happiness: linear-gradient(90deg, #ff9ecb, #ff6fa5);
  --energy: linear-gradient(90deg, #7fe3c1, #3ecfa5);
  --radius: 22px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: var(--font);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  background: #ffd9ec;
}

#scene {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  cursor: grab;
  /* `none`, not `manipulation`: the html-level `manipulation` still lets the
     browser claim a swipe as a scroll gesture, which fired pointercancel
     mid-drag and killed the mobile camera. The HUD keeps `manipulation`. */
  touch-action: none;
}
#scene:active { cursor: grabbing; }
#scene.pettable { cursor: pointer; }

/* ------------------------------------------------------------------ */
/* Loader                                                              */
/* ------------------------------------------------------------------ */

#loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, #ffe3f1 0%, #e8e4ff 55%, #d6f4ff 100%);
  transition: opacity 0.8s ease, visibility 0.8s;
}
#loader.done { opacity: 0; visibility: hidden; }

.loader-inner { text-align: center; }

.loader-paw {
  font-size: 64px;
  animation: paw-bounce 1.1s ease-in-out infinite;
  filter: drop-shadow(0 8px 12px rgba(120, 80, 160, 0.25));
}
@keyframes paw-bounce {
  0%, 100% { transform: translateY(0) rotate(-8deg); }
  50% { transform: translateY(-16px) rotate(8deg); }
}

.loader-title {
  margin-top: 14px;
  font-size: 40px;
  font-weight: 800;
  letter-spacing: 0.5px;
  background: linear-gradient(90deg, #ff7eb3, #9a7bff, #4fc3f7);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.loader-sub { margin-top: 4px; font-size: 16px; color: var(--ink-soft); }

.loader-bar {
  margin: 22px auto 0;
  width: 220px;
  height: 10px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.7);
  overflow: hidden;
  box-shadow: inset 0 2px 4px rgba(120, 80, 160, 0.15);
}
.loader-fill {
  height: 100%;
  width: 20%;
  border-radius: 99px;
  background: linear-gradient(90deg, #ff7eb3, #9a7bff);
  transition: width 0.3s ease;
}

/* ------------------------------------------------------------------ */
/* Shared glass cards                                                  */
/* ------------------------------------------------------------------ */

.glass {
  background: var(--card);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border: 1.5px solid var(--card-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* ------------------------------------------------------------------ */
/* Top HUD                                                             */
/* ------------------------------------------------------------------ */

#hud-top {
  position: fixed;
  top: max(14px, env(safe-area-inset-top));
  left: 16px;
  right: 16px;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  pointer-events: none;
}
#hud-top > * { pointer-events: auto; }

.nameplate {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 18px 10px 12px;
}

.avatar {
  position: relative;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  display: grid;
  place-items: center;
  background: linear-gradient(145deg, #ffd9a8, #ffb570);
  box-shadow: inset 0 -3px 6px rgba(200, 120, 40, 0.25);
}
.avatar > svg { display: block; }

/* mood badge overlapping the avatar's bottom-right corner */
.mood-badge {
  position: absolute;
  right: -5px;
  bottom: -5px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid #fff;
  display: grid;
  place-items: center;
  box-shadow: 0 2px 5px rgba(90, 60, 120, 0.25);
}
.mood-badge svg { display: block; }

.pet-name { font-size: 22px; font-weight: 800; line-height: 1.1; }
.pet-sub { font-size: 13px; color: var(--ink-soft); font-weight: 600; }

.top-right { display: flex; gap: 10px; align-items: center; }

.visitors {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 44px; /* match .icon-btn so the top-right cluster shares one metric */
  padding: 0 16px;
  font-weight: 700;
  font-size: 15px;
}
/* all-time visit total, riding in the same pill as the live count */
.visitors .visits-ever {
  color: var(--ink-soft);
  font-size: 13px;
  white-space: nowrap;
}
.visitors .visits-ever[hidden] { display: none; }
.visitors .dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #3ecfa5;
  box-shadow: 0 0 0 4px rgba(62, 207, 165, 0.25);
  animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot {
  0%, 100% { box-shadow: 0 0 0 3px rgba(62, 207, 165, 0.25); }
  50% { box-shadow: 0 0 0 6px rgba(62, 207, 165, 0.12); }
}

.icon-btn {
  width: 44px;
  height: 44px;
  font-size: 19px;
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--ink);
  transition: transform 0.15s ease;
}
.icon-btn:hover { transform: scale(1.08); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { display: block; }

/* speaker icon states — waves when on, slash when muted */
#sound-toggle .snd-off { display: none; }
#sound-toggle.muted .snd-wave { display: none; }
#sound-toggle.muted .snd-off { display: block; }

/* ------------------------------------------------------------------ */
/* Stats                                                               */
/* ------------------------------------------------------------------ */

#stats {
  position: fixed;
  /* anchored directly under the visitors pill + mute button so the right
     side reads as one aligned column mirroring the nameplate */
  top: calc(max(14px, env(safe-area-inset-top)) + 58px);
  right: 16px;
  z-index: 10;
  width: 210px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.stat { display: flex; align-items: center; gap: 10px; }
.stat-icon { font-size: 20px; filter: drop-shadow(0 2px 3px rgba(90, 60, 120, 0.2)); }
.stat-icon svg { display: block; }
.stat-body { flex: 1; }

.stat-label {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.stat-num {
  color: var(--ink);
  font-variant-numeric: tabular-nums; /* digits keep width as values tick */
  min-width: 3ch;
  text-align: right;
}

.bar {
  height: 12px;
  border-radius: 99px;
  background: rgba(120, 90, 150, 0.14);
  overflow: hidden;
  box-shadow: inset 0 2px 3px rgba(90, 60, 120, 0.12);
}
.bar-fill {
  height: 100%;
  width: 0; /* real value arrives with first server state — never fake 50% */
  border-radius: 99px;
  transition: width 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  position: relative;
}
.bar-fill::after {
  content: '';
  position: absolute;
  inset: 1.5px 3px auto 3px;
  height: 3.5px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.45);
}
.fill-hunger { background: var(--hunger); }
.fill-happiness { background: var(--happiness); }
.fill-energy { background: var(--energy); }

/* ------------------------------------------------------------------ */
/* Action buttons                                                      */
/* ------------------------------------------------------------------ */

#actions {
  position: fixed;
  bottom: max(20px, env(safe-area-inset-bottom));
  /* Stretched edge to edge and centred by `justify-content`, NOT parked at
     left:50% and pulled back with a transform.
     The old way was quietly costing half the screen. A `position: fixed`
     element with `width: auto` and only a `left` shrinks to fit inside the
     space from that left edge to the viewport's right edge — so anchoring at
     50% told the row it had HALF the window to lay out in. Seven 96px buttons
     want 768px, so on anything narrower than about 1536px the row folded into
     two off-centre rows on a desktop that had a thousand spare pixels. (It was
     already doing this below ~1310px with six buttons; the wardrobe made a very
     common laptop width the visible case.)
     Full width also means the flex-basis percentages the phone layout uses
     resolve against the viewport instead of against a width that was itself
     waiting on the children. */
  left: 0;
  right: 0;
  padding: 0 8px;
  z-index: 10;
  display: flex;
  gap: 16px;
  /* The row grew from three buttons to six (Feed Pet Play Box Brush Treat) and
     was still centred with no width limit, so on a phone it simply hung off
     BOTH edges — the first and last buttons were sliced in half and there was
     no way to reach them. It now wraps instead of overflowing, and can never
     be wider than the screen however many actions a future feature adds. */
  flex-wrap: wrap;
  justify-content: center;
  /* ...and now that the strip spans the window, it must not eat the clicks it
     is sitting on top of: click-to-walk lives on the canvas underneath, and a
     full-width invisible nav would have swallowed every tap along the bottom of
     the island. Only the buttons themselves are targets. */
  pointer-events: none;
}
#actions > * { pointer-events: auto; }

.action-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 96px;
  padding: 12px 22px 10px;
  border: none;
  border-radius: 26px;
  font-family: var(--font);
  cursor: pointer;
  /* solid pastel fills (no backdrop blur) so each action keeps its color
     identity over any scene behind it */
  background: #ffffff;
  border: 1.5px solid var(--card-border);
  box-shadow: var(--shadow);
  transition: transform 0.16s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
}
.action-btn:hover {
  transform: translateY(-4px) scale(1.04);
  box-shadow: 0 16px 36px rgba(90, 60, 120, 0.22), 0 3px 10px rgba(90, 60, 120, 0.12);
}
.action-btn:active { transform: translateY(0) scale(0.95); }
.action-btn:disabled { opacity: 0.55; pointer-events: none; }

.action-emoji { filter: drop-shadow(0 3px 4px rgba(90, 60, 120, 0.22)); }
.action-emoji svg { display: block; }
.action-label { font-size: 15px; font-weight: 800; color: var(--ink); letter-spacing: 0.3px; }

/* resting color identity per action (solid pastel fill),
   strengthened border on hover */
#btn-feed { background: #fff3e2; }
#btn-pet { background: #ffe9f3; }
#btn-play { background: #e6faf2; }
#btn-box { background: #fbf0e0; position: relative; }
#btn-box:hover { border-color: #d3a468; }
/* One box at a time. The old state was `disabled` plus a title tooltip: the
   whole button dropped to opacity 0.55, which reads as "this is broken", and the
   only explanation was a hover title no phone has ever displayed. Same treatment
   the Treat cooldown gets instead — full-strength icon, an explicit label, and a
   pip — so the button says "taken", not "dead". */
#btn-box.taken {
  opacity: 1;
  cursor: not-allowed;
  background: #f2e6d3;
  border-color: #d8bd94;
}
#btn-box.taken .action-emoji { opacity: 1; }
#btn-box.taken .action-label { color: #8a6a42; }
/* A plain amber dot, not a glyph: at the 11px the Treat countdown badge uses, an
   emoji renders as an unreadable brown smudge. The label carries the meaning. */
#btn-box.taken::after {
  content: '';
  position: absolute;
  top: -5px;
  right: -5px;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: #a97c45;
  border: 2px solid #fff;
  box-shadow: 0 2px 5px rgba(90, 60, 30, 0.35);
}
#btn-feed:hover { border-color: #ffb570; }
#btn-pet:hover { border-color: #ff9ecb; }
#btn-play:hover { border-color: #7fe3c1; }

/* ------------------------------------------------------------------ */
/* Treat picker                                                        */
/* ------------------------------------------------------------------ */
/* One more button in the row, and a small tray that lifts out of it. The tray
   is absolutely positioned off the slot, so opening it never reflows the
   action row underneath — the HUD keeps the footprint it was praised for. */

/* Brush is a latching MODE button: it keeps the row's resting look and only
   gains a ring while it is on, so the action row reads the same as it always
   has until you actually turn it on. */
#btn-brush { background: #e8f8f2; }
#btn-brush:hover { border-color: #7fd8bf; }
#btn-brush[aria-pressed="true"] {
  border-color: #3ecfa5;
  box-shadow: 0 0 0 3px rgba(62, 207, 165, 0.30), var(--shadow);
}

/* Brush-mode cursor. The custom glyph is a small brush; every declaration
   falls back to a keyword after the comma, so a browser that refuses the
   data URI still shows a sane cursor instead of an arrow. */
#scene.brush-mode {
  cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Crect x='9' y='3' width='4.6' height='7' rx='2.3' fill='%23e2b478' stroke='%23b8823f' stroke-width='1'/%3E%3Crect x='3' y='9' width='16.6' height='8' rx='4' fill='%233ecfa5' stroke='%232fae8c' stroke-width='1.1'/%3E%3Cpath d='M6.5 17.5v4.4M10.3 17.5v5.4M14.1 17.5v5.4M17.9 17.5v4.4' stroke='%23d9a05c' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") 11 3, grab;
}
#scene.brush-mode:active { cursor: grabbing; }

/* One line of guidance, centred above the action row, and nothing else. */
#brush-hint {
  position: fixed;
  bottom: 102px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.82);
  border: 1.5px solid rgba(62, 207, 165, 0.45);
  box-shadow: 0 6px 18px rgba(90, 60, 120, 0.13);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--ink-soft);
  white-space: nowrap;
  pointer-events: none;
  animation: tray-in 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#brush-hint[hidden] { display: none; }
/* clean captures never show the HUD, and brush mode never runs on them */
body.shot-mode #brush-hint { display: none; }

.action-slot { position: relative; display: flex; }
#btn-treat { background: #f3ecff; position: relative; }
#btn-treat:hover { border-color: #b79ae8; }
#btn-treat[aria-expanded="true"] {
  border-color: #b79ae8;
  box-shadow: 0 0 0 3px rgba(183, 154, 232, 0.28), var(--shadow);
}
/* Cooling off: the server refused a give and said how long to wait, so the
   button says so too. Before this the click simply did nothing — the single
   most common "is it broken?" moment in the whole feature. */
/* The dimming is applied to the button's CONTENTS, not the button, because
   .action-btn:disabled already drops the whole element to opacity 0.55 and a
   countdown you cannot read is not a countdown. The id+class selector outranks
   it, so the badge below renders at full strength. */
#btn-treat.cooling {
  cursor: not-allowed;
  opacity: 1;
}
#btn-treat.cooling .action-emoji,
#btn-treat.cooling .action-label {
  opacity: 0.5;
  filter: grayscale(0.6);
}
#btn-treat.cooling::after {
  content: attr(data-cooldown);
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 22px;
  padding: 1px 5px;
  border-radius: 999px;
  background: #7d63b8;
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
  box-shadow: 0 2px 5px rgba(60, 40, 100, 0.35);
}

.treat-tray {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%);
  padding: 10px 10px 8px;
  background: #ffffff;
  border: 1.5px solid var(--card-border);
  border-radius: 22px;
  box-shadow: var(--shadow);
  animation: tray-in 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.treat-tray[hidden] { display: none; }
/* the little nib pointing back down at the Treat button */
.treat-tray::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, -5px) rotate(45deg);
  width: 12px;
  height: 12px;
  background: #ffffff;
  border-right: 1.5px solid var(--card-border);
  border-bottom: 1.5px solid var(--card-border);
  border-radius: 0 0 3px 0;
}
@keyframes tray-in {
  from { opacity: 0; transform: translateX(-50%) translateY(8px) scale(0.94); }
  to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

.treat-tray-hint {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink-soft);
  text-align: center;
  letter-spacing: 0.2px;
  margin-bottom: 6px;
}
.treat-row { display: flex; gap: 6px; }

.treat-opt {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  /* 90px, not 82: "Chicken morsel" wrapped to two lines at 82 and the three
     options stopped reading as one row of equals */
  width: 90px;
  padding: 8px 4px 7px;
  border: 1.5px solid transparent;
  border-radius: 16px;
  background: transparent;
  font-family: var(--font);
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.16s ease, border-color 0.16s ease;
}
.treat-opt svg { display: block; filter: drop-shadow(0 2px 3px rgba(90, 60, 120, 0.18)); }
.treat-opt:hover { background: #faf6ff; border-color: #cdb8f0; transform: translateY(-3px); }
.treat-opt:active { transform: translateY(0) scale(0.95); }
.treat-name {
  font-size: 11px;
  font-weight: 800;
  color: var(--ink);
  line-height: 1.15;
  text-align: center;
}

/* Tried-today badge: ♥ loved it, • ate it, ✕ buried it. Empty (and invisible)
   until you have actually watched that outcome today; wiped at the server's
   Brisbane midnight. It marks what you have RULED OUT, which is what turns
   three anonymous buttons into a puzzle you can finish. */
.treat-badge {
  position: absolute;
  top: 3px;
  right: 5px;
  width: 17px;
  height: 17px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  color: #fff;
  background: transparent;
  opacity: 0;
  transition: opacity 0.18s ease;
}
.treat-opt.tried .treat-badge { opacity: 1; }
.treat-opt.tried { background: #f7f3ff; }
.treat-badge[data-outcome="favourite"] { background: #e2698f; }
.treat-badge[data-outcome="neutral"] { background: #9aa7b5; font-size: 15px; }
.treat-badge[data-outcome="disliked"] { background: #7e8b74; font-size: 10px; }

/* ------------------------------------------------------------------ */
/* Wardrobe picker                                                     */
/* ------------------------------------------------------------------ */
/* Reuses .treat-tray / .treat-opt / .treat-name wholesale — it is the same
   popover, and a second one with its own private geometry is how a HUD stops
   reading as one object. Only three things differ, and each earns it:
   a 3x3 GRID (nine options do not fit in a row), a "wearing" state (an outfit
   is a thing she is IN, not a thing you hand over), and pink instead of
   purple, so the two open trays are never mistaken for each other. */
#btn-outfit { background: #ffeef4; position: relative; }
#btn-outfit:hover { border-color: #eda3b8; }
#btn-outfit[aria-expanded="true"] {
  border-color: #eda3b8;
  box-shadow: 0 0 0 3px rgba(237, 163, 184, 0.3), var(--shadow);
}
/* Same cooldown treatment the Treat button gets, for the same reason: the
   change is refused world-wide, so the button has to say so in pixels. */
#btn-outfit.cooling { cursor: not-allowed; opacity: 1; }
#btn-outfit.cooling .action-emoji,
#btn-outfit.cooling .action-label { opacity: 0.5; filter: grayscale(0.6); }
#btn-outfit.cooling::after {
  content: attr(data-cooldown);
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 22px;
  padding: 1px 5px;
  border-radius: 999px;
  background: #c9647f;
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
  box-shadow: 0 2px 5px rgba(100, 40, 60, 0.35);
}

.outfit-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px 6px;
}
.outfit-opt { width: 78px; padding: 6px 3px 5px; }
.outfit-opt:hover { background: #fff4f7; border-color: #f0bccb; }
/* The live "wearing" mark. It is driven by the SERVER's state (ui.setOutfit),
   not by what this tab last clicked, so the tick moves the moment a friend
   changes her clothes. */
.outfit-check {
  position: absolute;
  top: 2px;
  right: 4px;
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: #e2698f;
  color: #fff;
  font-size: 10px;
  font-weight: 900;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.18s ease;
}
.outfit-opt.wearing .outfit-check { opacity: 1; }
.outfit-opt.wearing {
  background: #fdeef3;
  border-color: #e9a6bb;
}

/* ------------------------------------------------------------------ */
/* Speech bubble                                                       */
/* ------------------------------------------------------------------ */

#bubble {
  position: fixed;
  z-index: 9;
  transform: translate(-50%, -100%);
  background: rgba(255, 255, 255, 0.94);
  border-radius: 18px 18px 18px 4px;
  padding: 9px 16px;
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  box-shadow: var(--shadow);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#bubble.hidden { opacity: 0; transform: translate(-50%, -80%) scale(0.8); }

/* ------------------------------------------------------------------ */
/* Toasts                                                              */
/* ------------------------------------------------------------------ */

#toasts {
  position: fixed;
  bottom: 116px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 11;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.toast {
  background: rgba(74, 63, 86, 0.88);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  padding: 9px 18px;
  border-radius: 99px;
  box-shadow: 0 8px 22px rgba(40, 25, 60, 0.3);
  animation: toast-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.toast.leaving { animation: toast-out 0.4s ease forwards; }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(14px) scale(0.85); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes toast-out {
  to { opacity: 0; transform: translateY(-10px) scale(0.9); }
}

/* ------------------------------------------------------------------ */
/* First-visit intro popup                                             */
/* ------------------------------------------------------------------ */

#intro {
  position: fixed;
  inset: 0;
  /* over the whole HUD (10/11), under the loader (100) — so the loader's
     fade-out reveals the card already sitting there, one beat, no pop-pop */
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(74, 63, 86, 0.32);
  animation: intro-dim-in 0.4s ease;
}
#intro[hidden] { display: none; }

.intro-card {
  max-width: 430px;
  padding: 26px 30px 24px;
  border-radius: 26px;
  animation: intro-card-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.intro-lead { font-size: 17px; font-weight: 800; }
.intro-list {
  margin: 12px 0 14px;
  padding-left: 24px;
}
.intro-list li { margin: 7px 0; font-size: 15px; font-weight: 600; }
.intro-note { font-size: 14.5px; font-weight: 600; color: var(--ink-soft); }
.intro-close-btn {
  display: block;
  margin: 20px auto 0;
  padding: 11px 40px;
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  border-radius: 24px;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.3px;
  color: var(--ink);
  background: linear-gradient(160deg, #ffd9a0, #f5b872);
  box-shadow: 0 6px 16px rgba(90, 60, 120, 0.20);
  cursor: pointer;
  transition: transform 0.15s ease;
}
.intro-close-btn:hover { transform: scale(1.05); }
.intro-close-btn:active { transform: scale(0.97); }

@keyframes intro-dim-in { from { opacity: 0; } }
@keyframes intro-card-in {
  from { opacity: 0; transform: translateY(16px) scale(0.9); }
}

@media (max-width: 640px) {
  .intro-card { padding: 22px 22px 20px; }
  .intro-lead { font-size: 16px; }
  .intro-list li { font-size: 14px; }
}

/* ------------------------------------------------------------------ */
/* Small screens                                                       */
/* ------------------------------------------------------------------ */

@media (max-width: 640px) {
  #stats {
    top: auto;
    bottom: 108px;
    right: 12px;
    left: 12px;
    transform: none;
    width: auto;
    flex-direction: row;
    gap: 10px;
    padding: 12px;
  }
  .stat { flex: 1; }
  .stat-icon { font-size: 16px; }
  .action-btn { min-width: 0; padding: 10px 12px 8px; width: 100%; }
  /* Exactly FOUR per row, so the number of rows is DETERMINISTIC (seven
     actions = two rows) and the stat bars below can be given matching
     clearance. With free wrapping the row count changed with the label widths,
     which is how the stats ended up overlapping the buttons on some phones.
     It was three per row while there were six actions; the wardrobe made a
     seventh, and three-per-row would have taken the block to a third row and
     put the buttons straight back through the stats. Four keeps it at two rows
     at every width down to 360px (an 80px cell, against a 56px "Party hat"
     label at 13px — measured, not guessed). */
  /* `100%` here is the row's CONTENT box, which is the viewport less the 8px
     of padding either side — see the left:0/right:0 note on #actions above.
     While the row was shrink-wrapped this percentage resolved against a width
     that was itself waiting on the children, and the row came out about half
     the screen wide with every label spilling out of its pill. */
  #actions { gap: 8px 8px; }
  #actions > * { flex: 0 0 calc((100% - 24px) / 4); }
  /* Keep every label on one line: a wrapped label makes that button taller,
     which makes the whole row taller, which is what pushed the block back up
     into the stat bars at 360px. Fixed height in, fixed clearance out. */
  .action-label { white-space: nowrap; }
  .action-label { font-size: 13px; }
  /* the tray is wider than one button, so on a phone it centres on the whole
     action row instead of on the slot it hangs off */
  .treat-tray { left: auto; right: -6px; transform: none; animation: none; }
  .treat-tray::after { left: auto; right: 34px; }
  .treat-opt { width: 76px; }
  /* Nine cells three across: 3 x 68 + gaps + padding = 236px, which clears
     360px with the tray's own right:-6px anchor still on screen. */
  .outfit-opt { width: 68px; padding: 5px 2px 4px; }
  .outfit-grid { gap: 3px 4px; }
  .treat-name { font-size: 10px; }
  .pet-sub { display: none; }
}

/* Four actions per row means seven of them are always two rows on a phone, so
   the stats need a fixed two-row clearance rather than the single-row 108px
   they were written for. The wardrobe added a seventh action and did NOT add a
   row (see the four-per-row rule above), so this number is unchanged. */
@media (max-width: 640px) {
  #stats { bottom: 180px; }
}

/* Hide UI for clean screenshots (?shot=1) */
body.shot-mode #hud-top,
body.shot-mode #actions,
body.shot-mode #stats,
body.shot-mode #toasts,
body.shot-mode #bubble,
body.shot-mode #intro { display: none; }
