/*
 * MoqiKey's keyboard on the site (keyboard.js). Ported from the app's light keyboard:
 * ime/ui/KeysUi.kt, KeyboardUi.kt, KbMetrics.kt, Palette.kt, AiPanel.kt, Working.kt, VoiceUi.kt, MoqiButton.kt.
 *
 * Sizes follow the app's dp on a keyboard 400 units wide (--u = one dp at this width), so it keeps the
 * app's proportions from 300px to 420px; rows never go under 44px, so keys stay tappable on a phone.
 * Colours come from tokens.css; the board and MOQI's panel are glass.css material (tinted with
 * --glass-tint, never `background`). Motion: transform and opacity only.
 */

.mk {
  position: relative;
  display: block;
  inline-size: 100%;
  max-inline-size: 420px;
  margin-inline: auto;
  container-type: inline-size;
  text-align: start;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

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

.mk:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 6px;
  border-radius: var(--radius-card);
}

/* Buttons in the interactive keyboard look like the demo's spans. */
:where(.mk) :where(button) {
  appearance: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
}

.mk-in {
  --u: calc(100cqi / 400);
  --mk-band: max(38px, calc(44 * var(--u)));
  --mk-bar: max(44px, calc(50 * var(--u)));
  --mk-pad: calc(3 * var(--u));
  /* Every layout gets the same height (KbMetrics: 260 dp of keys), Zhuyin in five rows, English in four. */
  --mk-keys: max(calc(5 * 44px + 2 * var(--mk-pad)), calc(260 * var(--u)));
  --mk-rows: 5;
  --mk-row: calc((var(--mk-keys) - 2 * var(--mk-pad)) / var(--mk-rows));
  --mk-foot: calc(7 * var(--u));
  /* MOQI's panel makes the keyboard this much taller, as a tool does in the app. */
  --mk-grow: calc(var(--mk-keys) * .34);
  --mk-r: max(20px, calc(26 * var(--u)));
  --mk-key-r: calc(var(--radius-key) * .8);

  /* Palette.kt light, on the site's tokens */
  --mk-key: var(--color-paper);
  --mk-key-fn: color-mix(in oklch, var(--color-rule) 90%, var(--color-ink));
  --mk-key-shadow: color-mix(in oklch, var(--color-ink) 18%, transparent);
  --mk-press: color-mix(in oklch, var(--color-ink) 10%, transparent);
  --mk-tool: color-mix(in oklch, var(--color-paper) 95%, transparent);
  --mk-line: color-mix(in oklch, var(--color-ink) 7%, transparent);
  /* Theme colours (ime/ui/Themes.kt). MoqiKeyboard theme(id) sets these and the four above on the element;
     the defaults are MOQI 原色 on the site's tokens. MOQI's own parts (its key, panel, voice) never read them. */
  --mk-bg: color-mix(in oklch, var(--color-rule) 80%, transparent);
  --mk-ink: var(--color-ink);
  --mk-ink-2: var(--color-ink-2);
  --mk-hint: var(--color-muted);
  --mk-accent: var(--color-cyan);
  --mk-on-accent: var(--color-on-brand);
  --mk-accent-soft: var(--color-cyan-soft);

  position: relative;
  padding-block-start: var(--mk-band);
  color: var(--mk-ink);
  font-family: var(--font-body);
  line-height: 1.3;
}

.mk-in[data-layout="qwerty"] { --mk-rows: 4; }

/* The other languages' keyboards (ime-*.js): 速成, 두벌식, Telex and the 12-key kana in four rows, Thai in five. */
.mk-in[data-layout="quick"],
.mk-in[data-layout="dubeol"],
.mk-in[data-layout="telex"],
.mk-in[data-layout="flick"] { --mk-rows: 4; }
.mk-in[data-layout="kedmanee"] { --mk-rows: 5; }

/* A flick goes any way, so the 12-key grid keeps the finger (no scrolling from it). */
.mk--interactive .mk-in[data-layout="flick"] .mk-grids { touch-action: none; }

.mk-in.is-dark {
  --mk-line: rgb(255 255 255 / .09);
  --mk-key-shadow: rgb(0 0 0 / .45);
}

/* Room above for MOQI's panel, when the page asks for it (otherwise the panel rises over what is above). */
.mk--reserve .mk-in { padding-block-start: max(var(--mk-band), var(--mk-grow)); }

.mk-in.is-paused,
.mk-in.is-paused *,
.mk-in.is-paused *::before,
.mk-in.is-paused *::after { animation-play-state: paused !important; }

.mk-ico {
  display: block;
  inline-size: 1em;
  block-size: 1em;
  flex: none;
  fill: currentColor;
  overflow: visible;
}

.mk-ico .fa-secondary { opacity: .28; }

/* ---------------------------------------------------------------- the board */

.mk-board {
  position: relative;
  block-size: calc(var(--mk-bar) + var(--mk-keys) + var(--mk-foot));
}

/* The keyboard's frosted panel; the app's grey keyboard colour comes through as the tint. */
.mk-surface {
  --glass-tint: var(--mk-bg);
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: var(--mk-r);
}

.mk-body {
  position: absolute;
  inset-inline: 0;
  inset-block-start: var(--mk-bar);
  block-size: var(--mk-keys);
  z-index: 1;
  transition: opacity 240ms var(--ease-out), scale 320ms var(--ease-out);
}

.mk-top {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: var(--mk-bar);
  z-index: 3;
  transition: translate 480ms var(--ease-out);
}

/* MOQI's panel is open: the keys give way, the bar rises with the taller keyboard (just behind the
   droplet, so it always has glass under it). */
.mk-in.is-panel .mk-top,
.mk-in.is-panel .mk-band {
  translate: 0 calc(-1 * var(--mk-grow));
  transition: translate 520ms var(--ease-in-out) 40ms;
}

.mk-in.is-panel .mk-body {
  opacity: 0;
  scale: .985;
  pointer-events: none;
  transition-duration: 180ms, 260ms;
}

/* ---------------------------------------------------------------- keys */

.mk-grids {
  position: absolute;
  inset: 0;
  transition: opacity 160ms var(--ease-out);
}

.mk-in.is-voice .mk-grids {
  opacity: 0;
  pointer-events: none;
}

.mk-grid {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: var(--mk-pad);
  opacity: 0;
  visibility: hidden;
  transition: opacity 140ms var(--ease-in), visibility 0s linear 140ms;
}

.mk-grid.is-on {
  opacity: 1;
  visibility: visible;
  transition: opacity 220ms var(--ease-out) 70ms;
}

.mk-row {
  display: flex;
  block-size: var(--mk-row);
}

.mk-k {
  position: relative;
  display: flex;
  flex: 1 1 0;
  min-inline-size: 0;
  block-size: 100%;
  cursor: default;
}

.mk--interactive .mk-k { cursor: pointer; }
.mk--interactive .mk-grids { touch-action: pan-y; }

.mk-k__pad { flex: 0 1 0; }

/* A key two rows tall reaches over the empty cell below it (日本語かな's ⏎, as on iOS). */
.mk-k--gap { visibility: hidden; pointer-events: none; }
.mk-k--tall { z-index: 1; }
.mk-k--tall .mk-k__face { inset-block-end: calc(3 * var(--u) - var(--mk-row)); }

.mk-k__cap {
  position: relative;
  flex: 1 1 0;
  min-inline-size: 0;
}

.mk-k__face {
  position: absolute;
  inset: calc(3 * var(--u)) calc(2.5 * var(--u));
  display: grid;
  place-items: center;
  border-radius: var(--mk-key-r);
  background: var(--mk-key);
  /* The app draws the key's shadow 1 dp below it. */
  box-shadow: 0 max(1px, var(--u)) 0 var(--mk-key-shadow);
  transition: scale 320ms var(--ease-spring), background-color 300ms var(--ease-out), color 300ms var(--ease-out);
}

.mk-k__face::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--mk-press);
  opacity: 0;
  transition: opacity 140ms var(--ease-out);
}

.mk-k__face > * { position: relative; }

.mk-k--fn .mk-k__face { background: var(--mk-key-fn); }

.mk-k--enter .mk-k__face {
  background: var(--mk-accent);
  color: var(--mk-on-accent);
}

/* Pressed: in a little (wide keys less), darker, then a spring back (KeysUi.kt pressScale). */
.mk-k.is-down .mk-k__face {
  scale: .88;
  transition: scale 70ms var(--ease-out);
}

.mk-k--space.is-down .mk-k__face { scale: .95; }

.mk-k.is-down .mk-k__face::before {
  opacity: 1;
  transition: none;
}

.mk-in.is-shift .mk-k--shift .mk-k__face { background: var(--mk-accent-soft); }

.mk-k__l {
  font-size: max(15px, calc(19 * var(--u)));
  line-height: 1;
  white-space: nowrap;
}

.mk-k__l--tone { font-size: max(20px, calc(27 * var(--u))); }
.mk-k__l--lat { font-size: max(16px, calc(21 * var(--u))); }
.mk-k__l--dig { font-size: max(17px, calc(23 * var(--u))); }

.mk-k__l--fn {
  font-size: max(12px, calc(14 * var(--u)));
  font-weight: 500;
}

/* Cangjie radicals, kana, Hangul and Thai on their keys */
.mk-k__l--cj { font-size: max(17px, calc(21 * var(--u))); }
.mk-k__l--kana { font-size: max(19px, calc(25 * var(--u))); }
.mk-k__l--hangul { font-size: max(17px, calc(21 * var(--u))); }
.mk-k__l--thai { font-size: max(16px, calc(20 * var(--u))); line-height: 1.25; }
.mk-k__l--vi { font-size: max(16px, calc(21 * var(--u))); }

/* Shift shows each key's second character instead (Korean doubles, Thai's second layer). */
.mk-k__l--sh { display: none; }
.mk-in.is-shift .mk-k__l--base { display: none; }
.mk-in.is-shift .mk-k__l--sh { display: inline; }

/* The computer key a Cangjie radical is on, small in the corner, for typing on a real keyboard. */
.mk-k__sub {
  position: absolute;
  inset-block-end: calc(2.5 * var(--u));
  inset-inline-end: calc(4 * var(--u));
  font-family: var(--font-body);
  font-size: max(8px, calc(9 * var(--u)));
  line-height: 1;
  color: var(--mk-hint);
  text-transform: uppercase;
}

/* A key that is switched on (速成's 速). */
.mk-k.is-on .mk-k__face {
  background: var(--mk-accent-soft);
  color: var(--mk-ink);
}

.mk-k__l--name {
  font-size: max(11px, calc(12 * var(--u)));
  color: var(--mk-hint);
}

/* The long-press symbol, small in the corner. */
.mk-k__h {
  position: absolute;
  inset-block-start: calc(2 * var(--u));
  inset-inline-end: calc(4 * var(--u));
  font-size: max(8px, calc(9.5 * var(--u)));
  line-height: 1.1;
  color: var(--mk-hint);
}

.mk-k__ico { font-size: max(16px, calc(20 * var(--u))); }
.mk-k__ico--back { font-size: max(18px, calc(23 * var(--u))); }

.mk-k__ico--done { display: none; }
.mk-in.is-composing .mk-k__ico--send { display: none; }
.mk-in.is-composing .mk-k__ico--done { display: block; }

/* A space bar that names what it does while composing (変換) */
.mk-k__l--comp { display: none; }
.mk-in.is-composing .mk-k__l--idle { display: none; }
.mk-in.is-composing .mk-k__l--comp {
  display: inline;
  color: var(--mk-ink);
  font-weight: 500;
}

/* Space: ˉ (it types the first tone) and the small mic that long press opens. */
.mk-k__tone1 {
  position: absolute;
  inset-block-start: calc(1 * var(--u));
  inset-inline: 0;
  text-align: center;
  font-size: max(14px, calc(17 * var(--u)));
  line-height: 1;
  color: var(--mk-hint);
}

.mk-k__mic {
  position: absolute;
  inset-block-start: calc(4 * var(--u));
  inset-inline-end: calc(6 * var(--u));
  font-size: max(9px, calc(10 * var(--u)));
  color: var(--mk-hint);
  transform-origin: 50% 50%;
  transition: scale 200ms var(--ease-out), opacity 200ms var(--ease-out);
}

/* Held: the mic grows while voice is about to open. */
.mk-k.is-charging .mk-k__mic {
  scale: 1.9;
  color: var(--mk-ink);
  transition: scale 430ms var(--ease-in);
}

/* ---------------------------------------------------------------- the pressed key, enlarged */

.mk-pop {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 6;
  pointer-events: none;
  opacity: 0;
  scale: .94;
  transform-origin: 50% 100%;
  transition: opacity 120ms var(--ease-in), scale 120ms var(--ease-in);
}

.mk-pop.is-on {
  opacity: 1;
  scale: 1;
  transition: none;
}

.mk-pop__l {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: calc(10 * var(--u));
  background: var(--mk-key);
  box-shadow: 0 0 0 1px var(--mk-line);
  font-size: max(21px, calc(26 * var(--u)));
  line-height: 1;
}

/* A shadow drawn by hand: the bubble's shape again, a little down and to the right, with an uneven
   edge and a slight turn, over a soft spread. */
.mk-pop__shade {
  position: absolute;
  inset: 0;
  border-radius: 32% 24% 30% 22% / 22% 28% 24% 30%;
  background: color-mix(in oklch, var(--color-ink) 17%, transparent);
  filter: blur(.7px);
  translate: max(3px, calc(3.5 * var(--u))) max(5px, calc(6 * var(--u)));
  rotate: 1.6deg;
}

.mk-pop__shade::before {
  content: "";
  position: absolute;
  inset: 12% -6% -16% 4%;
  border-radius: 44% 56% 48% 52% / 38% 44% 56% 62%;
  background: color-mix(in oklch, var(--color-ink) 16%, transparent);
  filter: blur(9px);
  rotate: -3deg;
}

/* ---------------------------------------------------------------- the flick guide (12-key kana) */

/* The key's five kana in a cross round the finger; the one it points to is lit (KeysUi flick preview). */
.mk-flick {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 7;
  display: grid;
  grid-template: repeat(3, minmax(0, 1fr)) / repeat(3, minmax(0, 1fr));
  pointer-events: none;
  opacity: 0;
  transition: opacity 110ms var(--ease-in);
}

.mk-flick.is-on {
  opacity: 1;
  transition: none;
}

.mk-flick__o {
  display: grid;
  place-items: center;
  margin: calc(1.5 * var(--u));
  border-radius: calc(10 * var(--u));
  background: var(--mk-key);
  box-shadow:
    0 0 0 1px var(--mk-line),
    0 6px 14px -6px color-mix(in oklch, var(--color-ink) 32%, transparent);
  color: var(--mk-ink);
  font-size: max(18px, calc(23 * var(--u)));
  line-height: 1;
  transition: background-color 90ms var(--ease-out), color 90ms var(--ease-out);
}

.mk-flick__o--0 { grid-area: 2 / 2; }
.mk-flick__o--1 { grid-area: 2 / 1; }
.mk-flick__o--2 { grid-area: 1 / 2; }
.mk-flick__o--3 { grid-area: 2 / 3; }
.mk-flick__o--4 { grid-area: 3 / 2; }
.mk-flick__o.is-empty { visibility: hidden; }

.mk-flick__o.is-sel {
  background: var(--color-cyan);
  color: var(--color-on-brand);
}

/* ---------------------------------------------------------------- long-press choices */

.mk-alt {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 7;
  display: flex;
  border-radius: calc(12 * var(--u));
  background: var(--mk-key);
  box-shadow:
    0 0 0 1px var(--mk-line),
    0 3px 6px -2px color-mix(in oklch, var(--color-ink) 16%, transparent),
    0 14px 26px -10px color-mix(in oklch, var(--color-ink) 30%, transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 110ms var(--ease-in);
}

.mk-alt.is-on {
  opacity: 1;
  transition: none;
}

.mk-alt__row {
  position: relative;
  display: flex;
  inline-size: 100%;
}

.mk-alt__o {
  display: grid;
  place-items: center;
  flex: 0 0 var(--cell);
  font-size: max(16px, calc(20 * var(--u)));
  line-height: 1;
}

/* The chosen one is a rounded block inside the bubble, so the bubble's edge stays whole. */
.mk-alt__o.is-sel { color: var(--color-on-brand); }

.mk-alt__sel {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--cell);
  transition: translate 120ms var(--ease-out);
}

.mk-alt__sel.is-jump { transition: none; }

.mk-alt__sel::before {
  content: "";
  position: absolute;
  inset: calc(3 * var(--u));
  border-radius: calc(9 * var(--u));
  background: var(--color-cyan);
}

/* ---------------------------------------------------------------- tool bar and candidates */

.mk-tools,
.mk-cands {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  transition: opacity 180ms var(--ease-out), translate 240ms var(--ease-out);
}

/* The same gap between buttons as at the edges; 9 dp above, 3 below (KeyboardUi.kt Toolbar). */
.mk-tools {
  justify-content: space-evenly;
  padding-block: calc(9 * var(--u)) calc(3 * var(--u));
}

.mk-tool {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: calc(38 * var(--u));
  block-size: calc(38 * var(--u));
  flex: none;
  border-radius: 50%;
  background: var(--mk-tool);
  box-shadow:
    inset 0 1px 0 var(--glass-rim),
    0 0 0 1px var(--mk-line),
    0 1px 3px color-mix(in oklch, var(--color-ink) 10%, transparent);
  color: var(--mk-ink);
  font-size: calc(22 * var(--u));
  transition: scale 300ms var(--ease-spring), background-color 300ms var(--ease-out), color 300ms var(--ease-out);
}

/* Touch targets reach 44px around the round buttons. */
.mk--interactive .mk-tool::after,
.mk--interactive .mk-vbtn::after,
.mk--interactive .mk-mic__btn::after {
  content: "";
  position: absolute;
  inset: min(-4px, calc((100% - 44px) / 2));
  border-radius: 50%;
}

.mk--interactive .mk-vbtn { position: relative; }

.mk--interactive .mk-tool:active { scale: .86; transition-duration: 80ms; }

.mk-tool--moqi {
  background: none;
  box-shadow: none;
}

/* The person button (KeyboardUi.kt PersonButton, on by default): the bar's last glass circle, holding the
   avatar of the person MOQI is writing to (32 of its 38). */
.mk-avatar {
  display: grid;
  place-items: center;
  inline-size: calc(32 * var(--u));
  block-size: calc(32 * var(--u));
  border-radius: 50%;
  background: var(--moqi-avatar);
  color: var(--color-cyan-ink);
  font-size: calc(14.7 * var(--u));
  font-weight: 600;
  line-height: 1;
}

.mk-avatar.is-none {
  color: var(--color-ink-2);
}

.mk-avatar .mk-ico {
  font-size: calc(16 * var(--u));
}

.mk-tool__face {
  display: grid;
  place-items: center;
  inline-size: 100%;
  block-size: 100%;
  transform-origin: 50% 50%;
}

.mk-tool__face > * { flex: none; }

.mk-in.is-cands .mk-tools {
  opacity: 0;
  translate: 0 -6px;
  pointer-events: none;
}

.mk-cands {
  opacity: 0;
  translate: 0 6px;
  pointer-events: none;
}

.mk-in.is-cands .mk-cands,
.mk-top.is-cands .mk-cands {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
}

.mk-top.is-cands .mk-tools {
  opacity: 0;
  translate: 0 -6px;
  pointer-events: none;
}

.mk-cands__list {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-inline-size: 0;
  block-size: 100%;
  overflow: hidden;
  padding-inline-start: calc(4 * var(--u));
  -webkit-mask-image: linear-gradient(90deg, var(--color-ink) 86%, transparent);
  mask-image: linear-gradient(90deg, var(--color-ink) 86%, transparent);
}

.mk-cand {
  display: grid;
  place-items: center;
  flex: none;
  block-size: 100%;
  padding-inline: calc(13 * var(--u));
  font-size: max(15px, calc(18 * var(--u)));
  line-height: 1;
  white-space: nowrap;
  color: var(--color-ink);
}

.mk-cand > span {
  padding: .26em .5em;
  border-radius: var(--radius-pill);
  transition: opacity 120ms var(--ease-out);
}

/* What space would put in: the first candidate (the app lights it in its brand ink). */
.mk-cand.is-lit > span {
  background: var(--color-cyan-soft);
  font-weight: 600;
}

.mk-cand.is-down > span { opacity: .55; transition: none; }

.mk-cands__more {
  display: grid;
  place-items: center;
  inline-size: max(40px, calc(48 * var(--u)));
  block-size: 100%;
  flex: none;
  font-size: max(16px, calc(20 * var(--u)));
  color: var(--mk-ink-2);
}

/* ---------------------------------------------------------------- the floating Zhuyin tab */

.mk-band {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: var(--mk-band);
  z-index: 4;
  pointer-events: none;
  transition: translate 480ms var(--ease-out);
}

.mk-reading {
  --glass-tint: color-mix(in oklch, var(--color-paper) 84%, transparent);
  --glass-radius: calc(12 * var(--u));
  position: absolute;
  inset-inline-start: calc(10 * var(--u));
  inset-block-end: calc(6 * var(--u));
  display: inline-flex;
  align-items: center;
  min-block-size: max(30px, calc(32 * var(--u)));
  padding-inline: calc(11 * var(--u)) calc(13 * var(--u));
  border-radius: calc(12 * var(--u));
  font-size: max(15px, calc(17 * var(--u)));
  letter-spacing: .05em;
  line-height: 1;
  white-space: nowrap;
  opacity: 0;
  scale: .9;
  transform-origin: 0 100%;
  transition: opacity 140ms var(--ease-in), scale 140ms var(--ease-in);
}

.mk-reading.is-on {
  opacity: 1;
  scale: 1;
  transition: opacity 120ms var(--ease-out), scale 320ms var(--ease-spring);
}

/* Toasts (KeyboardUi.kt GlassToast): white glass with ink text at the bottom centre of the band (bottom right
   while the Zhuyin card shows), two lines at most; they rise in and sink away, as in the app. */
.mk-toast {
  --glass-tint: oklch(100% 0 0 / .94);
  --glass-radius: 999px;
  position: absolute;
  inset-inline: 0;
  inset-block-end: calc(6 * var(--u));
  display: -webkit-box;
  inline-size: max-content;
  max-inline-size: 86%;
  margin-inline: auto;
  padding: calc(6 * var(--u)) calc(14 * var(--u));
  overflow: hidden;
  border-radius: var(--radius-pill);
  color: var(--color-ink);
  font-size: max(12px, calc(13 * var(--u)));
  line-height: 1.35;
  text-align: center;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  opacity: 0;
  translate: 0 calc(8 * var(--u));
  transition: opacity 180ms var(--ease-in), translate 220ms var(--ease-in);
}

.mk-in.is-dark .mk-toast {
  --glass-tint: rgb(42 49 51 / .88);
  color: #EDF2F3;
}

.mk-toast.is-on {
  opacity: 1;
  translate: 0 0;
  transition: opacity 220ms var(--ease-out), translate 280ms var(--ease-out);
}

.mk-reading.is-on + .mk-toast {
  inset-inline: auto calc(10 * var(--u));
  margin-inline: 0;
}

.mk-reading > .is-new {
  display: inline-block;
  animation: mk-sym 220ms var(--ease-out);
}

@keyframes mk-sym {
  from { opacity: 0; translate: 0 5px; }
}

/* ---------------------------------------------------------------- MOQI's face (when the page has no moqi.js) */

.mk-face {
  --s: 100%;
  position: relative;
  display: block;
  inline-size: var(--s);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  isolation: isolate;
  container-type: inline-size;
  background: linear-gradient(180deg, var(--color-paper), color-mix(in oklch, var(--color-paper) 90%, var(--color-cyan)));
  box-shadow:
    inset 0 0 0 1px var(--glass-rim),
    0 1px 3px color-mix(in oklch, var(--color-ink) 14%, transparent);
}

/* The soft cyan glow inside the rim. */
.mk-face::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    color-mix(in oklch, var(--color-cyan) 0%, transparent) 58%,
    color-mix(in oklch, var(--color-cyan) 16%, transparent) 86%,
    color-mix(in oklch, var(--color-cyan) 50%, transparent));
  transition: opacity 400ms var(--ease-out);
}

.mk-face__open,
.mk-face__ring,
.mk-face__blush,
.mk-face__eyes {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

/* Open (the assistant is up): MOQI cyan with white eyes. */
.mk-face__open {
  background: linear-gradient(180deg,
    color-mix(in oklch, var(--color-cyan) 73%, var(--color-paper)),
    color-mix(in oklch, var(--color-cyan) 85%, var(--color-ink)));
  opacity: 0;
  transition: opacity 350ms var(--ease-in-out);
}

.mk-face.is-open .mk-face__open { opacity: 1; }
.mk-face.is-open::before,
.mk-face.is-thinking::before { opacity: 0; }

/* Thinking: cyan and pink running round the inside of the rim. */
.mk-face__ring {
  background: conic-gradient(var(--color-cyan), var(--color-pink), var(--color-cyan));
  -webkit-mask-image: radial-gradient(closest-side, transparent 50%, color-mix(in srgb, var(--color-ink) 75%, transparent) 80%, var(--color-ink));
  mask-image: radial-gradient(closest-side, transparent 50%, color-mix(in srgb, var(--color-ink) 75%, transparent) 80%, var(--color-ink));
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
  animation: mk-spin 1.7s linear infinite;
}

.mk-face.is-thinking .mk-face__ring { opacity: 1; }

@keyframes mk-spin { to { rotate: 1turn; } }

/* Eyes on the 38-unit grid of MoqiButton.kt; at rest they look at the keys (3.2, 2.6). */
.mk-face__eyes {
  translate: calc(3.2cqi * 100 / 38) calc(2.6cqi * 100 / 38);
  transition: translate 700ms var(--ease-out);
}

.mk-face.is-notice .mk-face__eyes { translate: calc(1cqi * 100 / 38) calc(-1.6cqi * 100 / 38); }

.mk-face.is-thinking .mk-face__eyes {
  translate: 0 calc(-.2cqi * 100 / 38);
  animation: mk-ponder 3.2s var(--ease-in-out) infinite;
}

@keyframes mk-ponder {
  0%, 100% { translate: calc(2.8cqi * 100 / 38) calc(-.2cqi * 100 / 38); }
  50% { translate: calc(-2.8cqi * 100 / 38) calc(-.2cqi * 100 / 38); }
}

.mk-face__eye {
  position: absolute;
  inset-inline-start: calc(100% * (19 - 4.9 - 2.5) / 38);
  inset-block-start: calc(100% * (18.2 - 4.8) / 38);
  inline-size: calc(100% * 5 / 38);
  block-size: calc(100% * 9.6 / 38);
  border-radius: 999px;
  background: var(--grad-moqi);
  box-shadow:
    0 0 0 calc(.8cqi * 100 / 38) color-mix(in oklch, var(--color-cyan) 16%, transparent),
    0 0 0 calc(1.6cqi * 100 / 38) color-mix(in oklch, var(--color-cyan) 8%, transparent);
  transition: scale 110ms var(--ease-out), opacity 120ms var(--ease-out);
}

.mk-face__eye--r { inset-inline-start: calc(100% * (19 + 4.9 - 2.5) / 38); }

/* The glint while waiting. */
.mk-face__eye::after {
  content: "";
  position: absolute;
  inset-inline-start: 20%;
  inset-block-start: 10%;
  inline-size: 42%;
  block-size: 20%;
  border-radius: 999px;
  background: var(--color-card);
  transition: opacity 120ms var(--ease-out);
}

.mk-face.is-blink .mk-face__eye { scale: 1 .1; transition-duration: 90ms; }
.mk-face.is-blink .mk-face__eye::after { opacity: 0; }

.mk-face.is-open .mk-face__eye {
  background: linear-gradient(180deg, var(--color-paper), color-mix(in oklch, var(--color-paper) 80%, var(--color-cyan)));
  box-shadow: 0 0 0 calc(.8cqi * 100 / 38) color-mix(in oklch, var(--color-paper) 30%, transparent);
}

.mk-face.is-open .mk-face__eye::after { opacity: 0; }

/* Thinking: wide squinting eyes, no glint. */
.mk-face.is-thinking .mk-face__eye { scale: 1.48 .31; }
.mk-face.is-thinking .mk-face__eye::after { opacity: 0; }

/* Happy: ^ ^ and a blush. */
.mk-face__smile {
  position: absolute;
  inset-block-start: calc(100% * (18.2 - 2.6) / 38);
  inline-size: calc(100% * 5.6 / 38);
  block-size: calc(100% * 5 / 38);
  border: calc(2.5cqi * 100 / 38) solid var(--color-cyan);
  border-color: var(--color-cyan) transparent transparent;
  border-radius: 50%;
  opacity: 0;
  scale: 1 .4;
  transition: opacity 120ms var(--ease-out), scale 220ms var(--ease-spring);
}

.mk-face__smile--l { inset-inline-start: calc(100% * (19 - 4.9 - 2.8) / 38); }
.mk-face__smile--r { inset-inline-start: calc(100% * (19 + 4.9 - 2.8) / 38); }

.mk-face.is-open .mk-face__smile { border-top-color: var(--color-paper); }

.mk-face.is-happy .mk-face__eye { opacity: 0; scale: 1 .3; }
.mk-face.is-happy .mk-face__smile { opacity: 1; scale: 1; }

.mk-face__blush::before,
.mk-face__blush::after {
  content: "";
  position: absolute;
  inset-block-start: calc(100% * (25 - 1.35) / 38);
  inline-size: calc(100% * 5.2 / 38);
  block-size: calc(100% * 2.7 / 38);
  border-radius: 50%;
  background: color-mix(in oklch, var(--color-pink) 65%, transparent);
  opacity: 0;
  transition: opacity 250ms var(--ease-out);
}

.mk-face__blush::before { inset-inline-start: calc(100% * (11.8 - 2.6) / 38); }
.mk-face__blush::after { inset-inline-start: calc(100% * (26.2 - 2.6) / 38); }
.mk-face.is-happy .mk-face__blush::before,
.mk-face.is-happy .mk-face__blush::after { opacity: 1; }

.mk-face--key { inline-size: 100%; }

.mk-face--mark {
  --s: max(20px, calc(24 * var(--u)));
  flex: none;
}

.mk-face--think { --s: max(38px, calc(44 * var(--u))); }

/* moqi.js MOQIs, sized with the keyboard. */
.mk-tool__face > .mk-moqi { --moqi-size: calc(38 * var(--u)); }

.mk-panel__mark {
  display: grid;
  flex: none;
}

.mk-panel__mark > .mk-moqi { --moqi-size: max(20px, calc(24 * var(--u))); }
.mk-think__moqi > .mk-moqi { --moqi-size: max(36px, calc(44 * var(--u))); }

/* ---------------------------------------------------------------- MOQI's panel */

.mk-panel {
  --glass-tint: color-mix(in oklch, var(--color-paper-2) 90%, transparent);
  /* MOQI's panel, its colour field, the AI marks and the reply rim keep MOQI's colours under any theme (as in
     the app, Themes.kt): the theme variables are set back to the default look for everything inside. */
  --mk-key: var(--color-paper);
  --mk-key-fn: color-mix(in oklch, var(--color-rule) 90%, var(--color-ink));
  --mk-key-shadow: color-mix(in oklch, var(--color-ink) 18%, transparent);
  --mk-press: color-mix(in oklch, var(--color-ink) 10%, transparent);
  --mk-tool: color-mix(in oklch, var(--color-paper) 95%, transparent);
  --mk-line: color-mix(in oklch, var(--color-ink) 7%, transparent);
  --mk-ink: var(--color-ink);
  --mk-ink-2: var(--color-ink-2);
  --mk-hint: var(--color-muted);
  --mk-accent: var(--color-cyan);
  --mk-on-accent: var(--color-on-brand);
  --mk-accent-soft: var(--color-cyan-soft);
  color: var(--color-ink);
  position: absolute;
  inset-inline: 0;
  inset-block: calc(-1 * var(--mk-grow)) 0;
  z-index: 2;
  border-radius: var(--mk-r);
  transform-origin: 9% 12%;
}

.mk-panel[hidden] { display: none; }

.mk-panel__in {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding-block-start: var(--mk-bar);
}

.mk-panel__head {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  flex: none;
  min-block-size: max(40px, calc(44 * var(--u)));
  padding-inline: calc(12 * var(--u)) calc(10 * var(--u));
}

.mk-panel__title {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  font-size: max(14px, calc(14.5 * var(--u)));
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Who MOQI is writing to: role · stage, as the app's persona chip. */
.mk-profile {
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  flex: 0 1 auto;
  min-inline-size: 0;
  max-inline-size: 62%;
  padding: calc(3 * var(--u)) calc(10 * var(--u)) calc(3 * var(--u)) calc(3 * var(--u));
  border-radius: var(--radius-pill);
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--mk-line);
  color: var(--color-ink-2);
  font-size: max(12px, calc(12.5 * var(--u)));
  white-space: nowrap;
}

.mk-profile[hidden] { display: none; }

.mk-profile__av {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: max(22px, calc(24 * var(--u)));
  block-size: max(22px, calc(24 * var(--u)));
  border-radius: 50%;
  background: var(--color-paper-3);
  color: var(--color-ink);
  font-size: max(11px, calc(11.5 * var(--u)));
  font-weight: 600;
}

.mk-profile__av .mk-ico { font-size: max(11px, calc(12 * var(--u))); color: var(--color-ink-2); }

.mk-profile__l {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mk-panel__scroll {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  flex: 1 1 auto;
  min-block-size: 0;
  overflow: hidden;
  padding: calc(2 * var(--u)) calc(10 * var(--u)) calc(12 * var(--u));
  scrollbar-width: none;
  /* Content scrolling under the head fades out rather than being cut. */
  -webkit-mask-image: linear-gradient(180deg, transparent, var(--color-ink) calc(8 * var(--u)), var(--color-ink) calc(100% - 12 * var(--u)), transparent);
  mask-image: linear-gradient(180deg, transparent, var(--color-ink) calc(8 * var(--u)), var(--color-ink) calc(100% - 12 * var(--u)), transparent);
}

.mk--solo .mk-panel__scroll {
  -webkit-mask-image: none;
  mask-image: none;
}

.mk--interactive .mk-panel__scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
}

.mk-panel__scroll::-webkit-scrollbar { display: none; }

.mk-blocks {
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  flex: 1 0 auto;
}

.mk-opts {
  display: flex;
  gap: calc(6 * var(--u));
  flex: none;
  overflow: hidden;
}

.mk-opts[hidden] { display: none; }

/* Chips stay monochrome; the chosen one takes the soft cyan fill the keyboard uses for selection. */
.mk-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: calc(5 * var(--u));
  flex: none;
  min-block-size: max(28px, calc(30 * var(--u)));
  padding-inline: calc(12 * var(--u));
  border-radius: var(--radius-pill);
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--mk-line);
  color: var(--color-ink-2);
  font-size: max(12px, calc(12.5 * var(--u)));
  line-height: 1.2;
  white-space: nowrap;
}

.mk-chip::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--color-cyan-soft);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--color-cyan) 30%, transparent);
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}

.mk-chip > * { position: relative; }

.mk-chip.is-on {
  color: var(--color-ink);
  font-weight: 600;
}

.mk-chip.is-on::before { opacity: 1; }

.mk-chip__ico { font-size: max(12px, calc(14 * var(--u))); }

/* 看懂對方's actions (AiPanel.kt, 0.4.9 新版4): the chips, then 幫我回 across the panel. */
.mk-acts {
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  padding-block-start: calc(2 * var(--u));
}

.mk-acts__chips {
  display: flex;
  flex-wrap: wrap;
  gap: calc(6 * var(--u));
}

/* BrandButton: a pill in MOQI's eye gradient (MOQI's own colour, the same in every theme), dark ink, a white
   sheen over the top half, a white rim and a soft shadow. */
.mk-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(7 * var(--u));
  min-block-size: max(40px, calc(44 * var(--u)));
  padding-inline: calc(18 * var(--u));
  border-radius: var(--radius-pill);
  background:
    linear-gradient(180deg, rgb(255 255 255 / .3), rgb(255 255 255 / 0) 55%),
    linear-gradient(90deg, #8BEFF5, #00C8D3, #FF8CC7);
  box-shadow:
    inset 0 0 0 1px rgb(255 255 255 / .5),
    0 2px 8px -2px var(--moqi-key-shadow);
  color: var(--color-on-brand);
  font-size: max(14px, calc(15 * var(--u)));
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  transition: scale 140ms var(--ease-out);
}

.mk-cta.is-down { scale: .96; }

.mk-cta__ico { font-size: max(15px, calc(17 * var(--u))); }

.mk-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--u));
  flex: none;
  padding: calc(8 * var(--u)) calc(12 * var(--u));
  border-radius: calc(12 * var(--u));
  background: var(--color-card);
  box-shadow:
    inset 0 0 0 1px var(--mk-line),
    0 1px 2px color-mix(in oklch, var(--color-ink) 5%, transparent);
}

.mk-card__label {
  color: var(--color-ink-2);
  font-size: max(11px, calc(11.5 * var(--u)));
  font-weight: 600;
  line-height: 1.3;
}

.mk-card__text {
  font-size: max(13px, calc(13.5 * var(--u)));
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.mk-card__text.is-big {
  font-size: max(14px, calc(15 * var(--u)));
  line-height: 1.45;
}

/* 怎麼回比較好: one tip per line */
.mk-card__text.is-list {
  white-space: pre-line;
}

.mk-card__text.is-mono,
.mk-card__sub.is-mono {
  font-family: var(--font-mono);
  font-size: max(12px, calc(12.5 * var(--u)));
  color: var(--color-ink-2);
}

.mk-card__sub {
  color: var(--color-ink-2);
  font-size: max(12px, calc(12 * var(--u)));
  line-height: 1.45;
}

.mk-card__note {
  margin-block-start: calc(2 * var(--u));
  color: var(--color-ink-2);
  font-size: max(11px, calc(11.5 * var(--u)));
  line-height: 1.4;
}

.mk-card__list {
  margin: 0;
  padding-inline-start: 1.15em;
  font-size: max(13px, calc(13 * var(--u)));
  line-height: 1.5;
}

.mk-card__list li::marker { color: var(--color-muted); }

/* A warning stays monochrome: a stronger outline and the warning mark. */
.mk-card--warn {
  flex-direction: row;
  align-items: flex-start;
  gap: calc(8 * var(--u));
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1.5px color-mix(in oklch, var(--color-ink) 62%, transparent);
}

.mk-card__ico {
  margin-block-start: 2px;
  font-size: max(14px, calc(15 * var(--u)));
}

.mk-card__title {
  font-size: max(12.5px, calc(13 * var(--u)));
  font-weight: 600;
}

.mk-card--warn .mk-card__text {
  margin-block-start: 2px;
  font-size: max(12.5px, calc(12.5 * var(--u)));
}

.mk-quote {
  flex: none;
  padding: calc(6 * var(--u)) calc(10 * var(--u));
  border-radius: calc(9 * var(--u));
  background: color-mix(in oklch, var(--color-paper-3) 72%, transparent);
  box-shadow: inset 0 0 0 1px var(--mk-line);
  color: var(--color-ink-2);
  font-size: max(12px, calc(12 * var(--u)));
  line-height: 1.45;
}

.mk-quote--lines {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--u));
}

.mk-quote--lines > span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.mk-note {
  flex: none;
  color: var(--color-ink-2);
  font-size: max(12px, calc(12 * var(--u)));
  line-height: 1.45;
}

.mk-shotline {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  flex: none;
  color: var(--color-ink-2);
  font-size: max(11.5px, calc(11.5 * var(--u)));
  font-weight: 600;
}

.mk-shotline .mk-ico { font-size: max(13px, calc(14 * var(--u))); }

/* A reply MOQI wrote: style, words, and your language under them. */
.mk-sugg {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--u));
  flex: none;
  inline-size: 100%;
  padding: calc(8 * var(--u)) calc(12 * var(--u));
  border-radius: calc(12 * var(--u));
  background: var(--color-card);
  box-shadow:
    inset 0 0 0 1px var(--mk-line),
    0 1px 2px color-mix(in oklch, var(--color-ink) 5%, transparent);
  transition: scale 300ms var(--ease-spring);
}

.mk-sugg::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--color-cyan-soft);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--color-cyan) 34%, transparent);
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}

.mk-sugg > * { position: relative; }

.mk-sugg.is-down {
  scale: .97;
  transition-duration: 80ms;
}

.mk-sugg.is-picked::before { opacity: 1; }

.mk--interactive .mk-sugg:active { scale: .97; transition-duration: 80ms; }

.mk-sugg:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.mk-sugg__style {
  color: var(--color-ink-2);
  font-size: max(11px, calc(11.5 * var(--u)));
  font-weight: 600;
}

.mk-sugg__text {
  font-size: max(13.5px, calc(14 * var(--u)));
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.mk-sugg__zh {
  color: var(--color-ink-2);
  font-size: max(12px, calc(12 * var(--u)));
  line-height: 1.4;
}

/* 取代 / 插入 under a translation. */
.mk-panel__foot {
  display: flex;
  gap: calc(8 * var(--u));
  flex: none;
  padding: calc(6 * var(--u)) calc(10 * var(--u)) calc(10 * var(--u));
}

.mk-panel__foot[hidden] { display: none; }

.mk-act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(6 * var(--u));
  min-block-size: max(34px, calc(36 * var(--u)));
  padding-inline: calc(14 * var(--u));
  border-radius: var(--radius-pill);
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--mk-line);
  font-size: max(13px, calc(13 * var(--u)));
  font-weight: 600;
  white-space: nowrap;
}

.mk-act .mk-ico { font-size: max(13px, calc(15 * var(--u))); }

.mk-act--primary {
  flex: 1 1 auto;
  background: var(--color-cyan);
  box-shadow: none;
  color: var(--color-on-brand);
}

/* MOQI thinks in the middle of the space the answer will fill (AiPanel.kt Thinking). */
.mk-think {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--u));
  flex: 1 0 auto;
  min-block-size: calc(var(--mk-keys) * .62);
}

.mk-think__moqi {
  display: grid;
  place-items: center;
}

.mk-think .mk-working {
  font-size: max(14px, calc(14.5 * var(--u)));
  font-weight: 600;
}

/* ---------------------------------------------------------------- the working label (Working.kt) */

.mk-working {
  display: inline-flex;
  align-items: center;
  gap: .3em;
  white-space: nowrap;
}

.mk-working__t {
  position: relative;
  display: inline-block;
}

/* A band of MOQI colour runs through the words: a window moving across them while the coloured copy
   inside it moves back, so the letters stay put and only the colour travels. */
.mk-working__track {
  position: absolute;
  inset: 0;
  pointer-events: none;
  animation: mk-shine 2.2s linear infinite;
}

.mk-working__win {
  position: absolute;
  inset-block: -.2em;
  inset-inline-start: 0;
  inline-size: 45%;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--color-ink) 30%, var(--color-ink) 70%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--color-ink) 30%, var(--color-ink) 70%, transparent);
}

.mk-working__ink {
  position: absolute;
  inset-block-start: .2em;
  inset-inline-start: 0;
  inline-size: calc(100% / .45);
  background: var(--grad-moqi-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  white-space: nowrap;
  animation: mk-shine-back 2.2s linear infinite;
}

@keyframes mk-shine {
  from { transform: translateX(-45%); }
  to { transform: translateX(117%); }
}

@keyframes mk-shine-back {
  from { transform: translateX(45%); }
  to { transform: translateX(-117%); }
}

/* Three dots after the words, cyan to pink, each brightening in turn; they always keep their room. */
.mk-working__dots {
  display: inline-flex;
  gap: .22em;
  padding-inline-start: .1em;
}

.mk-working__dots > i {
  display: block;
  inline-size: .3em;
  block-size: .3em;
  border-radius: 50%;
  background: var(--grad-moqi-text);
  background-size: 600% 100%;
  opacity: .3;
  scale: .8;
  animation: mk-dot 1.2s linear infinite;
}

.mk-working__dots > i:nth-child(2) { background-position: 50% 0; animation-delay: .4s; }
.mk-working__dots > i:nth-child(3) { background-position: 100% 0; animation-delay: .8s; }

@keyframes mk-dot {
  0% { opacity: .3; scale: .8; animation-timing-function: var(--ease-out); }
  16.7% { opacity: 1; scale: 1.1; animation-timing-function: var(--ease-in); }
  33.3%, 100% { opacity: .3; scale: .8; }
}

/* ---------------------------------------------------------------- voice (VoiceUi.kt) */

.mk-voice {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: calc(6 * var(--u)) calc(10 * var(--u));
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}

.mk-voice[hidden] { display: none; }
.mk-in.is-voice .mk-voice { opacity: 1; }

@starting-style {
  .mk-in.is-voice .mk-voice { opacity: 0; }
}

.mk-voice__chips {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

.mk-voice__auto {
  color: var(--color-ink-2);
  font-size: max(12px, calc(13 * var(--u)));
}

.mk-voice__mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--u));
  flex: 1 1 auto;
}

.mk-wave {
  position: relative;
  display: flex;
  justify-content: space-between;
  inline-size: calc(118 * var(--u));
  block-size: max(46px, calc(64 * var(--u)));
}

.mk-wave__bar {
  position: relative;
  inline-size: calc(10 * var(--u));
  block-size: 100%;
}

.mk-wave__set {
  position: absolute;
  inset: 0;
}

.mk-wave__set--p { opacity: 0; }

.mk-wave__cap,
.mk-wave__mid {
  position: absolute;
  inset-inline-start: 0;
  inline-size: 100%;
}

.mk-wave__cap {
  inset-block-start: calc(50% - 5 * var(--u));
  block-size: calc(10 * var(--u));
  border-radius: 50%;
}

.mk-wave__mid {
  inset-block: 0;
  scale: 1 0;
}

.mk-wave__set--c > * { background: var(--color-cyan); }
.mk-wave__set--p > * { background: var(--color-pink); }

.mk-voice__say {
  display: grid;
  place-items: center;
  min-block-size: 1.6em;
}

.mk-voice__say > * { grid-area: 1 / 1; }

.mk-voice__status {
  color: var(--color-ink-2);
  font-size: max(13px, calc(13.5 * var(--u)));
  text-align: center;
}

.mk-voice__working {
  color: var(--color-ink-2);
  font-size: max(13px, calc(13.5 * var(--u)));
  opacity: 0;
}

.mk-in[data-voice="thinking"] .mk-voice__status { opacity: 0; }
.mk-in[data-voice="thinking"] .mk-voice__working { opacity: 1; }

.mk-voice__row {
  display: flex;
  align-items: center;
  block-size: max(54px, calc(68 * var(--u)));
  padding-inline: calc(6 * var(--u));
}

.mk-voice__side {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  flex: 1 1 0;
}

.mk-voice__side--end { justify-content: flex-end; }

.mk-vbtn {
  display: grid;
  place-items: center;
  inline-size: calc(46 * var(--u));
  block-size: calc(46 * var(--u));
  border-radius: 50%;
  background: var(--mk-key-fn);
  color: var(--color-ink);
  font-size: max(15px, calc(19 * var(--u)));
  transition: scale 300ms var(--ease-spring);
}

.mk-vbtn--pill {
  inline-size: calc(66 * var(--u));
  border-radius: calc(23 * var(--u));
  background: var(--mk-key);
  box-shadow: 0 max(1px, var(--u)) 0 var(--mk-key-shadow);
}

.mk-vbtn--enter {
  background: var(--color-cyan);
  box-shadow: none;
  color: var(--color-on-brand);
}

.mk--interactive .mk-vbtn:active,
.mk--interactive .mk-mic__btn:active { scale: .9; transition-duration: 80ms; }

/* The ⎵ mark, drawn. */
.mk-vbtn__space {
  inline-size: calc(24 * var(--u));
  block-size: calc(9 * var(--u));
  border: max(1.5px, calc(1.6 * var(--u))) solid var(--color-ink-2);
  border-block-start: 0;
  border-radius: 0 0 2px 2px;
}

.mk-mic {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: calc(64 * var(--u));
  block-size: calc(64 * var(--u));
  flex: none;
}

.mk-mic > * { grid-area: 1 / 1; }

/* The ring swells with the voice. */
.mk-mic__ring {
  inline-size: calc(56 * var(--u));
  block-size: calc(56 * var(--u));
  border-radius: 50%;
  background: color-mix(in oklch, var(--color-cyan) 22%, transparent);
  opacity: 0;
  transition: opacity 200ms var(--ease-out);
}

.mk-mic__btn {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: calc(52 * var(--u));
  block-size: calc(52 * var(--u));
  border-radius: 50%;
  background: var(--color-cyan);
  color: var(--color-on-brand);
  font-size: max(17px, calc(22 * var(--u)));
  transition: scale 300ms var(--ease-spring);
}

.mk-in[data-voice="idle"] .mk-mic__btn {
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--mk-line);
  color: var(--color-ink);
}

/* ---------------------------------------------------------------- the page's input line (option `output`) */

.mk-out__comp {
  text-decoration: underline;
  text-decoration-color: var(--color-ink-2);
  text-decoration-thickness: 1.5px;
  text-underline-offset: .22em;
}

.mk-out__caret {
  display: inline-block;
  inline-size: 2px;
  block-size: 1.15em;
  margin-inline-start: 1px;
  vertical-align: -.2em;
  border-radius: 1px;
  background: var(--color-cyan);
  animation: mk-caret 1.06s steps(1) infinite;
}

@keyframes mk-caret {
  50% { opacity: 0; }
}

.mk-out.is-empty::after {
  content: attr(data-placeholder);
  color: var(--color-muted);
}

/* ---------------------------------------------------------------- panel only (`panelOnly`, e.g. story steps on a phone) */

.mk--solo .mk-in { padding-block-start: 0; }

.mk--solo .mk-panel {
  position: relative;
  inset: auto;
  min-block-size: 0;
}

.mk--solo .mk-panel__in {
  position: relative;
  inset: auto;
  padding-block-start: calc(4 * var(--u));
}

.mk--solo .mk-panel__scroll { overflow: visible; }
.mk--solo .mk-think { min-block-size: calc(150 * var(--u)); }
