/* chat.css - Professional chat styles.
   SINGLE OWNER of .chat-panel: base + responsive rules all live here (they
   previously straddled core.css and this file, which made the load order in
   app.html load-bearing).
   STALE-CACHE WARNING: this file is a plain <link> in app.html — NOT
   fingerprinted, NOT hot-reloaded. In dev the vite.config.ts watcher
   force-reloads the page on edit; a DEPLOYED kiosk only picks changes up on
   its next page (re)load — hard-reload the device if an old artifact
   reappears (full note in app.html). */

/* Chat panel — grid row 6 of .main-screen (below the orb band and the
   hold-to-speak pill row, above the bottom hint). Its HEIGHT is grid-driven:
   the row is fit-content(26dvh) (30dvh short screens, 24dvh portrait — see
   core.css), so the panel sizes to its messages up to the cap and the old
   per-breakpoint max-height:*vh rules are gone. Width leaves a gutter so the
   panel clears the fixed bottom-corner controls (logout / camera) at narrow
   widths. */
.chat-panel {
  grid-row: 6;
  grid-column: 1 / -1;
  justify-self: center;
  position: relative;
  width: min(700px, calc(100% - 9rem));
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--space-3) var(--space-4);
  box-sizing: border-box;
  z-index: var(--z-cards);
  opacity: 1;
  transition: opacity 0.3s ease;
  overflow: hidden;
  /* The parent .main-screen is pointer-events: none; the panel must always
     stay clickable. */
  pointer-events: auto;
  /* Opaque background so orb / audio bar never show through */
  background: color-mix(in srgb, var(--kuyil-bg) 95%, transparent);
  border: 1px solid color-mix(in srgb, var(--kuyil-line) 60%, transparent);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.6);
}

/* Hidden (idle/greeting): display:none collapses the fit-content grid row to
   zero, so the orb recenters in the full column instead of leaving a reserved
   empty slot. */
.chat-panel.hidden {
  display: none;
}

/* Chat panel visibility while the kiosk is active (moved from
   kiosk-states.css so this file owns every .chat-panel rule). */
body[data-kiosk-mode="active"] .chat-panel {
  opacity: 1;
  pointer-events: auto;
}

/* Chat window - compact, professional with shadow fade and auto-scroll.
   flex: 1 + min-height: 0 makes it fill the panel and scroll internally. */
#chat {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  /* Top padding pushes the first message clear of the fade zone below, so it
     stays fully readable when the chat isn't scrolled (the "Hello, how are
     you?" line was being dimmed by the mask). */
  padding: 1.75rem var(--space-3) var(--space-2);
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--kuyil-text) 15%, transparent) transparent;
  justify-content: flex-start;
  scroll-behavior: smooth;
  /* Older messages fade as they scroll up under the top edge. Kept short
     (≈1.75rem) and aligned with the padding above so the newest messages are
     never dimmed — only content that actually scrolls past the top fades. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    rgba(0, 0, 0, 0.4) 0.75rem,
    #000 1.75rem
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    rgba(0, 0, 0, 0.4) 0.75rem,
    #000 1.75rem
  );
}

#chat::-webkit-scrollbar {
  width: 4px;
}

#chat::-webkit-scrollbar-track {
  background: transparent;
}

#chat::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.15);
  border-radius: 2px;
}

/* Chat line (message row) — modern chat alignment: assistant bubbles lead
   from the start edge, visitor bubbles from the end edge (logical properties
   below, so dir=rtl flips the whole convention). One small translate+fade on
   entry; nothing animates continuously (perf lessons — see attract screen). */
.chat-line {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 0.625rem;
  padding: var(--space-1) 0;
  animation: fade-in-up 0.25s ease;
  flex-shrink: 0;
}

.chat-line.assistant {
  justify-content: flex-start;
}

.chat-line.user {
  justify-content: flex-end;
}

@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-line {
    animation: none;
  }
}

/* Sender label (You / Kuyil) - compact */
.chat-sender {
  font-size: var(--text-xs);
  font-weight: 600;
  color: color-mix(in srgb, var(--kuyil-text) 50%, transparent);
  min-width: 2.5rem;
  text-align: right;
  flex-shrink: 0;
  padding-top: var(--space-2);
  text-transform: uppercase;
  letter-spacing: 0.03125rem;
  line-height: 1.5;
}

.chat-sender.user {
  color: var(--accent-cyan);
}

.chat-sender.assistant {
  color: var(--accent-violet);
}

/* Message bubble — glass surfaces from the token system, sized as a reading
   surface: the assistant text is what the visitor actually reads, so it gets
   comfortable type (≈17–20px, 1.45 line-height) and a ~34ch measure. Bubbles
   hug their content (flex 0 1 auto) instead of spanning the panel, and carry
   an asymmetric radius — the corner on the speaker's side is flattened, the
   classic speech-bubble tail cue — via logical properties so RTL flips it. */
.chat-bubble {
  flex: 0 1 auto;
  max-width: min(34ch, 84%);
  background: color-mix(in srgb, var(--kuyil-text) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--kuyil-text) 9%, transparent);
  border-radius: var(--radius-lg);
  border-end-start-radius: 6px;
  padding: var(--space-2) var(--space-4);
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  line-height: 1.45;
  color: color-mix(in srgb, var(--kuyil-text) 95%, transparent);
  word-wrap: break-word;
  overflow-wrap: break-word;
  white-space: pre-wrap;
}

/* Visitor bubble — accent-tinted glass on the end edge, slightly smaller and
   quieter than the assistant's reading surface (their words are confirmation,
   not content). Tail corner flips to the end side. */
.chat-line.user .chat-bubble {
  background: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 13%, transparent);
  border-color: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 24%, transparent);
  border-radius: var(--radius-lg);
  border-end-end-radius: 6px;
  font-size: clamp(0.9375rem, 1.4vw, 1.0625rem);
  color: color-mix(in srgb, var(--kuyil-text) 82%, transparent);
}

/* Listening placeholder — dimmed, italic, pulsing dot (the visitor's ghost:
   a wordless dot until their OWN words stream in from STT partials). */
.listening-placeholder-bubble {
  color: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 60%, transparent) !important;
  font-style: italic;
  border-style: dashed !important;
}

.listening-placeholder-bubble span::after {
  content: "";
  display: inline-block;
  width: 0.4em;
  height: 0.4em;
  margin-left: 0.3em;
  margin-bottom: 0.1em;
  background: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 60%, transparent);
  border-radius: 50%;
  vertical-align: middle;
  animation: listening-pulse 1.2s ease-in-out infinite;
}

@keyframes listening-pulse {
  0%,
  100% {
    opacity: 0.3;
    transform: scale(0.8);
  }
  50% {
    opacity: 1;
    transform: scale(1.2);
  }
}

/* Streaming assistant bubble — the reply arriving live. NORMAL reading type
   (the old italic/dim "thinking" look made live text read as placeholder);
   liveness is a tiny cursor-dot pulse at the text end. Opacity/transform
   only — compositor work, no layout thrash per token. */
.chat-bubble--streaming span::after {
  content: "";
  display: inline-block;
  width: 0.35em;
  height: 0.35em;
  margin-inline-start: 0.35em;
  margin-bottom: 0.06em;
  background: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 85%, transparent);
  border-radius: 50%;
  vertical-align: baseline;
  animation: listening-pulse 1.1s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .listening-placeholder-bubble span::after,
  .chat-bubble--streaming span::after {
    animation: none;
    opacity: 0.7;
  }
}

/* Ask-details list — the questions the reply just asked (F&B meta.order
   .askDetails: LLM-authored strings in the visitor's language). A scannable
   block after the latest assistant bubble so the visitor answers everything
   in one utterance — slightly larger than bubble type because it is the thing
   they answer FROM. Code contributes only the wordless dot marker (THE ONE
   LAW), drawn as a pseudo-element on the start edge (logical flow, so each
   item's dir="auto" flips it for RTL questions). */
.chat-asklist {
  list-style: none;
  margin: var(--space-1) 0 0;
  padding: 0 var(--space-2);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex-shrink: 0;
  animation: fade-in-up 0.25s ease;
}

.chat-asklist li {
  display: flex;
  align-items: flex-start;
  gap: 0.55em;
  font-size: clamp(1.125rem, 1.8vw, 1.375rem);
  line-height: 1.4;
  font-weight: 500;
  /* Full ink (round-6 brightness sweep — was a 95% mix). */
  color: var(--kuyil-text);
  word-wrap: break-word;
  overflow-wrap: break-word;
}

/* The bullet: an accent dot (the listening-dot glyph family), vertically
   centred on the first line of its question. */
.chat-asklist li::before {
  content: "";
  flex-shrink: 0;
  width: 0.42em;
  height: 0.42em;
  margin-top: 0.5em;
  border-radius: 50%;
  background: color-mix(in srgb, var(--kuyil-accent, #a0c0ff) 80%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .chat-asklist {
    animation: none;
  }
}

/* Active (speaking) indicator — tinted by the speaking state colour. */
.chat-line-active .chat-bubble {
  border-color: color-mix(in srgb, var(--state-speaking) 40%, transparent);
  box-shadow: 0 0 15px color-mix(in srgb, var(--state-speaking) 10%, transparent);
}

/* Chat placeholder styles */
.chat-placeholder {
  text-align: center;
  padding: var(--space-5);
  color: color-mix(in srgb, var(--kuyil-text) 40%, transparent);
  font-size: var(--text-base);
}

.chat-placeholder.hidden {
  display: none;
}

#chat-placeholder.hidden {
  display: none;
}

/* (Hover styling removed — the kiosk is a touch surface; a hover repaint on
   every stray touch added nothing but paint work.) */

/* =====================================================================
   Aura CAPTION mode — the kiosk default. The conversation renders as large
   fading captions under the orb (last exchange only, sliced in ChatPanel):
   no boxed panel, no bubbles, no blur. A soft bottom scrim + text shadow
   keep contrast against the aurora without a panel (handbook 24, A11Y-040).
   The 'hotel' layout variant keeps the full transcript panel above.
   ===================================================================== */
.chat-panel--captions {
  background: radial-gradient(
    60% 100% at 50% 100%,
    color-mix(in srgb, var(--kuyil-bg) 55%, transparent),
    transparent
  );
  border: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  width: min(880px, calc(100% - 9rem));
}

/* Captions never scroll — they bottom-anchor (justify-content: flex-end), so
   the NEWEST words are always fully visible and overflow leaves through the
   TOP. A pathologically long caption (a runaway model reply dumped hundreds
   of chars into one caption, 2026-07-17) used to hard-clip mid-glyph at the
   top edge; the mask below dissolves the oldest lines in a soft upward fade
   instead — the same fade geometry as the boxed panel's scroll mask above.
   padding-top matches the mask's fully-opaque point (the boxed-mode padding
   trick) so a caption that FITS never dips into the fade zone: normal-length
   captions keep full ink, only genuinely overflowing text fades. */
.chat-panel--captions #chat {
  padding: 1.75rem var(--space-3) var(--space-2);
  gap: var(--space-2);
  overflow: hidden;
  justify-content: flex-end;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    rgba(0, 0, 0, 0.4) 0.75rem,
    #000 1.75rem
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    rgba(0, 0, 0, 0.4) 0.75rem,
    #000 1.75rem
  );
}

.chat-panel--captions .chat-line {
  justify-content: center;
}

.chat-panel--captions .chat-bubble {
  flex: 0 1 auto;
  background: none;
  border: none !important;
  padding: 0;
  text-align: center;
  text-wrap: balance;
  /* Captions read at distance across the panel — release the bubble measure. */
  max-width: 100%;
}

/* Visitor line — quieter, above the assistant caption. */
.chat-panel--captions .chat-line.user .chat-bubble {
  font-size: var(--text-base);
  font-weight: 400;
  color: color-mix(in srgb, var(--kuyil-text) 62%, transparent);
}

/* Assistant caption — the primary reading surface. One token DOWN from the
   original 2xl (round-8 owner fix: 2xl captions dwarfed the orb and pushed
   the checklist off the band on real replies). */
.chat-panel--captions .chat-line.assistant .chat-bubble {
  font-size: var(--text-xl);
  font-weight: 500;
  line-height: 1.35;
  color: var(--kuyil-text);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.55);
  font-style: normal;
}

.chat-panel--captions .chat-placeholder {
  padding: var(--space-3);
}

/* Captions mode drops the streaming cursor dot (round-6 owner screenshot):
   the ask-list bullets are the SAME accent-dot glyph directly below the
   caption, so the cursor chasing the caption's last word read as a stray
   bullet floating at the caption's edge — and the realtime bridge keeps the
   reply bubble streaming through the WHOLE audio playout, so it sat there
   for the entire spoken reply. Liveness in captions mode is already carried
   by the growing text and the orb/seam state colour; the boxed panel mode
   keeps its cursor (inside bubble chrome it is unambiguous). */
.chat-panel--captions .chat-bubble--streaming span::after {
  content: none;
}

/* Captions mode: the ask list centres under the caption as a content-hugging
   block (items keep start-aligned text — a centred ragged list is unscannable)
   and picks up the caption's distance-reading treatment. */
.chat-panel--captions .chat-asklist {
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  padding: 0;
}

.chat-panel--captions .chat-asklist li {
  font-size: var(--text-lg);
  color: var(--kuyil-text);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.55);
}

/* =====================================================================
   Responsive .chat-panel rules (same canonical breakpoints — see the comment
   block at the top of core.css). HEIGHT is owned by the grid row caps in
   core.css; only width/padding/radius vary here.
   ===================================================================== */
@media (max-width: 900px) {
  .chat-panel {
    /* Gutter clears the fixed bottom-corner controls (logout / camera). */
    width: calc(100% - 9rem);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
  }
}

@media (max-height: 700px) {
  .chat-panel {
    border-radius: var(--radius-md);
  }
}

@media (max-width: 480px) {
  .chat-panel {
    width: calc(100% - 7rem);
    padding: var(--space-2);
    border-radius: 10px;
  }
}

/* Portrait kiosks / tablets: chat docks across the bottom as a full-width bar
   (small side gutter), above the corner controls reserved by the main-screen
   bottom padding (core.css portrait block). */
@media (orientation: portrait) {
  .chat-panel {
    width: calc(100% - 1.5rem);
    max-width: none;
  }
}
