/* Talkingskill.com shared site styles — light default, .dark overrides */
body { -webkit-tap-highlight-color: transparent; }

/* Account gating. auth.js is the source of truth and toggles inline display on
   these elements once the session resolves; these CSS rules only set the
   pre-JS state so guests never flash the personal bits, and logged-in users
   never flash the "please sign in" gate. */
html.tc-auth-enabled:not(.tc-authed) [data-auth-only] { display: none !important; }
[data-guest-only] { display: none; }
.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
.glass { background: rgba(255,255,255,0.72); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
.dark .glass { background: rgba(15,23,42,0.6); }
.bouncy { transition: transform 180ms cubic-bezier(.34,1.56,.64,1), box-shadow 180ms ease, border-color 180ms ease; }
.bouncy:hover { transform: translateY(-3px); }
.bouncy:active { transform: scale(0.965); }
.meter-fill { transition: width 600ms cubic-bezier(.22,1,.36,1), background-color 400ms ease, box-shadow 400ms ease; }
.energy-fill { transition: width 500ms cubic-bezier(.22,1,.36,1); }
@keyframes flicker { 0%,100% { transform: scale(1) rotate(-3deg); } 50% { transform: scale(1.15) rotate(3deg); } }
.streak-flame { display: inline-block; animation: flicker 1.6s ease-in-out infinite; }
/* Entrance animations are transform-only: the visible end-state is the base style. */
@keyframes bubbleIn { from { transform: translateY(10px) scale(.96); } to { transform: none; } }
.bubble { animation: bubbleIn 260ms cubic-bezier(.22,1,.36,1); }
@keyframes dotPulse { 0%,80%,100% { transform: scale(.6); opacity: .4; } 40% { transform: scale(1); opacity: 1; } }
.typing-dot { animation: dotPulse 1.1s infinite ease-in-out; }
.typing-dot:nth-child(2) { animation-delay: .15s; }
.typing-dot:nth-child(3) { animation-delay: .3s; }
@keyframes confettiFall {
  0% { transform: translateY(-20px) rotate(0deg); opacity: 1; }
  100% { transform: translateY(460px) rotate(720deg); opacity: 0; }
}
.confetti-piece { position: absolute; top: 0; width: 9px; height: 14px; border-radius: 2px; animation: confettiFall 2.6s linear forwards; }
@keyframes overlayIn { from { transform: scale(.94); } to { transform: none; } }
.overlay-card { animation: overlayIn 320ms cubic-bezier(.22,1,.36,1); }
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.shake { animation: shake 320ms ease; }

/* ===== Floating +/- delta popups (interest meter & XP) =====
   A game-style number that springs up, pops, then drifts away. */
@keyframes deltaPop {
  0%   { transform: translate(-50%, 2px) scale(.4); opacity: 0; }
  16%  { transform: translate(-50%, -5px) scale(1.25); opacity: 1; }
  42%  { transform: translate(-50%, -13px) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -46px) scale(.9); opacity: 0; }
}
.delta-pop {
  position: absolute; left: 50%; top: -4px; z-index: 50;
  font-weight: 900; font-size: 15px; line-height: 1; white-space: nowrap;
  pointer-events: none; text-shadow: 0 1px 3px rgba(15,23,42,.25);
  animation: deltaPop 1150ms cubic-bezier(.22,1,.36,1) forwards;
}
.delta-pop.up   { color: #16a34a; }
.delta-pop.down { color: #ef4444; }
.dark .delta-pop.up   { color: #4ade80; }
.dark .delta-pop.down { color: #f87171; }

/* Meter "juice": a quick vertical squash-stretch on change */
@keyframes meterPulse { 0% { transform: scaleY(1); } 35% { transform: scaleY(1.65); } 100% { transform: scaleY(1); } }
.meter-pulse { animation: meterPulse 480ms cubic-bezier(.22,1,.36,1); transform-origin: center; }

/* ============================================================
   Interest as a horizontal "VIBE" meter (replaces the % meter)
   A heart that beats faster the more they like you, beside a glowing bar that
   fills on a good reply (+xp) and shrinks + cools toward blue on a bad one
   (−xp). Fun, juicy, on-brand; no numbers. Driven by data-level (1–5) on
   .vibe-meter, set from game.js.
   ============================================================ */
.vibe-meter {
  --fill: 58%;
  display: flex; align-items: center; gap: 7px; width: 122px; flex: 0 0 auto;
}
.vibe-heart {
  display: inline-flex; flex: 0 0 auto; font-size: 18px; line-height: 1;
  color: #2dd4bf; transform-origin: center;
  filter: drop-shadow(0 1px 3px rgba(45,212,191,.45));
  transition: color .5s ease;
  animation: heartbeat 1.6s ease-in-out infinite;
}
.vibe-heart .tc-ico { width: 1em; height: 1em; filter: none; }
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  12%      { transform: scale(1.3); }
  24%      { transform: scale(1); }
  38%      { transform: scale(1.18); }
  52%      { transform: scale(1); }
}
.vibe-track {
  position: relative; flex: 1 1 auto; height: 9px; border-radius: 9999px;
  background: rgba(148,163,184,.3);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.2);
}
.dark .vibe-track { background: rgba(255,255,255,.12); }
.vibe-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: var(--fill);
  border-radius: 9999px;
  background: linear-gradient(90deg, #2dd4bf, #34d399);
  box-shadow: 0 0 10px rgba(45,212,191,.6);
  transition: width .85s cubic-bezier(.22,1,.36,1), background .6s ease, box-shadow .6s ease;
  will-change: width;
}
/* Travelling sheen along the fill. */
.vibe-shine { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.vibe-shine::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.75), transparent);
  transform: translateX(-160%);
  animation: vibeShine 2.8s ease-in-out infinite;
}
@keyframes vibeShine { 0% { transform: translateX(-160%); } 55%, 100% { transform: translateX(420%); } }
/* Glowing knob riding the leading edge of the fill. */
.vibe-knob {
  position: absolute; right: -4px; top: 50%; width: 12px; height: 12px; border-radius: 50%;
  transform: translateY(-50%); color: #2dd4bf;
  background: radial-gradient(circle at 35% 30%, #fff, currentColor 72%);
  box-shadow: 0 0 8px 1px currentColor;
  animation: knobBob 1.9s ease-in-out infinite;
}
.vibe-knob::after {
  content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid currentColor; opacity: 0;
}
@keyframes knobBob { 0%,100% { transform: translateY(-50%) scale(1); } 50% { transform: translateY(-50%) scale(1.12); } }

/* Five fill levels — the bar grows as interest climbs, heart beats faster. */
.vibe-meter[data-level="1"] { --fill: 16%; }
.vibe-meter[data-level="2"] { --fill: 38%; }
.vibe-meter[data-level="3"] { --fill: 58%; }
.vibe-meter[data-level="4"] { --fill: 78%; }
.vibe-meter[data-level="5"] { --fill: 95%; }

/* Colour shifts cold→hot as they warm to you. */
.vibe-meter[data-level="1"] .vibe-fill { background: linear-gradient(90deg, #60a5fa, #93c5fd); box-shadow: 0 0 9px rgba(96,165,250,.55); }
.vibe-meter[data-level="2"] .vibe-fill { background: linear-gradient(90deg, #22d3ee, #67e8f9); box-shadow: 0 0 9px rgba(34,211,238,.55); }
.vibe-meter[data-level="3"] .vibe-fill { background: linear-gradient(90deg, #2dd4bf, #34d399); box-shadow: 0 0 10px rgba(45,212,191,.6); }
.vibe-meter[data-level="4"] .vibe-fill { background: linear-gradient(90deg, #fbbf24, #fb923c); box-shadow: 0 0 10px rgba(251,146,60,.6); }
.vibe-meter[data-level="5"] .vibe-fill { background: linear-gradient(90deg, #fb7185, #f43f5e); box-shadow: 0 0 12px rgba(244,63,94,.65); }
.vibe-meter[data-level="1"] .vibe-heart, .vibe-meter[data-level="1"] .vibe-knob { color: #60a5fa; }
.vibe-meter[data-level="2"] .vibe-heart, .vibe-meter[data-level="2"] .vibe-knob { color: #22d3ee; }
.vibe-meter[data-level="3"] .vibe-heart, .vibe-meter[data-level="3"] .vibe-knob { color: #2dd4bf; }
.vibe-meter[data-level="4"] .vibe-heart, .vibe-meter[data-level="4"] .vibe-knob { color: #f59e0b; }
.vibe-meter[data-level="5"] .vibe-heart, .vibe-meter[data-level="5"] .vibe-knob { color: #f43f5e; }
/* Heart races as interest climbs; barely flutters when they're cold. */
.vibe-meter[data-level="1"] .vibe-heart { animation-duration: 2.6s; opacity: .85; }
.vibe-meter[data-level="2"] .vibe-heart { animation-duration: 2.1s; }
.vibe-meter[data-level="3"] .vibe-heart { animation-duration: 1.6s; }
.vibe-meter[data-level="4"] .vibe-heart { animation-duration: 1.2s; }
.vibe-meter[data-level="5"] .vibe-heart { animation-duration: .95s; }

/* —— Reactions —— */
/* Good reply (+xp): heart leaps, bar flashes, knob pops a ring. */
.vibe-meter.flare .vibe-heart { animation: heartPop .8s ease; }
@keyframes heartPop { 0% { transform: scale(1); } 30% { transform: scale(1.6); } 60% { transform: scale(.95); } 100% { transform: scale(1); } }
.vibe-meter.flare .vibe-fill { animation: vibeFlash .8s ease; }
@keyframes vibeFlash { 0%,100% { filter: brightness(1); } 40% { filter: brightness(1.5); } }
.vibe-meter.flare .vibe-knob { animation: knobPop .8s ease; }
@keyframes knobPop { 0% { transform: translateY(-50%) scale(1); } 30% { transform: translateY(-50%) scale(1.7); } 100% { transform: translateY(-50%) scale(1); } }
.vibe-meter.flare .vibe-knob::after { animation: knobRing .75s ease-out; }
@keyframes knobRing { 0% { transform: scale(.55); opacity: .85; } 100% { transform: scale(2.6); opacity: 0; } }
/* Bad reply (−xp): the track shakes, the bar dims/cools, the heart flinches. */
.vibe-meter.gutter .vibe-track { animation: vibeShake .5s ease; }
@keyframes vibeShake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
.vibe-meter.gutter .vibe-fill { animation: vibeDim .8s ease; }
@keyframes vibeDim { 0%,100% { filter: brightness(1); } 40% { filter: brightness(.6) saturate(.55); } }
.vibe-meter.gutter .vibe-heart { animation: heartFlinch .6s ease; }
@keyframes heartFlinch { 0%,100% { transform: rotate(0) scale(1); } 25% { transform: rotate(-12deg) scale(.9); } 75% { transform: rotate(12deg) scale(.9); } }

/* XP bar: a bright shimmer sweep when XP is gained */
@keyframes xpShimmer { from { transform: translateX(-120%); } to { transform: translateX(260%); } }
.xp-shimmer { position: relative; overflow: hidden; }
.xp-shimmer::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 35%, rgba(255,255,255,.9) 50%, transparent 65%);
  animation: xpShimmer 850ms ease-out 1;
}

/* Level-up badge pop (badge is centred with translateX(-50%) — keep it) */
@keyframes badgePop {
  0%   { transform: translateX(-50%) scale(1) rotate(0); }
  30%  { transform: translateX(-50%) scale(1.55) rotate(-10deg); }
  60%  { transform: translateX(-50%) scale(1.12) rotate(7deg); }
  100% { transform: translateX(-50%) scale(1) rotate(0); }
}
.badge-pop { animation: badgePop 720ms cubic-bezier(.22,1,.36,1); }

/* Avatar cheer when you level up */
@keyframes cheer {
  0%,100% { transform: translateY(0) rotate(0); }
  25% { transform: translateY(-5px) rotate(-7deg); }
  60% { transform: translateY(-2px) rotate(6deg); }
}
.cheer { animation: cheer 620ms ease; }

/* ===== Icon micro-animations ===== */
/* Springy hover pop for icons inside cards (.bouncy) and links */
.icon-pop { display: inline-flex; transition: transform .25s cubic-bezier(.34,1.56,.64,1); will-change: transform; }
.bouncy:hover .icon-pop, a:hover .icon-pop, .icon-pop:hover { transform: scale(1.22) rotate(-7deg); }
/* Gentle idle float for the hero feature icons (staggered) */
@keyframes iconBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
.icon-bob { animation: iconBob 3.2s ease-in-out infinite; }
.icon-bob:nth-of-type(1) { animation-delay: 0s; }
.bob-1 { animation-delay: .0s; } .bob-2 { animation-delay: .5s; } .bob-3 { animation-delay: 1s; }

/* ===== 2D icons ===== */
/* Rounded "chip" icons (feature / philosophy / doors cards): clean flat tiles
   with a single soft ambient shadow and a gentle lift on hover — no bevels,
   gloss, or tilt. */
[role="img"][class*="rounded-2xl"] {
  position: relative;
  box-shadow: 0 6px 14px -8px rgba(15,23,42,.28);     /* soft ambient lift */
  transition: transform .25s cubic-bezier(.34,1.56,.64,1), box-shadow .25s ease;
}
.bouncy:hover [role="img"][class*="rounded-2xl"]:not(.icon-float),
a:hover [role="img"][class*="rounded-2xl"]:not(.icon-float),
[role="img"][class*="rounded-2xl"]:not(.icon-float):hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 12px 22px -10px rgba(15,23,42,.34);
}
/* Perpetual gentle float (hero feature icons) — flat, vertical only */
.icon-float { animation: iconFloat 4.6s ease-in-out infinite; }
.icon-float:nth-of-type(1) { animation-delay: 0s; }
@keyframes iconFloat {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
/* Round avatar icons (profile + NPC): flat with a soft ambient shadow */
[role="img"][class*="rounded-full"] {
  box-shadow: 0 6px 14px -8px rgba(15,23,42,.26);
}

/* ===== Level-up celebration ===== */
@keyframes levelToastIn {
  0%   { transform: translate(-50%, -34px) scale(.55); opacity: 0; }
  16%  { transform: translate(-50%, 0) scale(1.14); opacity: 1; }
  30%  { transform: translate(-50%, 0) scale(1); opacity: 1; }
  78%  { transform: translate(-50%, 0) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -24px) scale(.96); opacity: 0; }
}
.level-toast {
  position: fixed; left: 50%; top: 74px; z-index: 60; transform: translateX(-50%);
  padding: 10px 22px; border-radius: 9999px; white-space: nowrap; pointer-events: none;
  font-weight: 900; font-size: 16px; letter-spacing: .01em; color: #fff;
  background: linear-gradient(100deg, #f59e0b, #f97316 45%, #0d9488);
  background-size: 180% 100%; animation: levelToastIn 2600ms cubic-bezier(.22,1,.36,1) forwards, sheen 2600ms linear;
  box-shadow: 0 14px 36px -8px rgba(245,158,11,.6), 0 0 0 4px rgba(255,255,255,.55);
}
.dark .level-toast { box-shadow: 0 14px 36px -8px rgba(245,158,11,.55), 0 0 0 4px rgba(2,6,23,.6); }
@keyframes sheen { from { background-position: 160% 0; } to { background-position: -60% 0; } }

/* Sparkle burst radiating from the level badge */
@keyframes sparkleOut {
  0%   { transform: translate(-50%, -50%) scale(0); opacity: 1; }
  60%  { opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1.1); opacity: 0; }
}
.spark { position: absolute; left: 50%; top: 50%; font-size: 12px; pointer-events: none; z-index: 50; animation: sparkleOut 720ms ease-out forwards; }

/* ===== Streak-up celebration ===== */
@keyframes streakFlare {
  0%   { transform: scale(1) rotate(0); filter: drop-shadow(0 0 0 rgba(249,115,22,0)); }
  40%  { transform: scale(1.85) rotate(-8deg); filter: drop-shadow(0 0 12px rgba(249,115,22,.95)); }
  70%  { transform: scale(1.2) rotate(5deg); }
  100% { transform: scale(1) rotate(0); filter: drop-shadow(0 0 0 rgba(249,115,22,0)); }
}
.streak-flare { animation: streakFlare 760ms cubic-bezier(.22,1,.36,1) !important; }
@keyframes countPop { 0% { transform: scale(1); } 40% { transform: scale(1.7); color: #f97316; } 100% { transform: scale(1); } }
.count-pop { animation: countPop 640ms cubic-bezier(.22,1,.36,1); display: inline-block; }

/* ===== "MINI" corner-ribbon sticker (top-right of a card) ===== */
.ribbon-mini {
  position: absolute; top: 16px; right: -34px; z-index: 5;
  transform: rotate(45deg);
  padding: 4px 40px;
  font-size: 11px; font-weight: 900; letter-spacing: .14em; line-height: 1;
  color: #fff; text-align: center;
  background: linear-gradient(135deg, #fbbf24, #f97316);
  box-shadow: 0 4px 10px -2px rgba(249,115,22,.55), inset 0 0 0 1px rgba(255,255,255,.35);
  pointer-events: none;
}
/* little folded "tails" so it reads as a real ribbon wrapped over the corner */
.ribbon-mini::before, .ribbon-mini::after {
  content: ''; position: absolute; bottom: -5px; border: 3px solid #b45309; border-radius: 1px;
}
.ribbon-mini::before { left: 0;  border-right-color: transparent; border-bottom-color: transparent; }
.ribbon-mini::after  { right: 0; border-left-color: transparent;  border-bottom-color: transparent; }

/* ===== Hero banner logo (right side) ===== */
.hero-banner {
  z-index: 0;
  filter: drop-shadow(0 18px 40px rgba(13,148,136,.45));
  animation: heroFloat 6s ease-in-out infinite;
  will-change: transform;
}
@keyframes heroFloat {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-14px) rotate(1deg); }
}

/* Dark mode for the inlined hero chat: recolour its static surfaces to match
   the dark conversation panel. (Animated mood ring / vibe / button-fill colours
   stay the same in both themes.) CSS fill/stroke override the SVG's light
   presentation attributes. */
.dark .hero-card     { fill: url(#hcardDark); }
.dark .hero-name     { fill: #e6edf6; }
.dark .hero-sub      { fill: #7f8da3; }
.dark .hero-track    { fill: #24324a; }
.dark .hero-divider  { stroke: #25344c; }
.dark .hero-bubble   { fill: #1e293b; stroke: rgba(255, 255, 255, .08); }
.dark .hero-line     { fill: #475569; }
.dark .hero-badge    { fill: #0f172a; stroke: #1f2c43; }
.dark .hero-btn      { fill: #16233a; }
.dark .hero-btnline  { fill: #8a99af; }

@media (prefers-reduced-motion: reduce) {
  .streak-flame, .typing-dot, .confetti-piece, .icon-bob, .hero-banner, .icon-float { animation: none; }
  .bouncy, .meter-fill, .energy-fill, .icon-pop, [role="img"][class*="rounded-2xl"] { transition: none; }
  .delta-pop, .meter-pulse, .xp-shimmer::after, .badge-pop, .cheer,
  .level-toast, .spark, .streak-flare, .count-pop { animation-duration: .01ms; }
  img.icon-flat { animation: none; transform: none; }
  .tc-ico, .tc-float, .tc-flame, .tc-pulse { animation: tcIcoFade .3s ease both; transform: none; }
  .msg-in { animation: msgIn .3s ease both; }
  #chat-log { animation: none; }
  #sim-card.tc-frame, .tc-stage::before { animation: none; }
  .tc-emote { animation: none; }
  /* Vibe meter: keep the fill-level + colour cue (the meaning), stop the motion. */
  .vibe-heart, .vibe-knob, .vibe-shine::after,
  .vibe-meter.flare .vibe-heart, .vibe-meter.flare .vibe-fill, .vibe-meter.flare .vibe-knob,
  .vibe-meter.gutter .vibe-track, .vibe-meter.gutter .vibe-fill, .vibe-meter.gutter .vibe-heart { animation: none; }
  .vibe-fill { transition: none; }
}

/* Emojis rendered as images (see emoji.js). Sized to the current font so they
   sit inline like the glyphs they replace — including the large end-screen
   reactions inside text-5xl containers. */
img.tw-emoji {
  height: 1em;
  width: 1em;
  margin: 0 .06em 0 .08em;
  vertical-align: -0.12em;
  display: inline-block;
  object-fit: contain;
}

/* ============================================================
   Conversation panel — premium stage + frame
   ============================================================ */
/* During play the marketing sidebar steps aside and the panel takes centre
   stage (toggled by body.tc-playing from game.js). */
body.tc-playing .sim-copy { display: none; }
body.tc-playing .sim-grid {
  grid-template-columns: minmax(0, 500px);
  justify-content: center;
}
/* The panel is a FIXED size the whole game — it never grows as messages arrive.
   Inside the frame: a character rail beside the conversation column. The column
   is a flex column locked to the frame height; only the message list scrolls,
   while the header + reply buttons stay put. The rail scrolls on its own. */
body.tc-playing #sim-card.tc-frame {
  height: min(80vh, 600px);
  height: min(80dvh, 600px);
}
.sim-body { min-height: 0; }
body.tc-playing .sim-body { height: 100%; }
#sim-convo { min-width: 0; }
body.tc-playing #sim-convo > #chat-log {
  flex: 1 1 auto;
  min-height: 0;       /* lets the message list shrink and scroll within the fixed frame */
  max-height: none;
}
/* The rail only exists once game.js fills it — hide the empty column until then. */
#char-rail:empty { display: none; }
/* Trim page chrome a touch so the panel sits comfortably in view, and clip the
   ambient halo so it can never add a horizontal scrollbar. */
body.tc-playing main { padding-top: 1rem; padding-bottom: 1.25rem; overflow-x: clip; }

/* Ambient aura: a slow-rotating colour halo glowing behind the frame. */
.tc-stage { position: relative; }
.tc-stage::before {
  content: ""; position: absolute; inset: -22px; z-index: 0; border-radius: 44px;
  background: conic-gradient(from 0deg, #2dd4bf, #8b5cf6, #fb7185, #f59e0b, #2dd4bf);
  filter: blur(42px); opacity: 0.30; pointer-events: none;
  animation: stageAura 18s linear infinite;
}
.dark .tc-stage::before { opacity: 0.42; }
@keyframes stageAura { to { transform: rotate(360deg); } }
.tc-stage > * { position: relative; z-index: 1; }

/* The frame itself: a crisp card with a live gradient border + layered depth. */
#sim-card.tc-frame {
  --card-bg: #ffffff;
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card-bg), var(--card-bg)) padding-box,
    linear-gradient(130deg, #2dd4bf, #14b8a6 28%, #8b5cf6 68%, #fb7185) border-box;
  background-size: auto, 220% 220%;
  box-shadow:
    0 30px 64px -24px rgba(13, 148, 136, 0.45),
    0 10px 26px -14px rgba(15, 23, 42, 0.30),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  animation: frameShimmer 9s ease-in-out infinite;
}
.dark #sim-card.tc-frame {
  --card-bg: #0b1220;
  box-shadow:
    0 30px 70px -24px rgba(45, 212, 191, 0.30),
    0 10px 26px -14px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
@keyframes frameShimmer {
  0%, 100% { background-position: 0 0, 0% 50%; }
  50%      { background-position: 0 0, 100% 50%; }
}

/* ============================================================
   Conversation panel — chat redesign (game.js)
   ============================================================ */
/* Each message springs up into place, so the conversation feels alive. */
.msg-in { animation: msgIn .42s cubic-bezier(.2, .9, .3, 1.25) both; }
@keyframes msgIn {
  from { opacity: 0; transform: translateY(12px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
.chat-bubble { position: relative; line-height: 1.35; word-break: break-word; }
/* Living chat backdrop: a soft dot grid that drifts very slowly. */
#chat-log {
  background-image: radial-gradient(rgba(13, 148, 136, 0.10) 1px, transparent 1.4px);
  background-size: 22px 22px;
  animation: chatDrift 24s linear infinite;
}
.dark #chat-log { background-image: radial-gradient(rgba(94, 234, 212, 0.07) 1px, transparent 1.4px); }
@keyframes chatDrift { from { background-position: 0 0; } to { background-position: 22px 44px; } }

/* ============================================================
   Bespoke icon system (icons.js) — animated, brand-coloured line art.
   ============================================================ */
.tc-ico {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.18em;
  overflow: visible;
  filter: drop-shadow(0 3px 5px rgba(13, 148, 136, 0.16));
  transition: transform .25s cubic-bezier(.2, .9, .3, 1.3), filter .25s ease;
  animation: tcIcoFade .45s ease both;
}
@keyframes tcIcoFade { from { opacity: 0; } to { opacity: 1; } }

/* Lively pop + brighter glow when the user hovers the thing holding the icon. */
a:hover .tc-ico, button:hover .tc-ico, summary:hover .tc-ico,
.bouncy:hover .tc-ico, .glass:hover .tc-ico, label:hover .tc-ico {
  transform: scale(1.16) rotate(-6deg);
  filter: drop-shadow(0 6px 12px rgba(13, 148, 136, 0.42));
}

/* Inline line-icons that replace the chat emojis (status / scene / beat lines).
   They inherit the surrounding text colour so each one matches its mood line,
   and sit snugly before the text without the heavy chrome drop-shadow. */
.tc-chat-ico {
  display: inline-flex;
  align-items: center;
  margin-right: 0.3em;
  vertical-align: -0.02em;
}
.tc-chat-ico .tc-ico {
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.18em;
  filter: none;
}

/* ============================================================
   Answer buttons — every reply option shares the same calm blue until it's
   picked. On click game.js tags the chosen one with a result class so it turns
   green (good), amber (so-so) or red (poor). The others dim out.
   ============================================================ */
.tc-choice {
  border: 2px solid #bfdbfe;
  background: linear-gradient(180deg, #eff6ff, #ffffff);
  box-shadow: 0 1px 2px rgba(15, 23, 42, .05);
  transition: transform .18s ease, box-shadow .25s ease, border-color .25s ease, background .25s ease, opacity .2s ease;
}
.dark .tc-choice { border-color: rgba(59, 130, 246, .4); background: linear-gradient(180deg, rgba(37, 99, 235, .16), rgba(30, 41, 59, .55)); }
/* Hover only while the option is still clickable. */
.tc-choice:not(:disabled):hover { transform: translateY(-2px); border-color: #3b82f6; background: linear-gradient(180deg, #60a5fa, #3b82f6); box-shadow: 0 8px 20px rgba(59, 130, 246, .42); }
.tc-choice:not(:disabled):hover .tc-choice-main { font-weight: 900; color: #ffffff; }
.tc-choice:not(:disabled):hover .tc-choice-gloss { font-weight: 700; color: rgba(255, 255, 255, .85); }

/* Once a choice is made the un-picked options fade back. */
.tc-choice:disabled { opacity: .45; transform: none; }

/* Result of the picked option (green / amber / red). */
.tc-choice--correct, .tc-choice--mid, .tc-choice--wrong { opacity: 1 !important; transform: none !important; }
.tc-choice--correct { border-color: #16a34a !important; background: linear-gradient(180deg, #22c55e, #16a34a) !important; box-shadow: 0 8px 20px rgba(34, 197, 94, .45) !important; }
.tc-choice--mid     { border-color: #d97706 !important; background: linear-gradient(180deg, #f59e0b, #d97706) !important; box-shadow: 0 8px 20px rgba(245, 158, 11, .45) !important; }
.tc-choice--wrong   { border-color: #dc2626 !important; background: linear-gradient(180deg, #f43f5e, #dc2626) !important; box-shadow: 0 8px 20px rgba(244, 63, 94, .45) !important; }
.tc-choice--correct .tc-choice-main, .tc-choice--mid .tc-choice-main, .tc-choice--wrong .tc-choice-main { color: #ffffff !important; font-weight: 900; }
.tc-choice--correct .tc-choice-gloss, .tc-choice--mid .tc-choice-gloss, .tc-choice--wrong .tc-choice-gloss { color: rgba(255, 255, 255, .9) !important; }

/* ============================================================
   Neon mood frame — Sarah's avatar ring + corner badge glow in the colour of
   her current emotion. The wrapper carries data-level (set from game.js); the
   level palette matches the vibe meter so both read the same feeling.
   ============================================================ */
.tc-emote-wrap { --emc: #22d3ee; --emg: rgba(34, 211, 238, .7); }
.tc-emote-wrap[data-level="1"] { --emc: #60a5fa; --emg: rgba(96, 165, 250, .72); }
.tc-emote-wrap[data-level="2"] { --emc: #22d3ee; --emg: rgba(34, 211, 238, .72); }
.tc-emote-wrap[data-level="3"] { --emc: #2dd4bf; --emg: rgba(45, 212, 191, .78); }
.tc-emote-wrap[data-level="4"] { --emc: #f59e0b; --emg: rgba(245, 158, 11, .78); }
.tc-emote-wrap[data-level="5"] { --emc: #f43f5e; --emg: rgba(244, 63, 94, .82); }

.tc-emote {
  box-shadow: 0 0 0 2px var(--emc), 0 0 12px 2px var(--emg);
  transition: box-shadow .4s ease;
  animation: emotePulse 2.2s ease-in-out infinite;
}
@keyframes emotePulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--emc), 0 0 8px 1px var(--emg); }
  50%      { box-shadow: 0 0 0 2px var(--emc), 0 0 18px 5px var(--emg); }
}
.tc-emote-badge {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 18px;
  height: 18px;
  border-radius: 9999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ffffff;
  color: var(--emc);
  box-shadow: 0 0 0 2px #ffffff, 0 0 8px var(--emg);
}
.dark .tc-emote-badge { background: #0f172a; box-shadow: 0 0 0 2px #0f172a, 0 0 9px var(--emg); }
.tc-emote-badge .tc-ico { width: 12px; height: 12px; vertical-align: 0; filter: none; animation: none; }

/* Idle drift — a slow, calm float so icons feel alive without being busy. */
.tc-float { animation: tcIcoFade .45s ease both, tcFloat 3.6s ease-in-out .45s infinite; }
@keyframes tcFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

/* Signature flame flicker for the streak icon. */
.tc-flame { transform-origin: 50% 80%; animation: tcIcoFade .45s ease both, tcFlame 1.6s ease-in-out infinite; }
@keyframes tcFlame {
  0%, 100% { transform: scale(1) translateY(0); }
  40%      { transform: scale(1.07, .93) translateY(.5px); }
  70%      { transform: scale(.95, 1.08) translateY(-1px); }
}

/* Soft breathing pulse (interest meter / gauge). */
.tc-pulse { animation: tcIcoFade .45s ease both, tcPulse 2.6s ease-in-out infinite; }
@keyframes tcPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }

/* A satisfying one-shot spin on hover (replay / dice / globe). */
a:hover .tc-spin, button:hover .tc-spin, .bouncy:hover .tc-spin, .glass:hover .tc-spin {
  animation: tcSpin .7s cubic-bezier(.3, .8, .3, 1) both;
}
@keyframes tcSpin { to { transform: rotate(360deg); } }

/* Mapped emojis use Microsoft Fluent "Flat" art and get a gentle, lifelike
   vertical float with a soft drop shadow, so they feel alive while staying
   crisp and flat. Each icon's animation-delay is randomised in JS so a group
   (e.g. the category nav) shimmers out of sync instead of bobbing together. */
img.icon-flat {
  filter: drop-shadow(0 3px 5px rgba(15, 23, 42, 0.18));
  animation: iconFlatFloat 3.4s ease-in-out infinite;
  transform-origin: 50% 60%;
  will-change: transform;
}
@keyframes iconFlatFloat {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(-3px) scale(1.04); }
}
/* A satisfying pop on hover/focus of the thing holding the icon. */
a:hover img.icon-flat, button:hover img.icon-flat, .bouncy:hover img.icon-flat {
  animation-duration: 1.1s;
  filter: drop-shadow(0 6px 9px rgba(13, 148, 136, 0.35));
}
