/* Klui thinking bar + home greeting (Experimental) */

.thinking-status.klui-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 10px;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  transition: opacity 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.thinking-status.klui-bar::before {
  display: none;
}

/* Old shimmer targeted all descendant spans; klui-bar uses nested slot-text spans. */

.klui-bar .klui {
  position: relative;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  transform-origin: 50% 80%;
}

/* Tapping Klui hops (see playKluiReaction); paused mascots stay still. */
.klui {
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.klui[data-motion="paused"] {
  cursor: default;
}

.klui-svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  display: block;
  transform-origin: 50% 80%;
  filter: drop-shadow(0 4px 8px rgba(110, 155, 230, 0.22));
}

/* Gaze, expression, and blink each have their own transform layer. */
.klui-svg .face {
  transform-origin: 40px 38px;
  transform: none;
}

.klui-svg .eye-surface,
.klui-svg .eye,
.klui-svg .fx-stars path,
.klui-svg .fx-happy path {
  transform-box: fill-box;
  transform-origin: center;
}

.klui-bar .klui,
.empty-state .hero-line .klui {
  animation: klui-breathe 3.2s cubic-bezier(.45, 0, .55, 1) infinite;
}

@keyframes klui-breathe {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.018); }
}

.klui-bar .fx,
.hero-line .fx {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.klui-bar .fx.is-on,
.hero-line .fx.is-on {
  opacity: 1;
}

.klui-bar[data-state="thinking"] .fx-think { opacity: 1; }
.fx-think circle { opacity: 0; animation: klui-tdot 1.9s ease-in-out infinite; }
.fx-think circle:nth-child(2) { animation-delay: 0.28s; }
.fx-think circle:nth-child(3) { animation-delay: 0.56s; }
@keyframes klui-tdot {
  0%, 100% { opacity: 0; transform: translateY(3px); }
  35%, 70% { opacity: 1; transform: translateY(0); }
}

.klui-bar[data-state="searching"] .fx-search { opacity: 1; }

.klui-bar[data-state="writing"] .fx-tongue,
.klui-bar[data-state="writing"] .fx-pencil { opacity: 1; }
.klui-bar[data-state="writing"] .fx-pencil { animation: klui-pencil 0.32s linear infinite; transform-origin: 66px 52px; }
@keyframes klui-pencil {
  0%, 100% { rotate: -5deg; }
  50% { rotate: 5deg; }
}

.klui-bar[data-state="generating"] .eye { opacity: 0; }
.klui-bar[data-state="generating"] .fx-stars { opacity: 1; animation: klui-star 1.1s ease-in-out infinite; transform-origin: 40px 32px; }
@keyframes klui-star {
  0%, 100% { transform: scale(1) rotate(0); }
  50% { transform: scale(1.12) rotate(7deg); }
}
.klui-bar[data-state="generating"] .fx-sparkles { opacity: 1; }
.klui-bar[data-state="generating"] .fx-sheen { opacity: 1; animation: klui-sheen 1.8s linear infinite; }
@keyframes klui-sheen {
  from { transform: translateX(-28px); opacity: 0; }
  15% { opacity: 0.55; }
  50% { opacity: 0.35; }
  to { transform: translateX(52px); opacity: 0; }
}
.fx-sparkles path { fill: #ffd76a; opacity: 0; animation: klui-spark 1.5s ease-in-out infinite; }
.fx-sparkles path:nth-child(2) { animation-delay: 0.45s; }
.fx-sparkles path:nth-child(3) { animation-delay: 0.9s; }
@keyframes klui-spark {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  40%, 65% { opacity: 1; transform: scale(1); }
}

.klui-bar[data-state="reviewing"] .eye { opacity: 0; }
.klui-bar[data-state="reviewing"] .fx-happy,
.klui-bar[data-state="reviewing"] .fx-check { opacity: 1; }

.klui-copy {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.klui-state {
  font-weight: 700;
  font-size: 14px;
  line-height: 1.15;
  color: var(--text);
}

.klui-state.slot-text {
  color: var(--text);
  font-weight: 700;
  font-size: 14px;
}

.klui-state .char-face {
  font-weight: 700;
  font-size: 14px;
}

.klui-phrase {
  font-size: 12px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--text-tertiary);
  min-height: 1.3em;
}

.klui-phrase.slot-text {
  color: var(--text-tertiary);
  font-size: 12px;
  font-weight: 500;
}

.klui-phrase .char-face {
  font-size: 12px;
  font-weight: 500;
}

/* Home greeting */
.empty-state .hero-line {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: min(720px, 100%);
  min-height: 48px;
}

.empty-state .hero-line .klui {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  overflow: visible;
  transform-origin: 50% 80%;
}

.empty-state .hero-line .klui-svg {
  overflow: visible;
  display: block;
}

.empty-state .klui-fedora,
.empty-state .klui-shades {
  pointer-events: none;
}

.empty-state .type-line {
  display: flex;
  align-items: center;
  width: auto;
  min-width: 0;
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(18px, 2vw, 24px);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.25;
  text-align: left;
  color: var(--text);
}

.empty-state .type-text {
  white-space: nowrap;
  overflow: hidden;
}

.empty-state .caret {
  display: inline-block;
  width: 0.5em;
  height: 1.05em;
  margin-left: 3px;
  background: var(--text);
  border-radius: 1px;
  vertical-align: -0.12em;
  animation: klui-caret 1.05s steps(1) infinite;
  flex: 0 0 auto;
}

@keyframes klui-caret {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

.empty-state .caret.is-solid {
  animation: none;
  opacity: 1;
}

.empty-state .caret.is-hidden {
  display: none;
}

.hero-line .klui[data-mood="think"] .fx-think { opacity: 1; }

.hero-line .klui[data-mood="spark"] .eye { opacity: 0; }
.hero-line .klui[data-mood="spark"] .fx-stars { opacity: 1; animation: klui-star 1.1s ease-in-out infinite; transform-origin: 40px 32px; }
.hero-line .klui[data-mood="spark"] .fx-sparkles { opacity: 1; }
.hero-line .klui[data-mood="happy"] .eye { opacity: 0; }
.hero-line .klui[data-mood="happy"] .fx-happy { opacity: 1; }

/* Hidden, completed, and offscreen mascots hold their expression. */
.klui[data-motion="paused"],
.klui[data-motion="paused"] * {
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .klui, .klui *, .empty-state .caret {
    animation: none !important;
    transition: none !important;
  }
  .klui-svg .face { transform: none !important; }
}

/* ── Spectrum model picker (Experimental) ── */
@font-face {
  font-family: "Korataki";
  /* Only when installed on the device; the font files were never shipped, so Orbitron shows otherwise. */
  src: local("Korataki"), local("Korataki Regular");
  font-display: swap;
}

.composer-model-wrap {
  position: relative;
}

.composer-model-btn.heat-btn {
  width: auto;
  min-width: 96px;
  height: 32px;
  padding: 0;
  justify-content: center;
  background: transparent;
  border: 0;
  box-shadow: none;
  color: var(--text);
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.composer-model-btn.heat-btn:hover {
  background: transparent;
  border: 0;
}

@media (hover: hover) and (pointer: fine) {
  .composer-model-btn.heat-btn:active {
    transform: scale(0.97);
  }
}

.composer-model-btn.heat-btn[aria-expanded="true"] {
  border: 0;
  box-shadow: none;
}

.composer-model-btn.heat-btn.pro-active {
  background: transparent;
  border: 0;
  color: var(--text);
}

.heat-bar {
  position: relative;
  container-type: inline-size;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 8%, var(--bg));
  overflow: hidden;
  display: block;
  box-shadow: 0 0 0 1px var(--border-light);
}

.composer-model-btn.heat-btn[aria-expanded="true"] .heat-bar {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent, #3b82f6) 55%, var(--border-light)),
    0 0 0 3px color-mix(in srgb, var(--accent, #3b82f6) 16%, transparent);
}

.heat-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  border-radius: 999px;
  background: #83c98e;
  box-shadow: 0 0 12px color-mix(in srgb, #5ca66b 24%, transparent);
  transition:
    width 150ms cubic-bezier(0.23, 1, 0.32, 1),
    box-shadow 220ms cubic-bezier(0.23, 1, 0.32, 1);
  overflow: hidden;
  z-index: 1;
}

.composer-model-btn.heat-btn.think-active .heat-fill {
  background: linear-gradient(90deg, #93c5fd, #2563eb);
  box-shadow: 0 0 12px color-mix(in srgb, #3b82f6 28%, transparent);
}

.composer-model-btn.heat-btn.nitro-active .heat-fill .heat-name {
  color: #123c20;
}

/* Soft L4→L5 hue morph: purple layer fades in over blue (GPU opacity) */
.heat-fill::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, #e9d5ff, #c084fc, #9333ea, #6b21a8);
  opacity: 0;
  filter: blur(0);
  transition:
    opacity 220ms cubic-bezier(0.23, 1, 0.32, 1),
    filter 220ms cubic-bezier(0.23, 1, 0.32, 1);
  pointer-events: none;
  z-index: 0;
}

.composer-model-btn.heat-btn.pro-active .heat-fill {
  box-shadow: 0 0 12px color-mix(in srgb, #9333ea 28%, transparent);
}

.composer-model-btn.heat-btn.pro-active .heat-fill::after {
  opacity: 1;
}

.heat-name {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  font-family: "Korataki", "Orbitron", sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1;
  text-transform: uppercase;
  pointer-events: none;
  user-select: none;
  transition: opacity 160ms cubic-bezier(0.23, 1, 0.32, 1), filter 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.heat-bar > .heat-name {
  color: var(--text);
  opacity: 0.72;
  z-index: 0;
}

.heat-fill .heat-name {
  width: 100cqw;
  color: #fff;
  opacity: 1;
  z-index: 1;
}

.spectrum-pop {
  position: absolute;
  left: 0;
  bottom: calc(100% + 8px);
  width: 300px;
  max-width: min(300px, 80vw);
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px 16px 14px;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.04),
    0 18px 50px rgba(0, 0, 0, 0.35),
    0 4px 14px rgba(0, 0, 0, 0.12);
  opacity: 0;
  transform: translateY(6px) scale(0.98);
  transform-origin: 24px 100%;
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
  z-index: 60;
}

.spectrum-pop.open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.spectrum-head {
  font-size: 14px;
  font-weight: 650;
  color: var(--text-secondary);
  margin: 0 0 14px;
  letter-spacing: -0.01em;
}

.spectrum-track {
  position: relative;
  height: 18px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 12%, var(--bg));
  cursor: pointer;
  touch-action: none;
}

.spectrum-fill {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #4f8cff, #2563eb);
  transition: width 130ms ease-out;
}

.spectrum-steps {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  pointer-events: none;
}

.spectrum-steps i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--text) 28%, transparent);
}

.spectrum-steps i.lit {
  background: rgba(255, 255, 255, 0.92);
}

.spectrum-thumb {
  position: absolute;
  top: 50%;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.06),
    0 4px 12px rgba(0, 0, 0, 0.18),
    0 0 0 1px rgba(0, 0, 0, 0.06);
  transform: translate(-50%, -50%);
  transition: left 130ms ease-out;
  pointer-events: none;
}

.spectrum-ends {
  display: flex;
  justify-content: space-between;
  margin-top: 12px;
  font-size: 12px;
  font-weight: 650;
  color: var(--text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .spectrum-pop,
  .spectrum-fill,
  .spectrum-thumb,
  .heat-fill,
  .heat-fill::after,
  .heat-name,
  .composer-model-btn.heat-btn {
    transition: none;
  }

  .composer-model-btn.heat-btn:active {
    transform: none;
  }
}

/* The home art frames the workspace while keeping the composer area quiet. */
.app-shell {
  position: relative;
}

.home-wallpaper {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
  pointer-events: none;
  z-index: 0;
  user-select: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition:
    opacity 220ms ease-out,
    transform 220ms ease-out,
    visibility 0s linear 220ms;
}

body.chat-empty .home-wallpaper {
  opacity: 0.94;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

/* Once a chat starts, the home scene stays behind it as a faint monochrome print of the same art,
   aligned exactly with the home wallpaper so the switch reads as the colour draining out.
   It sits at full strength in the side gutters and eases off (but never vanishes) under the
   reading column, so the scene still reads edge to edge. */
.chat-wallpaper-outline {
  position: absolute;
  inset: 0;
  grid-column: 1 / -1;
  grid-row: 1;
  z-index: 0;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 520ms ease-out,
    visibility 0s linear 520ms;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 14%, rgb(0 0 0 / 0.5) 32%, rgb(0 0 0 / 0.38) 50%, rgb(0 0 0 / 0.5) 68%, #000 86%, #000 100%);
  mask-image: linear-gradient(90deg, #000 0%, #000 14%, rgb(0 0 0 / 0.5) 32%, rgb(0 0 0 / 0.38) 50%, rgb(0 0 0 / 0.5) 68%, #000 86%, #000 100%);
}

.chat-wallpaper-outline::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--text);
  -webkit-mask: var(--chat-outline-image, none) center bottom / cover no-repeat;
  mask: var(--chat-outline-image, none) center bottom / cover no-repeat;
}

body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]) .chat-wallpaper-outline {
  opacity: 0.2;
  visibility: visible;
  transition-delay: 0s;
}

body[data-mode="dark"]:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]) .chat-wallpaper-outline {
  opacity: 0.26;
}

body.study-open .chat-wallpaper-outline,
body.study-session-open .chat-wallpaper-outline {
  visibility: hidden !important;
}

/* Let the print run under the collapsed rail like the home wallpaper does. */
@media (min-width: 901px) {
  body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]):not(.study-open):not(.study-session-open):not(.sidebar-expanded):not(.guest-mode) .sidebar {
    background: transparent;
    border-right-color: color-mix(in srgb, var(--border-light) 40%, transparent);
    border-bottom-color: color-mix(in srgb, var(--border-light) 40%, transparent);
  }

  body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]):not(.study-open):not(.study-session-open):not(.sidebar-expanded):not(.guest-mode) .sidebar-top,
  body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]):not(.study-open):not(.study-session-open):not(.sidebar-expanded):not(.guest-mode) .sidebar-bottom {
    background: color-mix(in srgb, var(--bg) 72%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }

  body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]):not(.study-open):not(.study-session-open):not(.sidebar-expanded):not(.guest-mode) .sidebar-top {
    border-radius: inherit;
  }
}

@media (max-width: 860px) {
  body:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]) .chat-wallpaper-outline {
    opacity: 0.16;
    -webkit-mask-image: none;
    mask-image: none;
  }
  body[data-mode="dark"]:not(.chat-empty):not(.temporary-chat):not([data-wallpaper="none"]) .chat-wallpaper-outline {
    opacity: 0.2;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-wallpaper-outline {
    transition: none;
  }
}

/* Temporary chat is a blank sheet with one hand-drawn, erasable line. */
.temporary-chat-art {
  position: fixed;
  inset: 0;
  width: 100vw;
  min-width: 100vw;
  max-width: none;
  height: 100dvh;
  z-index: 0;
  color: #111;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  user-select: none;
  transition: opacity 420ms cubic-bezier(0.65, 0, 0.35, 1) 140ms;
}

body[data-mode="dark"] .temporary-chat-art {
  color: #f5f5f5;
  background: #050505;
}

.temporary-chat-line {
  fill: none;
  stroke: currentColor;
  stroke-width: 8;
  stroke-linecap: round;
  stroke-linejoin: round;
  shape-rendering: geometricPrecision;
  transition: stroke-dashoffset 520ms cubic-bezier(0.65, 0, 0.35, 1);
}

.temporary-chat-line-fragments {
  stroke-dasharray: 70 92;
  stroke-dashoffset: 1000;
}

.temporary-chat-line-connector {
  stroke-dasharray: 1000 1000;
  stroke-dashoffset: 1000;
}

body.chat-empty.temporary-chat .temporary-chat-art {
  opacity: 1;
  transition-duration: 460ms;
  transition-delay: 0ms;
}

body.chat-empty.temporary-chat .temporary-chat-line-fragments {
  stroke-dashoffset: 0;
  transition-duration: 1400ms;
  transition-delay: 100ms;
}

body.chat-empty.temporary-chat .temporary-chat-line-connector {
  stroke-dashoffset: 0;
  transition-duration: 900ms;
  transition-delay: 1150ms;
}

/* A sent temporary message replaces the home art; do not unwind it over chat. */
body.temporary-chat:not(.chat-empty) .temporary-chat-art,
body.temporary-chat:not(.chat-empty) .temporary-chat-line {
  transition: none;
}

body.chat-empty.temporary-chat .home-wallpaper {
  opacity: 0;
}

/* Keep the animated stroke out of the only transparent reading region. */
body.chat-empty.temporary-chat .empty-state .hero-line {
  position: relative;
  z-index: 1;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 0 0 18px #fff;
}

body[data-mode="dark"].chat-empty.temporary-chat .empty-state .hero-line {
  background: #050505;
  box-shadow: 0 0 0 18px #050505;
}

@media (max-width: 600px) {
  .temporary-chat-line {
    stroke-width: 5;
  }

  body.chat-empty.temporary-chat .empty-state .hero-line {
    box-shadow: 0 0 0 12px #fff;
  }

  body[data-mode="dark"].chat-empty.temporary-chat .empty-state .hero-line {
    box-shadow: 0 0 0 12px #050505;
  }
}

@media (prefers-reduced-motion: reduce) {
  .temporary-chat-art,
  .temporary-chat-line {
    transition: none;
  }
}

body[data-wallpaper="none"] .home-wallpaper {
  display: none;
}

body[data-mode="dark"][data-wallpaper="alpine"] .home-wallpaper,
body[data-mode="dark"][data-wallpaper="valley"] .home-wallpaper {
  background: url("/images/home-night-sky.webp?v=20260723-1") center / cover no-repeat;
}

@media (min-width: 901px) {
  body.chat-empty:not(.sidebar-expanded):not(.guest-mode) .sidebar {
    background: transparent;
    border-right-color: color-mix(in srgb, var(--border-light) 14%, transparent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  body.chat-empty:not(.sidebar-expanded):not(.guest-mode) .sidebar-top,
  body.chat-empty:not(.sidebar-expanded):not(.guest-mode) .sidebar-bottom {
    background: color-mix(in srgb, var(--bg) 28%, transparent);
    -webkit-backdrop-filter: blur(8px) saturate(0.92);
    backdrop-filter: blur(8px) saturate(0.92);
  }

  body.chat-empty:not(.sidebar-expanded):not(.guest-mode) .sidebar-top {
    border-radius: inherit;
  }

  body.chat-empty.sidebar-expanded .sidebar,
  body.chat-empty.guest-mode .sidebar {
    background: color-mix(in srgb, var(--bg) 66%, transparent);
    border-right-color: color-mix(in srgb, var(--border-light) 35%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(0.8);
    backdrop-filter: blur(16px) saturate(0.8);
  }
}

body.chat-empty .composer-area {
  z-index: 3;
}

@media (prefers-reduced-motion: reduce) {
  .home-wallpaper {
    transform: none;
    transition: none;
  }
}

/* ---------- Composer Klui (composerKlui.js) ----------
   A blocky Klui standing on the composer's top edge. The SVG's viewBox is 23 x 12 units, drawn
   at a whole 4px a unit so every edge stays crisp; its body is centered 8 units from the right edge. */
.composer-klui {
  --kp-unit: 4px;
  position: absolute;
  right: 83px;
  bottom: 100%;
  z-index: 3;
  width: calc(var(--kp-unit) * 23);
  height: calc(var(--kp-unit) * 12);
  margin-bottom: -1px;
  pointer-events: none;
}

.composer-klui[data-shown="false"] .kp-stage {
  visibility: hidden;
}

/* Something else is using the space above the composer. */
.composer-wrap:has(.followup-queue:not(.hidden), .clarification-card:not(.hidden), .attachment-model-notice[aria-hidden="false"]) .composer-klui {
  opacity: 0;
}

/* Only the bottom is clipped, so Klui sinks into (and rises out of) the composer's edge. */
.kp-stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  clip-path: inset(-60px -60px 0 -60px);
}

.kp-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Turning: a quick squash hides the swap between front and side views. */
.kp-turner {
  transform-origin: 8px 12px;
  transition: transform 70ms steps(2, end);
}

.composer-klui.is-turning .kp-turner {
  transform: scaleX(.3);
}

.composer-klui[data-facing="front"] :is(.kp-face-side, .kp-arm-side),
.composer-klui[data-facing="side"] :is(.kp-face-front, .kp-arms-front) {
  display: none;
}

.kp-eyes-shut,
.composer-klui[data-blink="true"] .kp-eyes-open {
  visibility: hidden;
}

.composer-klui[data-blink="true"] .kp-eyes-shut {
  visibility: visible;
}

/* Idle: a tiny double flap of the arms every few seconds. */
.composer-klui[data-shown="true"][data-facing="front"] .kp-arms-front {
  animation: kp-flap 3.4s steps(1, end) 1.2s infinite;
}

@keyframes kp-flap {
  0%, 84%, 90%, 100% { transform: none; }
  87%, 93% { transform: translateY(-1px); }
}

/* Laptop: pops up shut, opens, and later shuts and drops away. */
.kp-laptop {
  opacity: 0;
  transform: translateY(2px);
  transition: transform 120ms steps(2, end), opacity 120ms steps(2, end);
}

.composer-klui:is([data-laptop="shut"], [data-laptop="open"]) .kp-laptop {
  opacity: 1;
  transform: none;
}

.composer-klui:not([data-laptop="open"]) .kp-lid-open,
.composer-klui[data-laptop="open"] .kp-lid-shut,
.kp-keys rect {
  visibility: hidden;
}

/* Typing: the hand taps the keys, the screen flickers, and key taps float up. */
.composer-klui[data-typing="true"] .kp-arm-side { animation: kp-tap 240ms steps(1, end) infinite; }
.composer-klui[data-typing="true"] .kp-screen { animation: kp-flicker 700ms steps(1, end) infinite; }
.composer-klui[data-typing="true"] .kp-keys rect { visibility: visible; animation: kp-key 720ms steps(3, end) infinite; }
.composer-klui[data-typing="true"] .kp-keys rect:nth-child(2) { animation-delay: 360ms; }

@keyframes kp-tap {
  0% { transform: none; }
  50% { transform: translateY(1px); }
}

@keyframes kp-flicker {
  0%, 100% { opacity: 1; }
  40% { opacity: .65; }
  70% { opacity: .85; }
}

@keyframes kp-key {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-3px); }
}

/* Portals: flat glowing rings that snap open and shut. The composer's has a back half behind
   Klui and a front lip over it, so Klui sinks into the hole. */
.kp-portal {
  --kp-portal-w: 52px;
  position: absolute;
  width: var(--kp-portal-w);
  height: calc(var(--kp-portal-w) * .24);
  border-radius: 50%;
  background: radial-gradient(closest-side, #1b1446 0 45%, #5b6cff 64%, #a9d6ff 82%, transparent 100%);
  box-shadow: 0 0 10px 1px rgba(120, 150, 255, 0.55);
  translate: -50% -50%;
  transform: scale(0, .3);
  opacity: 0;
  pointer-events: none;
  transition: transform 90ms cubic-bezier(.3, 1.5, .6, 1), opacity 60ms linear;
}

.composer-klui .kp-portal {
  left: calc(100% - var(--kp-unit) * 8);
  top: 100%;
}

.composer-klui .kp-portal.is-front {
  z-index: 2;
  clip-path: inset(50% -20px -20px -20px);
}

.composer-klui[data-portal="open"] .kp-portal,
.kp-portal.is-drop[data-open="true"] {
  transform: none;
  opacity: 1;
}

.kp-portal.is-drop {
  position: fixed;
  z-index: 60;
}

/* Tapping Klui: only its body takes taps, and only while it is standing there. */
.kp-hit {
  position: absolute;
  left: calc(var(--kp-unit) * 8);
  top: calc(var(--kp-unit) * 2);
  width: calc(var(--kp-unit) * 14);
  height: calc(var(--kp-unit) * 10);
  pointer-events: none;
  -webkit-tap-highlight-color: transparent;
}

.composer-klui[data-shown="true"] .kp-hit {
  pointer-events: auto;
  cursor: pointer;
}

.kp-svg {
  transform-origin: 65% 100%;
}

/* Running off: the legs take turns and the body bobs. */
.composer-klui.is-running .kp-hit {
  pointer-events: none;
}

.composer-klui.is-running .kp-legs rect:first-child { animation: kp-stride 160ms steps(1, end) infinite; }
.composer-klui.is-running .kp-legs rect:last-child { animation: kp-stride 160ms steps(1, end) 80ms infinite; }
.composer-klui.is-running .kp-stage { animation: kp-bob 160ms steps(1, end) infinite; }

@keyframes kp-stride {
  50% { transform: translateY(-1px); }
}

@keyframes kp-bob {
  50% { transform: translateY(-2px); }
}

/* The gate Klui runs into: a portal standing on the composer's far edge. */
.composer > .kp-portal.is-gate {
  position: absolute;
  bottom: calc(100% - 3px);
  z-index: 4;
  width: 12px;
  height: 50px;
  translate: -50% 0;
  transform: scale(.2, 0);
  transform-origin: 50% 100%;
  background: radial-gradient(closest-side, #1b1446 0 40%, #5b6cff 62%, #a9d6ff 82%, transparent 100%);
  transition: transform 140ms cubic-bezier(.3, 1.5, .6, 1), opacity 90ms linear;
}

.composer > .kp-portal.is-gate[data-open="true"] {
  transform: none;
  opacity: 1;
}

/* The thinking bar's mascot waits out of sight until it drops out of its portal. */
body.klui-portal-pending .klui-bar.is-active .klui {
  visibility: hidden;
}

@media (max-width: 768px) {
  .composer-klui {
    right: 60px;
  }
}

/* Ambient motion stops; running off after being tapped still strides, since the user asked for it. */
@media (prefers-reduced-motion: reduce) {
  .composer-klui:not(.is-running),
  .composer-klui:not(.is-running) * {
    animation: none !important;
    transition: none !important;
  }
}
