/* kiosk-base.css — surface-level rules shared by all three apps.
 *
 * Scope discipline: this file only holds rules that are about the *surface*
 * (device box, native avatar, touch, scroll). Each app keeps its own portrait
 * reflow inline, next to the selectors it owns.
 *
 * Load order: kiosk-boot.js → this file → the app's own <style>.
 */

/* ── The station box ───────────────────────────────────────────────────────
 * FLUID, not a fixed 1080×1920 pixel box. The device is nominally 1080×1920,
 * but the host is WebView2 — desktop Chromium, which IGNORES <meta viewport>.
 * So a hard `width:1080px` does not scale down when the actual view is narrower
 * (emulator, windowed host, any other panel); it simply overflows and crops.
 * Fill whatever we're given and let the orientation queries do the reflow.
 *
 * No page-level scroll or rubber-banding: panels scroll internally instead. A
 * kiosk page that scrolls as a whole strands the guest where the avatar can't
 * see them.
 */
:root[data-surface="station"],
:root[data-surface="station"] body {
  width: 100%;
  max-width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
}

:root[data-surface="station"] {
  /* Reserved band at the bottom of the screen. The reference Tailwater kiosk
   * reserves nothing, so this starts at 0 — but the native avatar is composited
   * by the host and the protocol docs never state where it sits. If it turns out
   * to occlude the lower screen on-device, this is the single number to change:
   * every app's portrait layout pads against it. */
  --station-safe-bottom: 0px;

  /* ONE DESIGN UNIT — the basis for every station size.
   *
   * = 1% of the 1080-wide design, but capped by what the height can afford
   *   (the design is 1080×1920, so one design-width percent equals 0.5625vh).
   *
   * Scaling by the LIMITING dimension is the whole point. Sizing off vw alone
   * looks right at the nominal 9:16 but overflows vertically on any view that is
   * shorter relative to its width — and with the page clipped to the viewport
   * that silently eats the top and bottom of the layout rather than scrolling.
   * With --u, a shorter view shrinks proportionally and stays whole.
   *
   * At 1080×1920 → 10.8px. At 900×1400 → 7.88px (height-limited).
   */
  --u: min(1vw, 0.5625vh);
}

/* Touch, not pointer. Kills the 300ms tap delay and stops long-press selection
 * turning into a text-selection mess on a public screen. */
:root[data-surface="station"] * {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

:root[data-surface="station"] :where(button, .btn, a, label, summary) {
  -webkit-user-select: none;
  user-select: none;
}

/* Text the guest may genuinely want to select/edit stays selectable. */
:root[data-surface="station"] :where(input, textarea) {
  -webkit-user-select: text;
  user-select: text;
}

/* ── The avatar ────────────────────────────────────────────────────────────
 * On station the avatar is rendered and voiced NATIVELY by the host, outside the
 * page — so the in-page Companion panel must not render. On web it must, which
 * is why this is scoped rather than unconditional.
 */
:root[data-surface="station"] #avatar-container {
  display: none !important;
}

/* ── Touch targets ─────────────────────────────────────────────────────────
 * 44px floor per the SDK hardening checklist. Applied only on station so the web
 * build keeps its denser desktop proportions.
 */
:root[data-surface="station"] :where(button, .btn, input, select, textarea, [role="button"]) {
  min-height: 44px;
}

:root[data-surface="station"] :where(button, .btn, [role="button"]) {
  min-width: 44px;
}

/* ── Hover is a lie on a touchscreen ───────────────────────────────────────
 * A tap leaves :hover stuck on the last-touched element until something else is
 * touched, so hover-driven movement reads as a stuck, broken UI. Neutralise the
 * motion; leave colour changes, which are harmless as a pressed state.
 *
 * SCOPED TO INTERACTIVE ELEMENTS ON PURPOSE. This was once `*:hover`, which is a
 * trap: :hover applies to every ancestor of the pointer, so hovering anywhere at
 * all matched layout containers too and `!important`-killed their transforms —
 * including the scale-and-centre transform on #kiosk-fit, which made the whole
 * kiosk board snap to unscaled 1080x1920 anchored at the viewport centre and
 * spill off screen. Never blanket-reset transform.
 */
:root[data-surface="station"] :where(a, button, .btn, [role="button"], summary, label):hover {
  transform: none !important;
}

/* Give back a real pressed state, since hover no longer signals anything. */
:root[data-surface="station"] :where(button, .btn, [role="button"]):active {
  filter: brightness(0.92);
}

/* Nothing on a kiosk should show a text cursor or a resize handle. */
:root[data-surface="station"] :where(button, .btn, [role="button"]) {
  cursor: default;
}

:root[data-surface="station"] textarea {
  resize: none;
}

/* ── Touch feedback ────────────────────────────────────────────────────────
 * A finger covers whatever it presses, so a guest gets no confirmation that the
 * screen registered the touch — on a kiosk that reads as an unresponsive panel
 * and provokes repeated jabbing. A soft bloom expanding from the contact point
 * acknowledges every touch, including ones that land on nothing.
 *
 * Injected into <body> by station-kiosk.js in viewport coordinates, so it is
 * unaffected by the scaled kiosk board.
 */
.kiosk-ripple {
  position: fixed;
  z-index: 2147483000;
  pointer-events: none;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 161, 243, 0.55) 0%,
    rgba(221, 82, 203, 0.32) 45%,
    transparent 70%);
  filter: blur(6px);
  animation: kioskRipple 620ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes kioskRipple {
  from { transform: scale(1);  opacity: 0.95; }
  to   { transform: scale(20); opacity: 0; }
}

/* Guests who need reduced motion still get the acknowledgement, just static. */
@media (prefers-reduced-motion: reduce) {
  .kiosk-ripple { animation-duration: 260ms; }
  @keyframes kioskRipple {
    from { transform: scale(6); opacity: 0.6; }
    to   { transform: scale(6); opacity: 0; }
  }
}

/* ── Escape hatches ────────────────────────────────────────────────────────
 * A guest who leaves the page bricks the kiosk until staff intervene. Downloads
 * and new windows are unreachable on the device anyway, so hide the affordance
 * rather than leaving a dead control on screen.
 */
:root[data-surface="station"] :where(a[download], a[target="_blank"]) {
  display: none !important;
}

/* ── Scrollbars ────────────────────────────────────────────────────────────
 * There is no mouse, so a scrollbar is decoration. Keep panels scrollable by
 * touch but drop the gutter.
 */
:root[data-surface="station"] ::-webkit-scrollbar {
  width: 0;
  height: 0;
}

:root[data-surface="station"] {
  scrollbar-width: none;
}

/* ── Return handoff overlay ────────────────────────────────────────────────
 * Kai renders a two-orb handoff screen before sending the device to a
 * specialist, because he is still the page on screen at that moment. Coming
 * BACK, the page that has to render it is the specialist — and Maple, Northwind
 * and Beacon are three separate apps with their own design systems and no such
 * screen, so the return was a hard cut while the outbound was choreographed.
 *
 * This is that screen, written once here (every channel already loads this
 * file) and self-contained: literal colours rather than Kai's tokens, because
 * the specialists do not define them. Mirrors his duo — same orb treatment,
 * same link, same packet — but reversed, so context reads as flowing home.
 *
 * Station only. On web the specialist is an iframe inside Kai's shell and the
 * shell owns the transition; showing this there would double it up.
 */
.kiosk-handoff {
  position: fixed; inset: 0; z-index: 2147483000;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0; padding: 6vw;
  background: radial-gradient(70% 50% at 50% 38%, #1a0a24 0%, #08050e 62%, #050308 100%);
  opacity: 0; transition: opacity 420ms ease;
  /* The guest must not be able to poke the demo underneath mid-transition. */
  pointer-events: all; -webkit-user-select: none; user-select: none;
}
.kiosk-handoff.on { opacity: 1; }

.kiosk-handoff .kh-eyebrow {
  font-size: clamp(10px, 1.1vw, 13px); font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 161, 243, 0.75); margin-bottom: 1.4vh;
}
.kiosk-handoff .kh-title {
  margin: 0 0 4.5vh; text-align: center;
  font-size: clamp(22px, 3.4vw, 46px); font-weight: 700; line-height: 1.2;
  color: #f7f3ff;
}
.kiosk-handoff .kh-title b {
  font-weight: 700;
  background: linear-gradient(92deg, #FFA1F3, #EA2DD2 46%, #8A63FF);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.kiosk-handoff .kh-duo {
  position: relative; display: flex; align-items: center; justify-content: center;
}
.kiosk-handoff .kh-tag {
  position: absolute; left: 50%; bottom: calc(100% + 14px); transform: translateX(-50%);
  white-space: nowrap; font-size: clamp(9px, 1vw, 12px); font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; color: rgba(247, 243, 255, 0.5);
}

.kiosk-handoff .kh-orb { position: relative; --orb: min(190px, 26vw, 20vh); width: var(--orb); height: var(--orb); flex: 0 0 auto; }
.kiosk-handoff .kh-halo {
  position: absolute; inset: -22px; border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%, rgba(221,82,203,0.45), rgba(255,16,232,0.12) 50%, transparent 72%);
  filter: blur(8px); animation: khBreathe 3.4s ease-in-out infinite;
}
.kiosk-handoff .kh-orb.to .kh-halo {
  background: radial-gradient(50% 50% at 50% 50%, rgba(138,99,255,0.45), rgba(221,82,203,0.12) 50%, transparent 72%);
}
.kiosk-handoff .kh-ring {
  position: absolute; inset: 0; border-radius: 50%; padding: 2px;
  background: conic-gradient(from 200deg, #FFA1F3, #DD52CB, #BE369D, #370971, #FFA1F3);
  box-shadow: 0 0 36px rgba(255, 16, 232, 0.32);
  isolation: isolate; z-index: 1;
}
.kiosk-handoff .kh-orb.to .kh-ring {
  background: conic-gradient(from 200deg, #370971, #EA2DD2, #FFA1F3, #370971);
  box-shadow: 0 0 36px rgba(138, 99, 255, 0.32);
}
.kiosk-handoff .kh-ring img {
  width: 100%; height: 100%; display: block; border-radius: 50%; object-fit: cover;
  background: radial-gradient(65% 60% at 50% 38%, #320f2b, #0a0410 78%);
  clip-path: circle(50% at 50% 50%);
}
.kiosk-handoff .kh-badge {
  position: absolute; bottom: 6px; left: 50%; transform: translateX(-50%) translateY(50%);
  background: #0b0b0d; border: 1px solid rgba(255, 161, 243, 0.4); border-radius: 999px;
  padding: 4px 11px; font-size: clamp(9px, 0.95vw, 11px); font-weight: 600; white-space: nowrap;
  display: flex; align-items: center; gap: 6px; z-index: 10; color: #f7f3ff;
}
.kiosk-handoff .kh-orb.to .kh-badge { border-color: rgba(186, 150, 255, 0.5); }
.kiosk-handoff .kh-badge .r { color: rgba(247, 243, 255, 0.55); }

.kiosk-handoff .kh-link {
  position: relative; width: clamp(60px, 14vw, 180px); height: 2px; margin: 0 4px; z-index: 3;
  /* Flows left-to-right, TOWARD the `.to` orb — which on this screen is Kai,
     because the return swaps who stands where: specialist left, Kai right.
     Direction is carried by the orbs, not by the animation. Reversing the
     packet on top of the swap pointed the context back at the specialist and
     read as an outbound handoff. Colours track the halos: pink `from`,
     purple `to`. */
  background: linear-gradient(90deg, rgba(255,161,243,0.15), rgba(255,161,243,0.7), rgba(186,150,255,0.7), rgba(186,150,255,0.15));
}
.kiosk-handoff .kh-pkt {
  position: absolute; top: 50%; left: 10%; transform: translateY(-50%);
  width: 9px; height: 9px; border-radius: 50%; background: #fff;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
  animation: khTravel 2.4s cubic-bezier(.5, 0, .5, 1) infinite;
}

@keyframes khBreathe { 0%,100% { opacity: 0.7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.05); } }
@keyframes khTravel  { 0% { left: 10%; opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { left: 90%; opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .kiosk-handoff, .kiosk-handoff .kh-halo, .kiosk-handoff .kh-pkt { animation: none; transition: none; }
}
