/* ============================================================================
 * kit/frame.css — the chrome around any field.
 * Placement + styling lifted from the live Thoughtnado frame (its real class
 * names: .topbar / .qcount / .hint / .corner-mark / .footer-link / .pausebtn /
 * .pause-overlay / .ending), so a canvas on the floor looks like family from
 * frame one. The floor (engine.js) renders this chrome from config.
 * Pairs with tokens.css + tweaks.css.
 * ========================================================================== */

html,
body {
	margin: 0;
	height: 100%;
	width: 100%;
	background: var(--bg);
	color: var(--fg);
	font-family: var(--font-sans);
	overflow: hidden;
	cursor: crosshair;
}
body {
	user-select: none;
	-webkit-user-select: none;
	-webkit-touch-callout: none;
}
/* iOS: keep the selection loupe OFF the canvas/board (it steals focus from the
   hidden typing input and freezes typing), but ON for real inputs so the email
   field + the typing input keep their caret, selection and paste. */
input,
textarea,
[contenteditable="true"] {
	-webkit-user-select: text;
	user-select: text;
	-webkit-touch-callout: default;
}

/* ---- playfield: field + display pattern share this one movable layer, so the
   keyboard lift moves them together (no relative motion = no particle blast). The
   transition glides the lift instead of snapping. Chrome stays outside it. ---- */
#kit-playfield {
	position: fixed;
	inset: 0;
	z-index: 0;
	will-change: transform;
	/* ease-OUT (quick to move, gentle to settle) reads smoother than the default
	   ease for follow-the-keyboard motion; a touch longer so it glides, not darts. */
	transition: transform 0.45s cubic-bezier(0.33, 1, 0.68, 1);
}

/* ---- the stage every field lives in; a field is a .wp root (canvas optional) ---- */
#kit-stage {
	position: fixed;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}
#kit-stage .wp {
	position: absolute;
	inset: 0;
}
#kit-stage > .wp.active {
	z-index: 1;
}
#kit-stage canvas.wp-canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

/* ---- progress ring (optional; shows the journey clock 0->1) ---- */
#kit-progress {
	position: fixed;
	pointer-events: none;
	z-index: 0;
	left: 50%;
	top: 8%;
	transform: translate(-50%, -50%);
	transition: opacity 480ms ease-out;
	opacity: 0;
}
#kit-progress.show {
	opacity: 1;
}
#kit-progress-arc {
	stroke-width: var(--timer-stroke, 1.5);
	transition: stroke-dashoffset 140ms linear;
}

/* ---- standing prompt (optional module) ---- */
#kit-prompt {
	position: fixed;
	top: 8%;
	left: 50%;
	transform: translateX(-50%);
	z-index: 2;
	width: min(80%, 900px);
	text-align: center;
	pointer-events: none;
	font-family: var(--font-display);
	font-weight: 600;
	font-size: clamp(20px, 2.6vw, 30px);
	letter-spacing: -0.02em;
	line-height: 1.25;
	color: var(--fg);
	opacity: 0.92;
	font-variation-settings:
		"opsz" 30,
		"wdth" 95;
	text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
}
#kit-prompt .mark {
	background: var(--marker);
	color: var(--marker-ink);
	padding: 0 0.2em;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}
#kit-prompt.editing {
	outline: none;
	box-shadow: 0 0 0 1px var(--cyan);
	background: rgba(63, 182, 200, 0.06);
	border-radius: 3px;
	cursor: text;
	white-space: pre-wrap;
}
body.is-author #kit-prompt {
	cursor: text;
}

/* ---- stepped sequence: the answer line under the prompt ---- */
/* The size here is the fallback for a canvas that declares no answerSize dial.
   A canvas that declares one is sized by the engine, which multiplies the dial
   by FW_TYPED_LINE_SCALE; both are the same move, so they are kept in step. */
#kit-answerline {
	position: fixed;
	left: 50%;
	transform: translateX(-50%);
	z-index: 2;
	width: min(80%, 760px);
	text-align: center;
	pointer-events: none;
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 35px;
	font-variation-settings:
		"opsz" 24,
		"wdth" 100;
	/* Someone reading back a word they typed must be able to count its letters.
	   The display face joins ff, fi and fl into one glyph, so an attendee typing
	   "stuff" saw "stuf" and said so in the live session chat. The letters were
	   always in the data; only the drawing lost one. */
	font-variant-ligatures: none;
	line-height: 1.35;
	color: var(--fg);
	min-height: 1.4em;
	text-shadow:
		0 0 1px rgba(0, 0, 0, 0.95),
		0 0 3px rgba(0, 0, 0, 0.85),
		0 0 6px rgba(0, 0, 0, 0.55);
}
.kit-caret {
	display: inline-block;
	width: 3px;
	height: 1.1em;
	background: var(--cyan);
	margin-left: 2px;
	transform: translateY(0.16em);
	animation: kit-caret-blink 1s step-end infinite;
}
@keyframes kit-caret-blink {
	0%,
	60% {
		opacity: 1;
	}
	61%,
	100% {
		opacity: 0;
	}
}

/* ---- topbar (top-left): mAI canvas · canvas/field/title/build ---- */
.topbar {
	position: fixed;
	top: 18px;
	left: 18px;
	z-index: 5;
	pointer-events: none;
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--muted);
	display: flex;
	flex-direction: column;
	gap: 3px;
	line-height: 1.35;
	/* see "the status block fades while the reader is away from the top", below */
	transition:
		opacity var(--dur-panel) var(--ease),
		visibility 0s var(--ease) 0s;
}
.topbar .tb-title {
	color: var(--fg);
	font-size: 12px;
	letter-spacing: 0.04em;
	margin-bottom: 3px;
	white-space: nowrap;
}
.topbar .tb-title .brand {
	color: var(--marker);
	font-weight: 500;
}
.topbar .tb-status {
	margin-left: 9px;
	color: var(--cyan);
	font-size: 9px;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	vertical-align: middle;
	white-space: nowrap;
}
.topbar .wip-dot {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--cyan);
	animation: wip-pulse 1.6s ease-in-out infinite;
}
@keyframes wip-pulse {
	0%,
	100% {
		opacity: 1;
	}
	50% {
		opacity: 0.3;
	}
}
.topbar .tb-row {
	display: flex;
	gap: 8px;
	white-space: nowrap;
}
.topbar .k {
	color: var(--marker);
	text-transform: uppercase;
	letter-spacing: 0.07em;
	font-weight: 500;
	min-width: 52px;
}
.topbar .v {
	color: var(--fg-soft);
	white-space: nowrap;
}
.topbar .inf {
	color: var(--muted);
}

/* ---- qcount (top-right, under the pause button) — stepped experiences ---- */
.qcount {
	position: fixed;
	top: 52px;
	right: 18px;
	z-index: 5;
	pointer-events: none;
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--muted);
	text-align: right;
	white-space: nowrap;
	transition: opacity 400ms;
}
.qcount .num {
	color: var(--fg);
	font-size: 13px;
}
.qcount .stage {
	margin-top: 4px;
	color: var(--marker);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* ---- chip keys (top-right, parked under the pause / skip / question counter)
   Author-only, written by the engine: the two keys that show and hide the two
   chips, so a chip hidden in an earlier session never leaves the author with no
   way back. Quiet by design, and it never takes a tap. ---- */
.chip-keys {
	position: fixed;
	top: calc(env(safe-area-inset-top, 0px) + 86px);
	right: 18px;
	z-index: 5;
	pointer-events: none;
	font-family: var(--font-mono);
	font-size: 11px;
	line-height: 1.7;
	color: var(--fg-soft);
	background: color-mix(in srgb, var(--bg) 72%, transparent);
	border-radius: 2px;
	padding: 5px 9px;
	text-align: right;
	white-space: nowrap;
}
.chip-keys[hidden] {
	display: none;
}
.chip-keys-label {
	color: var(--muted);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}
.chip-keys-key {
	color: var(--fg);
	margin-right: 8px;
}

/* ---- hint (bottom-centre; .top parks it at the top) ---- */
.hint {
	position: fixed;
	bottom: 18px;
	left: 50%;
	transform: translateX(-50%);
	z-index: 5;
	pointer-events: none;
	font-family: var(--font-mono);
	font-size: 12px;
	color: var(--fg-soft);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	transition: opacity 400ms;
}
.hint.top {
	bottom: auto;
	top: 18px;
}
.hint kbd {
	font-family: var(--font-mono);
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid var(--border);
	padding: 1px 5px;
	border-radius: 2px;
	color: var(--fg-soft);
	font-size: 10px;
	letter-spacing: 0;
	text-transform: none;
}

/* ---- corner crops ---- */
.corner-mark {
	position: fixed;
	z-index: 4;
	width: 14px;
	height: 14px;
	pointer-events: none;
	color: var(--whisper);
}
.corner-mark.tl {
	top: 8px;
	left: 8px;
	border-top: 1px solid currentColor;
	border-left: 1px solid currentColor;
}
.corner-mark.tr {
	top: 8px;
	right: 8px;
	border-top: 1px solid currentColor;
	border-right: 1px solid currentColor;
}
.corner-mark.bl {
	bottom: 8px;
	left: 8px;
	border-bottom: 1px solid currentColor;
	border-left: 1px solid currentColor;
}
.corner-mark.br {
	bottom: 8px;
	right: 8px;
	border-bottom: 1px solid currentColor;
	border-right: 1px solid currentColor;
}

/* ---- footer links (corners) ---- */
.footer-link {
	position: fixed;
	bottom: 18px;
	z-index: 5;
	pointer-events: auto;
	font-family: var(--font-mono);
	font-size: 10px;
	color: var(--muted);
	text-decoration: none;
	letter-spacing: 0.06em;
	white-space: nowrap;
	transition: color 120ms;
}
.footer-link:hover {
	color: var(--cyan);
}
.footer-copy {
	left: 18px;
}
.footer-made {
	right: 18px;
}
.footer-made .heart {
	color: var(--clay);
}
.footer-how {
	right: 18px;
	bottom: 44px;
}
.footer-how .arr {
	transition: transform 120ms;
	display: inline-block;
}
.footer-how:hover .arr {
	transform: translateX(2px);
}

/* ---- the status block fades while the reader is away from the top ----
   The status block is fixed over the viewport, and on a canvas whose content
   scrolls the words pass straight underneath it. At a phone width the column is
   nearly the whole viewport, so the two overprint each other and neither can be
   read (seen live at 360px and 390px, 29 July 2026).

   The canvas layer that owns the scrolling element reports that the reader has
   moved away from the top (engine.js: window.maiCanvasSetScrolledAwayFromTop),
   the shell puts this class on <body>, and this rule plus the transition on
   .topbar are the whole of what "faded" means. A canvas that never reports never
   gets the class, so its chrome stands exactly as it always did.

   It fades at every width — it is the behaviour Mike asked for, not a phone
   patch, and it overprints on a wide screen too. The footer links are a different
   problem with a different answer: they sit at the bottom, where words are under
   them even before anybody scrolls, so a fade tied to scrolling could not have
   cleared them. They keep still at every width, and the Message column dissolves
   above them instead — see #msg-scroll in public/message/canvas.html.

   VISIBILITY, NOT OPACITY ALONE. The author module writes an inline
   pointer-events:auto onto every chrome word it makes Alt-click editable, and an
   inline style beats any stylesheet rule — so a faded-out word would still have
   taken the tap. visibility is set nowhere else, is not overridden by a child,
   and takes the element out of hit-testing entirely. It flips at the END of the
   fade out and at the START of the fade in (the 0s delay on the base rules
   above), so neither direction of the fade is ever cut short. */
body.is-scrolled-away-from-top .topbar {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition:
		opacity var(--dur-panel) var(--ease),
		visibility 0s var(--ease) var(--dur-panel);
}

/* ---- author control cluster: panel toggles stacked under the top-left chrome ---- */
#kit-authbar {
	position: fixed;
	right: 18px;
	top: 16px;
	z-index: 61;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 6px;
}
/* The rule above is an author declaration, so it beats the browser's own
   [hidden] { display: none } — without this the chip stays on screen when the
   engine hides it (the selector chip's "hide controls" view state). Say it
   here so `hidden` means hidden on this element. */
#kit-authbar[hidden] {
	display: none;
}
#kit-authbar .tweaks-toggle {
	position: static;
	inset: auto;
	left: auto;
	right: auto;
	bottom: auto;
	top: auto;
}
/* Author step-nav buttons (previous/next/skip/end) — chip-styled but cyan-tinted
   so they read as actions, not panel toggles. */
#kit-authbar .tweaks-toggle.authbar-nav {
	color: var(--cyan);
	border-color: #3a4a52;
}
#kit-authbar .tweaks-toggle.authbar-nav:hover {
	color: var(--cyan-hover);
	border-color: var(--cyan);
}
/* Fold header (full-width, top of the grid): collapses the whole cluster. */
#kit-authbar .authbar-fold {
	grid-column: 1 / -1;
	font-family: var(--font-mono);
	font-size: 9px;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--fg-soft);
	background: var(--panel);
	border: 1px solid var(--border);
	border-radius: 2px;
	padding: 3px 8px;
	cursor: pointer;
	text-align: center;
}
#kit-authbar .authbar-fold:hover {
	color: var(--fg-soft);
}
#kit-authbar:not(.unified).folded > * {
	display: none !important;
}
#kit-authbar:not(.unified).folded > .authbar-fold {
	display: block !important;
}

/* ---- Unified chip (opt-in): button grid header + the active panel docked below,
   as one draggable chip. Collapsing (fold) hides the controls, keeps the buttons. ---- */
#kit-authbar.unified {
	align-items: stretch;
	width: 320px;
	max-width: calc(100vw - 36px);
}
#kit-authbar.unified .authbar-chips {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 6px;
}
#kit-authbar.unified .authbar-fold {
	display: block;
}
/* the docked panels: in-flow under the buttons, full width, only the open one shows.
   Capped + scrollable so a long control list never runs off-screen — the button grid
   above stays put, the controls scroll within. */
#kit-authbar.unified .tweaks-panel {
	position: static !important;
	inset: auto !important;
	left: auto !important;
	right: auto !important;
	top: auto !important;
	bottom: auto !important;
	width: 100% !important;
	max-width: none !important;
	margin: 0 !important;
	max-height: calc(100vh - 140px);
	overflow-y: auto;
	overflow-x: hidden;
	overscroll-behavior: contain;
	display: none;
}
#kit-authbar.unified .tweaks-panel.open {
	display: block;
}
/* collapse = only the buttons: fold hides the controls, the grid + header stay */
#kit-authbar.unified.folded .tweaks-panel {
	display: none !important;
}
/* The issue reporter's button, relocated into the author grid (8th cell):
   match the panel chips instead of the cyan floating fab. Visibility is still
   governed by #ir-fab.on (the author "Issue reporter" toggle). */
#kit-authbar #ir-fab {
	position: static;
	left: auto;
	right: auto;
	top: auto;
	bottom: auto;
	width: 100%;
	min-width: 0;
	justify-content: center;
	gap: 4px;
	font-size: 10px;
	padding: 5px 10px;
	color: var(--fg-soft);
	background: var(--panel);
	border-color: var(--border);
}

#kit-authbar.chip-v2 {
	--authbar-chip-width: min(var(--controls-chip-v2-layout-width, 360px), calc(100vw - 52px));
	--authbar-catalogue-slot-actions-width: calc(var(--s-24) + var(--s-16) + var(--s-4));
	align-items: stretch;
	gap: 0;
	box-sizing: border-box;
	width: var(--authbar-chip-width);
	max-width: calc(100vw - 36px);
	padding: 0;
	background: color-mix(in oklab, var(--panel) 92%, var(--bg));
	border: 1px solid var(--border);
	border-radius: 8px;
	box-shadow: 0 18px 50px rgba(0, 0, 0, 0.42);
	color: var(--fg);
	overflow: hidden;
	transform: scale(var(--controls-chip-scale, 0.72));
	transform-origin: top left;
}
#kit-authbar.chip-v2 .authbar-chip-row {
	display: grid;
	grid-template-columns: 34px repeat(4, minmax(0, 1fr)) 34px 34px;
	align-items: center;
	gap: 4px;
	box-sizing: border-box;
	width: 100%;
	padding: 7px;
	white-space: nowrap;
}
#kit-authbar.chip-v2 .authbar-grip {
	width: 34px;
	height: 32px;
	box-sizing: border-box;
	border: 1px solid var(--rule);
	border-radius: 6px;
	background:
		radial-gradient(var(--muted) 1.5px, transparent 1.6px) 5px 5px / 8px 8px,
		color-mix(in oklab, var(--bg) 62%, transparent);
	cursor: move;
}
#kit-authbar.chip-v2 .authbar-canvas-btn,
#kit-authbar.chip-v2 .authbar-slot-btn,
#kit-authbar.chip-v2 .authbar-history-btn,
#kit-authbar.chip-v2 .authbar-screen-size-add,
#kit-authbar.chip-v2 .authbar-screen-size-remove {
	appearance: none;
	height: 32px;
	box-sizing: border-box;
	border: 1px solid var(--rule);
	border-radius: 6px;
	background: color-mix(in oklab, var(--bg) 68%, transparent);
	color: var(--muted);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.09em;
	line-height: 1;
	text-align: center;
	text-transform: uppercase;
	white-space: nowrap;
}
#kit-authbar.chip-v2 .authbar-canvas-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	width: 100%;
	min-width: 0;
	padding: 0 8px;
}
/* The screen size badge is a live readout, not a panel button: it spans the
   whole chip row on its own line so the four canvas buttons keep their grid. */
#kit-authbar.chip-v2 .authbar-screen-size {
	grid-column: 1 / -1;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px;
	min-width: 0;
}
#kit-authbar.chip-v2 .authbar-screen-size-label {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--cyan);
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.09em;
	line-height: 1;
	text-transform: uppercase;
}
#kit-authbar.chip-v2 .authbar-screen-size-add {
	flex: 1 1 auto;
	min-width: 0;
	padding: 0 8px;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* A set is active AND another can be added below its boundary: the add button
   takes its own line under the active set's name, so neither string is squeezed
   into an ellipsis on the narrow chip this feature exists for. */
#kit-authbar.chip-v2 .authbar-screen-size-label ~ .authbar-screen-size-add {
	flex-basis: 100%;
}
#kit-authbar.chip-v2 .authbar-screen-size-remove {
	flex: 0 0 34px;
	width: 34px;
	padding: 0;
	font-size: 16px;
	letter-spacing: 0;
}
#kit-authbar.chip-v2 .authbar-screen-size-add:hover,
#kit-authbar.chip-v2 .authbar-screen-size-remove:hover {
	border-color: color-mix(in oklab, var(--cyan) 64%, var(--border));
	background: color-mix(in oklab, var(--cyan) 16%, transparent);
	color: var(--cyan);
}
#kit-authbar.chip-v2 .authbar-slots-row {
	display: grid;
	grid-template-columns: 34px repeat(4, minmax(0, 1fr)) 34px 34px;
	align-items: center;
	gap: 4px;
	box-sizing: border-box;
	width: 100%;
	padding: 0 7px 7px;
}
#kit-authbar.chip-v2 .authbar-slot-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 0;
	width: 100%;
	padding: 0 8px;
	overflow: hidden;
	text-overflow: ellipsis;
}
#kit-authbar.chip-v2 .authbar-slot-btn:first-child {
	grid-column: 2;
}
#kit-authbar.chip-v2 .authbar-history-btn {
	width: 34px;
	padding: 0;
	font-size: 18px;
	letter-spacing: 0;
	line-height: 30px;
}
#kit-authbar.chip-v2 .authbar-canvas-btn.open,
#kit-authbar.chip-v2 .authbar-canvas-btn:hover,
#kit-authbar.chip-v2 .authbar-slot-btn.open,
#kit-authbar.chip-v2 .authbar-slot-btn:hover {
	border-color: color-mix(in oklab, var(--cyan) 64%, var(--border));
	background: color-mix(in oklab, var(--cyan) 16%, transparent);
	color: var(--cyan);
}
#kit-authbar.chip-v2 .authbar-history-btn:hover:not(:disabled) {
	border-color: var(--marker);
	color: var(--marker);
}
/* Step nav (stepped canvases only): previous / next / skip / end share the row
   undo and redo sit on, taking the columns they leave empty, so the chip does
   not grow a line for them. Cyan-tinted like the old cluster's nav, because
   these move the exercise rather than change a setting. */
#kit-authbar.chip-v2 .authbar-step-nav {
	grid-column: 3 / -1;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 4px;
	min-width: 0;
}
#kit-authbar.chip-v2 .authbar-step-btn {
	appearance: none;
	flex: 0 1 auto;
	height: 32px;
	min-width: 0;
	box-sizing: border-box;
	padding: 0 8px;
	overflow: hidden;
	border: 1px solid color-mix(in oklab, var(--cyan) 34%, var(--rule));
	border-radius: 6px;
	background: color-mix(in oklab, var(--bg) 68%, transparent);
	color: color-mix(in oklab, var(--cyan) 72%, var(--muted));
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.09em;
	line-height: 1;
	text-align: center;
	text-overflow: ellipsis;
	text-transform: uppercase;
	white-space: nowrap;
}
#kit-authbar.chip-v2 .authbar-step-btn:hover {
	border-color: color-mix(in oklab, var(--cyan) 64%, var(--border));
	background: color-mix(in oklab, var(--cyan) 16%, transparent);
	color: var(--cyan);
}
#kit-authbar.chip-v2 .authbar-history-btn:disabled {
	color: var(--fg-soft);
	border-color: var(--border);
	opacity: 0.62;
	cursor: default;
}
#kit-authbar.chip-v2 .tweaks-route-tool:disabled,
#kit-authbar.chip-v2 .tweaks-catalogue-action:disabled,
#kit-authbar.chip-v2 .tweaks-catalogue-slot-action:disabled,
#kit-authbar.chip-v2 .control-point-row:disabled {
	color: var(--fg-soft);
	border-color: var(--border);
	opacity: 0.62;
	cursor: default;
}
#kit-authbar.chip-v2 .tweaks-catalogue-row:has(> .tweaks-catalogue-slot-actions) {
	grid-template-columns: minmax(0, 1fr) minmax(0, var(--authbar-catalogue-slot-actions-width));
}
/* An OPEN explanation gets the whole row and the slot actions drop below it (Mike,
   2026-07-30). Sharing the row with the slot column left the paragraph ~85px wide at
   the smallest chip size, which read two words per line. Only rows whose explainer is
   open restack, so the closed catalogue keeps its compact side-by-side shape. This
   rule must sit in the chip-v2 layer: the row-above wins over tweaks.css on
   specificity, so an override there alone never lands. */
#kit-authbar.chip-v2 .tweaks-catalogue-row.shows-explainer:has(> .tweaks-catalogue-slot-actions) {
	grid-template-columns: minmax(0, 1fr);
}
#kit-authbar.chip-v2 .tweaks-catalogue-row.shows-explainer > .tweaks-catalogue-slot-actions {
	width: var(--authbar-catalogue-slot-actions-width);
	justify-self: start;
}
/* A wide head (long label + readout + route badge) must wrap inside its own
   column, never spill under the slot actions in the next column. */
#kit-authbar.chip-v2 .tweaks-catalogue-row .tweaks-row-head {
	flex-wrap: wrap;
}
#kit-authbar.chip-v2 .tweaks-catalogue-slot-actions {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--s-1);
	width: 100%;
	min-width: 0;
}
#kit-authbar.chip-v2 .tweaks-catalogue-category-slot-actions {
	flex: 0 0 var(--authbar-catalogue-slot-actions-width);
	align-self: center;
	width: var(--authbar-catalogue-slot-actions-width);
	padding: var(--s-1);
}
#kit-authbar.chip-v2 .tweaks-catalogue-slot-action {
	appearance: none;
	min-width: 0;
	padding: var(--s-1) var(--s-2);
	border: 1px solid var(--rule);
	border-radius: var(--r-sm);
	background: color-mix(in oklab, var(--bg) 68%, transparent);
	color: var(--muted);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 9px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
#kit-authbar.chip-v2 .tweaks-catalogue-slot-action.is-active,
#kit-authbar.chip-v2 .tweaks-catalogue-slot-action:hover {
	border-color: color-mix(in oklab, var(--cyan) 64%, var(--border));
	color: var(--cyan);
}
#kit-authbar.chip-v2 .is-orphaned-control {
	filter: grayscale(1);
	opacity: 0.48;
}
#kit-authbar.chip-v2 .authbar-canvas-btn .ir-n {
	color: var(--marker);
}
#kit-authbar.chip-v2 .tweaks-panel {
	position: static !important;
	inset: auto !important;
	left: auto !important;
	right: auto !important;
	top: auto !important;
	bottom: auto !important;
	display: none;
	box-sizing: border-box;
	width: 100% !important;
	max-width: none !important;
	max-height: var(--controls-chip-v2-max-height, calc(100vh - 128px));
	margin: 0 !important;
	border-right: 0;
	border-bottom: 0;
	border-left: 0;
	border-radius: 0;
	overflow-y: auto;
	overflow-x: hidden;
	overscroll-behavior: contain;
}
#kit-authbar.chip-v2 .tweaks-panel.open {
	display: flex;
}
#kit-authbar.chip-v2 .tweaks-head,
#kit-authbar.chip-v2 .tweaks-actions {
	background: var(--panel);
	z-index: 3;
}
#kit-authbar.chip-v2 .tweaks-head {
	align-items: center;
	flex-wrap: wrap;
	padding: 14px;
}
#kit-authbar.chip-v2 .tweaks-head-title {
	color: var(--cyan);
	font-weight: 400;
}
/* ---- preview-journey buttons (author): lit when auditioning an end ---- */
.preview-btn-start.active {
	color: var(--cyan);
	border-color: var(--cyan);
}
.preview-btn-end.active {
	color: var(--marker);
	border-color: var(--marker);
}

/* ---- pause button (top-right) = the save / sign-up control ---- */
.pausebtn {
	position: fixed;
	top: calc(env(safe-area-inset-top, 0px) + 18px);
	right: 18px;
	z-index: 6;
	cursor: pointer;
	pointer-events: auto;
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--fg-soft);
	background: rgba(12, 12, 13, 0.6);
	border: 1px solid var(--fg-soft);
	padding: 6px 13px;
	border-radius: 2px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	min-width: 76px;
	transition:
		color 120ms,
		border-color 120ms,
		background 120ms;
}
.pausebtn:hover {
	color: var(--cyan);
	border-color: var(--cyan);
}
/* Earned-loud: once there's an answer worth keeping, the keep-corner goes bold +
   bright (marker fill), per DESIGN-CHROME. Toggled via .has-work on first commit. */
.pausebtn.has-work {
	color: var(--marker-ink);
	background: var(--marker);
	border-color: var(--marker);
	font-weight: 700;
}
.pausebtn.has-work:hover {
	color: var(--marker-ink);
	border-color: var(--marker-ink);
}
.pausebtn[hidden] {
	display: none;
}

/* ---- skip button (instruction screens) ---- */
/* Skip = a quiet sibling of the pause: same size + look, parked directly under it
   (top-right). Skips the intro only. Shown on instruction screens via .show. */
.skipbtn {
	position: fixed;
	top: calc(env(safe-area-inset-top, 0px) + 52px);
	right: 18px;
	z-index: 6;
	cursor: pointer;
	pointer-events: auto;
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--fg-soft);
	background: rgba(12, 12, 13, 0.6);
	border: 1px solid var(--fg-soft);
	padding: 6px 13px;
	border-radius: 2px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	display: none;
	align-items: center;
	justify-content: center;
	gap: 6px;
	min-width: 76px;
	transition:
		color 120ms,
		border-color 120ms,
		opacity 200ms;
}
.skipbtn:hover {
	color: var(--cyan);
	border-color: var(--cyan);
}
.skipbtn.show {
	display: inline-flex;
}

/* ---- send to Mike pill (public/workshop/send.js) ---- */
/* The pill wears .pausebtn for the whole of its look — Mike's decision, 2
   September 2026: it belongs to the DOWNLOAD PROGRESS family and should not
   carry a second, copied version of it. This class is only what is its OWN: its
   slot, one step further down the same stack (18 → 52 → 86, the stack's own
   34px pitch), and the stacking it already had, so a dragged chip frame
   (z-index 48) cannot bury the control that opens its panel. The pill keeps
   this slot whether or not the download and skip buttons above it are present,
   so it never moves under a person mid-exercise; the legend below is what
   yields. No earned-loud state: this button has never had one. */
.sendbtn {
	top: calc(env(safe-area-inset-top, 0px) + 86px);
	z-index: 60;
}
/* The author shortcuts legend takes the third slot when it is the only thing
   down there, and the fourth when the pill has taken the third — written by
   send.js onto the document root as it turns the pill on and off. Without this
   the legend (86px) and the pill sat in the same place, which is exactly what a
   signed-in author saw on 2 September 2026. */
.has-sendbtn .chip-keys {
	top: calc(env(safe-area-inset-top, 0px) + 120px);
}
/* The ending board takes the same slot, for the same reason, and must move with
   the line above it if that slot ever changes. The pill is the one thing in this
   stack that paints ABOVE the board, so when the board scrolls, cards travelled
   under the pill on their way past and it sat over the save block as well: ten of
   fifteen on a 390x844 phone, one on a 1440x900 desktop (round two review,
   3 September 2026). A scroll container clips its content at the padding box, so
   a transparent top border is a strip no card can enter, and a background paints
   across the border box, so the veil still covers the window and the look does
   not change. The class is written and removed by send.js on the document root on
   every refresh, the live switch-off included, so the strip comes and goes with
   the pill; env() and calc() re-evaluate on rotation by themselves. The rest of
   this stack sits BELOW the board and is covered BY it, which is the other way
   round and not the board's business. */
html.has-sendbtn .ending.scrolls {
	border-top: calc(env(safe-area-inset-top, 0px) + 120px) solid transparent;
}

body.is-author .tweaks-toggle {
	bottom: 50px;
}

/* ---- generic kit buttons (save bars etc.) ---- */
.kit-btn {
	appearance: none;
	cursor: pointer;
	pointer-events: auto;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	padding: 10px 18px;
	border-radius: 3px;
	transition:
		filter 0.12s,
		border-color 0.12s,
		color 0.12s;
}
.kit-btn.solid {
	color: var(--marker-ink);
	background: var(--marker);
	border: 1px solid var(--marker);
}
.kit-btn.solid:hover {
	filter: brightness(1.08);
}
.kit-btn.ghost {
	color: var(--fg-soft);
	background: transparent;
	border: 1px solid var(--border);
}
.kit-btn.ghost:hover {
	color: var(--cyan);
	border-color: var(--cyan);
}

/* ---- pause overlay (the save / create-account surface) ---- */
.pause-overlay {
	position: fixed;
	inset: 0;
	z-index: 20;
	display: none;
	align-items: center;
	justify-content: center;
	background: rgba(16, 16, 18, 0.74);
	-webkit-backdrop-filter: blur(7px) saturate(0.5);
	backdrop-filter: blur(7px) saturate(0.5);
	cursor: default;
	pointer-events: auto;
}
.pause-overlay.open {
	display: flex;
}
.pause-card {
	max-width: 440px;
	padding: 0 32px;
	text-align: center;
	color: var(--fg);
}
.pause-kicker {
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--muted);
	margin-bottom: 18px;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 9px;
	white-space: nowrap;
}
.pause-kicker .dot {
	width: 6px;
	height: 6px;
	border-radius: 999px;
	background: var(--cyan);
}
.pause-title {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: 34px;
	line-height: 1.18;
	letter-spacing: -0.02em;
	font-variation-settings:
		"opsz" 34,
		"wdth" 95;
	margin: 0 0 16px;
}
.pause-title em {
	font-style: normal;
	color: var(--cyan);
}
.pause-title .mark,
.pause-body .mark {
	background: var(--marker);
	color: var(--marker-ink);
	padding: 0 5px;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}
.pause-body {
	font-family: var(--font-sans);
	font-size: 15px;
	line-height: 1.6;
	color: var(--fg-soft);
	margin: 0 auto 28px;
	max-width: 380px;
}
.pause-actions {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
}
.pause-cta {
	appearance: none;
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--marker-ink);
	background: var(--marker);
	border: 1px solid var(--marker);
	padding: 11px 22px;
	border-radius: 3px;
	white-space: nowrap;
	transition:
		background 120ms,
		border-color 120ms,
		transform 120ms;
}
.pause-cta:hover {
	background: var(--marker-dark, var(--marker));
}
.pause-cta:active {
	transform: translateY(0.5px);
}
/* "Save my work" state: flip yellow → cyan so the button's change of job is
   unmistakable. Same button in both flows (email reveal, Google/signed-in
   re-render); engine.js toggles .is-save. The base transition animates it. */
.pause-cta.is-save {
	color: var(--cyan-ink);
	background: var(--cyan);
	border-color: var(--cyan);
}
.pause-cta.is-save:hover {
	background: var(--cyan-hover);
	border-color: var(--cyan-hover);
}
.pause-open {
	appearance: none;
	cursor: pointer;
	background: transparent;
	border: none;
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.04em;
	color: var(--fg-soft);
	padding: 2px 8px;
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: var(--border);
	white-space: nowrap;
	transition: color 120ms;
}
.pause-open:hover {
	color: var(--cyan);
}
/* The load button standing as the save button's peer, which it only does on a canvas
   that gave it a word of its own. The plain "or open a saved file" link keeps the
   footnote look it has always had. */
.pause-open.is-load {
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--cyan);
	border: 1px solid var(--cyan);
	border-radius: 3px;
	padding: 11px 22px;
	text-decoration: none;
}
.pause-open.is-load:hover {
	color: var(--cyan-ink);
	background: var(--cyan);
}
.pause-resume {
	appearance: none;
	cursor: pointer;
	background: transparent;
	border: 1px solid var(--border);
	font-family: var(--font-mono);
	font-size: 13px;
	letter-spacing: 0.08em;
	color: var(--fg-soft);
	padding: 8px 16px;
	border-radius: 3px;
	transition:
		color 120ms,
		border-color 120ms;
}
.pause-resume:hover {
	color: var(--cyan);
	border-color: var(--cyan);
}
/* ---- Sign in with Google (primary option above the email flow) ---- */
.pause-google {
	appearance: none;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 9px;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--fg-soft);
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid var(--border);
	padding: 10px 20px;
	border-radius: 3px;
	white-space: nowrap;
	transition:
		color 120ms,
		border-color 120ms,
		background 120ms;
}
.pause-google:hover {
	border-color: var(--fg-soft);
	background: rgba(255, 255, 255, 0.09);
}
.pause-google .g-icon {
	font-weight: 700;
	font-size: 13px;
	letter-spacing: 0;
	/* the Google blue G — recognisable without shipping the full 4-colour logo */
	color: #4285f4;
}
.pause-or {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 180px;
	opacity: 0.55;
	color: var(--fg-soft);
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}
.pause-or::before,
.pause-or::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--border);
}

/* ---- shared email capture (pause + ending) ---- */
.email-cap {
	display: flex;
	gap: 8px;
	align-items: stretch;
	flex-wrap: wrap;
	justify-content: center;
	pointer-events: auto;
}
.email-cap input[type="email"] {
	font-family: var(--font-mono);
	font-size: 13px;
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid var(--border);
	color: var(--fg);
	padding: 11px 14px;
	border-radius: 3px;
	min-width: 248px;
	outline: none;
	transition: border-color 120ms;
}
.email-cap input[type="email"]:focus {
	border-color: var(--cyan);
}
.email-cap input[type="email"]::placeholder {
	color: var(--muted);
}
.email-cap .email-err {
	width: 100%;
	text-align: center;
	color: var(--alert);
	font-family: var(--font-mono);
	font-size: 11px;
}

/* ---- ending board (optional module; results + credits-roll on phones) ---- */
.ending {
	position: fixed;
	inset: 0;
	z-index: 15;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 32px;
	padding: 64px 56px 56px;
	pointer-events: none;
	/* Every word on this board may break inside itself if it has to. An answer
	   holding one unbroken run of characters used to paint as a single line wider
	   than its card and off the side of the board, where nothing could reach it:
	   the board clips sideways and the page itself never scrolls (see html, body
	   at the top of this file). On a phone it was worse still, because the single
	   column takes the width of its widest line, so one such answer dragged the
	   whole column off both edges of the screen. This sits on the board rather
	   than on the card because the heading, the encourage line and the subnote are
	   author-typed free text too, outside any card, with the same trap under them.
	   It costs an ordinary board nothing: a break inside a word only ever happens
	   when the line would otherwise overflow. */
	overflow-wrap: anywhere;
	background: rgba(11, 11, 13, var(--kit-ending-veil, 0.62));
	-webkit-backdrop-filter: blur(2px) saturate(0.95);
	backdrop-filter: blur(2px) saturate(0.95);
	opacity: 0;
	transition: opacity 700ms;
}
.ending.open {
	opacity: 1;
}
/* A board with more answers than one screen holds at a readable size scrolls,
   rather than being squeezed until nobody can read it or run off the sides where
   nobody can reach it. The engine turns this on: on every phone, and on a desktop
   only when the fitted board is still taller than the space. A board that already
   fits keeps exactly the centred one-screen board it has now. pointer-events go
   back on because the overlay has to be the thing the wheel and the finger are
   touching before it can scroll at all. */
.ending.scrolls {
	justify-content: flex-start;
	/* auto, never hidden: if anything ever is wider than the board in spite of the
	   wrap above, it can be reached instead of being silently swallowed. This is
	   the same rule sideways that the line below is downwards, and it is what makes
	   the fit step's width fallback mean anything. */
	overflow-x: auto;
	overflow-y: auto;
	overscroll-behavior: contain;
	pointer-events: auto;
}
.ending-head {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: 30px;
	line-height: 1.18;
	letter-spacing: -0.02em;
	text-align: center;
	max-width: 900px;
	color: var(--fg);
	font-variation-settings:
		"opsz" 30,
		"wdth" 95;
	pointer-events: auto;
}
.ending-head .mark {
	background: var(--marker);
	color: var(--marker-ink);
	padding: 0 5px;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}
.ending-cta {
	pointer-events: auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
}
.ending-btn {
	appearance: none;
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--marker-ink);
	background: var(--marker);
	border: 1px solid var(--marker);
	padding: 12px 24px;
	border-radius: 3px;
	transition:
		filter 120ms,
		transform 120ms;
}
.ending-btn:hover {
	filter: brightness(1.08);
}
.ending-btn:active {
	transform: translateY(0.5px);
}
.ending-btn.secondary {
	color: var(--fg-soft);
	background: transparent;
	border-color: var(--border);
}
.ending-btn.secondary:hover {
	color: var(--cyan);
	border-color: var(--cyan);
}
.ending-subnote {
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.06em;
	color: var(--fg-soft);
	text-align: center;
}
.ending-roll {
	display: contents;
}
.ending-encourage {
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.5;
	color: var(--fg-soft);
	text-align: center;
	max-width: 460px;
}
.ending-btnrow {
	display: flex;
	gap: 12px;
	flex-wrap: wrap;
	justify-content: center;
}
.ending-grid {
	display: grid;
	gap: 34px 48px;
	justify-content: center;
	max-width: 1640px;
	width: 100%;
	transform-origin: top center;
}
.ending-col {
	display: flex;
	flex-direction: column;
	gap: 14px;
}
.ending-q {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: 22px;
	line-height: 1.25;
	letter-spacing: -0.01em;
	padding-bottom: 12px;
	border-bottom: 1px solid var(--rule);
	text-wrap: balance;
}
.ending-q .mark {
	background: var(--marker);
	color: var(--marker-ink);
	padding: 0 4px;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}
.ending-answers {
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.ending-a {
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.4;
	color: var(--fg-soft);
	text-wrap: pretty;
}
.ending-a::before {
	content: "·";
	margin-right: 8px;
	color: var(--cyan);
}
[contenteditable].editing {
	outline: none;
	box-shadow: 0 0 0 1px var(--cyan);
	background: rgba(63, 182, 200, 0.06);
	border-radius: 3px;
	cursor: text;
}
body.is-author .ending-head,
body.is-author .ending-encourage,
body.is-author .ending-subnote {
	cursor: text;
}

/* mobile: the head + grid are one column the person scrolls themselves, with the
   save block riding at the top of it. The block used to be pinned over the column
   while the column rolled past underneath like film credits, so a card was covered
   on its way by and could not be held still to read. It now sits first in the
   column and scrolls away with everything else, which is the one arrangement in
   which it can never cover a card. */
@media (max-width: 600px) {
	.ending-cta {
		order: -1;
		align-self: stretch;
		gap: 12px;
		padding: calc(env(safe-area-inset-top, 0px) + 14px) 20px 16px;
		background: rgba(11, 11, 13, 0.94);
		-webkit-backdrop-filter: blur(8px) saturate(0.95);
		backdrop-filter: blur(8px) saturate(0.95);
		border-bottom: 1px solid var(--rule, rgba(255, 255, 255, 0.1));
	}
}

/* ---- phones: keep the chrome, clear the device bars, respect safe areas ---- */
@media (max-width: 600px) {
	.topbar {
		top: calc(env(safe-area-inset-top, 0px) + 10px);
		left: calc(env(safe-area-inset-left, 0px) + 12px);
		font-size: 10px;
		gap: 2px;
	}
	.topbar .tb-title {
		font-size: 11px;
	}
	.pausebtn {
		top: calc(env(safe-area-inset-top, 0px) + 10px);
		right: calc(env(safe-area-inset-right, 0px) + 12px);
	}
	.qcount {
		top: calc(env(safe-area-inset-top, 0px) + 44px);
		right: calc(env(safe-area-inset-right, 0px) + 12px);
	}
	/* The pill IS a .pausebtn, so the phone rule above would otherwise move it
	   back on top of the download button. It needs a phone rule of its own —
	   but it has to clear the button actually above it, not the slot above it.
	   .skipbtn has NO phone override, so on a phone it keeps its desktop 52 and
	   runs to 81 (every button in this stack renders 29px high). The pill's
	   first phone offset was 78, three pixels inside the skip button. It keeps
	   the desktop's own slot instead, which already clears a skip button at 52,
	   and the legend keeps the slot under it. Nothing about the download or
	   skip rules is touched. */
	.sendbtn {
		top: calc(env(safe-area-inset-top, 0px) + 86px);
	}
	.has-sendbtn .chip-keys {
		top: calc(env(safe-area-inset-top, 0px) + 120px);
	}
	.footer-how {
		bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
		right: calc(env(safe-area-inset-right, 0px) + 12px);
	}
	.footer-copy {
		left: calc(env(safe-area-inset-left, 0px) + 12px);
		bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
	}
	.footer-made {
		display: none;
	}
	.hint {
		bottom: calc(env(safe-area-inset-bottom, 0px) + 40px);
		width: auto;
		max-width: 92vw;
		font-size: 10px;
		text-align: center;
	}
	.hint.top {
		top: calc(env(safe-area-inset-top, 0px) + 96px);
		bottom: auto;
	}
	#kit-prompt {
		top: 6%;
		font-size: clamp(18px, 5vw, 24px);
		width: 88%;
	}
	.corner-mark {
		display: none;
	}
}

/* ========================================================================== *
 * Mobile guards (Tim's field test)
 * ========================================================================== */

/* Rotate gate: phones in landscape get a full-screen "turn upright" cover. The
   canvas is built for portrait; iPad (taller) and desktop (fine pointer) are
   excluded by the short-height + coarse-pointer query. */
.rotate-gate {
	display: none;
}
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
	.rotate-gate {
		display: flex;
		position: fixed;
		inset: 0;
		z-index: 9999;
		align-items: center;
		justify-content: center;
		text-align: center;
		padding: 24px;
		background: var(--bg, #0c0c0d);
	}
	.rotate-gate-msg {
		font-family: var(--font-mono);
		font-size: 15px;
		letter-spacing: 0.02em;
		color: var(--fg-soft, #f1ebdb);
	}
}

/* Once questions start, drop the top-left build chrome on phones — it crowds the
   answer area and the keyboard shoves the layout into it (Tim #004). */
@media (max-width: 600px) {
	body.kit-in-questions .topbar {
		display: none;
	}
}

/* A pattern places objects on the main canvas. With no pattern selected, the
   same authored objects remain visible here as a computed reading. */
.pattern-side-tray {
	position: absolute;
	top: 96px;
	right: 18px;
	z-index: 18;
	display: grid;
	gap: var(--s-2);
	width: min(340px, calc(100vw - 36px));
	max-height: calc(100vh - 140px);
	overflow: auto;
	padding: var(--s-3);
	border: 1px solid var(--rule);
	background: var(--panel);
	color: var(--fg);
	box-shadow: var(--shadow-md);
	touch-action: auto;
}
.pattern-side-tray-title {
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
	color: var(--muted);
}
.pattern-side-tray-object {
	padding: var(--s-3);
	border: 1px solid var(--rule);
	font-family: var(--font-sans);
	font-size: 13px;
	line-height: 1.45;
	background: var(--bg);
}

/* Shared real-agent session windows. A supported canvas opts into mounting these
   through CanvasKit; provider conversations remain owned by their native harness. */
.ai-session-shell-offer {
	position: fixed;
	top: 18px;
	right: 20px;
	z-index: 74;
	border: 1px solid var(--accent);
	border-radius: var(--r-sm);
	background: var(--accent);
	color: var(--accent-ink);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: var(--tracking-caps);
	line-height: 1;
	padding: var(--s-3) var(--s-4);
	text-transform: uppercase;
}
.codex-chat-window,
.codex-chat-window *,
.claude-code-chat-window,
.claude-code-chat-window * {
	box-sizing: border-box;
}
	/* ============ real Codex task window (Mike-local only) ============ */
.codex-chat-window {
		position: fixed; top: 92px; right: 20px; z-index: 76;
		width: min(460px, calc(100vw - 24px)); height: min(680px, calc(100vh - 116px));
		display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto auto;
		grid-template-areas: "head" "toolbar" "history" "pending" "form";
		overflow: hidden; border: 1px solid var(--fg); border-radius: var(--r-sm);
		background: var(--panel); color: var(--fg); box-shadow: var(--shadow-lg);
		font-family: var(--font-sans);
	}
.codex-chat-window[hidden] { display: none; }
.codex-chat-head {
		grid-area: head;
		display: flex; align-items: center; justify-content: flex-start; gap: var(--s-2);
		padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--rule);
		background: var(--fg); color: var(--bg); user-select: none;
	}
.codex-chat-identity { display: grid; gap: 2px; min-width: 0; margin-right: auto; }
.codex-chat-kicker,
.codex-chat-task-label,
.codex-chat-message-role {
		font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
	}
.codex-chat-kicker { color: var(--accent); }
.codex-chat-heading {
		overflow: hidden; font-family: var(--font-display); font-size: 20px; font-weight: 400;
		line-height: 1.05; text-overflow: ellipsis; white-space: nowrap;
	}
.codex-chat-close {
		flex: 0 0 auto; border: 0; background: transparent; color: inherit; cursor: pointer;
		font-family: var(--font-mono); font-size: 22px; line-height: 1; padding: var(--s-1);
	}
.codex-chat-status,
.codex-chat-thread-meta {
		margin: 0; padding: var(--s-2) var(--s-4); font-size: 11px; line-height: 1.4;
	}
.codex-chat-task-row {
		grid-area: task;
		display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--s-2); align-items: center;
		padding: var(--s-3) var(--s-4) var(--s-1);
	}
.codex-chat-select,
.codex-chat-input {
		width: 100%; min-width: 0; border: 1px solid var(--rule); border-radius: var(--r-sm);
		background: var(--bg); color: var(--fg); font-family: var(--font-sans); font-size: 13px;
	}
.codex-chat-select { padding: var(--s-2); }
.codex-chat-refresh,
.codex-chat-send {
		border: 1px solid var(--fg); border-radius: var(--r-sm); cursor: pointer;
		font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
		padding: var(--s-2) var(--s-3);
	}
.codex-chat-refresh { background: transparent; color: var(--fg); }
.codex-chat-send { justify-self: end; background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.codex-chat-refresh:disabled,
.codex-chat-send:disabled { cursor: default; opacity: 0.45; }
.codex-chat-thread-meta {
		grid-area: meta;
		overflow: hidden; padding-top: 0; color: var(--whisper); font-family: var(--font-mono);
		text-overflow: ellipsis; white-space: nowrap;
	}
.codex-chat-status { grid-area: status; color: var(--muted); }
.codex-chat-status[data-kind="error"] { color: var(--status-alert); }
.codex-chat-status[data-kind="ready"] { color: var(--status-ok); }
.codex-chat-handoff {
		grid-area: handoff;
		margin: 0 var(--s-4) var(--s-2); padding: var(--s-3); border: 1px solid var(--status-alert);
		background: color-mix(in srgb, var(--status-alert) 10%, var(--panel));
	}
.codex-chat-handoff[hidden] { display: none; }
.codex-chat-handoff strong { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: var(--tracking-caps); }
.codex-chat-handoff p { margin: var(--s-1) 0 0; color: var(--muted); font-size: 12px; line-height: 1.4; }
.codex-chat-messages {
		grid-area: messages;
		overflow: auto; display: grid; align-content: start; gap: var(--s-3); padding: var(--s-3) var(--s-4);
		border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
	}
.codex-chat-message { display: grid; gap: var(--s-1); max-width: 92%; }
.codex-chat-message.is-user { justify-self: end; }
.codex-chat-message.is-assistant { justify-self: start; }
.codex-chat-message-role { color: var(--muted); }
.codex-chat-message.is-user .codex-chat-message-role { text-align: right; }
.codex-chat-message-text {
		margin: 0; padding: var(--s-3); border: 1px solid var(--rule); border-radius: var(--r-sm);
		background: var(--bg); font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere;
	}
.codex-chat-message.is-assistant .codex-chat-message-text { border-left: 3px solid var(--accent); }
.codex-chat-empty { margin: auto; color: var(--muted); font-size: 12px; }
.codex-chat-form {
	grid-area: form;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto auto;
	align-items: end;
	gap: var(--s-2);
	padding: var(--s-2) var(--s-3);
}
.codex-chat-input { resize: none; padding: var(--s-3); line-height: 1.45; }

	/* ============ real Claude Code session window (Mike-local only) ============ */
.claude-code-chat-window {
		position: fixed; top: 116px; left: 20px; z-index: 75;
		width: min(460px, calc(100vw - 24px)); height: min(640px, calc(100vh - 188px));
		display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto auto;
		grid-template-areas: "head" "toolbar" "history" "pending" "form";
		overflow: hidden; border: 1px solid var(--fg); border-radius: var(--r-sm);
		background: var(--panel); color: var(--fg); box-shadow: var(--shadow-lg);
		font-family: var(--font-sans);
	}
.claude-code-chat-window[hidden] { display: none; }
.claude-code-chat-head {
		grid-area: head;
		display: flex; align-items: center; justify-content: flex-start; gap: var(--s-2);
		padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--fg);
		background: var(--accent); color: var(--accent-ink); user-select: none;
	}
.claude-code-chat-identity { display: grid; gap: 2px; min-width: 0; margin-right: auto; }
.claude-code-chat-kicker,
.claude-code-chat-session-label,
.claude-code-chat-message-role {
		font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
	}
.claude-code-chat-kicker { color: var(--accent-ink); }
.claude-code-chat-heading {
		overflow: hidden; font-family: var(--font-display); font-size: 20px; font-weight: 400;
		line-height: 1.05; text-overflow: ellipsis; white-space: nowrap;
	}
.claude-code-chat-close {
		flex: 0 0 auto; border: 0; background: transparent; color: inherit; cursor: pointer;
		font-family: var(--font-mono); font-size: 22px; line-height: 1; padding: var(--s-1);
	}
.claude-code-chat-status,
.claude-code-chat-session-meta {
		margin: 0; padding: var(--s-2) var(--s-4); font-size: 11px; line-height: 1.4;
	}
.claude-code-chat-session-row {
		grid-area: session;
		display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--s-2); align-items: center;
		padding: var(--s-3) var(--s-4) var(--s-1);
	}
.claude-code-chat-select,
.claude-code-chat-input {
		width: 100%; min-width: 0; border: 1px solid var(--rule); border-radius: var(--r-sm);
		background: var(--bg); color: var(--fg); font-family: var(--font-sans); font-size: 13px;
	}
.claude-code-chat-select { padding: var(--s-2); }
.claude-code-chat-refresh,
.claude-code-chat-send {
		border: 1px solid var(--fg); border-radius: var(--r-sm); cursor: pointer;
		font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
		padding: var(--s-2) var(--s-3);
	}
.claude-code-chat-refresh { background: transparent; color: var(--fg); }
.claude-code-chat-send {
		justify-self: end; background: var(--accent); color: var(--accent-ink); border-color: var(--accent); white-space: nowrap;
	}
.claude-code-chat-refresh:disabled,
.claude-code-chat-send:disabled { cursor: default; opacity: 0.45; }
.claude-code-chat-session-meta {
		grid-area: meta;
		overflow: hidden; padding-top: 0; color: var(--whisper); font-family: var(--font-mono);
		text-overflow: ellipsis; white-space: nowrap;
	}
.claude-code-chat-status { grid-area: status; color: var(--muted); }
.claude-code-chat-status[data-kind="error"] { color: var(--status-alert); }
.claude-code-chat-status[data-kind="ready"] { color: var(--status-ok); }
.claude-code-chat-handoff {
		grid-area: handoff;
		margin: 0 var(--s-4) var(--s-2); padding: var(--s-3); border: 1px solid var(--status-alert);
		background: color-mix(in srgb, var(--status-alert) 10%, var(--panel));
	}
.claude-code-chat-handoff[hidden] { display: none; }
.claude-code-chat-handoff strong {
		font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: var(--tracking-caps);
	}
.claude-code-chat-handoff p {
		margin: var(--s-1) 0 0; color: var(--muted); font-size: 12px; line-height: 1.4;
	}
.claude-code-chat-messages {
		grid-area: messages;
		overflow: auto; display: grid; align-content: start; gap: var(--s-3); padding: var(--s-3) var(--s-4);
		border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
	}
.claude-code-chat-message { display: grid; gap: var(--s-1); max-width: 92%; }
.claude-code-chat-message.is-user { justify-self: end; }
.claude-code-chat-message.is-assistant { justify-self: start; }
.claude-code-chat-message-role { color: var(--muted); }
.claude-code-chat-message.is-user .claude-code-chat-message-role { text-align: right; }
.claude-code-chat-message-text {
		margin: 0; padding: var(--s-3); border: 1px solid var(--rule); border-radius: var(--r-sm);
		background: var(--bg); font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere;
	}
.claude-code-chat-message.is-assistant .claude-code-chat-message-text {
		border-left: 3px solid var(--accent);
	}
.claude-code-chat-empty { margin: auto; color: var(--muted); font-size: 12px; }
.claude-code-chat-form {
	grid-area: form;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto auto;
	align-items: end;
	gap: var(--s-2);
	padding: var(--s-2) var(--s-3);
}
.claude-code-chat-input { resize: none; padding: var(--s-3); line-height: 1.45; }

/* CanvasKit owns the shared real-agent presentation. The saved choice remains
   STACK or SIDES; narrow viewports receive STACK as a computed layout only. */
[data-ai-session-window][data-ai-session-layout="stack"] {
	right: 20px;
	left: auto;
	width: min(520px, calc(100vw - 40px));
	height: min(420px, calc((100vh - 132px) / 2));
}
[data-ai-session-window][data-ai-session-layout="stack"][data-ai-session-provider="claude-code"] {
	top: 72px;
	bottom: auto;
}
[data-ai-session-window][data-ai-session-layout="stack"][data-ai-session-provider="codex"] {
	top: auto;
	bottom: 20px;
}
[data-ai-session-window][data-ai-session-layout="sides"] {
	top: 72px;
	bottom: 20px;
	width: calc((100vw - 60px) / 2);
	height: calc(100vh - 92px);
}
[data-ai-session-window][data-ai-session-layout="sides"][data-ai-session-provider="claude-code"] {
	left: 20px;
	right: auto;
}
[data-ai-session-window][data-ai-session-layout="sides"][data-ai-session-provider="codex"] {
	left: auto;
	right: 20px;
}
[data-ai-session-window][data-ai-session-folded="true"] {
	height: auto !important;
	grid-template-rows: auto;
	grid-template-areas: "head";
}
[data-ai-session-window][data-ai-session-folded="true"] > :not([data-ai-session-header]) {
	display: none;
}
.ai-session-head-tools {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	gap: var(--s-2);
	margin-left: 0;
}
.ai-session-tools-host {
	display: contents;
}
.ai-session-info {
	position: relative;
	flex: 0 0 auto;
	margin: 0;
}
.ai-session-info-button {
	display: grid;
	place-items: center;
	width: 20px;
	height: 20px;
	border: 1px solid currentColor;
	border-radius: 50%;
	background: transparent;
	color: inherit;
	cursor: help;
	font-family: var(--font-mono);
	font-size: 10px;
	font-style: normal;
	line-height: 1;
	list-style: none;
}
.ai-session-info-button::-webkit-details-marker {
	display: none;
}
.ai-session-info-copy {
	position: absolute;
	top: calc(100% + var(--s-2));
	right: 0;
	z-index: 3;
	display: none;
	width: min(320px, calc(100vw - 40px));
	margin: 0;
	padding: var(--s-3);
	border: 1px solid var(--fg);
	border-radius: var(--r-sm);
	background: var(--panel);
	color: var(--fg);
	box-shadow: var(--shadow-lg);
	font-family: var(--font-sans);
	font-size: 12px;
	font-weight: 400;
	line-height: 1.45;
	text-transform: none;
	letter-spacing: normal;
	user-select: text;
}
.ai-session-info[open] > .ai-session-info-copy,
.ai-session-info:not([data-ai-session-info-dismissed]):hover > .ai-session-info-copy {
	display: block;
}
.ai-session-layout-control {
	display: inline-flex;
	align-items: center;
	border: 1px solid currentColor;
	border-radius: var(--r-sm);
	overflow: hidden;
}
.ai-session-layout-choice,
.ai-session-fold,
.ai-session-another,
.ai-session-capture {
	border: 0;
	background: transparent;
	color: inherit;
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 9px;
	letter-spacing: var(--tracking-caps);
	line-height: 1;
	padding: var(--s-2);
}
.ai-session-layout-choice + .ai-session-layout-choice {
	border-left: 1px solid currentColor;
}
.ai-session-layout-choice[aria-pressed="true"] {
	background: currentColor;
	color: var(--bg);
}
.claude-code-chat-head .ai-session-layout-choice[aria-pressed="true"] {
	color: var(--accent);
}
.ai-session-toolbar {
	grid-area: toolbar;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--s-2) var(--s-3);
	min-width: 0;
	padding: var(--s-2) var(--s-4);
	border-bottom: 1px solid var(--rule);
}
.ai-session-toolbar .codex-chat-task-row,
.ai-session-toolbar .claude-code-chat-session-row {
	grid-area: auto;
	grid-template-columns: minmax(0, 1fr) auto;
	min-width: 0;
	padding: 0;
}
.codex-chat-task-label,
.claude-code-chat-session-label {
	display: none;
}
.ai-session-connection {
	grid-area: auto;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: var(--s-2);
	min-width: 0;
	padding: 0;
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
.ai-session-condition {
	color: var(--muted);
}
[data-ai-session-condition="connected"] .ai-session-condition {
	color: var(--status-ok);
}
[data-ai-session-condition="reconnect-needed"] .ai-session-condition,
[data-ai-session-condition="unreachable"] .ai-session-condition {
	color: var(--status-alert);
}
.ai-session-reconnect {
	border: 1px solid currentColor;
	border-radius: var(--r-sm);
	background: transparent;
	color: var(--fg);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 9px;
	letter-spacing: var(--tracking-caps);
	padding: var(--s-2);
	text-transform: uppercase;
}
.ai-session-reconnect:disabled {
	display: none;
}
.ai-session-context {
	grid-column: 1 / -1;
	display: flex;
	gap: var(--s-2);
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
}
.ai-session-context[hidden] {
	display: none;
}
.ai-session-context > * {
	grid-area: auto;
	min-width: 0;
	margin: 0;
	padding: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.ai-session-progress {
	grid-column: 1 / -1;
	color: var(--muted);
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
[data-ai-session-drive-state="running"] .ai-session-progress {
	color: var(--accent);
}
[data-ai-session-drive-state="waiting"] .ai-session-progress {
	color: var(--status-warn);
}
[data-ai-session-drive-state="completed"] .ai-session-progress {
	color: var(--status-ok);
}
.ai-session-stop,
.ai-session-pending-choice {
	border: 1px solid currentColor;
	border-radius: var(--r-sm);
	background: transparent;
	color: var(--fg);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 9px;
	letter-spacing: var(--tracking-caps);
	padding: var(--s-2);
	text-transform: uppercase;
}
.ai-session-stop:disabled {
	cursor: default;
	opacity: 0.4;
}
.ai-session-pending-request {
	grid-area: pending;
	display: grid;
	gap: var(--s-2);
	max-height: min(300px, 42vh);
	overflow: auto;
	padding: var(--s-3) var(--s-4);
	border-top: 1px solid var(--status-warn);
	background: color-mix(in srgb, var(--status-warn) 8%, var(--panel));
}
.ai-session-pending-request[hidden] {
	display: none;
}
.ai-session-pending-kind,
.ai-session-pending-status,
.ai-session-pending-payload {
	margin: 0;
}
.ai-session-pending-kind,
.ai-session-pending-status {
	color: var(--muted);
	font-size: 11px;
}
.ai-session-pending-payload {
	max-height: 140px;
	overflow: auto;
	padding: var(--s-2);
	border: 1px solid var(--rule);
	background: var(--bg);
	color: var(--fg);
	font-family: var(--font-mono);
	font-size: 10px;
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}
.ai-session-pending-choices {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-2);
}
.ai-session-capture-overlay {
	position: fixed;
	inset: 0;
	z-index: 90;
	display: grid;
	place-items: center;
	padding: var(--s-4);
	background: color-mix(in srgb, var(--bg) 76%, transparent);
}
.ai-session-capture-card {
	display: grid;
	gap: var(--s-3);
	width: min(620px, 100%);
	max-height: calc(100vh - var(--s-8));
	overflow: auto;
	padding: var(--s-5);
	border: 1px solid var(--fg);
	border-radius: var(--r-sm);
	background: var(--panel);
	color: var(--fg);
	box-shadow: var(--shadow-lg);
}
.ai-session-capture-card > p,
.ai-session-capture-card legend {
	margin: 0;
	color: var(--muted);
}
.ai-session-capture-text {
	width: 100%;
	min-height: 150px;
	resize: vertical;
	padding: var(--s-3);
	border: 1px solid var(--rule);
	border-radius: var(--r-sm);
	background: var(--bg);
	color: var(--fg);
	font: inherit;
}
.ai-session-capture-relations {
	display: grid;
	gap: var(--s-2);
	margin: 0;
	padding: var(--s-3);
	border: 1px solid var(--rule);
}
.ai-session-capture-relations label {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	font-family: var(--font-mono);
	font-size: 11px;
}
.ai-session-capture-actions {
	display: flex;
	justify-content: flex-end;
	gap: var(--s-2);
}
.ai-session-capture-actions button {
	border: 1px solid var(--fg);
	border-radius: var(--r-sm);
	background: transparent;
	color: var(--fg);
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 10px;
	padding: var(--s-2) var(--s-3);
}
.ai-session-context > :first-child {
	flex: 0 1 auto;
}
.ai-session-context > :last-child {
	flex: 1 1 auto;
}
.codex-chat-status[data-kind="ready"],
.claude-code-chat-status[data-kind="ready"] {
	display: none;
}
.ai-session-history {
	grid-area: history;
	min-width: 0;
	min-height: 0;
	overflow-x: hidden;
	overflow-y: auto;
	overscroll-behavior: contain;
	border-bottom: 1px solid var(--rule);
}
.ai-session-history > .codex-chat-messages,
.ai-session-history > .claude-code-chat-messages {
	grid-area: auto;
	min-width: 0;
	min-height: 0;
	overflow: visible;
	border-top: 0;
	border-bottom: 0;
}
.codex-chat-form,
.claude-code-chat-form {
	position: relative;
	z-index: 1;
	min-width: 0;
	background: var(--panel);
}
.codex-chat-form > .codex-chat-send,
.claude-code-chat-form > .claude-code-chat-send {
	align-self: end;
	justify-self: end;
	white-space: nowrap;
	text-transform: none;
}
.codex-chat-input,
.claude-code-chat-input {
	max-height: min(180px, 30vh);
	overflow-y: auto;
}
.ai-session-resize-handle {
	position: absolute;
	z-index: 4;
	display: block;
	width: 12px;
	height: 12px;
	border: 1px solid var(--fg);
	background: var(--panel);
	touch-action: none;
}
.ai-session-resize-handle.is-nw {
	top: 2px;
	left: 2px;
	cursor: nwse-resize;
}
.ai-session-resize-handle.is-ne {
	top: 2px;
	right: 2px;
	cursor: nesw-resize;
}
.ai-session-resize-handle.is-sw {
	bottom: 2px;
	left: 2px;
	cursor: nesw-resize;
}
.ai-session-resize-handle.is-se {
	right: 2px;
	bottom: 2px;
	cursor: nwse-resize;
}
[data-ai-session-window][data-ai-session-folded="true"] > .ai-session-resize-handle {
	display: none !important;
}

/* ---- live connection between a canvas and the user's local canvas machine ---- */
.ai-machine-connection {
	position: fixed;
	top: 72px;
	right: 20px;
	z-index: 77;
	display: grid;
	gap: var(--s-2);
	width: min(420px, calc(100vw - 40px));
	padding: var(--s-3);
	border: 1px solid var(--fg);
	border-radius: var(--r-sm);
	background: var(--panel);
	color: var(--fg);
	box-shadow: var(--shadow-lg);
	font-family: var(--font-mono);
	user-select: text;
}
.ai-machine-connection[hidden] {
	display: none;
}
.ai-machine-connection-header,
.ai-machine-status-row,
.ai-machine-pairing-form,
.ai-machine-actions {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	min-width: 0;
}
.ai-machine-pairing-form[hidden] {
	display: none;
}
.ai-machine-local-pairing {
	display: grid;
	gap: var(--s-1);
	padding: var(--s-3);
	border: 1px solid var(--rule);
	border-radius: var(--r-sm);
	background: var(--bg);
}
.ai-machine-local-pairing[hidden] {
	display: none;
}
.ai-machine-local-pairing-label,
.ai-machine-local-pairing-expiry {
	color: var(--muted);
	font-size: 10px;
}
.ai-machine-local-pairing-label {
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
.ai-machine-local-pairing-code {
	color: var(--fg);
	font-size: clamp(18px, 5vw, 24px);
	font-weight: 500;
	letter-spacing: 0.08em;
	line-height: 1.2;
	overflow-wrap: anywhere;
}
.ai-machine-connection-heading {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	font-size: 12px;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.ai-machine-info,
.ai-machine-close,
.ai-machine-pairing-button,
.ai-machine-reconnect,
.ai-machine-probe {
	border: 1px solid var(--rule);
	border-radius: var(--r-sm);
	background: transparent;
	color: inherit;
	cursor: pointer;
	font: inherit;
	font-size: 10px;
	padding: var(--s-2);
	white-space: nowrap;
}
.ai-machine-info,
.ai-machine-close {
	display: grid;
	flex: 0 0 28px;
	width: 28px;
	height: 28px;
	place-items: center;
	padding: 0;
}
.ai-machine-close {
	font-size: 18px;
}
.ai-machine-status-row {
	justify-content: space-between;
	font-size: 10px;
}
.ai-machine-status {
	flex: 0 0 auto;
	color: var(--muted);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
.ai-machine-connection[data-condition="connected"] .ai-machine-status {
	color: var(--status-ok);
}
.ai-machine-connection[data-condition="connecting"] .ai-machine-status,
.ai-machine-connection[data-condition="reconnecting"] .ai-machine-status,
.ai-machine-connection[data-condition="pairing"] .ai-machine-status {
	color: var(--status-warn);
}
.ai-machine-observed {
	min-width: 0;
	overflow: hidden;
	color: var(--muted);
	text-overflow: ellipsis;
	white-space: nowrap;
}
.ai-machine-pairing-input {
	flex: 1 1 auto;
	min-width: 0;
	padding: var(--s-2);
	border: 1px solid var(--rule);
	border-radius: var(--r-sm);
	background: var(--bg);
	color: var(--fg);
	font: inherit;
	text-transform: uppercase;
}
.ai-machine-actions {
	justify-content: flex-end;
}
.ai-machine-probe-result {
	min-height: 1em;
	color: var(--muted);
	font-size: 10px;
	text-align: right;
}
.ai-machine-connection button:disabled {
	cursor: default;
	opacity: 0.45;
}
@media (max-width: 480px) {
	.ai-machine-connection {
		top: 60px;
		right: var(--s-3);
		width: calc(100vw - (var(--s-3) * 2));
	}
}
