/* =============================================================================
 * Kiviland v3 — the founder's second and third passes (2026-09-06):
 *   the simple flat kivi (the one that walks through the sky), plain greens, no neon
 *   the menu dial (collapsed to the chosen mode, opens on hover)
 *   the pane as wide as the connectors sheet, room at the top and bottom, an obvious left/right
 *   the keyboard key (closed by default) · the speaker in a circle
 *   the home stamp · the avatar with its quota ring and first name · the orange wrench
 *   the room line and the breathing dial · numbered errand headers
 *   disconnect: everything greys, the kivi asks to connect under a radial glow
 * Loaded last; overrides earlier sheets on purpose.
 * ========================================================================== */

:root {
  --kl-leaf: #3d8b4a;            /* the kiwi's own green, from the sky plates */
  --kl-leaf-deep: #2f6f3b;
  --kl-leaf-soft: #cfe6d0;
  --gold: #c9922e;               /* the last five minutes, the room's 'moderate' dot: a calm amber (was never defined) */
  --kl-leaf-glow: rgba(61, 139, 74, 0.35);
  --kl-disc: #f6f2e5;             /* the cream the kiwi stands on (sampled from the stills and loops) */
  --kl-paper-grey: rgba(234, 234, 230, 0.96); /* D36: walkie's paper — the cream goes cool while the button waits */
  --kl-paper-opaque: #fcfaf3;     /* the same cream at alpha 1: chrome a phone must not see through */
  --kl-orange: #e8892b;          /* D55: the apps word. A warm, unlit orange — the old #ff7a1a lit up like a signal */
  /* D66: the ONE phone breakpoint. A media query cannot read a custom property, so this token
     does not drive the phone blocks at the foot of this sheet — it NAMES them, next to the
     colours, and `test/kiviland-app.test.mjs` asserts that it, every phone media query in this
     sheet and `PHONE_MAX_PX` in `kl-device.js` are the same number. Two disagreeing thresholds
     are what left the page half in each layout between 641 and 664. */
  --kl-phone-max: 640px;
  --kl-pane-w: clamp(460px, 42vw, 620px);
  --kl-pane-pad-y: 40px;
  --kl-pane-pad-x: 28px;
  --kl-gutter: 72px;            /* the orb is 64px: a gutter narrower than it clips the disc at the scroller's edge */
  --kl-orb: 64px;
  --kl-mark: 44px;
}

/* ------------------------------------------------------------ the flat kivi */
.kl-orb.is-v2::before { background: radial-gradient(circle, var(--kl-leaf-glow) 0%, rgba(61, 139, 74, 0.12) 45%, transparent 70%); }
.kl-orb.is-v2 { --kl-bloom: calc(4px + 22px * var(--kl-level, 0)); }
.kl-orb.is-v2 .kl-orb__disc { background: var(--kl-disc); box-shadow: 0 0 0 2px var(--kl-leaf), 0 0 var(--kl-bloom) var(--kl-leaf-glow), 0 2px 6px rgba(0, 0, 0, 0.08); }
.kl-orb.is-v2 .kl-wash { opacity: 0.22; mix-blend-mode: multiply; }
/* the kiwi fills the disc, edge to edge (the founder, 2026-09-07: one coherent circle, not a square card inside it);
   the frame's cream is the disc's, so the circle is all there is to see */
.kl-orb.is-v2 .kl-orb__disc > img, .kl-orb.is-v2 .kl-orb__disc > video { position: absolute; inset: 0; width: 100%; height: 100%; padding: 0; border-radius: 50%; object-fit: cover; z-index: 2; filter: none; }
.kl-orb.is-v2.is-muted .kl-orb__disc, .kl-stage[data-muted='true'] .kl-orb.is-v2 .kl-orb__disc { box-shadow: 0 0 0 2px var(--hairline-strong); filter: saturate(0.4); }
.kl-dots i { background: var(--kl-leaf); }
.kl-state::before { background: currentColor; }
.kl-stage[data-phase='kivi'] .kl-state, .kl-stage[data-phase='greeting'] .kl-state { color: var(--kl-leaf-deep); }

/* ------------------------------------------------------- the listening pulse */
/* kivi is listening (waiting with the mic open, or you speaking): the disc breathes and two rings leave it
   in turn. CSS only, keyed on the stage, so it never depends on a timer the tab may throttle. */
.kl-orb__pulse { position: absolute; inset: 0; border-radius: 50%; border: 1.5px solid var(--kl-leaf); opacity: 0; pointer-events: none; z-index: 0; will-change: transform, opacity; }
.kl-stage[data-phase='waiting'][data-mic='open'] .kl-orb .kl-orb__pulse, .kl-stage[data-phase='you'] .kl-orb .kl-orb__pulse { animation: kl-orb-pulse 2.4s cubic-bezier(0.2, 0.6, 0.3, 1) infinite; }
.kl-stage[data-phase='waiting'][data-mic='open'] .kl-orb .kl-orb__pulse--2, .kl-stage[data-phase='you'] .kl-orb .kl-orb__pulse--2 { animation-delay: 1.2s; }
.kl-stage[data-phase='waiting'][data-mic='open'] .kl-orb .kl-orb__disc, .kl-stage[data-phase='you'] .kl-orb .kl-orb__disc { animation: kl-orb-breathe 2.4s ease-in-out infinite; }
@keyframes kl-orb-pulse { 0% { transform: scale(1); opacity: 0.6; } 60% { opacity: 0.18; } 100% { transform: scale(1.8); opacity: 0; } }
@keyframes kl-orb-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
/* the head's dot keeps time with it */
.kl-stage[data-phase='waiting'][data-mic='open'] .kl-state::before, .kl-stage[data-phase='you'] .kl-state::before { animation: kl-state-pulse 2.4s ease-in-out infinite; }
@keyframes kl-state-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.6); opacity: 0.55; } }
/* the floor seat holds the orb and its dots now (the mark lives in your gutter) */
.kl-floor__mark { height: auto; min-height: 64px; gap: 10px; overflow: visible; }
.kl-floor__mark .kl-dots { order: -1; } /* the dots rise from the orb, not hang under it */
.kl-floor__mark .kl-orb { order: 0; }
.kl-floor__mark .kl-dots--up { gap: 5px; }

/* ------------------------------------------------------- the listening focus */
/* while you speak the orb comes to the centre and grows; the words being heard run under it;
   the transcript, the head and the floor blur behind. D33. */
.kl-pane__focus { position: absolute; inset: 0; z-index: 3; display: grid; align-content: center; justify-items: center; gap: 44px; padding: 0 var(--kl-pane-pad-x); pointer-events: none; }
/* the seat is a grid: the dots on the first row, kivi's orb and your avatar on the second, in the
   same cell, so one can fade into the other (D33, the founder's second pass) */
.kl-focus__seat { --kl-orb: 136px; --kl-mark: 136px; display: grid; grid-template-rows: auto auto; justify-items: center; row-gap: 16px; }
.kl-focus__seat .kl-dots { grid-row: 1; grid-column: 1; --kl-amp: 1.7; }
.kl-focus__seat .kl-dots--up { gap: 7px; }
.kl-focus__seat .kl-dots i:nth-child(1) { width: 6px; height: 6px; }
.kl-focus__seat .kl-dots i:nth-child(2) { width: 9px; height: 9px; }
.kl-focus__seat .kl-dots i:nth-child(3) { width: 12px; height: 12px; }
.kl-focus__seat .kl-orb, .kl-focus__seat .kl-mark { grid-row: 2; grid-column: 1; }
.kl-focus__seat .kl-speaker { display: none; }
/* the cross-fade: kivi's orb arrives, then gives way to you */
.kl-focus__seat .kl-orb { transition: opacity 380ms var(--ease), transform 380ms var(--ease); }
.kl-pane.is-focus-you .kl-focus__seat .kl-orb { opacity: 0; transform: scale(0.9); pointer-events: none; }
.kl-pane.is-focus-you .kl-focus__seat .kl-orb .kl-orb__pulse { animation: none; opacity: 0; }
.kl-focus__seat .kl-mark { opacity: 0; transform: scale(0.94); transition: opacity 380ms var(--ease), transform 380ms var(--ease), box-shadow 80ms linear; }
.kl-pane.is-focus-you .kl-focus__seat .kl-mark { opacity: 1; transform: none; }
/* your pulse: the same rings, in the listening amber, and a halo that swells with your voice */
.kl-mark__pulse { position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--kl-state-listening); opacity: 0; pointer-events: none; z-index: 0; }
.kl-pane.is-focus-you .kl-focus__seat .kl-mark .kl-mark__pulse { animation: kl-orb-pulse 2.4s cubic-bezier(0.2, 0.6, 0.3, 1) infinite; }
.kl-pane.is-focus-you .kl-focus__seat .kl-mark .kl-mark__pulse--2 { animation-delay: 1.2s; }
.kl-focus__seat .kl-mark { box-shadow: 0 0 0 2.5px var(--kl-state-listening), 0 0 0 calc(8px + 26px * var(--kl-mark-lvl, 0)) rgba(151, 55, 4, 0.12), 0 0 calc(28px + 44px * var(--kl-mark-lvl, 0)) rgba(151, 55, 4, 0.3), 0 12px 30px rgba(0, 0, 0, 0.14); }
.kl-focus__seat .kl-mark::after, .kl-focus__seat .kl-mark::before { display: none; }
.kl-focus__seat .kl-mark__stencil { position: relative; z-index: 1; }
/* the halo swells with your voice (--kl-mic from the orb); the rings keep their own time */
.kl-focus__seat .kl-orb.is-v2 .kl-orb__disc { box-shadow: 0 0 0 2.5px var(--kl-leaf), 0 0 0 calc(8px + 26px * var(--kl-mic, 0)) rgba(61, 139, 74, 0.12), 0 0 calc(28px + 44px * var(--kl-mic, 0)) var(--kl-leaf-glow), 0 12px 30px rgba(0, 0, 0, 0.12); transition: box-shadow 80ms linear; }
.kl-focus__seat .kl-orb .kl-orb__pulse { border-width: 2px; }
.kl-focus__caption { margin: 0; max-width: 76%; min-height: 1.6em; text-align: center; font-family: var(--font-serif); font-style: italic; font-size: 1.1875rem; line-height: 1.5; color: var(--ink1); text-wrap: balance; }
.kl-focus__caption:empty { display: none; }
.kl-focus__caption .kl-word { display: inline; opacity: 0; animation: kl-word-in 160ms var(--ease) forwards; }
.kl-focus__caption .is-interim { color: var(--ink2); }
.kl-scroller, .kl-floor, .kl-pane__head { transition: filter 320ms var(--ease), opacity 320ms var(--ease); }
.kl-pane.is-focus .kl-scroller, .kl-pane.is-focus .kl-floor, .kl-pane.is-focus .kl-pane__head { filter: blur(7px); opacity: 0.42; pointer-events: none; }
.kl-stage[data-perf='low'] .kl-pane.is-focus .kl-scroller, .kl-stage[data-perf='low'] .kl-pane.is-focus .kl-floor { filter: none; opacity: 0.3; }

/* --------------------------------------------------------------- the pane */
/* depth: a long soft shadow onto the scene, a hairline of light along the top edge */
.kl-pane { box-shadow: 0 34px 90px -34px rgba(20, 22, 20, 0.5), 0 2px 8px rgba(20, 22, 20, 0.06), inset 0 1px 0 rgba(255, 255, 255, 0.7); }
/* kivi's card while it is being said: a breath of leaf around it, gone once it is done */
.kl-card { transition: transform 300ms var(--ease), color 300ms var(--ease), background-color 300ms var(--ease), border-color 400ms var(--ease), box-shadow 400ms var(--ease); }
/* D34 — the spawn card: the invitation reads as an aside under the marque line */
.kl-card--invite .kl-card__text { color: var(--ink2); }
/* The flow grows from the BOTTOM (`justify-content: flex-end`), which put the one invitation card
   exactly where the connect orb stands — the orb sat across its own instruction at every width.
   At spawn the card goes to the top of the scroller and leaves the centre to the orb. */
.kl-stage[data-phase='spawn'] .kl-flow { justify-content: flex-start; }
.kl-turn--kivi .kl-card.is-writing, .kl-turn--centre .kl-card.is-writing { border-color: var(--kl-leaf-soft); box-shadow: 0 0 0 3px rgba(61, 139, 74, 0.08); }
/* the copy law, enforced where the words are drawn: the cascade's persona capitalises, the page does not */
/* the words are shown as they were said and written — capitals and punctuation intact (the founder, 2026-09-07); the old lowercase law is gone */
.kl-card__text, .kl-card__lead, .kl-focus__caption { text-transform: none; }
/* your words: the amber of the listening ring on the mark, kept to a hairline */
.kl-turn--you .kl-card { border-left: 2px solid rgba(151, 55, 4, 0.18); }

.kl-pane { width: var(--kl-pane-w); left: calc((100vw - var(--kl-pane-w)) / 2); }
.kl-pane__head { top: 16px; left: var(--kl-pane-pad-x); right: var(--kl-pane-pad-x); }
/* the floor: the orb and its dots on the top row, the suggestion line under them, the key at the left.
   The conversation sits above it and grows upward from the orb, like a talk does */
.kl-scroller { inset: var(--kl-pane-pad-y) var(--kl-pane-pad-x) 148px; }
.kl-flow { padding: 16px 0 24px; gap: 18px; min-height: 100%; justify-content: flex-end; }
.kl-floor { --kl-floor-bottom: 16px; height: 132px; bottom: var(--kl-floor-bottom); grid-template-columns: 1fr; grid-template-rows: 1fr auto; row-gap: 8px; }
/* one column, always: a note landing beside the seat (or beside the suggestion line) used to open a
   second column and push the orb and the line left of centre */
.kl-floor > * { grid-column: 1; }
.kl-floor .kl-ticker, .kl-floor .kl-hint, .kl-floor .kl-note, .kl-floor.is-text-only .kl-note { grid-row: 2; }
.kl-floor.is-text-only .kl-ticker { grid-row: 2; margin-bottom: 0; }
/* a note takes the suggestion line's place while it shows */
.kl-floor:has(.kl-note.is-in) .kl-ticker { opacity: 0; }
/* left and right are two different places: you sit on the left edge with your avatar, kivi on the right edge
   under its orb; each side leaves a clear stretch of the width empty on the other side */
.kl-turn { grid-template-columns: var(--kl-gutter) minmax(0, 1fr) var(--kl-gutter); }
/* the orb and the mark sit in front of the cards, whole */
.kl-turn__gutter { z-index: 2; overflow: visible; }
.kl-turn--you .kl-card { margin-right: 18%; border-top-left-radius: 4px; }
.kl-turn--kivi .kl-card, .kl-turn--nudge .kl-card, .kl-turn--clipping .kl-card, .kl-turn--approval .kl-card { margin-left: 18%; border-top-right-radius: 4px; }
.kl-turn--centre .kl-card { margin: 0 6%; }
.kl-card { padding: 14px 16px; }
/* the speaker: a circle you can see */
.kl-pane__speaker, .kl-orb__speaker, .kl-speaker { width: 34px; height: 34px; border-radius: 50%; display: inline-grid; place-items: center; border: 1px solid var(--hairline-strong); background: var(--surface1); color: var(--ink1); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06); }
.kl-pane__speaker:empty { display: none; }
.kl-pane__speaker svg, .kl-orb__speaker svg, .kl-speaker svg { width: 16px; height: 16px; }
.kl-stage[data-muted='true'] .kl-speaker { color: var(--kl-state-listening); border-color: currentColor; }

.kl-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: 9999px; background: var(--kl-pill-green); color: #fff; border: 0; font: inherit; font-size: 0.8125rem; cursor: pointer; box-shadow: 0 0 0 3px var(--kl-lavender); }
.kl-chip:hover { background: #256b4c; }

/* D73: the room line's rules are gone with the reading itself — room sense is a VAD
   preset now and draws nothing. `.kl-chip` (its suggestion chip's base) is kept: it is the
   generic chip. */

/* the keyboard key: bottom-left of the pane, closed by default; the field opens beside it */
.kl-typekey { position: absolute; left: calc(var(--kl-pane-pad-x) - 12px + 46px); bottom: calc(var(--kl-keys-bottom, 42px) - var(--kl-floor-bottom, 16px)); width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--hairline-strong); background: var(--surface1); color: var(--ink2); display: grid; place-items: center; cursor: pointer; z-index: 2; transition: color 120ms var(--ease), transform 120ms var(--ease), box-shadow 200ms var(--ease); }
.kl-typekey:hover { color: var(--ink1); transform: translateY(-1px); }
.kl-typekey[aria-expanded='true'] { color: var(--accent); border-color: var(--accent); }
.kl-typekey:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.kl-floor.is-text-only .kl-typekey { box-shadow: 0 0 0 4px rgba(61, 139, 74, 0.18); color: var(--accent); }
.kl-type { position: absolute; left: calc(var(--kl-pane-pad-x) - 12px + 96px); right: calc(var(--kl-pane-pad-x) - 12px + 50px); bottom: 26px; margin: 0; }
.kl-type[hidden] { display: none; }
.kl-type__field { width: 100%; height: 38px; padding: 0 14px; border-radius: 9999px; border: 1px solid var(--hairline-strong); background: var(--surface1); font: inherit; font-size: 0.9375rem; color: var(--ink1); }
.kl-type__field:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--kl-lavender); }
.kl-floor .kl-hint { left: calc(var(--kl-pane-pad-x) - 12px + 96px); right: calc(var(--kl-pane-pad-x) - 12px + 50px); text-align: left; }
.kl-floor .kl-ticker { bottom: auto; }
.kl-stage[data-phase='closed'] .kl-typekey, .kl-stage[data-phase='gate'] .kl-typekey { opacity: 0.35; pointer-events: none; }

/* ---------------------------------------------------------- the menu dial */
.kl-dial[data-layout='menu'] { left: var(--kl-dial-x); top: 50%; transform: translateY(-50%); width: auto; height: auto; overflow: visible; padding: 0; background: none; border: 0; backdrop-filter: none; -webkit-backdrop-filter: none; opacity: 1; filter: none; -webkit-mask-image: none; mask-image: none; }
.kl-dial__current { display: inline-flex; align-items: center; gap: 10px; padding: 6px 14px 6px 6px; border-radius: 9999px; background: var(--kl-glass); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); border: 1px solid var(--hairline); font: inherit; color: var(--ink1); cursor: pointer; transition: box-shadow 200ms var(--ease), transform 200ms var(--kl-ease-soft), opacity 200ms var(--ease); opacity: 0.94; }
.kl-dial__current:hover, .kl-dial[data-layout='menu'].is-open .kl-dial__current { opacity: 1; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14); }
.kl-dial__pill { font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.01em; }
.kl-dial__current::after { content: '▾'; font-size: 0.75rem; color: var(--ink2); margin-left: 2px; transition: transform 200ms var(--ease); }
.kl-dial[data-layout='menu'].is-open .kl-dial__current::after { transform: rotate(180deg); }
.kl-dial__menu { position: absolute; left: 0; top: calc(100% + 8px); width: 300px; transform: none !important; display: grid; gap: 6px; padding: 8px; border-radius: var(--r-md); background: var(--kl-glass); -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); border: 1px solid var(--hairline); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18); opacity: 0; pointer-events: none; transform-origin: top left; scale: 0.96; translate: 0 -4px; transition: opacity 160ms var(--ease), scale 200ms var(--kl-ease-soft), translate 200ms var(--kl-ease-soft); }
.kl-dial__menu::before { display: none; }
.kl-dial[data-layout='menu'].is-open .kl-dial__menu { opacity: 1; pointer-events: auto; scale: 1; translate: 0 0; }
.kl-dial[data-layout='menu'] .kl-dial__stop { display: grid; grid-template-columns: 48px 1fr; column-gap: 10px; align-items: center; height: auto; padding: 8px 10px 8px 6px; border-radius: 12px; background: var(--surface1); border: 1px solid transparent; text-align: left; cursor: pointer; color: var(--ink1); box-sizing: border-box; width: 100%; transition: background 120ms var(--ease), border-color 120ms var(--ease), transform 120ms var(--ease); }
/* D41: hover is a MOUSE affordance. On a touch screen it sticks to the last row a finger touched
   and reads as a selection that is not there — the pressed state below is what a thumb gets. */
@media (hover: hover) {
  .kl-dial[data-layout='menu'] .kl-dial__stop:hover { background: var(--surface2); transform: translateX(2px); }
}
.kl-dial[data-layout='menu'] .kl-dial__stop { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
.kl-dial[data-layout='menu'] .kl-dial__stop.is-pressed { background: var(--surface2); transform: scale(0.985); transition-duration: 60ms; }
.kl-dial[data-layout='menu'] .kl-dial__stop[aria-checked='true'] { border-color: var(--kl-leaf); box-shadow: 0 0 0 3px rgba(61, 139, 74, 0.16); }
.kl-dial[data-layout='menu'] .kl-dial__still, .kl-dial__still--current { grid-column: 1; grid-row: 1; width: 44px; height: 44px; opacity: 1; padding: 0; border-radius: 50%; object-fit: cover; background: var(--kl-disc); box-shadow: 0 0 0 1.5px var(--kl-leaf); }
/* column 2, named rather than auto-placed: at ≤900 the tablet block hides `.kl-dial__still`, which
   takes it out of the grid entirely — and the text then flowed into the 48px column the still had
   left behind, which is what turned every phone caption into a one-word-per-line tower. */
.kl-dial__text { display: grid; gap: 2px; min-width: 0; grid-column: 2; }
.kl-dial[data-layout='menu'] .kl-dial__label { grid-column: auto; font-size: 0.9375rem; font-weight: 600; color: var(--ink1); letter-spacing: 0.01em; }
.kl-dial[data-layout='menu'] .kl-dial__caption { grid-column: auto; opacity: 1; font-size: 0.75rem; line-height: 1.3; color: var(--ink2); padding: 3px 8px; border-radius: 6px; background: var(--surface2); border: 1px solid var(--hairline); display: inline-block; justify-self: start; }
.kl-dial[data-layout='menu'] .kl-dial__stop[aria-checked='true'] .kl-dial__caption { background: var(--kl-leaf-soft); border-color: var(--kl-leaf); color: var(--ink1); }
.kl-dial[data-layout='menu'] .kl-dial__stop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kl-stage[data-mode='eager'] .kl-dial__still--current { animation: kl-hop 600ms var(--kl-ease-soft) 1; }
.kl-dial.is-breathing .kl-dial__current { animation: kl-dial-breathe 1.6s ease-in-out infinite; box-shadow: 0 0 0 4px var(--kl-leaf-glow), 0 0 28px var(--kl-leaf-glow); }
/* its own name: `kl-breathe` belongs to the dots (kiviland.css), and a second definition here silenced them */
@keyframes kl-dial-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.kl-stage[data-connectors='open'] .kl-dial[data-layout='menu'], .kl-stage[data-phase='closed'] .kl-dial[data-layout='menu'] { opacity: 0.35; pointer-events: none; }

/* =============================================================================
 * D36 / D37 / D38 — walkie: kivi's orb IS the button.
 *
 * Everything here is under `[data-mode='walkie']` or `.kl-orb.is-button`, so
 * eager and patient are not touched by one declaration of it.
 * ========================================================================== */

/* the paper goes cool grey while the button waits, and back to the translucent cream of the
   listening focus the moment the press is down — the two states of the room, in one colour */

/* the floor has to be tall enough to stand a 96px button in. The old walkie rule scaled the
   44px mark by 1.2 for the same reason and is gone: the orb is the thing now. */
.kl-stage[data-mode='walkie'] .kl-floor { height: 140px; }
.kl-stage[data-mode='walkie'] .kl-floor__mark { height: 104px; transform: none; }
.kl-stage[data-mode='walkie'] .kl-scroller { bottom: 168px; }
/* the floor rides higher in walkie on a phone: the caption hangs 10px BELOW the 136px orb, and at
   the plain height it was drawn under the control bar */
.kl-stage[data-layout='phone'][data-mode='walkie'] .kl-floor { --kl-floor-bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 34px); height: 176px; bottom: var(--kl-floor-bottom); }
.kl-stage[data-layout='phone'][data-mode='walkie'] .kl-floor__mark { height: 144px; }
.kl-stage[data-layout='phone'][data-mode='walkie'] .kl-scroller { bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 214px); }

/* the button, only where it is a button: at the floor, between turns. In a card's gutter or in
   the focus the orb is 52px and wearing nobody's glow — the size is a property, not a rule, so
   whichever host it is sitting in keeps its own. */
.kl-floor__mark .kl-orb.is-button { --kl-orb: 96px; cursor: pointer; }
.kl-stage[data-layout='phone'] .kl-floor__mark .kl-orb.is-button { --kl-orb: 136px; }
.kl-orb.is-button .kl-orb__disc { touch-action: none; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; }
.kl-floor__mark .kl-orb.is-button .kl-orb__disc { box-shadow: 0 0 0 2px var(--kl-leaf), 0 0 16px var(--kl-leaf-glow), 0 6px 18px rgba(0, 0, 0, 0.12); animation: kl-button-glow 2.4s ease-in-out infinite; }
.kl-floor__mark .kl-orb.is-button .kl-orb__disc:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
@keyframes kl-button-glow {
  0%, 100% { box-shadow: 0 0 0 2px var(--kl-leaf), 0 0 16px var(--kl-leaf-glow), 0 6px 18px rgba(0, 0, 0, 0.12); }
  50% { box-shadow: 0 0 0 3px var(--kl-leaf), 0 0 30px var(--kl-leaf-glow), 0 6px 18px rgba(0, 0, 0, 0.12); }
}
/* pressed or latched: the glow gives way to the listening amber, and the disc sinks a little.
   D45 — `is-held` and `--kl-held-level` are the SEAT's now, not the orb's: the orb travels into a
   card's gutter while kivi speaks and the button must not travel with it. */
.kl-stage[data-mode='walkie'] .kl-floor__mark.is-held .kl-orb.is-button .kl-orb__disc { animation: none; transform: scale(0.97); box-shadow: 0 0 0 2.5px var(--kl-state-listening), 0 0 calc(20px + 40px * var(--kl-held-level, 0)) rgba(151, 55, 4, 0.34), 0 6px 18px rgba(0, 0, 0, 0.12); }

/* ---------------------------------------------------------------- D45 / D46
 * The press target is the SEAT, and your avatar holds it while kivi speaks.
 *
 * The seat is the one element in the floor no phase relocates. In walkie it is
 * a one-column grid so that whatever disc is standing in it — kivi's orb, your
 * bright avatar in the listening focus, or the quiet user key below — occupies
 * the SAME cell: identical box, identical position, no layout shift between
 * phases. (`is-focus-host` says the same thing for the focus and still wins.)
 * ========================================================================== */
/* the box is FIXED, not the sum of what happens to be standing in it: a seat that shrank to its
   contents collapsed to zero width the moment a turn ended with the orb elsewhere, and a target
   with no width is a button that is not there (D45) */
.kl-stage[data-mode='walkie'] .kl-floor__mark { width: 96px; display: grid; grid-template-rows: auto auto; justify-items: center; align-content: end; cursor: pointer; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; }
.kl-stage[data-layout='phone'][data-mode='walkie'] .kl-floor__mark { width: 136px; }
.kl-stage[data-mode='walkie'] .kl-floor__mark > .kl-orb,
.kl-stage[data-mode='walkie'] .kl-floor__mark > .kl-mark { grid-row: 1; grid-column: 1; }
.kl-stage[data-mode='walkie'] .kl-floor__mark > .kl-dots { grid-row: 2; grid-column: 1; }
.kl-stage[data-mode='walkie'] .kl-floor__mark:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 9999px; }

/* D46 — the user key: your animal, on the orb's disc, at a third of its shine. It is the same
   `.kl-mark` element the listening focus uses (which rests at 0 and rises to 1 as you take the
   floor) — this is the quiet middle of that treatment, and it is why the two cannot disagree
   about the box. It is never a control of its own: the seat under it is. */
.kl-stage[data-mode='walkie'] .kl-floor__mark { --kl-mark: 96px; }
.kl-stage[data-layout='phone'][data-mode='walkie'] .kl-floor__mark { --kl-mark: 136px; }
.kl-stage[data-mode='walkie'] .kl-mark.is-key { opacity: 0.38; transition: opacity 220ms var(--ease), transform 220ms var(--ease), box-shadow 80ms linear; box-shadow: 0 0 0 2px rgba(90, 138, 58, 0.34), 0 6px 18px rgba(0, 0, 0, 0.1); }
.kl-stage[data-mode='walkie'] .kl-mark.is-key .kl-mark__pulse { display: none; }
.kl-stage[data-mode='walkie'] .kl-mark.is-key::after, .kl-stage[data-mode='walkie'] .kl-mark.is-key::before { display: none; }
/* pressed: the same sink and the same listening ring the orb takes, from the same class on the seat */
.kl-stage[data-mode='walkie'] .kl-floor__mark.is-held .kl-mark.is-key { opacity: 0.82; transform: scale(0.97); box-shadow: 0 0 0 2.5px var(--kl-state-listening), 0 0 calc(20px + 40px * var(--kl-held-level, 0)) rgba(151, 55, 4, 0.34), 0 6px 18px rgba(0, 0, 0, 0.12); }

/* the line beneath it — only at the floor, only between turns: the orb wears this class wherever
   it travels, and a caption under a card's gutter would be nonsense */
.kl-orb__hint { display: none; position: absolute; left: 50%; top: calc(100% + 10px); transform: translateX(-50%); white-space: nowrap; font-size: 0.8125rem; line-height: 18px; font-weight: 600; color: var(--ink1); padding: 5px 12px; border-radius: 9999px; background: var(--kl-glass-strong); border: 1px solid var(--hairline); pointer-events: none; }
.kl-stage[data-phase='waiting'] .kl-floor__mark .kl-orb.is-button .kl-orb__hint { display: block; }

/* D38 — the focus, in place. The transcript and the head blur; the floor does NOT, because the
   thing being focused is standing in it. */
/* the low-perf rule below (`data-perf='low'`, which every screen ≤900 gets) outranked this one and
   dimmed the whole floor to .3 — the button, your avatar and its rings with it */
.kl-pane.is-focus.is-focus-floor .kl-floor,
.kl-stage[data-perf='low'] .kl-pane.is-focus.is-focus-floor .kl-floor { filter: none; opacity: 1; pointer-events: auto; }
/* the words being heard sit just above the floor the button is standing in: 140 for the floor,
   20 for the pane's own gap under it, and a line of air */
.kl-pane.is-focus-floor .kl-pane__focus { align-content: end; padding-bottom: 172px; gap: 0; }
.kl-stage[data-layout='phone'] .kl-pane.is-focus-floor .kl-pane__focus { padding-bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 196px); }
.kl-pane.is-focus-floor .kl-focus__seat { display: none; }
/* your mark, on the disc kivi was standing on: the same amber rings and level halo D33 gives it
   in the centre, at the button's size. The selectors are listed rather than folded into an
   `:is()` on purpose — `:is()` takes its widest argument's specificity, and eager and patient
   must resolve exactly as they did. */
.kl-floor__mark.is-focus-host { --kl-orb: 96px; --kl-mark: 96px; }
.kl-stage[data-layout='phone'] .kl-floor__mark.is-focus-host { --kl-orb: 136px; --kl-mark: 136px; }
.kl-floor__mark.is-focus-host .kl-orb, .kl-floor__mark.is-focus-host .kl-mark { grid-row: 1; grid-column: 1; }
.kl-floor__mark.is-focus-host { display: grid; justify-items: center; align-content: end; }
.kl-floor__mark.is-focus-host .kl-orb { transition: opacity 160ms var(--ease), transform 160ms var(--ease); }
.kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-orb { opacity: 0; transform: scale(0.9); pointer-events: none; }
.kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-orb .kl-orb__pulse { animation: none; opacity: 0; }
.kl-floor__mark.is-focus-host .kl-mark { opacity: 0; transform: scale(0.94); transition: opacity 380ms var(--ease), transform 380ms var(--ease), box-shadow 80ms linear; }
.kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-mark { opacity: 1; transform: none; }
.kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-mark .kl-mark__pulse { animation: kl-orb-pulse 2.4s cubic-bezier(0.2, 0.6, 0.3, 1) infinite; }
.kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-mark .kl-mark__pulse--2 { animation-delay: 1.2s; }
.kl-floor__mark.is-focus-host .kl-mark { box-shadow: 0 0 0 2.5px var(--kl-state-listening), 0 0 0 calc(8px + 26px * var(--kl-mark-lvl, 0)) rgba(151, 55, 4, 0.12), 0 0 calc(28px + 44px * var(--kl-mark-lvl, 0)) rgba(151, 55, 4, 0.3), 0 12px 30px rgba(0, 0, 0, 0.14); }
.kl-floor__mark.is-focus-host .kl-mark::after, .kl-floor__mark.is-focus-host .kl-mark::before { display: none; }
.kl-floor__mark.is-focus-host .kl-mark__stencil { position: relative; z-index: 1; }
.kl-floor__mark.is-focus-host .kl-orb__hint, .kl-floor__mark.is-focus-host .kl-dots { display: none; }

/* while the press is down, the floor's two keys step out of the focus: they were sitting inside
   your avatar's outer ring */
.kl-stage[data-ptt='on'] .kl-typekey, .kl-stage[data-ptt='on'] .kl-newsession { opacity: 0; pointer-events: none; transition: opacity 200ms var(--ease); }

/* D39 — the press is the switch: the mic key has nothing left to say in walkie */
/* D60: the floor mic stays beside the keyboard in every mode on the wide layout */
/* and the floor's keycap hint is the orb's own line now — one instruction, under the thing it
   is about, rather than two in different corners */
.kl-stage[data-mode='walkie'] .kl-hint { display: none; }

/* walkie-talkie: the sphere is the thing, lit and labelled (the fallback for a page whose orb
   cannot be pressed; with the orb as the button `kl-slider.js` leaves it hidden) */
.kl-sphere { width: 84px; height: 84px; left: calc(var(--kl-dial-x) - 10px); background: var(--kl-disc); border: 2px solid var(--kl-leaf); box-shadow: 0 0 18px var(--kl-leaf-glow), 0 4px 12px rgba(0, 0, 0, 0.12); overflow: visible; }
.kl-sphere__stencil { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.kl-sphere__word { position: absolute; left: 50%; top: calc(100% + 8px); transform: translateX(-50%); white-space: nowrap; font-size: 0.8125rem; font-weight: 600; color: var(--ink1); padding: 4px 10px; border-radius: 9999px; background: var(--kl-glass); border: 1px solid var(--hairline); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); pointer-events: none; }
.kl-sphere.is-in.is-held { transform: scale(1.1); border-color: var(--kl-state-listening); box-shadow: 0 0 28px rgba(151, 55, 4, 0.35), 0 0 0 6px rgba(151, 55, 4, 0.18); }
.kl-sphere.is-in.is-held .kl-sphere__word { color: var(--kl-state-listening); }
.kl-sphere__caption { display: none; }
/* the sphere-era `.kl-hint { display: block }` is gone: it sat AFTER D36's `display: none` at the
   same specificity and quietly won, so walkie kept printing "space or press the orb to talk" in
   the floor as well as under the orb. */

/* D35 — the phone's bottom control bar. It exists only under 640 (see the block at the end). */
.kl-bar { display: none; z-index: 5; left: 0; right: 0; bottom: 0; height: calc(var(--kl-bar-h, 56px) + env(safe-area-inset-bottom)); background: var(--kl-glass-strong); -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); border-top: 1px solid var(--hairline); pointer-events: none; }

/* -------------------------------------------------------------- the chrome */
.kl-stage { --kl-keys-bottom: 42px; }
.kl-nav { gap: 16px; }
.kl-nav__stamp { position: relative; display: inline-grid; align-items: center; height: 40px; padding: 0 16px; border-radius: 9999px; text-decoration: none; color: var(--ink1); background: var(--kl-glass); border: 1px solid var(--hairline); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); overflow: hidden; }
.kl-nav__face { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; transition: opacity 160ms var(--ease), transform 200ms var(--kl-ease-soft); }
.kl-nav__face--home { opacity: 0; transform: translateY(8px); }
/* D69 — the three ways the home face is reached are one state. A pointer hovers it, a keyboard
   focuses it and a thumb presses it; all three swap the face, so all three must also swap the
   PILL (the green block at the foot of this sheet), or the cream wordmark and the white "home ↗"
   land on cream paper and the pill reads as empty. */
.kl-nav__stamp:hover .kl-nav__face--land, .kl-nav__stamp:focus-visible .kl-nav__face--land, .kl-nav__stamp:active .kl-nav__face--land { opacity: 0; transform: translateY(-8px); }
.kl-nav__stamp:hover .kl-nav__face--home, .kl-nav__stamp:focus-visible .kl-nav__face--home, .kl-nav__stamp:active .kl-nav__face--home { opacity: 1; transform: none; }
.kl-nav__stamp:hover { background: var(--kl-pill-green); color: #fff; border-color: transparent; box-shadow: 0 0 0 3px var(--kl-lavender); }
.kl-nav__stamp:hover .kl-nav__ink, .kl-nav__stamp:focus-visible .kl-nav__ink, .kl-nav__stamp:active .kl-nav__ink { display: none; }
.kl-nav__stamp:hover .kl-nav__cream, .kl-nav__stamp:focus-visible .kl-nav__cream, .kl-nav__stamp:active .kl-nav__cream { display: block; }
.kl-nav__face--home img { height: 18px; width: auto; }
.kl-nav__home { font-size: 0.875rem; font-weight: 500; }
.kl-stage[data-band='night'] .kl-nav__stamp, .kl-stage[data-band='evening'] .kl-nav__stamp { color: var(--ink1); }
.kl-nav__name { position: relative; overflow: visible; cursor: default; font-size: 0.9375rem; font-weight: 500; color: var(--ink1); padding: 7px 16px; border-radius: 9999px; background: var(--kl-glass); border: 1px solid var(--hairline); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kl-nav__name[hidden] { display: none; }
.kl-nav__profile { position: relative; width: 44px; height: 44px; padding: 0; border-radius: 50%; border: 0; background: #06070e; box-shadow: 0 0 0 1px var(--hairline-strong); overflow: visible; cursor: pointer; display: grid; place-items: center; }
.kl-nav__profile[hidden] { display: none; }
.kl-nav__avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; display: block; }
/* the fill: a small bottle of jelly behind the name — its length is the day's remaining time, the
   front a soft meniscus that settles, a highlight along the top, a shade deeper at the bottom */
.kl-nav__name .kl-fill { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; overflow: visible; pointer-events: none; color: var(--kl-leaf); }
.kl-nav__name-text { position: relative; z-index: 1; }
.kl-fill__jelly { fill: currentColor; opacity: 0.42; }
.kl-fill__gloss { fill: #fff; opacity: 0.34; }
.kl-fill__rim { fill: none; stroke: #fff; stroke-opacity: 0.75; stroke-width: 1.2; stroke-linecap: round; }
.kl-nav__name[data-quota='low'] .kl-fill { color: var(--gold); }
.kl-nav__name[data-quota='out'] .kl-fill { color: var(--kl-state-listening); }
/* hover on the name: how much of how much is left, on one line */
.kl-nav__name[data-tip]::after { content: attr(data-tip); position: absolute; top: calc(100% + 8px); right: 0; z-index: 9; white-space: nowrap; font-size: 0.75rem; font-weight: 500; line-height: 1; padding: 7px 10px; border-radius: 8px; background: var(--ink1); color: #fff; opacity: 0; transform: translateY(-4px); pointer-events: none; transition: opacity 140ms var(--ease), transform 140ms var(--ease); }
.kl-nav__name[data-tip]:hover::after, .kl-nav__name[data-tip]:focus-visible::after { opacity: 1; transform: none; }
.kl-nav__profile:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.kl-popover { width: 272px; gap: 10px; }
.kl-popover__quota { margin: 0; font-family: var(--font-marque); font-size: 1.25rem; color: var(--kl-leaf-deep); }
.kl-popover__quota small { display: block; font-family: var(--font-body); font-size: 0.75rem; color: var(--ink2); margin-top: 2px; }
.kl-popover__quota.is-low { color: var(--gold); }
.kl-popover__quota.is-out { color: var(--kl-state-listening); }
.kl-popover__label { margin: 0; font-size: 0.75rem; color: var(--ink2); }
.kl-popover__pick { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin: 0; padding: 0; list-style: none; }
.kl-popover__pick button { width: 100%; aspect-ratio: 1; padding: 0; border-radius: 50%; border: 2px solid transparent; background: #06070e; overflow: hidden; cursor: pointer; }
.kl-popover__pick img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.kl-popover__pick button[aria-pressed='true'] { border-color: var(--kl-leaf); box-shadow: 0 0 0 2px var(--kl-leaf-soft); }
.kl-popover__pick button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kl-wrench { display: inline-flex; align-items: center; justify-content: center; width: auto; height: 44px; padding: 0 18px; border-radius: 9999px; color: var(--kl-orange); background: var(--kl-glass); border: 1px solid var(--hairline); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); font: inherit; font-size: 1rem; }
.kl-wrench[hidden] { display: none; }
/* D55: no glyph at any width. The key is the word, and the word carries the colour. */
.kl-wrench__label { color: var(--kl-orange); font-weight: 700; letter-spacing: 0.01em; }
.kl-wrench:hover { box-shadow: 0 0 0 3px rgba(232, 137, 43, 0.22); }

/* ------------------------------------------------------------- disconnect */
.kl-stage[data-phase='closed']::after { content: ''; position: fixed; inset: 0; z-index: 6; pointer-events: none; background: radial-gradient(circle at 50% 50%, rgba(246, 243, 234, 0) 90px, rgba(246, 243, 234, 0.35) 220px, rgba(20, 22, 20, 0.45) 620px, rgba(20, 22, 20, 0.6) 100%); }
.kl-stage[data-phase='closed'] .kl-pane { opacity: 0.9; }
.kl-stage[data-phase='closed'] .kl-scroller { opacity: 0.35; }
.kl-connect { z-index: 7; }
.kl-connect:focus-visible { outline: none; }
.kl-connect__orb { background: var(--kl-disc); box-shadow: 0 0 0 3px var(--kl-leaf), 0 0 0 14px rgba(246, 243, 234, 0.55), 0 0 60px 20px rgba(246, 243, 234, 0.7), 0 10px 30px rgba(0, 0, 0, 0.25); }
.kl-connect__orb::after { background: radial-gradient(circle, var(--kl-leaf-glow) 0%, transparent 70%); }
.kl-connect__orb img, .kl-connect__orb video { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.kl-connect:focus-visible .kl-connect__orb { outline: 2px solid var(--accent); outline-offset: 6px; }
.kl-connect__word { color: var(--ink1); }

/* ---------------------------------------------------------- the sound key (D54)
   One speaker. Sound on: the cone and its two waves. Sound off: the waves go and the slash
   arrives — the same 45° stroke the microphone key uses, so a person learns one sign, not two.
   `aria-pressed` on this key is TRUE when the sound is ON (it is a "sound on" switch), which is
   the opposite sense to `.kl-micoff` below (pressed = muted); the rules read the attribute, not
   the word, so the asymmetry stays in one place. */
.kl-sound__glyph { display: inline-flex; align-items: center; height: auto; gap: 0; }
.kl-sound__glyph svg { display: block; }
.kl-sound .kl-sound__slash { opacity: 0; transition: opacity 140ms var(--ease); }
.kl-sound .kl-sound__wave { opacity: 1; transition: opacity 140ms var(--ease); }
.kl-sound[aria-pressed='false'] .kl-sound__wave { opacity: 0; }
.kl-sound[aria-pressed='false'] .kl-sound__slash { opacity: 1; }
.kl-sound[aria-pressed='false'] { color: var(--kl-state-listening); border-color: currentColor; }

/* ------------------------------------------------- the microphone key (D43)
   Beside the sound key at the bottom left, in the same paper chip and the same ink. The sound
   key gets a floor of 112px so the pair never shuffles when its word grows from "on" to "off". */
.kl-sound { min-width: 112px; }
/* D56: expanded, the microphone key stands ON TOP of the sound key rather than beside it — one
   column of switches at the bottom left, mic over sound, each with its own word. */
.kl-micoff {
  z-index: 5; left: 32px; bottom: 70px;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px 6px 12px; border-radius: 9999px;
  background: var(--kl-glass); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  border: 1px solid var(--hairline);
  font: inherit; font-size: 0.8125rem; color: var(--ink2); cursor: pointer;
  transition: color 140ms var(--ease), border-color 140ms var(--ease), opacity 260ms var(--ease);
}
.kl-micoff:hover { color: var(--ink1); }
.kl-micoff:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.kl-micoff__glyph { display: inline-flex; }
.kl-micoff__glyph svg { display: block; }
.kl-micoff .kl-micoff__slash { opacity: 0; transition: opacity 140ms var(--ease); }
/* pressed = the microphone is OFF: the slash, and the colour the floor's mic key uses */
.kl-micoff[aria-pressed='true'] { color: var(--kl-state-listening); border-color: currentColor; }
.kl-micoff[aria-pressed='true'] .kl-micoff__slash { opacity: 1; }
.kl-stage[data-mic='denied'] .kl-micoff, .kl-stage[data-phase='closed'] .kl-micoff { opacity: 0.35; pointer-events: none; }
.kl-stage[data-band='night'] .kl-micoff, .kl-stage[data-band='evening'] .kl-micoff { color: var(--ink2); }

/* ------------------------------------------------------------- the marks */
.kl-mark { background: #06070e !important; box-shadow: 0 0 0 1.5px var(--kl-leaf); overflow: visible; } /* visible: the listening ring and the pulse live outside the disc */
.kl-mark__stencil { width: 100% !important; height: 100% !important; border-radius: 50%; object-fit: cover; display: block; }

/* ---------------------------------------------------------- the errand rail */
.kl-pill__alias { font-family: var(--font-mono); font-size: 0.75rem; font-weight: 600; color: var(--ink1); }
.kl-pill__alias::before { content: '#'; color: var(--ink2); margin-right: 1px; }
.kl-pill__face { cursor: pointer; }

/* ------------------------------------------------------------ small screens */
@media (max-width: 900px) {
  .kl-dial[data-layout='menu'] { left: 12px; top: auto; bottom: 12px; transform: none; }
  .kl-dial__menu { top: auto; bottom: calc(100% + 8px); transform-origin: bottom left; }
  /* the insignia rides every width. kiviland.css's own ≤900 block hides `.kl-dial__still` for the
     old vertical track; that rule is scoped away from this layout now, and the sheet's rows and
     the pill keep their kiwi at a phone-sized 36px between 641 and 900 (a phone in landscape is
     in this band, and it was the one width where the rows showed a name and no face). */
  .kl-dial[data-layout='menu'] .kl-dial__still, .kl-dial[data-layout='menu'] .kl-dial__still--current { display: block; width: 36px; height: 36px; grid-column: 1; }
  .kl-dial[data-layout='menu'] .kl-dial__stop { grid-template-columns: 36px 1fr; }
  .kl-nav__name { display: none; }
  /* D66 — no width loses a control. This band used to hide the sound key (kiviland.css) and the
     microphone key with it, and put nothing in their place: the phone's control bar starts at
     641 px further down, so from 641 to 900 there was no mute and no microphone switch at all —
     and a phone held sideways (`data-phone='true'`, wider than 640) landed in exactly that hole
     with its floor mic hidden too. Both keys come back here in the phone bar's own dress, 40 px
     circles at the bottom right, clear of the apps word. The ≤640 block below is later in the
     sheet at the same specificity, so a real phone still reads exactly as it did. */
  .kl-dial[data-layout='menu'] { right: auto; } /* the dial's invisible box stopped at 120px from the right: the keys sit there now */
  .kl-sound { display: inline-flex; left: auto; right: 88px; top: auto; bottom: 8px; width: 40px; height: 40px; min-width: 0; padding: 0; justify-content: center; border-radius: 9999px; background: var(--kl-glass-strong); border: 1px solid var(--hairline); z-index: 6; }
  .kl-sound [data-kl-sound-label], .kl-sound > span:not(.kl-sound__glyph) { display: none; }
  .kl-micoff { display: inline-flex; left: auto; right: 136px; top: auto; bottom: 8px; width: 40px; height: 40px; min-width: 0; padding: 0; justify-content: center; border-radius: 9999px; background: var(--kl-glass-strong); border: 1px solid var(--hairline); z-index: 6; }
  .kl-micoff [data-kl-micoff-label] { display: none; }
  /* D55: the word is the key, so it is never hidden — and kiviland.css's 44px square is undone */
  .kl-wrench { width: auto; height: 40px; padding: 0 16px; }
  .kl-turn--you .kl-card { margin-right: 8%; }
  .kl-turn--kivi .kl-card, .kl-turn--nudge .kl-card, .kl-turn--clipping .kl-card, .kl-turn--approval .kl-card { margin-left: 8%; }
}

@media (prefers-reduced-motion: reduce) {
  .kl-orb__pulse, .kl-stage[data-phase='waiting'][data-mic='open'] .kl-orb .kl-orb__pulse, .kl-stage[data-phase='you'] .kl-orb .kl-orb__pulse { animation: none; opacity: 0.35; transform: scale(1.18); }
  .kl-stage[data-phase='waiting'][data-mic='open'] .kl-orb .kl-orb__disc, .kl-stage[data-phase='you'] .kl-orb .kl-orb__disc, .kl-stage[data-phase='waiting'][data-mic='open'] .kl-state::before, .kl-stage[data-phase='you'] .kl-state::before { animation: none; }
  .kl-focus__caption .kl-word { animation: none; opacity: 1; }
  .kl-mark__pulse, .kl-pane.is-focus-you .kl-focus__seat .kl-mark .kl-mark__pulse { animation: none; opacity: 0.35; transform: scale(1.18); }
  .kl-focus__seat .kl-orb, .kl-focus__seat .kl-mark { transition-duration: 1ms; }
  .kl-floor__mark.is-focus-host .kl-orb, .kl-floor__mark.is-focus-host .kl-mark { transition-duration: 1ms; }
  .kl-pane.is-focus-you .kl-floor__mark.is-focus-host .kl-mark .kl-mark__pulse { animation: none; opacity: 0.35; transform: scale(1.18); }
  /* D36: the button keeps its ring, loses the breathing */
  .kl-floor__mark .kl-orb.is-button .kl-orb__disc { animation: none; }
  .kl-scroller, .kl-floor, .kl-pane__head { transition-duration: 1ms; }
}

/* loops over stills: the video sits on the image and shows once it has a frame */
.kl-orb__loop { opacity: 0; }
.kl-orb__loop.is-on.is-ready { opacity: 1; }
.kl-loop { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; opacity: 0; pointer-events: none; transition: opacity 300ms var(--ease); }
.kl-loop.is-ready { opacity: 1; }
.kl-nav__profile .kl-loop { inset: 2px; width: 40px; height: 40px; }
.kl-pane__head { gap: 8px; flex-wrap: nowrap; overflow: visible; }
.kl-pane__head .kl-state { flex: 0 0 auto; }
.kl-pane__head .kl-pane__speaker { margin-left: auto; }

/* the whole result of an errand, under its log in the expanded rail entry */
.kl-pill__detail { margin: 8px 0 0; font-size: 12.5px; line-height: 1.45; opacity: 0.85; max-height: 180px; overflow: auto; white-space: pre-wrap; text-transform: none; }

/* the ring and the hover line must not be clipped by the pill (its ellipsis rule hides overflow) */
.kl-nav__name { overflow: visible; text-overflow: clip; }

/* ---- 2026-09-07, the founder's floor pass ---- */
/* the microphone switch sits beside the keyboard key, both close to the pane's edge */
.kl-micbtn { position: absolute; left: calc(var(--kl-pane-pad-x) - 12px); bottom: 26px; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--hairline-strong); background: var(--surface1); color: var(--ink2); display: grid; place-items: center; padding: 0; cursor: pointer; transition: color 140ms var(--ease), transform 140ms var(--ease), opacity 320ms var(--ease); }
.kl-micbtn:hover { color: var(--ink1); transform: translateY(-1px); }
.kl-micbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.kl-micbtn .kl-micbtn__slash { opacity: 0; transition: opacity 140ms var(--ease); }
.kl-micbtn[aria-pressed='true'] { color: var(--kl-state-listening); border-color: var(--kl-state-listening); }
.kl-micbtn[aria-pressed='true'] .kl-micbtn__slash { opacity: 1; }
.kl-stage[data-mic='denied'] .kl-micbtn, .kl-stage[data-phase='closed'] .kl-micbtn, .kl-stage[data-phase='gate'] .kl-micbtn { opacity: 0.35; pointer-events: none; }
/* typing: the orb and the speaker under the field fade out instead of showing through it */
.kl-floor__mark, .kl-pane__speaker { transition: opacity 260ms var(--ease); }
.kl-pane.is-typing .kl-floor__mark, .kl-pane.is-typing .kl-pane__speaker, .kl-pane.is-typing .kl-ticker { opacity: 0; pointer-events: none; }
/* a fresh session: the small refresh at the pane's bottom-right */
.kl-newsession { position: absolute; right: calc(2 * var(--kl-pane-pad-x) - 12px); /* the mic sits at pad + (pad − 12) from the left edge: the same from the right */ bottom: var(--kl-keys-bottom, 42px); /* the keys sit in the floor, which is 16px up from the pane's edge */ z-index: 3; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--hairline-strong); background: var(--surface1); color: var(--ink2); display: grid; place-items: center; padding: 0; cursor: pointer; transition: color 140ms var(--ease), transform 320ms var(--kl-ease-soft); }
.kl-newsession:hover { color: var(--ink1); transform: rotate(-40deg); }
.kl-newsession:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* the clock's lines — "still on it", the idle rungs — are marginalia: dotted, no fill, whatever the card rules say */
.kl-pane .kl-turn--nudge .kl-card { background: transparent; border: 1px dotted var(--hairline-strong); box-shadow: none; }

/* ---- 2026-09-07: no backdrop blur anywhere (the founder: "scrolling makes the entire window except
   the pane flicker badly — fix it properly for once and for all"). Every glass chip on the stage
   re-sampled its backdrop on each frame the leaders or the pane repainted; on a loaded machine that
   is a full-window flicker under every scroll. The chips are paper now: a firmer glass colour, no
   blur. The leaders and the sky get their own compositor layers so a redraw stays inside them. ---- */
.kl-pane, .kl-pill, .kl-connectors, .kl-nav__mark, .kl-nav__stamp, .kl-nav__signin, .kl-nav__profile, .kl-nav__name, .kl-sound, .kl-wrench, .kl-dial, .kl-dial__current, .kl-dial__menu, .kl-sphere__word, .kl-connect__word, .kl-connect__note, .kl-connect__why:not(:empty) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.kl-connectors { background: var(--kl-glass-strong, rgba(252, 250, 243, 0.96)); }
.kl-pill { background: rgba(252, 250, 243, 0.97); }
.kl-nav__mark, .kl-nav__stamp, .kl-nav__signin, .kl-nav__name, .kl-sound, .kl-wrench, .kl-dial, .kl-dial__menu, .kl-sphere__word, .kl-connect__word, .kl-connect__note, .kl-connect__why:not(:empty) { background: var(--kl-glass-strong, rgba(252, 250, 243, 0.96)); }
.kl-leaders { contain: strict; will-change: transform; }
.kl-sky { will-change: transform; transform: translateZ(0); }
.kl-rail { contain: layout; }

/* ---- long turns (2026-09-07): three quarters of the pane at most, ending in an ellipsis; a click
   opens the whole card, a click closes it again; selecting text never toggles ---- */
.kl-card.is-clamped { max-height: var(--kl-card-max, 60dvh); overflow: hidden; cursor: pointer; }
.kl-card.is-clamped::after { content: '…'; position: absolute; right: 12px; bottom: 4px; font-size: 1.25rem; line-height: 1; color: var(--ink2); padding: 0 4px; border-radius: 6px; background: var(--kl-glass-strong, rgba(252, 250, 243, 0.96)); }
.kl-turn--nudge .kl-card.is-clamped::after { content: none; }
.kl-card.is-expanded { cursor: pointer; }
.kl-card.is-clamped:focus-visible, .kl-card.is-expanded:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* =============================================================================
 * D35 — the phone. At ≤640 the pane IS the screen.
 *
 * Last in the last stylesheet on purpose: this block has to win over the base
 * geometry, the ≤900 tablet rule and the module files, and a phone is the one
 * width where every one of them is wrong. Nothing here is keyed on a mode, so
 * eager and patient read exactly as they do above 640.
 *
 * Heights are `100dvh`, never `100vh`: `position: fixed; inset: 0` resolves to
 * the LARGE viewport on ios safari, so the browser's own bottom bar would sit
 * over the control bar and eat the dial. `env(safe-area-inset-*)` pads the two
 * strips for the notch and the home indicator.
 * ========================================================================== */
@media (max-width: 640px) {
  .kl-stage { --kl-keys-bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 34px); }
  :root {
    --kl-nav-h: 48px;
    --kl-bar-h: 56px;
    --kl-pane-w: 100vw;
    --kl-pane-top: 0px;
    --kl-pane-bottom: 0px;
    --kl-pane-pad-x: 16px;
    --kl-pane-pad-y: 16px;
    /* the gutters are where the orb and your mark sit; at 360px the desktop's
       56 + 56 left a 216px line, so both shrink with the screen */
    --kl-gutter: 44px;
    --kl-orb: 44px;
    --kl-mark: 38px;
    --kl-dial-x: 12px;
    --kl-card-max: 56dvh;
  }
  html:has(.kl-stage), body:has(.kl-stage) { height: 100dvh; }
  .kl-stage { height: 100dvh; }

  /* the pane is the screen */
  .kl-pane { left: 0; right: 0; top: 0; bottom: 0; width: 100vw; min-height: 0; border-radius: 0; border-left: 0; border-right: 0; border-top: 0; border-bottom: 0; }
  .kl-stage[data-connectors='open'] .kl-pane { left: 0; }
  /* D57/D72: the head is gone at every width now (see the block at the foot of this sheet), so
     the phone has nothing left of its own to hide. The 26px it reserved is the conversation's. */
  .kl-scroller {
    top: calc(var(--kl-nav-h) + env(safe-area-inset-top) + 8px);
    bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 128px);
    left: var(--kl-pane-pad-x);
    right: var(--kl-pane-pad-x);
  }
  /* D53: the floor's last row is the note, and the note is full width — at +8px it ran straight
     through the maker's mark. It clears the mark's strip now, at the +34px walkie has always
     used; the scroller keeps its 96px gap above the floor's foot. */
  .kl-floor { --kl-floor-bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 32px); bottom: var(--kl-floor-bottom); }
  .kl-turn--you .kl-card { margin-right: 0; }
  .kl-turn--kivi .kl-card, .kl-turn--nudge .kl-card, .kl-turn--clipping .kl-card, .kl-turn--approval .kl-card { margin-left: 0; }
  .kl-turn--centre .kl-card { margin: 0; }

  /* the nav strip over the pane's top */
  .kl-nav { height: var(--kl-nav-h); margin-top: env(safe-area-inset-top); padding: 0 12px; gap: 12px; background: transparent; --kl-was: var(--kl-paper-opaque); border-bottom: 1px solid var(--hairline); }
  .kl-nav__beta { display: inline; font-size: 0.625rem; margin-left: 5px; }
  /* the desktop stamp pulls itself 12px left so its TEXT lines up with the 32px nav padding. With
     12px of padding that lands the pill's own edge on x=0 — flush to the glass, and chopped by a
     phone's rounded corner. The pill keeps its 12px like everything else here. */
  .kl-nav__stamp { margin-left: 0; padding: 6px 12px; max-width: 52vw; }
  .kl-nav__stamp .kl-nav__face--land { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .kl-nav__signin, .kl-nav__profile { margin-right: 0; flex: 0 0 auto; }
  /* the control bar over the pane's bottom, and the three controls that sit in it */
  .kl-bar { display: block; background: var(--kl-paper-opaque); -webkit-backdrop-filter: none; backdrop-filter: none; }
  /* the fresh-session key hangs off the PANE, not the floor, so it did not follow the floor up over
     the bar — it sat 14px inside the band with the dial and the sound key */
  /* D53: the maker's mark takes the strip just over the apps key, so the fresh-session key
     climbs 26px to clear it — nothing on the right edge overlaps anything else. */
  .kl-newsession { bottom: var(--kl-keys-bottom); right: 12px; }
  .kl-dial[data-layout='menu'] { left: 12px; right: auto; top: auto; bottom: calc(env(safe-area-inset-bottom) + 8px); transform: none; z-index: 6; }
  .kl-dial__current { padding: 4px 12px 4px 4px; }
  .kl-dial[data-layout='menu'] .kl-dial__still--current { width: 32px; height: 32px; }
  .kl-dial__pill { font-size: 0.875rem; }

  /* ---- the mode sheet: three rows of one line each, off the bottom ----
     It was three cards the height of the screen. Three things did that, and all three are undone
     here: the tablet block hid the still (so the text fell into its column — fixed structurally
     above), the desktop caption is a bordered contrasting BOX (a paragraph on a 72px line), and
     the sheet had no ceiling. A phone gets a 56px row, one line of caption, and a lid. */
  .kl-dial__menu {
    position: fixed; left: 0; right: 0; top: auto; width: auto;
    bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom));
    /* over the bar, the floor and the nav — a sheet you can see the room through is not a sheet */
    z-index: 8;
    max-height: 60dvh; overflow-y: auto; overscroll-behavior: contain;
    background: var(--kl-paper-opaque);
    -webkit-backdrop-filter: none; backdrop-filter: none;
    border: 0; border-top: 1px solid var(--hairline);
    border-radius: var(--r-md) var(--r-md) 0 0;
    box-shadow: 0 -12px 36px rgba(0, 0, 0, 0.18);
    transform-origin: bottom center;
    padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
    gap: 4px;
  }
  .kl-dial[data-layout='menu'] .kl-dial__stop {
    grid-template-columns: 32px 1fr; column-gap: 12px; align-items: center;
    min-height: 56px; padding: 8px 12px; border-radius: 12px;
    /* the selected row is a left rule and a tint, not a ring around a card */
    border: 0; border-left: 3px solid transparent; box-shadow: none;
    background: none;
  }
  @media (hover: hover) {
    .kl-dial[data-layout='menu'] .kl-dial__stop:hover { background: var(--surface2); transform: none; }
  }
  /* the thumb's own state: the row darkens for as long as it is held, and never after */
  .kl-dial[data-layout='menu'] .kl-dial__stop.is-pressed { background: var(--kl-leaf-soft); transform: none; }
  .kl-dial[data-layout='menu'] .kl-dial__stop[aria-checked='true'] { border-left-color: var(--kl-leaf); background: var(--kl-leaf-soft); box-shadow: none; }
  /* the still comes back — 32px, and its column is what keeps the text in column 2 */
  .kl-dial[data-layout='menu'] .kl-dial__still { display: block; width: 32px; height: 32px; grid-column: 1; }
  .kl-dial__text { row-gap: 1px; }
  .kl-dial[data-layout='menu'] .kl-dial__label { font-size: 0.9375rem; white-space: nowrap; }
  /* one line, in ink2, clipped rather than wrapped: the box was a desktop affordance */
  .kl-dial[data-layout='menu'] .kl-dial__caption,
  .kl-dial[data-layout='menu'] .kl-dial__stop[aria-checked='true'] .kl-dial__caption {
    display: block; max-width: 100%; padding: 0; border: 0; background: none;
    font-size: 0.75rem; line-height: 1.35; color: var(--ink2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* D55 widened the apps key from a 40px disc to the word, so the pair beside it steps right */
  .kl-sound { display: inline-flex; left: auto; right: 88px; top: auto; bottom: calc(env(safe-area-inset-bottom) + 8px); width: 40px; height: 40px; padding: 0; justify-content: center; border-radius: 9999px; background: var(--kl-glass-strong); border: 1px solid var(--hairline); z-index: 6; }
  .kl-sound [data-kl-sound-label], .kl-sound > span:not(.kl-sound__glyph) { display: none; }
  .kl-sound { min-width: 0; }
  /* the microphone key keeps its place beside the sound key on the bar (D43) */
  /* D56: on the phone the microphone key keeps its place BESIDE the speaker (there is no room
     for a column on the bar) — the pair reads as one control, the way it always has. */
  .kl-micoff { display: inline-flex; left: auto; right: 136px; top: auto; bottom: calc(env(safe-area-inset-bottom) + 8px); width: 40px; height: 40px; min-width: 0; padding: 0; justify-content: center; border-radius: 9999px; background: var(--kl-glass-strong); border: 1px solid var(--hairline); z-index: 6; }
  .kl-micoff [data-kl-micoff-label] { display: none; }
  .kl-wrench { right: 12px; bottom: calc(env(safe-area-inset-bottom) + 8px); width: auto; height: 40px; padding: 0 14px; z-index: 6; font-size: 0.9375rem; }

  /* the sphere never sits under a thumb reaching for the dial */
  .kl-sphere { left: auto; right: 16px; bottom: calc(var(--kl-bar-h) + env(safe-area-inset-bottom) + 28px); width: 72px; height: 72px; }

  /* the sheet comes up from the bottom over everything, short of the notch */
  .kl-connectors { top: calc(env(safe-area-inset-top) + 8dvh); bottom: 0; left: 0; right: 0; width: 100vw; }

  /* the connect orb never overflows a 360px screen */
  .kl-connect { padding: 16px; max-width: calc(100vw - 32px); }
}

/* =============================================================================
 * THE FOUNDER'S FOURTH PASS (2026-09-08) — D50–D57
 * The phone stops explaining itself, the keys say what they do, and the page is signed.
 * ========================================================================== */

/* ---- D52 · the space bar, drawn ----
   The keycap rides the walkie hint's baseline. `.kl-orb__hint` is `white-space: nowrap`, so the
   glyph must not add a line box of its own. */
.kl-keycap { display: inline-block; vertical-align: middle; width: 26px; height: 14px; margin-left: 4px; margin-top: -2px; opacity: 0.85; }

/* ---- D57 · a phone shows no top-of-pane info ----
   D72 took this to every width; the rule lives at the foot of this sheet, unscoped. */

/* ---- D53 · the maker's mark ----
   Bottom centre of the screen, small, in a hand, translucent enough to be part of the painting
   rather than a label over it. It sits OUTSIDE `.kl-stage`, so nothing here can be caught by the
   grayscale a closed session puts over the page — the one blue thing stays blue. */
.kl-signature {
  position: fixed;
  z-index: 6;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  margin: 0;
  max-width: 92vw;
  white-space: nowrap;
  font-family: 'Caveat', 'Segoe Script', 'Bradley Hand', cursive;
  font-style: normal;
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: 0.01em;
  color: rgba(40, 42, 38, 0.55);
  text-shadow: 0 1px 2px rgba(255, 255, 255, 0.35);
  pointer-events: none; /* the ink is decoration; only the name is a target */
  user-select: none;
}
.kl-signature__who {
  pointer-events: auto;
  color: var(--kl-v2-blue);
  text-decoration: underline;
  text-underline-offset: 2px;
  opacity: 0.9;
}
.kl-signature__who:hover, .kl-signature__who:focus-visible { opacity: 1; }
/* over the night and evening skies the ink is dark on dark: the mark goes to the paper's cream */
.kl-stage[data-band='night'] ~ .kl-signature, .kl-stage[data-band='evening'] ~ .kl-signature { color: rgba(246, 243, 234, 0.6); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35); }

/* the phone drops the "full stack" and moves to the bottom right, just over the apps key.
   Two triggers, one result: the phone LAYOUT (≤640) and a phone BROWSER at any width. */
/* D77: the phone MOVES the mark, it no longer shortens it — the line is the same at both
   widths now, so `.kl-signature__full` and `.kl-signature__any` and the rules that hid them
   are gone with the words themselves. */
@media (max-width: 640px) {
  .kl-signature { left: auto; right: 12px; bottom: calc(var(--kl-bar-h, 56px) + env(safe-area-inset-bottom) + 6px); transform: none; font-size: 1rem; }
}
:root[data-phone='true'] .kl-signature { left: auto; right: 12px; bottom: calc(var(--kl-bar-h, 56px) + env(safe-area-inset-bottom) + 6px); transform: none; font-size: 1rem; }

/* D58 — the two corner keys share one anchor. `--kl-keys-bottom` is the pane-relative bottom of
   both the keyboard key (inside the floor, so it subtracts the floor's own `--kl-floor-bottom`) and
   the refresh key (in the pane), at every width and in every mode; a lifted floor no longer carries
   one key away from the other. On a phone browser at any width both sit 12px from their edge. */
.kl-stage[data-phone='true'] .kl-newsession, .kl-stage[data-layout='phone'] .kl-newsession { right: 12px; }
.kl-stage[data-phone='true'] .kl-typekey, .kl-stage[data-layout='phone'] .kl-typekey { left: calc(12px - var(--kl-pane-pad-x)); }
.kl-stage[data-phone='true'] .kl-nav__stamp { margin-left: 0; }

/* D59 revised (2026-09-08 evening): no nav band anywhere; the stamp pill and the avatar float on the video as before. */
.kl-nav__beta { color: #3d8b4a; opacity: 1; font-weight: 700; }
/* D68 — the pill reads "kivi land": "kivi" stays the ink it has always been and "land" is bold,
   in the theme's own orange (`--kl-orange`, D55's warm #e8892b — the same colour the apps key
   wears, so the page has one orange and not two). `beta` keeps the leaf green it was just fixed
   to. The whole face fades out on hover, where the green "kivi home" face takes over (D69), so
   neither colour is ever asked to sit on the green.

   D75 — the two words live inside ONE wrapper, `.kl-nav__word`. `.kl-nav__face` is an
   `inline-flex` with `gap: 8px`, so when D68 first split the word the text node "kivi" and the
   `land` span became two flex items and the gap opened 8px INSIDE the name (the founder: "there
   is a lot of space between kivi and land in the pill"). The wrapper puts the face back to the
   two flex items it had before the split — the name, then `beta` — and the space between "kivi"
   and "land" is the one ordinary space in the markup, nothing else. Nothing here may add a
   margin, a padding or a letter-spacing to `.kl-nav__land`. */
.kl-nav__word { display: inline; }
.kl-nav__land { font-weight: 700; color: var(--kl-orange); }

/* D60 revised — wide: the floor mic beside the keyboard AND the bottom-left "mic off" pill, one
   state with two faces (as before the batch). Phone: the floor mic hidden, the keyboard takes its
   slot at 12px, the bar carries the mic beside the speaker. */
.kl-stage[data-layout='phone'] .kl-micbtn, .kl-stage[data-phone='true'] .kl-micbtn { display: none; }

/* D61 — the mic-off pill: the walkie hint turns yellow and says so the moment the mic is shut. */
.kl-orb__hint.is-micoff { display: block; background: #fff1b3; border-color: #e0c45a; color: #4a3b00; }
.kl-floor__mark.is-focus-host .kl-orb__hint.is-micoff { display: block; }

/* D62 / D67 — the page is not a white pane, at ANY width.
 *
 * D62 gave the phone a light veil over the sky instead of a sheet of paper, and gave kivi's
 * cards and yours two pale pastels so a glance says who spoke. The founder, dragging the window
 * about (2026-09-09): "i like the glassy central pane with bit different colored text boxes for
 * bot and user turns — which comes when you minimize the window size to mobile form factor — can
 * you make that consistent for when the window is expanded too?"
 *
 * So the `[data-layout='phone']` scope comes off all of it: the veil, the blur, the walkie grey,
 * the spawn/closed state and the two card colours are the base rules now. What stays phone-only
 * is what is about the phone's GEOMETRY rather than its colour — the pane there is the whole
 * screen, and a full-bleed screen casts no shadow, so `box-shadow: none` keeps its scope and the
 * wide pane keeps the long soft shadow that makes it a card on the sky (D29).
 *
 * The blur is 3px, on the pane and the bar only. The 2026-09-07 flicker pass took the 16–24px
 * backdrop blur off every chip on the stage and that stands: a chip is small, redrawn on every
 * leader frame, and there are a dozen of them. This is one big surface at a fifth of the radius,
 * which is what the phone has been running since D62.
 *
 * `.kl-turn--user` was a typo for `.kl-turn--you` — the class the pane actually writes — so the
 * person's card has never once taken its colour, on the phone or anywhere. Fixed here: "bot and
 * user turns" are two colours, which is what the founder is asking to keep. */
.kl-stage[data-layout='phone'] .kl-nav, .kl-stage[data-phone='true'] .kl-nav { background: transparent; color: var(--ink1); }
.kl-stage[data-layout='phone'] .kl-nav__stamp, .kl-stage[data-phone='true'] .kl-nav__stamp { background: rgba(252, 250, 243, 0.92); }
.kl-pane { background: rgba(252, 250, 243, 0.5); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.kl-stage[data-layout='phone'] .kl-pane { box-shadow: none; }
.kl-stage[data-mode='walkie'] .kl-pane, .kl-stage[data-mode='walkie'][data-ptt='on'] .kl-pane { background: rgba(244, 244, 240, 0.5); }
.kl-stage[data-phase='spawn'] .kl-pane, .kl-stage[data-phase='closed'] .kl-pane { background: rgba(252, 250, 243, 0.3); }
.kl-bar { background: rgba(252, 250, 243, 0.5); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.kl-turn--kivi .kl-card { background: #eef6e6; }
.kl-turn--you .kl-card { background: #fff8dc; }
/* a card that has receded behind a newer one still fades to the pale wash it always has */
.kl-turn--kivi .kl-card.is-receded, .kl-turn--you .kl-card.is-receded { background: rgba(255, 255, 255, 0.35); }
/* the veil is a veil because the blur stands behind it. Where there is no backdrop filter the
   pane goes back to paper — kiviland.css's own `@supports not` rule for `.kl-pane` no longer
   reaches, because these rules are later and (for the three states) more specific. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  /* D79: without a backdrop filter the veil is a plain translucent wash — never paper, never white */
  .kl-pane, .kl-bar { background: rgba(252, 250, 243, 0.6); }
  .kl-stage[data-mode='walkie'] .kl-pane, .kl-stage[data-mode='walkie'][data-ptt='on'] .kl-pane { background: rgba(244, 244, 240, 0.6); }
  .kl-stage[data-phase='spawn'] .kl-pane, .kl-stage[data-phase='closed'] .kl-pane { background: rgba(252, 250, 243, 0.35); }
}
/* D79 — the chat pane is translucent in every condition: a slow-frame probe (data-perf='low') drops the
   blur but keeps the wash; no mode, phase, press or probe may paint it opaque. */
.kl-stage[data-perf='low'] .kl-pane { background: rgba(252, 250, 243, 0.6); -webkit-backdrop-filter: none; backdrop-filter: none; }
.kl-stage[data-perf='low'][data-mode='walkie'] .kl-pane { background: rgba(244, 244, 240, 0.6); }

/* D44 revised — the speaker rides the kivi orb again in the wide layout, icon only: the
   "tap to hear kivi" caption stays gone, and the phone keeps its bar speaker instead. */
.kl-speaker__caption { display: none !important; }
.kl-stage[data-layout='phone'] .kl-speaker, .kl-stage[data-phone='true'] .kl-speaker { display: none; }
.kl-pane__speaker { display: none; }

/* =============================================================================
 * D69 — the home face is GREEN at every width, and on every way of reaching it.
 *
 * The founder, on a narrow window: "hovering on kiviland yield kivi home pill with white
 * background rendering kivi text invisible - fix it by making the pill green on hover in mobile
 * form too".
 *
 * Three rules out-ranked `.kl-nav__stamp:hover` (0,2,0) and painted the resting pill over the
 * hovered one, leaving `color: #fff` and the cream wordmark on cream paper:
 *   · D62's `.kl-stage[data-layout='phone'] .kl-nav__stamp` and its `[data-phone='true']` twin
 *     (0,3,0) — the founder's bug, at phone width and on a phone held sideways;
 *   · `.kl-stage[data-band='night'|'evening'] .kl-nav__stamp` (0,3,0) — the same hole after dark,
 *     with the ink going to `--ink1` on the green instead;
 *   · nothing at all for `:focus-visible` and `:active`, which swap the FACE above but never
 *     asked for the pill — so a keyboard, and a thumb, reached the invisible state too.
 *
 * Listing the selectors rather than folding them into one `:is()` is the sheet's habit (see the
 * focus-host block): `:is()` takes its widest argument's specificity, and every branch here has
 * to win by exactly as much as the rule it answers and no more.
 * ========================================================================== */
.kl-nav__stamp:hover,
.kl-nav__stamp:focus-visible,
.kl-nav__stamp:active,
.kl-stage[data-layout='phone'] .kl-nav__stamp:hover,
.kl-stage[data-layout='phone'] .kl-nav__stamp:focus-visible,
.kl-stage[data-layout='phone'] .kl-nav__stamp:active,
.kl-stage[data-phone='true'] .kl-nav__stamp:hover,
.kl-stage[data-phone='true'] .kl-nav__stamp:focus-visible,
.kl-stage[data-phone='true'] .kl-nav__stamp:active,
.kl-stage[data-band='night'] .kl-nav__stamp:hover,
.kl-stage[data-band='night'] .kl-nav__stamp:focus-visible,
.kl-stage[data-band='night'] .kl-nav__stamp:active,
.kl-stage[data-band='evening'] .kl-nav__stamp:hover,
.kl-stage[data-band='evening'] .kl-nav__stamp:focus-visible,
.kl-stage[data-band='evening'] .kl-nav__stamp:active {
  background: var(--kl-pill-green);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 0 0 3px var(--kl-lavender);
}
/* the keyboard still gets a ring of its own: the green is the state, not the focus */
.kl-nav__stamp:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* =============================================================================
 * D72 — no strip at the top of the pane, at any width.
 *
 * The founder, on the wide layout: "the wide pane is translucent, that's great — but also remove
 * the top bar from wide screen too, similar to it being not there on the mobile screen."
 *
 * That strip is `.kl-pane__head`: the state word ("listening", "thinking") on the left, the room
 * reading beside it, the speaker at the right. D57 called it a desk affordance and took it off
 * the phone; the founder has now looked at the desk and said the same thing there. The pane is
 * the conversation and nothing else, and the conversation says these things in kivi's own voice.
 *
 * The markup STAYS: `[data-kl-state]` still carries `data-word` for QA and the lanes' harness,
 * `.kl-pane__speaker` has been `display: none` since D44 revised, and the orb's gaze, the phase
 * attributes and the room's VAD presets are all untouched — this removes a strip, not a state.
 *
 * The `.kl-nav` chrome at the top of the STAGE is not a band and never was (D59 revised): it has
 * no background of its own at any width, and the stamp pill and the avatar float on the video.
 * ========================================================================== */
.kl-pane__head { display: none; }

/* D63 — the bird arrives with the tap. While the session is still connecting the seated orb is
   already visible and breathing, a touch dimmed, so a mint that takes two seconds on a real
   backend is not two seconds of empty floor; it simply wakes when `ready` arrives. */
.kl-stage[data-phase='connecting'] .kl-floor__mark .kl-orb { opacity: 0.86; animation: kl-orb-breathe 1.2s ease-in-out infinite; }
.kl-stage[data-phase='connecting'] .kl-floor__mark .kl-orb__hint { display: none; }
@media (prefers-reduced-motion: reduce) { .kl-stage[data-phase='connecting'] .kl-floor__mark .kl-orb { animation: none; } }
