*,
*::before,
*::after {
  box-sizing: border-box;
}

:root {
  --cell: 24px; /* grid cell size, kept in sync by pixel-screen.js */
  /* Typing mode, written by typing-mode.js */
  --card-sx: 1;
  --card-sy: 1;
  --card-offset: 0px;
  --bar-lift: 0px;
  --vv-offset: 0px; /* how far the browser has panned the page for the keyboard */
  /* One duration and one curve for the card, its corners and the bar's lift,
     in both directions. */
  --card-time: 550ms;
  --card-ease: cubic-bezier(0.25, 0.1, 0.25, 1);
  --bar: 48px; /* height of the ask bar */
  --fg: #16181d;
  --muted: rgba(22, 24, 29, 0.6);
  --faint: rgba(22, 24, 29, 0.42);
  --focus: #2563eb;
  /* The one floating material, shared with the info card. */
  --glass: rgba(255, 255, 255, 0.88);
  --glass-solid: #fff;
  --glass-border: rgba(0, 0, 0, 0.1);
}

/* A critically damped spring, sampled: it settles with no overshoot. */
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    --card-ease: linear(
      0, 0.0661, 0.2032, 0.3554, 0.4963, 0.6161, 0.7127, 0.7881, 0.8454, 0.8883, 0.9199, 0.9429, 0.9596,
      0.9715, 0.98, 0.986, 0.9902, 0.9932, 0.9953, 0.9967, 0.9978, 0.9985, 0.9989, 0.9993, 1
    );
  }
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  overflow: hidden;
  overscroll-behavior: none;
  background: #fff; /* the backdrop behind the card */
  color: var(--muted);
  /* Leaving typing mode, the backdrop stays black until the card has grown
     back, then switches; faded sooner, the border would seem to vanish. */
  transition: background-color 0s var(--card-time);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-optical-sizing: auto;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

[hidden] {
  display: none !important;
}

/* Selected text is black, not the browser's blue. */
::selection {
  background: var(--fg);
  color: #fff;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- typing mode ------------------------------------------------------------- */

/* The content layer. While the input has focus it shrinks into a rounded
   card on a black backdrop; only transform and border-radius move. */
.card {
  position: fixed;
  inset: 0;
  overflow: hidden;
  overflow: clip;
  background: #fff;
  transform-origin: 50% 0;
  transform: translateY(calc(var(--vv-offset) + var(--card-offset))) scale(var(--card-sx), var(--card-sy));
  transition: transform var(--card-time) var(--card-ease), border-radius var(--card-time) var(--card-ease);
}

/* Entering, the backdrop is black from the first frame. */
.typing body {
  background: #000;
  transition: none;
}

/* Divided by the scale so the corners come out round at 36px on screen. */
.typing .card {
  border-radius: calc(36px / var(--card-sx)) / calc(36px / var(--card-sy));
}

/* The top-corner button steps aside while typing. */
body > .ic {
  translate: 0 var(--vv-offset);
  transition: transform 100ms ease-out, opacity 200ms ease;
}

.typing body > .ic {
  opacity: 0;
  pointer-events: none;
}

/* --- WebGL screen ----------------------------------------------------------- */

#screen {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  image-rendering: pixelated;
}

#app {
  position: relative;
  z-index: 1;
}

/* --- stage ------------------------------------------------------------------- */

.stage {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
  touch-action: manipulation;
}

/* A 9x10 cell slot; the shader draws the robot into it. */
.robot {
  flex: none;
  width: calc(9 * var(--cell));
  height: calc(10 * var(--cell));
  margin: 0 0 2rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.robot[aria-disabled='true'] {
  cursor: default;
}

.robot:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
}

[data-view='chat'] .robot {
  margin-bottom: 0;
}

/* Aman's portrait is 32x38 cells, plus a row for the bob. */
.robot.is-face {
  width: calc(32 * var(--cell));
  height: calc(39 * var(--cell));
}

/* Top-right corner: swaps the robot for the portrait, and back. */
.face-toggle {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 50%;
  color: var(--fg);
  cursor: pointer;
  translate: 0 var(--vv-offset);
  transition: transform 100ms ease-out, opacity 200ms ease, background-color 150ms ease, color 150ms ease;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.face-toggle:active {
  transform: scale(0.94);
}

.face-toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.face-toggle svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* On a phone the open info card spans the screen and would cover the switch,
   so the switch moves down to sit 8px under it. It rides the card's own
   spring (--ic-p, published by info-card.js), overshoot and all. 458px is the
   widest screen on which the open card (380px at most) reaches the switch. */
@media (max-width: 458px) {
  .face-toggle {
    translate: 0 calc(var(--vv-offset) + var(--ic-p, 0) * (var(--ic-open-h, 0px) + 8px));
  }
}

/* Like the info card, it steps aside while typing. */
.typing .face-toggle {
  opacity: 0;
  pointer-events: none;
}

/* Without WebGL there is nothing to swap. */
.no-webgl .face-toggle {
  display: none;
}

.hint,
.disclaimer {
  margin: 0;
  font-weight: 500;
  text-align: center;
}

/* Larger text is tracked tighter, small text slightly looser. */
.hint {
  color: var(--fg);
  font-size: 1.125rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.disclaimer {
  position: fixed;
  right: 0;
  bottom: 32px;
  left: 0;
  padding: 0 16px;
  color: var(--faint);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.01em;
}

/* Under the portrait both lines sit on its shirt. */
.card:has(.robot.is-face) .hint {
  color: #fff;
}

.card:has(.robot.is-face) .disclaimer {
  color: rgba(255, 255, 255, 0.6);
}

/* Under the robot it sits a little lower, clear of the bobbing feet. */
.robot:not(.is-face) + .hint {
  margin-top: 3rem;
}

/* Both step out while the robot and the portrait swap. */
.hint,
.disclaimer {
  transition: opacity 200ms ease;
}

.is-swapping .hint,
.is-swapping .disclaimer {
  opacity: 0;
}

.fade-in {
  animation: fade-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) var(--delay, 0s) both;
}

@keyframes fade-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

/* --- loader ------------------------------------------------------------------ */

/* A 5x1 cell slot; the shader draws the loading boxes into it. */
.loader {
  flex: none;
  width: calc(5 * var(--cell));
  height: var(--cell);
}

/* While thinking it sits where the ask bar was. */
[data-view='chat'] .loader {
  position: fixed;
  right: 0;
  bottom: calc(32px + (var(--bar) - var(--cell)) / 2);
  left: 0;
  margin: 0 auto;
}

/* --- glass ------------------------------------------------------------------- */

/* Translucent floating layer: blurred backdrop, hairline edge, soft shadow. */
.glass {
  border: 1px solid var(--glass-border);
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  backdrop-filter: blur(18px) saturate(1.5);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.08);
  color: var(--fg);
}

/* --- surfaces ---------------------------------------------------------------- */

/* The ask bar and the subtitles share one spot above the bottom edge. Their
   opacity, transform and blur are written by app.js from a spring. */
.ask,
.subtitles {
  position: fixed;
  right: 0;
  bottom: 32px;
  left: 0;
  width: fit-content;
  max-width: calc(100% - 32px);
  margin: 0 auto;
  transform-origin: 50% 100%;
  will-change: transform, opacity;
}

.ask.is-gone,
.subtitles.is-gone {
  visibility: hidden;
}

/* --- subtitles --------------------------------------------------------------- */

.subtitles {
  max-width: min(640px, 100% - 32px);
  min-height: var(--bar);
  padding: 12px 20px;
  border-radius: 24px;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.45;
  text-align: center;
  text-wrap: pretty;
}

.caret {
  margin-left: 2px;
  color: var(--muted);
  animation: blink 1s steps(1) infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

/* --- ask bar ----------------------------------------------------------------- */

/* Lifted to sit above the keyboard, or inside the card on desktop. Uses
   `translate` so it composes with the spring's transform. */
.ask {
  display: flex;
  align-items: center;
  gap: 8px;
  translate: 0 calc(-1 * var(--bar-lift));
  transition: translate var(--card-time) var(--card-ease);
}

/* The field and its send button live in one capsule. */
.ask-capsule {
  display: flex;
  flex: 0 1 340px;
  align-items: center;
  width: 340px;
  min-width: 0;
  height: var(--bar);
  padding: 0 5px 0 0;
  border-radius: calc(var(--bar) / 2);
}

/* Snapped to the pixel grid, which counts its cells from the top-left corner:
   the bottom edge of both sits on a grid line, and the ask bar is a whole
   number of cells wide and tall, starting on a grid line. */
@supports (width: round(nearest, 1px, 1px)) {
  .ask,
  .subtitles {
    bottom: calc(100% - round(nearest, 100% - 32px, var(--cell)));
  }

  .ask {
    --ask-width: round(down, min(340px, 100vw - 32px), var(--cell));
    right: auto;
    left: round(nearest, (100% - var(--ask-width)) / 2, var(--cell));
    margin: 0;
  }

  .ask-capsule {
    flex-basis: var(--ask-width);
    width: var(--ask-width);
    height: round(nearest, var(--bar), var(--cell));
  }
}

.ask-field {
  flex: 1;
  min-width: 0;
  height: 100%;
  padding: 0 8px 0 18px;
  border: 0;
  outline: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.9375rem;
}

.ask-field::placeholder {
  color: var(--muted);
  opacity: 1;
}

.ask-btn {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Slow to let go, so a quick tap still reads. */
  transition: transform 220ms ease-out, opacity 200ms ease-out, background-color 150ms ease-out;
}

/* Feedback lands on the press itself, immediately. */
.ask-btn:active {
  transform: scale(0.92);
  transition-duration: 80ms;
}

.ask-btn:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.ask-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The one solid, high-contrast control: the primary action. */
.ask-send {
  width: 38px;
  height: 38px;
  border: 0;
  background: var(--fg);
  color: #fff;
}

.ask-send[aria-disabled='true'] {
  opacity: 0.28;
  transform: scale(0.9);
}

@media (hover: hover) {
  .ask-send:not([aria-disabled='true']):hover {
    background: #34373e;
  }
}

/* Below 16px, iOS zooms the page when the field is focused. */
@media (pointer: coarse) {
  .ask-field {
    font-size: 1rem;
  }
}

/* --- accessibility ----------------------------------------------------------- */

/* Reduced motion: nothing travels; surfaces cross-fade in place. */
@media (prefers-reduced-motion: reduce) {
  .fade-in,
  .caret {
    animation: none;
  }

  /* Typing mode switches instantly. */
  body,
  .card,
  body > .ic,
  .face-toggle {
    transition: none;
  }

  .ask,
  .subtitles {
    transition: opacity 200ms ease, visibility 0s;
  }

  .ask.is-gone,
  .subtitles.is-gone {
    transition: opacity 200ms ease, visibility 0s 200ms;
  }

  .ask-btn,
  .ask-btn:active,
  .ask-send[aria-disabled='true'] {
    transform: none;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .glass {
    background: var(--glass-solid);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

@media (prefers-contrast: more) {
  :root {
    --muted: rgba(22, 24, 29, 0.85);
    --faint: rgba(22, 24, 29, 0.75);
    --glass-border: rgba(0, 0, 0, 0.6);
  }

  .glass {
    background: var(--glass-solid);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
