/* ============================================================ tokens */
:root {
	/* brand presets carry a light and a dark variant so contrast holds both ways */
	--brand-light: #15916B;
	--brand-dark: #3FD6A6;

	--bg: #ffffff;
	--bg-subtle: #f4f3ee;
	--bg-raised: #fbfbf9;
	--bg-hover: #f2f1ec;
	--border: #e7e5de;
	--border-strong: #d6d3ca;
	--text: #08231c;
	--text-muted: #6e7b75;
	--chrome: #08231c;
	--chrome-2: #0c2a22;
	/* scrollbars — nuvocloud.eu's mint thumb; the track follows the theme */
	--scroll-thumb: color-mix(in oklab, var(--brand) 90%, #000000);
	--scroll-thumb-hover: color-mix(in oklab, var(--brand) 76%, #ffffff);
	--scroll-track: color-mix(in oklab, var(--brand) 13%, #ffffff);
	--chrome-text: #ffffff;
	--chrome-muted: rgba(255, 255, 255, 0.62);
	/* Selected app in the bar: a wash of the brand and a lighter brand tint
	   for the label, so a brand preset recolours the top navigation too. */
	--chrome-active: color-mix(in srgb, var(--brand-dark) 26%, transparent);
	--chrome-active-text: color-mix(in srgb, var(--brand-dark) 62%, #ffffff);

	/* Darkened from #c4521a. Against --warn-bg it measured 4.14:1, just under
	   AA, and every badge that pairs the two is 9.5-10px bold -- exactly the
	   size where a near-miss is a real miss. Now 5.4:1 on the badge and 6.0:1
	   on white. --warn is only ever used as a text colour, never a fill, so
	   darkening it raises contrast everywhere it appears and lowers it
	   nowhere. */
	--warn: #a8420f;
	--warn-bg: #fdf1e8;
	--warn-border: #f0c9a8;
	--danger: #b5322c;
	--ok: #15916b;
	--here-fg: #0f6b4f;
	--tab-fg: #798e84;
	--tab-fg-hover: var(--brand);
	--tab-add-fg: #94a29a;

	--brand: var(--brand-light);
	--brand-text: #ffffff;
	--brand-soft: color-mix(in oklab, var(--brand) 11%, var(--bg));
	--brand-line: color-mix(in oklab, var(--brand) 34%, var(--bg));

	--r-sm: 4px;
	--r: 8px;
	--r-lg: 12px;
	--r-xl: 16px;
	--tap: 34px;
	--header-h: 44px;

	--display: 'Space Grotesk', 'Manrope', system-ui, sans-serif;
	--body: 'Manrope', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
	color-scheme: light;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--bg: #0f1b18;
		--bg-subtle: #0b1512;
		--bg-raised: #14231f;
		--bg-hover: #172722;
		--border: #1e322c;
		--border-strong: #2a423a;
		--text: #e8f0ec;
		--text-muted: #94a69e;
		--chrome: #06110e;
		--chrome-2: #0a1714;
		--warn: #ff9e4d;
		--warn-bg: #2a1c10;
		--warn-border: #4a3018;
		--danger: #f08079;
		--ok: #3fd6a6;
		--here-fg: #4cae8c;
		--tab-fg: #476e5e;
		--tab-add-fg: #3d584d;
		--brand: var(--brand-dark);
		--brand-text: #06110e;
		--scroll-thumb: color-mix(in oklab, var(--brand) 68%, #000000);
		--scroll-thumb-hover: var(--brand);
		--scroll-track: color-mix(in oklab, var(--brand) 17%, #000000);
		color-scheme: dark;
	}
}

:root[data-theme="dark"] {
	--bg: #0f1b18;
	--bg-subtle: #0b1512;
	--bg-raised: #14231f;
	--bg-hover: #172722;
	--border: #1e322c;
	--border-strong: #2a423a;
	--text: #e8f0ec;
	--text-muted: #94a69e;
	--chrome: #06110e;
	--chrome-2: #0a1714;
	--warn: #ff9e4d;
	--warn-bg: #2a1c10;
	--warn-border: #4a3018;
	--danger: #f08079;
	--ok: #3fd6a6;
	--here-fg: #4cae8c;
	--tab-fg: #476e5e;
	--tab-add-fg: #3d584d;
	--brand: var(--brand-dark);
	--brand-text: #06110e;
	--scroll-thumb: color-mix(in oklab, var(--brand) 68%, #000000);
	--scroll-thumb-hover: var(--brand);
	--scroll-track: color-mix(in oklab, var(--brand) 17%, #000000);
	color-scheme: dark;
}

/* Scrollbars, everywhere: the same bars as nuvocloud.eu (html scrollbar-color
   for Firefox — the property inherits — and the WebKit pseudo-elements for
   everything else). Containers that hide their bar (.rail, .tabstrip, …) keep
   doing so: their own rules are more specific than these. */
html { scrollbar-width: auto; scrollbar-color: var(--scroll-thumb) var(--scroll-track); }
*::-webkit-scrollbar { width: 14px; height: 14px; background: var(--scroll-track); }
*::-webkit-scrollbar-track { background: var(--scroll-track); }
*::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 8px; border: 3px solid var(--scroll-track); }
*::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); }
*::-webkit-scrollbar-button { background: var(--scroll-track); }
*::-webkit-scrollbar-corner { background: var(--scroll-track); }

/* brand presets — independent of theme */
:root[data-brand="nextcloud"] { --brand-light: #00679e; --brand-dark: #5ab6e8; }
:root[data-brand="amber"] { --brand-light: #a85a12; --brand-dark: #ff9e4d; }
:root[data-brand="violet"] { --brand-light: #63459f; --brand-dark: #b49af0; }

/* Channel tabs sit deliberately quiet. Anyone who has asked their OS for more
   contrast gets the louder pair back automatically. */
@media (prefers-contrast: more) {
	:root { --tab-fg: #0f6b4f; --tab-add-fg: #55665e; }
	:root[data-theme="dark"] { --tab-fg: #5aad8f; --tab-add-fg: #94a69e; }
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) { --tab-fg: #5aad8f; --tab-add-fg: #94a69e; }
}

* { box-sizing: border-box; }

body {
	margin: 0;
	background: var(--bg);
	color: var(--text);
	font-family: var(--body);
	font-size: 15px;
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
	border-radius: var(--r-sm);
}

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		transition-duration: 0.01ms !important;
	}
}

button { font: inherit; color: inherit; cursor: pointer; }

/* ============================================================== shell */
.app {
	height: 100vh;
	height: 100dvh;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.hdr {
	height: var(--header-h);
	flex-shrink: 0;
	background: var(--chrome);
	display: flex;
	align-items: center;
	gap: 4px;
	padding-inline: 8px;
}

.hdr__brand {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 348px;
	flex-shrink: 0;
}

/* ---- the login gate ----
   Two looks. Plain (boot): a quiet cream ground and a spinner, because every
   page load passes through it. Hero (sign-in): the nuvocloud.eu hero -- ink,
   the site's scenes cross-fading on the right, sign-in on the left. */
#nv-login-gate { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: #faf9f5; font-family: Manrope, system-ui, sans-serif; color: #1a1a1a; overflow: hidden; }
#nv-login-gate.nvg--hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; justify-content: stretch; background: #08231C; color: #F4F3EE; }
.nvg__plain { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 24px; max-width: 92vw; }
.nvg__art { grid-column: 2; grid-row: 1; position: relative; overflow: hidden; pointer-events: none; }
.nvg__art::before { content: ''; position: absolute; inset: 0; z-index: 1; background: linear-gradient(90deg, #08231C 0%, rgba(8, 35, 28, .4) 50%, transparent 100%); }
.nvg__slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1.6s ease; will-change: opacity; }
.nvg__slide.active { opacity: 1; }
.nvg__slide svg { display: block; width: 100%; height: 100%; }
.nvg__col { grid-column: 1 / -1; grid-row: 1; position: relative; z-index: 2; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px; padding: 28px 24px; scrollbar-width: none; }
.nvg__col::-webkit-scrollbar { display: none; }
.nvg__logo { display: flex; align-items: center; gap: 12px; flex: none; }
.nvg__logo svg { width: 46px; height: 46px; flex: none; }
.nvg__logo .wordmark { font-size: 30px; color: #F4F3EE; }
/* The iframe IS the card: radius and shadow live on the element, where the
   frame's own edge cannot clip them. The page inside is a plain white surface. */
.nvg__frame { flex: none; width: 400px; max-width: 100%; height: 420px; border: 0; border-radius: 22px; background: #fff; box-shadow: 0 0 0 1px rgba(244, 243, 238, .08), 0 30px 80px -24px rgba(0, 0, 0, .6); transition: height .18s ease; animation: nvg-rise .5s cubic-bezier(.2, .7, .2, 1) both; }
@keyframes nvg-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes nvSpin { to { transform: rotate(360deg); } }
.nvg__spin { width: 30px; height: 30px; border-radius: 50%; border: 3px solid rgba(21, 145, 107, .22); border-top-color: #15916B; animation: nvSpin .7s linear infinite; }
.nvg--hero .nvg__spin { border-color: rgba(63, 214, 166, .2); border-top-color: #3FD6A6; }
.nvg__msg { font-size: 14.5px; line-height: 1.55; color: rgba(244, 243, 238, .66); max-width: 320px; text-align: center; }
.nvg__msg--err { color: #FF9C8A; }
.nvg__btn { background: #15916B; color: #fff; border: 0; padding: 12px 24px; border-radius: 13px; font: inherit; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 9px 22px -7px rgba(21, 145, 107, .55); transition: transform .15s ease, background .2s ease; }
.nvg__btn:hover { background: #22B98A; transform: translateY(-1px); }
.nvg__btn:focus-visible, .nvg__quiet:focus-visible { outline: 2px solid #3FD6A6; outline-offset: 3px; }
.nvg__quiet { border: 0; background: none; color: rgba(244, 243, 238, .55); font: inherit; font-size: 13px; cursor: pointer; padding: 6px 10px; border-radius: 8px; }
.nvg__quiet:hover { color: #F4F3EE; }
/* Narrow: the art goes behind everything at 60% under a vertical veil --
   exactly what the site does with its hero below 1024px. */
@media (max-width: 1024px) {
	#nv-login-gate.nvg--hero { grid-template-columns: minmax(0, 1fr); }
	.nvg__art { grid-column: 1; position: absolute; inset: 0; opacity: .6; }
	.nvg__art::before { background: linear-gradient(180deg, rgba(8, 35, 28, .55) 0%, rgba(8, 35, 28, .2) 42%, rgba(8, 35, 28, .62) 100%); }
}
/* Phone: the block starts about an eighth of the way down -- clear of the top
   edge, still in the upper half. When the keyboard comes up it slides to the
   top of what is left (see .is-kb), so the padding is animated. */
@media (max-width: 640px) {
	.nvg__col { justify-content: flex-start; gap: 22px; padding: max(clamp(44px, 12vh, 112px), calc(env(safe-area-inset-top, 0px) + 22px)) 16px 24px; transition: padding-top .24s ease, gap .24s ease; }
	.nvg__logo svg { width: 38px; height: 38px; }
	.nvg__logo .wordmark { font-size: 25px; }
}
/* Keyboard up (set from the visual viewport, see nvGateViewport): the gate is
   only as tall as what is still visible. The logo STAYS -- logo and card move
   up together and tighten a little, so the brand and the field being typed in
   are both on screen: 14 + 32 + 14 + a 257px card is 317px, and the shortest
   area a current iPhone leaves above its keyboard is about 390. Only the
   Cancel link goes; it would be under the keyboard anyway. */
#nv-login-gate.is-kb { bottom: auto; }
#nv-login-gate.is-kb .nvg__col { justify-content: flex-start; gap: 14px; padding-top: max(14px, calc(env(safe-area-inset-top, 0px) + 6px)); padding-bottom: 12px; }
#nv-login-gate.is-kb .nvg__logo svg { width: 32px; height: 32px; }
#nv-login-gate.is-kb .nvg__logo .wordmark { font-size: 22px; }
#nv-login-gate.is-kb .nvg__quiet { display: none; }
@media (prefers-reduced-motion: reduce) { .nvg__slide { transition: none; } .nvg__frame { animation: none; } .nvg__col { transition: none; } }

/* the NuvoCloud wordmark, matching nuvocloud.eu exactly */
.wordmark {
	font-family: var(--display);
	font-size: 18px;
	letter-spacing: -0.02em;
	white-space: nowrap;
	line-height: 1;
	color: var(--chrome-text);
}

.wordmark .nuvo { font-weight: 700; }
.wordmark .cloud { font-weight: 500; color: #3fd6a6; }
.wordmark .eu { font-weight: 600; font-size: 0.52em; color: #ff8a3d; vertical-align: 0.15em; margin-inline-start: 0.05em; }

.hdr__apps { display: flex; align-items: center; gap: 2px; flex-grow: 1; }

.hdr__app {
	height: var(--tap);
	padding-inline: 12px;
	border: none;
	border-radius: var(--r);
	background: transparent;
	color: var(--chrome-muted);
	font-size: 13px;
	font-weight: 500;
	display: flex;
	align-items: center;
	gap: 7px;
	white-space: nowrap;
}

.hdr__app:hover { background: rgba(255, 255, 255, 0.08); color: var(--chrome-text); }
.hdr__app[aria-current="true"] { background: var(--chrome-active); color: var(--chrome-active-text); font-weight: 600; }

.hdr__right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* The app bar never squeezes: a button and its glyph keep their size at every
   width. From 1280px down the labels fold to glyphs and the brand column stops
   reserving the sidebar's width; the BETA pill and the colour picker (which
   also lives in Settings) step aside so the controls stay on screen. */
.hdr__apps { min-width: 0; }
.hdr__app { flex-shrink: 0; }
.hdr__app > svg, .launch__hub { flex-shrink: 0; }
@media (min-width: 1024px) and (max-width: 1279.98px) {
	.hdr__brand { width: auto; margin-inline-end: 10px; }
	.hdr__app, .launch__btn { padding-inline: 11px; gap: 0; font-size: 0; }
	.hdr__app > svg, .launch__hub { width: 20px; height: 20px; }
	.hdr__app .pill-count { font-size: 11px; margin-inline-start: 4px; }
	.hdr__app .wip-badge { display: none; }
	.proto-pill, .brandpick { display: none !important; }
}

.proto-pill {
	height: 22px;
	padding-inline: 9px;
	border-radius: 100px;
	border: 1px solid rgba(255, 255, 255, 0.24);
	color: var(--chrome-muted);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	display: flex;
	align-items: center;
}

/* Brand colour: one dot in the current colour (it is var(--brand), so it
   follows the choice by itself); the four choices sit in a small popover. */
.brandpick { position: relative; display: flex; }
.brandpick__btn { width: var(--tap); height: var(--tap); padding: 0; border: none; border-radius: var(--r); background: transparent; display: grid; place-items: center; cursor: pointer; }
.brandpick__stack { display: flex; align-items: center; padding-inline-start: 5px; transition: transform .18s ease; }
.brandpick__stack .bp-d { width: 12px; height: 12px; border-radius: 50%; margin-inline-start: -5px; background: var(--c); box-shadow: 0 0 0 1.5px var(--chrome); position: relative; }
/* a fixed cascade: each disc sits under the one to its left */
.bp-d[data-brand="nuvo"] { z-index: 3; } .bp-d[data-brand="nextcloud"] { z-index: 2; } .bp-d[data-brand="amber"] { z-index: 1; } .bp-d[data-brand="violet"] { z-index: 0; }
/* the active brand jumps to the front: first and on top */
:root:not([data-brand]) .bp-d[data-brand="nuvo"], :root[data-brand="nuvo"] .bp-d[data-brand="nuvo"], :root[data-brand="nextcloud"] .bp-d[data-brand="nextcloud"], :root[data-brand="amber"] .bp-d[data-brand="amber"], :root[data-brand="violet"] .bp-d[data-brand="violet"] { order: -1; z-index: 4; }
.brandpick__btn:hover, .brandpick__btn:focus-visible { background: color-mix(in srgb, var(--chrome-text) 8%, transparent); outline: none; }
.brandpick__btn:hover .brandpick__stack, .brandpick__btn[aria-expanded="true"] .brandpick__stack { transform: scale(1.08); }
.brandpick__pop { position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 90; display: flex; gap: 6px; padding: 7px; background: var(--bg); border: 1px solid var(--border); border-radius: 100px; box-shadow: 0 14px 36px rgba(6, 17, 14, .28); transform-origin: top right; animation: launch-panel 240ms cubic-bezier(.2, 1.1, .3, 1); }
.brandpick__pop[hidden] { display: none; }
.brandpick__pop .swatch { width: 24px; height: 24px; }

.swatch {
	width: 18px;
	height: 18px;
	border-radius: 100px;
	border: 2px solid transparent;
	padding: 0;
	background-clip: content-box;
}

.swatch[aria-pressed="true"] { border-color: color-mix(in srgb, var(--text) 75%, transparent); }

.body { flex-grow: 1; display: flex; min-height: 0; }

/* =========================================================== rail */
.rail {
	width: 56px;
	flex-shrink: 0;
	background: var(--chrome-2);
	display: flex;
	flex-direction: column;
	align-items: center;
	padding-block: 10px;
	gap: 6px;
	overflow-y: auto;
	scrollbar-width: none;
}

.rail::-webkit-scrollbar { display: none; }

.rail__item { position: relative; width: 48px; display: flex; justify-content: center; flex-shrink: 0; }

.rail__marker {
	position: absolute;
	inset-inline-start: -4px;
	top: 8px;
	width: 3px;
	height: 24px;
	border-radius: 100px;
	background: var(--brand-dark);
}

.rail__tile {
	width: 40px;
	height: 40px;
	border-radius: var(--r-lg);
	border: none;
	color: #fff;
	font-family: var(--display);
	font-size: 14px;
	font-weight: 600;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: transform 120ms ease;
}

.rail__tile:hover { transform: scale(1.07); }

.rail__tile--add {
	background: transparent;
	border: 1.5px dashed rgba(255, 255, 255, 0.24);
	color: rgba(255, 255, 255, 0.6);
}

.rail__badge {
	position: absolute;
	top: -3px;
	inset-inline-end: 1px;
	min-width: 19px;
	height: 19px;
	padding-inline: 5px;
	border-radius: 100px;
	background: #ff8a3d;
	color: #08231c;
	font-size: 11px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 2px solid var(--chrome-2);
}

.rail__sep { width: 24px; height: 1px; background: rgba(255, 255, 255, 0.12); margin-block: 4px; flex-shrink: 0; }

/* =================================================== channel list */
.list {
	width: 300px;
	flex-shrink: 0;
	background: var(--bg-subtle);
	border-inline-end: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	min-height: 0;
}

.list__head { padding: 14px 14px 10px; display: flex; flex-direction: column; gap: 2px; }
.list__title { font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -0.2px; }
.list__sub { font-size: 13px; color: var(--text-muted); }

.list__search { padding-inline: 14px; padding-block-end: 10px; }

.list__scroll {
	flex-grow: 1;
	overflow-y: auto;
	padding-inline: 8px;
	padding-block-end: 14px;
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.sect {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 14px 6px 4px;
	font-size: 12px;
	font-weight: 700;
	color: var(--text-muted);
	letter-spacing: 0.4px;
	text-transform: uppercase;
}

.sect__toggle {
	display: flex;
	align-items: center;
	gap: 7px;
	background: none;
	border: none;
	padding: 0;
	font: inherit;
	color: inherit;
	border-radius: var(--r-sm);
}

.sect__toggle:hover { color: var(--text); }

.sect__chev { display: flex; transition: transform 140ms ease; flex-shrink: 0; }
.sect__toggle[aria-expanded="true"] .sect__chev { transform: rotate(90deg); }

.sect__n { font-weight: 600; letter-spacing: 0; opacity: 0.65; }

.sect__btn {
	margin-inline-start: auto;
	background: none;
	border: none;
	color: var(--text-muted);
	display: flex;
	padding: 3px;
	border-radius: var(--r-sm);
}

.sect__btn:hover { background: var(--border); color: var(--text); }

.chan {
	min-height: var(--tap);
	border-radius: var(--r);
	border: none;
	background: transparent;
	display: flex;
	align-items: center;
	gap: 9px;
	padding-inline: 10px;
	font-size: 14px;
	text-align: start;
	width: 100%;
}

.chan:hover { background: var(--bg-hover); }
/* Your own chat: pinned first, half-faded until you reach for it. */
.chan--self { opacity: .5; transition: opacity .15s ease; }
.chan--self:hover, .chan--self:focus-visible, .chan--self[aria-current="true"] { opacity: 1; }
.chan[aria-current="true"] { background: var(--brand); color: var(--brand-text); font-weight: 600; }
.chan__hash { opacity: 0.6; font-weight: 600; flex-shrink: 0; }
.chan__name { flex-grow: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pill-count {
	min-width: 20px;
	height: 20px;
	padding-inline: 6px;
	border-radius: 100px;
	background: var(--text);
	color: var(--bg);
	font-size: 11px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	font-variant-numeric: tabular-nums;
}

.chan[aria-current="true"] .pill-count { background: var(--brand-text); color: var(--brand); }

/* ==================================================== channel view */
.main { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; background: var(--bg); }

.topbar {
	height: 52px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 12px;
	padding-inline: 16px;
	border-block-end: 1px solid var(--border);
}

.topbar__icon {
	width: 34px;
	height: 34px;
	border-radius: var(--r);
	background: var(--brand-soft);
	color: var(--brand);
	font-size: 17px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.topbar__text { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; }
.topbar__name { font-size: 15px; font-weight: 600; line-height: 20px; }
.topbar__desc { font-size: 13px; color: var(--text-muted); line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tabstrip {
	min-height: 44px;
	flex-shrink: 0;
	display: flex;
	align-items: stretch;
	gap: 2px;
	padding-inline: 12px;
	border-block-end: 1px solid var(--border);
	overflow-x: auto;
	scrollbar-width: thin;
}

.tab {
	display: flex;
	align-items: center;
	gap: 7px;
	padding-inline: 12px;
	font-size: 14px;
	font-weight: 500;
	color: var(--tab-fg);
	background: none;
	border: none;
	white-space: nowrap;
	position: relative;
}

.tab { transition: color 140ms ease; }
.tab:hover { background: var(--bg-hover); color: var(--tab-fg-hover); }
.tab[aria-current="true"] { color: var(--brand); font-weight: 600; box-shadow: inset 0 -2px 0 0 var(--brand); }
.tab--add { color: var(--tab-add-fg); }

.tab__x {
	display: flex;
	border: none;
	background: none;
	opacity: 0.5;
	padding: 2px;
	margin-inline-start: 2px;
	border-radius: var(--r-sm);
}

.tab__x:hover { opacity: 1; background: var(--bg-hover); }

.pane { flex-grow: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }

/* =========================================================== chat */
.chat { display: flex; flex-direction: column; flex-grow: 1; min-height: 0; }

.chat__scroll {
	flex-grow: 1;
	overflow-y: auto;
	padding: 18px 20px 8px;
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.day {
	display: flex;
	align-items: center;
	gap: 12px;
	color: var(--text-muted);
	font-size: 12px;
	font-weight: 600;
}

.day::before, .day::after { content: ''; flex-grow: 1; height: 1px; background: var(--border); }
/* ===== Talk+ chat gaps: unread line, jump flash, history bar, pins, search ===== */
.day--new { color: var(--brand); font-weight: 600; }
.day--new::before, .day--new::after { background: var(--brand-line); }
@keyframes msgflash { 0%, 40% { background: var(--brand-soft); } 100% { background: transparent; } }
.msg--flash { animation: msgflash 1.6s ease-out; border-radius: 8px; }
.pollcard.msg--flash { border-radius: var(--r-lg); }
.chat__older { display: flex; align-items: center; gap: 10px; padding: 8px 14px; background: var(--brand-soft); border-block-start: 1px solid var(--brand-line); font-size: 13px; }
.chat__older .btn { margin-inline-start: auto; }
.pinbar { display: flex; align-items: center; gap: 8px; padding: 8px 14px; background: var(--brand-soft); border-block-end: 1px solid var(--brand-line); font-size: 13px; cursor: pointer; }
.pinbar__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-grow: 1; }
.pinbar__chev { flex-shrink: 0; color: var(--text-muted); }
.pinbar__list { background: var(--bg-raised); border-block-end: 1px solid var(--brand-line); max-height: 40vh; overflow: auto; padding: 4px 8px; }
.pinbar__row { display: flex; align-items: center; gap: 4px; }
.pinbar__row .sph-row { flex-grow: 1; }
.chatsearch { display: flex; align-items: center; gap: 8px; padding: 8px 14px; border-block-end: 1px solid var(--border); background: var(--bg-subtle); }
.chatsearch .input { flex-grow: 1; }
.chatsearch__ic { flex-shrink: 0; color: var(--text-muted); }
.chatsearch__n { flex-shrink: 0; font-size: 12.5px; }
.chatsearch__list { max-height: 40vh; overflow: auto; background: var(--bg-raised); border-block-end: 1px solid var(--border); }
.chatsearch__list:empty { display: none; }
mark { background: var(--brand-soft); color: inherit; border-radius: 3px; padding: 0 2px; }
.topbar__pop { position: absolute; top: calc(100% + 6px); inset-inline-end: 0; z-index: 20; display: flex; flex-direction: column; gap: 8px; padding: 12px; background: var(--bg-raised); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 40px rgba(0,0,0,.18); width: 240px; }
.topbar__pop__hint { font-size: 12px; color: var(--text-muted); }

.msg { display: flex; gap: 12px; }

.av {
	width: 34px;
	height: 34px;
	border-radius: 100px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 12px;
	font-weight: 700;
	color: #fff;
}

.av--sm { width: 30px; height: 30px; font-size: 11px; }
.av--xs { width: 26px; height: 26px; font-size: 10px; }
/* A real profile picture sits on top of the initials; if it fails to load the
   class is dropped and the letters underneath are what you see. */
.av--img { position: relative; overflow: hidden; }
.av--img > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }
.av--ring { box-shadow: 0 0 0 2px var(--bg); }
/* "NuvoCloud has been updated" — bottom-centre, above the dock (95), below the modal backdrop (100). */
.nuvo-update { position: fixed; inset-inline: 0; inset-block-end: max(18px, env(safe-area-inset-bottom)); margin: 0 auto; width: fit-content; max-width: calc(100% - 24px); z-index: 99; display: flex; align-items: center; gap: 12px; padding: 10px 10px 10px 16px; background: var(--panel, var(--bg)); color: var(--text); border: 1px solid var(--border); border-radius: 100px; box-shadow: 0 12px 40px rgba(0, 0, 0, .28); font-size: 13.5px; animation: nuvoUpdateIn .28s ease-out; }
.nuvo-update__dot { width: 9px; height: 9px; border-radius: 100px; background: var(--brand); box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 22%, transparent); flex-shrink: 0; }
@keyframes nuvoUpdateIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.msg__body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.msg__meta { display: flex; align-items: baseline; gap: 8px; }
.msg__author { font-size: 14px; font-weight: 600; }
.msg__time { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.msg__text .q { display: block; padding-inline-start: 10px; border-inline-start: 2px solid var(--brand-line); color: var(--text-muted); }
.msg__text { font-size: 15px; max-width: 66ch; white-space: pre-wrap; overflow-wrap: anywhere; }

.msg--system { font-size: 13px; color: var(--text-muted); padding-inline-start: 46px; display: flex; align-items: center; gap: 10px; }

/* ===== Talk+ live messaging (Stage 2): actions, reactions, pickers ===== */
.msg { position: relative; }
.msg__edited { font-size: 11px; color: var(--text-muted); font-style: italic; }
.msg--pending { opacity: .55; }
.msg--pending .msg__actions { display: none; }

.msg__actions {
	position: absolute; top: -13px; inset-inline-end: 6px;
	display: flex; gap: 1px; padding: 2px;
	background: var(--bg-raised); border: 1px solid var(--border);
	border-radius: 9px; box-shadow: 0 5px 16px rgba(0, 0, 0, .11);
	opacity: 0; transform: translateY(3px); pointer-events: none;
	transition: opacity .12s ease, transform .12s ease; z-index: 4;
}
.msg:hover .msg__actions, .msg__actions:focus-within { opacity: 1; transform: none; pointer-events: auto; }
.msg__act {
	width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;
	border: 0; background: transparent; border-radius: 6px; cursor: pointer; color: var(--text-muted);
}
.msg__act:hover { background: var(--bg-hover); color: var(--text); }
.msg__act--danger:hover { color: var(--danger); }

.msg__reactions { display: flex; flex-wrap: wrap; gap: 5px; margin-block-start: 5px; }
.rx {
	display: inline-flex; align-items: center; gap: 5px;
	padding: 1px 9px 1px 7px; height: 26px;
	border: 1px solid var(--border); border-radius: 100px;
	background: var(--bg-subtle); cursor: pointer; font-size: 14px; color: var(--text); line-height: 1;
}
.rx:hover { border-color: var(--border-strong); }
.rx--mine { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); font-weight: 600; }
.rx__n { font-variant-numeric: tabular-nums; font-size: 12px; }

.emojipop {
	position: absolute; z-index: 6; top: 16px; inset-inline-end: 6px;
	display: flex; gap: 2px; padding: 5px;
	background: var(--bg-raised); border: 1px solid var(--border);
	border-radius: 11px; box-shadow: 0 8px 26px rgba(0, 0, 0, .17);
}
.emojipop button {
	width: 34px; height: 34px; border: 0; background: transparent; cursor: pointer;
	border-radius: 7px; font-size: 19px; line-height: 1;
}
.emojipop button:hover { background: var(--bg-hover); }

/* per-message "more" menu — cross-app actions (Add to board / Create event) */
.msgmenu {
	position: absolute; z-index: 6; top: 16px; inset-inline-end: 6px; min-width: 184px;
	display: flex; flex-direction: column; padding: 5px;
	background: var(--bg-raised); border: 1px solid var(--border);
	border-radius: 11px; box-shadow: 0 8px 26px rgba(0, 0, 0, .17);
}
.msgmenu button {
	display: flex; align-items: center; gap: 10px; padding: 8px 10px;
	border: 0; background: transparent; cursor: pointer; border-radius: 7px;
	font-size: 13.5px; color: var(--text); text-align: start; width: 100%;
}
.msgmenu button:hover { background: var(--bg-hover); }
.msgmenu svg { color: var(--brand); flex-shrink: 0; }

/* @mention autocomplete, opens upward above the composer */
.mentionpop {
	position: absolute; z-index: 20; inset-inline: 0; bottom: calc(100% + 6px);
	max-height: 244px; overflow-y: auto;
	background: var(--bg-raised); border: 1px solid var(--border);
	border-radius: 11px; box-shadow: 0 10px 32px rgba(0, 0, 0, .19); padding: 5px;
}
.mentionpop__i {
	display: flex; align-items: center; gap: 10px; padding: 7px 9px;
	border-radius: 7px; cursor: pointer; font-size: 14px;
}
.mentionpop__i--on, .mentionpop__i:hover { background: var(--brand-soft); }
.mentionpop__sub { color: var(--text-muted); font-size: 12px; margin-inline-start: auto; }

/* reply-in-thread banner above the composer */
.replybar {
	display: flex; align-items: center; gap: 10px; margin-block-end: 8px;
	padding: 7px 12px; border-inline-start: 3px solid var(--brand);
	background: var(--brand-soft); border-radius: var(--r);
}
.replybar__t { min-width: 0; font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.replybar__t b { color: var(--brand); }
.replybar__x { margin-inline-start: auto; border: 0; background: transparent; cursor: pointer; color: var(--text-muted); display: flex; flex-shrink: 0; }
/* the message a reply answers, quoted above it: the mail composer's blockquote in the brand colour */
.msg__quote { display: flex; flex-direction: column; gap: 1px; align-items: flex-start; text-align: start; max-width: 66ch; margin: 1px 0 3px; padding: 4px 10px; border: 0; border-inline-start: 3px solid var(--brand); border-radius: 0 var(--r-sm) var(--r-sm) 0; background: var(--brand-soft); color: var(--text-muted); font: inherit; font-size: 13px; line-height: 1.35; cursor: pointer; }
.msg__quote:hover { color: var(--text); }
.msg__quote:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.msg__quote__a { font-weight: 600; color: var(--brand); }
.msg__quote__x { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }

/* a quoted parent shown on a threaded reply */
.msg__parent {
	border-inline-start: 3px solid var(--border-strong); background: var(--bg-subtle);
	border-radius: 0 var(--r-sm) var(--r-sm) 0; padding: 4px 10px; margin-block-end: 4px;
	font-size: 13px; color: var(--text-muted); max-width: 60ch;
}
.msg__parent b { color: var(--text); font-weight: 600; }

/* an @mention rendered inside a message body */
.mention { color: var(--brand); font-weight: 600; background: var(--brand-soft); padding: 0 4px; border-radius: 4px; }

/* inline loading state for a channel tab (Files/Runbook), lighter than the dial */
.tf-load { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 48px 0; }
.tf-spin { width: 20px; height: 20px; border-radius: 100px; border: 2.5px solid var(--border); border-top-color: var(--brand); animation: nuvo-spin 0.8s linear infinite; }

/* Runbook editor — a plain, focused Markdown textarea */
.rbedit { display: flex; flex-direction: column; height: 100%; min-height: 0; padding: 16px 20px; }
.rbedit__ta {
	flex: 1; min-height: 0; width: 100%; resize: none;
	border: 1px solid var(--border); border-radius: var(--r); background: var(--bg-raised);
	color: var(--text); padding: 16px 18px; font: 14px/1.6 ui-monospace, 'Cascadia Code', 'Consolas', monospace;
	tab-size: 2;
}
.rbedit__ta:focus { outline: none; border-color: var(--brand); }
.rbedit__hint { padding-block-start: 8px; font-size: 12px; color: var(--text-muted); }
.rbdoc { max-width: 76ch; }

/* Flow tab — read-only status badge (writes happen in the Flow app) */
.flbadge { font-size: 11px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; padding: 3px 9px; border-radius: 100px; background: var(--bg-hover); color: var(--text-muted); }
.flbadge--on { background: var(--brand-soft); color: var(--brand); }

/* Poll card in the chat stream */
.pollcard { max-width: 440px; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-raised); padding: 14px 16px; margin-block-start: 2px; }
.pollcard__h { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: var(--text-muted); }
.pollcard__h svg { color: var(--brand); }
.pollcard__q { font-size: 15px; font-weight: 600; margin: 8px 0 12px; }
.pollopt { display: flex; align-items: center; gap: 10px; width: 100%; margin-block-end: 7px; border-radius: 9px; font-size: 14px; text-align: start; }
.pollopt--vote { padding: 9px 12px; border: 1px solid var(--border); background: var(--bg); color: var(--text); cursor: pointer; }
.pollopt--vote:hover { border-color: var(--brand-line); background: var(--brand-soft); }
.pollopt__radio { width: 16px; height: 16px; border-radius: 100px; border: 2px solid var(--border-strong); flex-shrink: 0; }
.pollopt--vote:hover .pollopt__radio { border-color: var(--brand); }
.pollopt--res { position: relative; padding: 9px 12px; overflow: hidden; background: var(--bg-subtle); isolation: isolate; }
.pollopt__bar { position: absolute; inset-block: 0; inset-inline-start: 0; z-index: -1; background: var(--brand-soft); border-radius: 9px; transition: width .35s ease; }
.pollopt--mine .pollopt__bar { background: color-mix(in oklab, var(--brand) 22%, var(--bg)); }
.pollopt__l { display: flex; align-items: center; gap: 6px; min-width: 0; overflow-wrap: anywhere; }
.pollopt--mine .pollopt__l { font-weight: 600; }
.pollopt__l svg { color: var(--brand); flex-shrink: 0; }
.pollopt__n { margin-inline-start: auto; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; padding-inline-start: 10px; }
.pollcard__f { display: flex; align-items: center; gap: 10px; margin-block-start: 10px; font-size: 12px; }

/* Poll composer modal */
.poll-opts { display: flex; flex-direction: column; gap: 8px; }
.poll-optrow { display: flex; align-items: center; gap: 8px; }
.poll-optrow .input { flex: 1; }

/* ===== NuvoCloud call window (real Talk call, embedded + reskinned) ===== */
/* The class sets display:flex, which on its own defeats the `hidden` attribute
   (a class selector beats the UA `[hidden]` rule, and the served wrapper has no
   `[hidden]{display:none!important}` reset) — so teardown's `el.hidden = true`
   would leave an empty panel on screen. This keeps `hidden` authoritative. */
.nuvo-call[hidden] { display: none !important; }
/* The call window hangs just under the header (never over it), centred left to
   right, and never taller than the room between the header and the bottom of
   the viewport — so the FaceTime pill at its foot is always on screen. */
.nuvo-call {
	position: fixed; z-index: 96;
	inset-block-start: calc(var(--header-h) + 14px); inset-inline-start: 50%; transform: translateX(-50%);
	width: min(940px, 94vw); height: min(608px, calc(100vh - var(--header-h) - 28px));
	display: flex; flex-direction: column;
	background: #0f1b18; color: #fff;
	border: 1px solid rgba(255, 255, 255, .10); border-radius: 18px; overflow: hidden;
	box-shadow: 0 30px 90px rgba(0, 0, 0, .55);
	animation: nuvo-call-in .22s ease-out both;
}
@keyframes nuvo-call-in { from { opacity: 0; transform: translateX(-50%) translateY(-8px) scale(.985); } to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); } }
.nuvo-call__bar { display: flex; align-items: center; gap: 12px; flex-shrink: 0; padding: 10px 12px 10px 14px; background: linear-gradient(180deg, rgba(0, 0, 0, .30), transparent); }
.nuvo-call__id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.nuvo-call__id .av { flex-shrink: 0; width: 30px; height: 30px; object-fit: cover; }
.nuvo-call__meta { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.nuvo-call__meta b { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nuvo-call__t { font-size: 12px; color: rgba(255, 255, 255, .62); font-variant-numeric: tabular-nums; }
.nuvo-call__actions { margin-inline-start: auto; display: flex; align-items: center; gap: 4px; }
.nuvo-call__btn { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border: 0; border-radius: 100px; cursor: pointer; background: rgba(255, 255, 255, .10); color: #fff; transition: background .12s, transform .12s; }
.nuvo-call__btn:hover { background: rgba(255, 255, 255, .22); }
.nuvo-call__btn:active { transform: scale(.94); }
.nuvo-call__btn--leave { background: var(--danger); }
.nuvo-call__btn--leave:hover { background: #c9403a; }
.nuvo-call__stage { position: relative; flex: 1; min-height: 0; background: #0b1512; }
.nuvo-call__stage iframe { width: 100%; height: 100%; border: 0; display: block; background: #0b1512; }
/* NuvoCloud connect veil — covers the embedded Talk while it sets the call up,
   so Nextcloud's own chat / device-check screens never show. Lifts once the
   call view mounts. The branded dial is half the app-loader's size. */
.nuvo-call__loading {
	position: absolute; inset: 0; z-index: 3;
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
	background: #0b1512;
	animation: nuvo-loader-in .2s ease-out both;
}
.nuvo-call__loading[hidden] { display: none !important; }
.nuvo-call__loading .nuvo-loader__dial { width: 52px; height: 52px; }
.nuvo-call__loadmsg { font-size: 13px; color: rgba(255, 255, 255, .6); letter-spacing: .01em; }
.nuvo-call__piphint { display: none; }
/* Ringing roster on the veil of a channel call: the people Talk is ringing,
   overlapped like avGroup, on the veil's own dark ground. */
.nuvo-call__ring { display: flex; align-items: center; margin-block-start: -4px; }
.nuvo-call__ring .av { margin-inline-start: -8px; box-shadow: 0 0 0 2px #0b1512; }
.nuvo-call__ring .av:first-child { margin-inline-start: 0; }
/* ===== incoming-call banner ===== top centre, above menus (90) and below the
   modal backdrop (100). Theme tokens throughout, so it reads on both grounds. */
.nuvo-ring {
	position: fixed; inset-block-start: calc(12px + var(--sat, 0px)); inset-inline: 0; z-index: 98;
	display: flex; justify-content: center; pointer-events: none; padding-inline: 12px;
}
.nuvo-ring[hidden] { display: none; }
.nuvo-ring__card {
	pointer-events: auto; display: flex; align-items: center; gap: 12px; max-width: 100%;
	padding: 10px 12px 10px 12px; border-radius: 16px;
	background: var(--bg-raised); color: var(--text); border: 1px solid var(--border-strong);
	box-shadow: 0 18px 48px -14px rgba(4, 16, 13, 0.55);
	animation: nuvo-ring-in .28s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes nuvo-ring-in { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
.nuvo-ring__av { position: relative; display: inline-flex; flex: 0 0 auto; border-radius: 50%; }
.nuvo-ring__av::after {
	content: ''; position: absolute; inset: -3px; border-radius: 50%;
	border: 2px solid #22B98A; animation: nuvo-ring-pulse 1.6s ease-out infinite;
}
@keyframes nuvo-ring-pulse { 0% { opacity: .9; transform: scale(.92); } 100% { opacity: 0; transform: scale(1.35); } }
.nuvo-ring__txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; margin-inline-end: 4px; }
.nuvo-ring__who { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nuvo-ring__where { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nuvo-ring__acts { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.nuvo-ring__btn {
	display: inline-flex; align-items: center; gap: 6px; height: 36px; padding-inline: 12px;
	border: 0; border-radius: 100px; cursor: pointer; font: inherit; font-size: 13px; font-weight: 600;
	transition: transform .12s, filter .12s;
}
.nuvo-ring__btn:hover { filter: brightness(1.06); }
.nuvo-ring__btn:active { transform: scale(.96); }
.nuvo-ring__btn--join { background: #22B98A; color: #08231C; }
.nuvo-ring__btn--decline { background: var(--danger); color: #fff; }
.nuvo-ring__mute {
	width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
	border: 0; border-radius: 100px; background: transparent; color: var(--text-muted); cursor: pointer;
}
.nuvo-ring__mute:hover { background: var(--bg-hover); color: var(--text); }
@media (max-width: 640px) {
	.nuvo-ring__btn span { display: none; }
	.nuvo-ring__btn { width: 36px; padding-inline: 0; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { .nuvo-ring__card, .nuvo-ring__av::after { animation: none; } }
/* "Live call" pill on a channel / chat row: a call is running there now. It is
   a span (the row itself is a button) and carries its own data-act to join. */
.nuvo-livepill {
	display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0;
	height: 20px; padding-inline: 7px; border-radius: 100px;
	font-size: 11px; font-weight: 700; cursor: pointer;
	background: color-mix(in oklab, #22B98A 18%, var(--bg)); color: #0f7a58;
}
.nuvo-livepill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #22B98A; animation: nuvo-livepill 1.4s ease-in-out infinite; }
.nuvo-livepill:hover { background: color-mix(in oklab, #22B98A 30%, var(--bg)); }
.chan[aria-current="true"] .nuvo-livepill { background: rgba(255, 255, 255, .22); color: var(--brand-text); }
.chan[aria-current="true"] .nuvo-livepill::before { background: currentColor; }
@keyframes nuvo-livepill { 0%, 100% { opacity: .45; transform: scale(.85); } 50% { opacity: 1; transform: scale(1); } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .nuvo-livepill { color: #6fe3b8; } }
:root[data-theme="dark"] .nuvo-livepill { color: #6fe3b8; }
@media (prefers-reduced-motion: reduce) { .nuvo-livepill::before { animation: none; } }

.nuvo-call--full { inset: 0; transform: none; width: 100vw; height: 100vh; border-radius: 0; border: 0; max-width: none; animation: none; }

.nuvo-call--pip {
	inset-block-start: auto; inset-inline-start: auto;
	inset-block-end: calc(var(--tabbar-h, 0px) + 20px); inset-inline-end: 20px; transform: none; animation: none;
	width: 300px; height: 190px; border-radius: 14px;
}
.nuvo-call--pip .nuvo-call__bar { position: absolute; inset-block-start: 0; inset-inline: 0; z-index: 2; padding: 6px; background: linear-gradient(180deg, rgba(0, 0, 0, .55), transparent); opacity: 0; transition: opacity .15s; }
.nuvo-call--pip:hover .nuvo-call__bar { opacity: 1; }
.nuvo-call--pip .nuvo-call__id,
.nuvo-call--pip .nuvo-call__btn[data-act="call-add"],
.nuvo-call--pip .nuvo-call__btn[data-act="call-invite"],
.nuvo-call--pip .nuvo-call__btn[data-act="call-full"] { display: none; }
.nuvo-call--pip .nuvo-call__actions { margin: 0 0 0 auto; }
.nuvo-call--pip .nuvo-call__piphint {
	display: inline-flex; align-items: center; justify-content: center; gap: 6px;
	position: absolute; inset-block-end: 8px; inset-inline: 8px; z-index: 3;
	border: 0; border-radius: 100px; cursor: pointer; background: rgba(0, 0, 0, .58); color: #fff;
	font-size: 12px; font-weight: 600; padding: 8px 10px; opacity: 0; transition: opacity .15s;
}
.nuvo-call--pip:hover .nuvo-call__piphint { opacity: 1; }

.nuvo-call--audio:not(.nuvo-call--full):not(.nuvo-call--pip) { width: min(560px, 92vw); height: min(430px, calc(100vh - var(--header-h) - 28px)); }

/* Phones: the window fills the room between the header and the bottom tab bar
   (safe area included), edge to edge with a small gutter, so the whole call —
   tiles and the control pill — is on screen without a single scroll. PiP sits
   above the tab bar; full screen covers everything as before. */
@media (max-width: 767.98px) {
	.nuvo-call:not(.nuvo-call--full):not(.nuvo-call--pip) {
		inset-block-start: calc(var(--header-h) + 8px);
		/* the tab bar paints a hairline + padding above --tabbar-h; 18px clears it */
		inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + 18px);
		inset-inline: 8px; width: auto; height: auto; max-width: none;
		transform: none; border-radius: 16px; animation: nuvo-call-in-m .22s ease-out both;
	}
	.nuvo-call--audio:not(.nuvo-call--full):not(.nuvo-call--pip) { width: auto; height: auto; }
	.nuvo-call__bar { padding: 8px 10px 8px 12px; gap: 8px; }
	.nuvo-call__btn { width: 40px; height: 40px; }
	/* room for the name: the invite-link button lives in the ⋯ of Talk itself on a phone */
	.nuvo-call__btn[data-act="call-invite"] { display: none; }
	.nuvo-call--pip { width: 46vw; max-width: 230px; height: auto; aspect-ratio: 4 / 3; inset-inline-end: 12px; inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + 20px); }
	.nuvo-call--pip .nuvo-call__bar { opacity: 1; }
	.nuvo-call--pip .nuvo-call__piphint { opacity: 1; }
	.nuvo-call--full { inset: 0; padding-block-start: var(--sat, 0px); }
}
@keyframes nuvo-call-in-m { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (max-width: 767.98px) {
	.nuvo-call:not(.nuvo-call--pip) { inset: 0; transform: none; width: 100vw; height: 100dvh; border-radius: 0; border: 0; animation: none; }
}

.composer__box { position: relative; }
.composer { position: relative; }

.chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	height: 26px;
	padding-inline: 10px;
	border-radius: 100px;
	background: var(--brand-soft);
	color: var(--brand);
	font-size: 12px;
	font-weight: 600;
	border: none;
	align-self: flex-start;
	margin-block-start: 2px;
}

.filecard {
	margin-block-start: 4px;
	width: 300px;
	max-width: 100%;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg-raised);
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 12px;
	text-align: start;
}

.filecard:hover { border-color: var(--brand-line); }
.filecard { cursor: pointer; color: inherit; font: inherit; }
/* Send later rows: plain rows with their two actions on the meta line. */
.mrow--out { cursor: default; }
/* The compose window. Addressing is a stack of quiet lines with a hairline
   between them — the same reading the message gets when it is opened — and
   everything below the subject belongs to the message. */
.cpw { max-width: 840px; height: 86dvh; }
/* A file held over the composer: the sheet says where it will land. The
   sheet is white in both themes, so the colours are its own. */
.cpw.cpw--drop { outline: 2px dashed #19C37D; outline-offset: -6px; }
.cpw.cpw--drop .cpw__body { background: #ecf9f2; transition: background .15s; }
/* Maximized: the window is the composer. The backdrop drops its padding,
   the corners go, the writing sheet stays a readable width in the middle. */
.backdrop:has(> .cpw--full) { padding: 0; }
.cpw.cpw--full { max-width: none; width: 100%; height: 100dvh; max-height: 100dvh; border-radius: 0; border: 0; }
.cpw--full .cpw__head, .cpw--full .cpw__bar, .cpw--full .cpw__body, .cpw--full .cpw__atts, .cpw--full .cpw__foot { width: 100%; max-width: 1180px; margin-inline: auto; }
.cpw__max { flex-shrink: 0; }
.cpw__head { flex-shrink: 0; padding: 6px 8px 0 18px; }
.cpw__row { display: flex; align-items: center; gap: 10px; min-height: 40px; border-block-end: 1px solid var(--border); padding-inline-end: 8px; }
.cpw__lbl { flex: 0 0 auto; min-width: 38px; font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.cpw__in { flex: 1 1 auto; min-width: 0; border: none; background: none; font: inherit; font-size: 14px; color: var(--text); padding: 8px 0; }
.cpw__in:focus { outline: none; }
.cpw__in::placeholder { color: var(--text-muted); }
.cpw__sel { cursor: pointer; }
.cpw__toggles { display: flex; gap: 2px; flex-shrink: 0; }
.cpw__t { border: none; background: none; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--text-muted); cursor: pointer; padding: 4px 6px; border-radius: 6px; }
.cpw__t:hover { color: var(--brand); background: var(--bg-hover); }
.cpw__x { flex-shrink: 0; margin-inline-start: 2px; }
.cpw__row--subj { border-block-end: 1px solid var(--border); }
.cpw__subj { flex: 1 1 auto; min-width: 0; border: none; background: none; font-family: var(--display); font-size: 19px; font-weight: 600; letter-spacing: -0.2px; color: var(--text); padding: 10px 0; }
.cpw__subj:focus { outline: none; }
.cpw__subj::placeholder { color: var(--text-muted); font-weight: 500; }
/* The writing surface is a white sheet with dark text in BOTH themes, like
   the reading pane: mail is read on white by everyone it goes to, so it is
   written on white too. color-scheme keeps the caret and selection light. */
.cpw__body { flex: 1 1 auto; min-height: 0; display: flex; padding: 0 18px 12px; }
/* Serene on purpose: the writing surface is the page, not a field on it.
   Scoped to .cpw so it wins over the base .ev-notes rules, which are declared
   later in this sheet — order would otherwise decide it, and lose. */
.cpw .ev-notes--mail {
	flex: 1 1 auto;
	min-height: 0;
	max-height: none;
	resize: none;
	border: 1px solid var(--border);
	border-radius: 14px;
	background: #fff;
	color: #10221B;
	color-scheme: light;
	padding: 18px 22px 24px;
	font-size: 15px;
	line-height: 1.62;
}
.cpw .ev-notes--mail:focus { box-shadow: none; border-color: #19C37D; }
.cpw .ev-notes--mail:empty::before { color: #7b8a83; }
.cpw .ev-notes--mail a { color: #0f7a5a; }
.cpw .ev-notes--mail blockquote { color: #3d4d46; }
.cpw .ev-notes--mail img { max-width: 100%; height: auto; }
.cpw .ev-notes--mail table { border-collapse: collapse; }
/* Settings > Mail: one signature card per mailbox. The sheet stays white in
   dark mode, like the composer's: a signature is seen on white by whoever
   receives it. */
.sg-card { flex-direction: column; align-items: stretch; gap: 10px; margin-block-start: 12px; padding: 14px 16px; }
.sg-card__h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; font-size: 14px; }
.sg-card .cpw__bar { padding: 4px 6px; border: 1px solid var(--border); border-radius: 10px; }
.sg-card .ev-notes--mail { min-height: 120px; max-height: 320px; overflow: auto; resize: vertical; border: 1px solid var(--border); border-radius: 12px; background: #fff; color: #10221B; color-scheme: light; padding: 14px 16px; font-size: 14px; line-height: 1.5; }
.sg-card .ev-notes--mail:focus { box-shadow: none; border-color: #19C37D; }
.sg-card .ev-notes--mail:empty::before { color: #7b8a83; }
.sg-card .ev-notes--mail a { color: #0f7a5a; }
.sg-card .ev-notes--mail img { max-width: 100%; height: auto; }
.sg-card .ev-notes--mail table { border-collapse: collapse; }
.sg-opts { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.sg-opt { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; user-select: none; }
.sg-acts { display: flex; align-items: center; gap: 12px; }
.sg-state { font-size: 12.5px; }
.sg-colorw { position: relative; overflow: hidden; cursor: pointer; }
.sg-colorw .sg-color { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; border: 0; padding: 0; }
.sg-none { padding-block: 8px; font-size: 13px; }
.cpw__atts { flex-shrink: 0; display: flex; gap: 8px; flex-wrap: wrap; padding: 10px 18px 0; }
.cpw__when { flex-shrink: 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 12px 18px 0; }
.cpw__when .input { width: auto; }
.cpw__foot { flex-shrink: 0; display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-block-start: 1px solid var(--border); }
/* The formatting bar sits between the subject and the page, so what it does
   is next to what it does it to. Grouped by what the buttons mean, with one
   hairline under the lot rather than a border around each group. */
.cpw__bar { flex-shrink: 0; display: flex; align-items: center; gap: 2px; flex-wrap: wrap; padding: 7px 14px; border-block-end: 1px solid var(--border); background: var(--bg-subtle); }
.cpw__grp { display: flex; align-items: center; gap: 2px; }
.cpw__bar .ibtn { width: 30px; height: 30px; border-radius: 8px; color: var(--text-muted); transition: background .14s ease, color .14s ease; }
.cpw__bar .ibtn:hover { color: var(--text); background: var(--bg-hover); }
.cpw__bar .ibtn[aria-pressed="true"] { color: var(--brand); background: var(--brand-soft, rgba(34, 185, 138, .16)); }
.cpw__clip { margin-inline-start: 4px; }
.cpw__sep { width: 1px; height: 16px; background: var(--border); margin-inline: 7px; }
.cpw__grp { position: relative; }
/* Text style: a real select, so it works with a keyboard and on a phone. */
.cpw__style { height: 30px; border: 1px solid transparent; border-radius: 8px; background: none; color: var(--text-muted); font: inherit; font-size: 12.5px; font-weight: 600; padding: 0 4px; max-width: 132px; cursor: pointer; }
.cpw__style:hover { color: var(--text); background: var(--bg-hover); }
.cpw__style:focus { outline: none; border-color: var(--brand); color: var(--text); }
/* A toolbar popover: swatches, emoji or the link fields, right under its button. */
.cpw__pop { position: absolute; inset-block-start: calc(100% + 6px); inset-inline-start: 0; z-index: 30; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 32px rgba(0, 0, 0, .18); padding: 10px; max-width: calc(100vw - 32px); }
.cpw__pop--sw { display: grid; grid-template-columns: repeat(6, 26px); gap: 6px; }
.cpw__sw { width: 26px; height: 26px; border-radius: 50%; border: 1px solid rgba(0, 0, 0, .14); cursor: pointer; padding: 0; transition: transform .12s ease; }
.cpw__sw:hover { transform: scale(1.14); }
.cpw__sw--none { background: linear-gradient(135deg, transparent 44%, var(--danger) 46%, var(--danger) 54%, transparent 56%), #fff; }
.cpw__pop--emo { display: grid; grid-template-columns: repeat(8, 32px); gap: 2px; }
.cpw__emo { width: 32px; height: 32px; border: none; background: none; font-size: 19px; line-height: 1; border-radius: 8px; cursor: pointer; padding: 0; }
.cpw__emo:hover { background: var(--bg-hover); }
.cpw__pop--link { display: flex; flex-direction: column; gap: 6px; width: 320px; }
.cpw__pop--link .input { width: 100%; }
.cpw__pop__acts { display: flex; gap: 6px; align-items: center; margin-block-start: 4px; }
/* A small window (a half-screen laptop) keeps the bar on one line: the
   alignment group is the first to go. */
@media (max-width: 900px) { .cpw__grp--opt { display: none; } }
@media (max-width: 640px) { .cpw__style { max-width: 100px; } }
/* Sending in the background: a small ring at the bottom draws itself full
   over two seconds, then turns into a check mark. A refused send stays
   until it is dealt with, because the message is only here now. */
.msend-root { position: fixed; inset-block-end: calc(20px + var(--sab, 0px) + var(--kb, 0px)); inset-inline-end: 20px; z-index: 950; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; pointer-events: none; }
.msend { pointer-events: auto; display: flex; align-items: center; gap: 10px; padding: 8px 16px 8px 10px; border-radius: 100px; background: var(--text); color: var(--bg); font-size: 13px; font-weight: 600; box-shadow: 0 8px 24px rgba(0, 0, 0, .18); animation: msend-in .22s ease-out; }
.msend--out { animation: msend-out .28s ease-in forwards; }
.msend__ring { position: relative; width: 24px; height: 24px; flex-shrink: 0; }
.msend__ring svg { width: 24px; height: 24px; display: block; transform: rotate(-90deg); }
.msend__track { fill: none; stroke: currentColor; stroke-opacity: .22; stroke-width: 3; }
.msend__arc { fill: none; stroke: var(--brand); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 94.25; stroke-dashoffset: 94.25; animation: msend-fill 2s cubic-bezier(.4, 0, .2, 1) forwards; transform-origin: center; }
.msend--wait .msend__arc { stroke-dashoffset: 30; animation: msend-turn .9s linear infinite; }
.msend__check { position: absolute; inset: 0; display: grid; place-items: center; color: var(--brand); opacity: 0; transform: scale(.4); }
.msend--done .msend__arc { stroke-dashoffset: 0; animation: none; }
.msend--done .msend__check { opacity: 1; transform: scale(1); transition: opacity .18s ease, transform .3s cubic-bezier(.2, 1.4, .4, 1); }
.msend--err { background: var(--bg); color: var(--text); border: 1px solid var(--danger); padding-inline-end: 8px; }
.msend--err .msend__arc, .msend--err .msend__track { display: none; }
.msend--err .msend__check { opacity: 1; transform: none; color: var(--danger); }
.msend__t { white-space: nowrap; max-width: 46vw; overflow: hidden; text-overflow: ellipsis; }
.msend .btn { padding: 4px 10px; font-size: 12.5px; min-height: 0; }
.msend .ibtn { width: 28px; height: 28px; color: var(--text-muted); }
@keyframes msend-fill { to { stroke-dashoffset: 0; } }
@keyframes msend-turn { to { transform: rotate(360deg); } }
@keyframes msend-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes msend-out { to { opacity: 0; transform: translateY(6px); } }
@media (max-width: 640px) { .msend-root { inset-inline: 16px; align-items: center; } .msend__t { max-width: none; } }
@media (max-width: 640px) {
	.cpw { height: 100dvh; max-height: none; border-radius: 0; border: 0; }
	.cpw__foot { flex-wrap: wrap; }
	.cpw__foot .btn { flex: 1 1 auto; justify-content: center; }
}
/* A compose attachment: the file, its size, one way in and one way out. */
.matt--chip { gap: 0; padding: 0; overflow: hidden; }
.matt__open { display: flex; align-items: center; gap: 8px; padding: 8px 4px 8px 10px; border: none; background: none; font: inherit; color: inherit; text-align: start; min-width: 0; }
button.matt__open { cursor: pointer; }
button.matt__open:hover { background: var(--bg-hover); }
.matt__ic { width: 18px; height: 18px; display: grid; place-items: center; color: var(--brand); flex-shrink: 0; }
.matt__spin { width: 16px; height: 16px; border-width: 2px; }
.matt__t { display: flex; flex-direction: column; min-width: 0; }
.matt__t b { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.matt__t .muted { font-size: 12px; }
.matt--chip .ibtn { width: 28px; height: 28px; margin-inline-end: 4px; flex-shrink: 0; }
.matt--busy { opacity: .8; }
.cp-more { border: none; background: none; font: inherit; font-size: 12px; font-weight: 600; color: var(--brand); cursor: pointer; padding: 0 4px; margin-inline-start: auto; }
.cp-more:hover { text-decoration: underline; }
.mtag--draft { background: var(--brand-soft); color: var(--brand); }
.mrow__acts { display: flex; gap: 6px; margin-block-start: 6px; }
.btn--xs { height: 26px; padding-inline: 8px; font-size: 12px; }
.mrow__date--warn { color: var(--danger, #c9302c); font-weight: 600; }
/* A picture shows itself: a small thumbnail (never the full image), name and size under it. */
.filecard--img { flex-direction: column; align-items: stretch; width: 260px; padding: 6px; gap: 6px; }
.filecard__thumb { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: calc(var(--r-lg) - 4px); background: var(--bg-subtle); }
.filecard__meta { display: flex; flex-direction: column; min-width: 0; text-align: start; padding: 0 4px 2px; }
.filecard__n { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filecard__s { font-size: 12px; color: var(--text-muted); }
/* Documents: one page outline, a colour per kind, a short label — PDF, DOC, XLS, PPT, TXT, ZIP. */
.fdoc { position: relative; width: 36px; height: 44px; flex-shrink: 0; display: grid; place-items: end center; --fdoc-c: #6B7A74; }
.fdoc svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.fdoc b { position: relative; font-size: 9px; font-weight: 800; letter-spacing: .04em; line-height: 1.3; color: #fff; background: var(--fdoc-c); border-radius: 3px; padding: 1px 4px; margin-bottom: 5px; }

.callcard {
	margin-inline-start: 46px;
	width: 420px;
	max-width: 100%;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg-raised);
	padding: 12px 14px;
	display: flex;
	align-items: center;
	gap: 12px;
}

.typing { display: flex; gap: 12px; align-items: center; color: var(--text-muted); font-size: 13px; }
.dots { display: inline-flex; gap: 3px; }
.dots i { width: 5px; height: 5px; border-radius: 100px; background: currentColor; animation: blink 1.2s infinite; }
.dots i:nth-child(2) { animation-delay: 0.2s; }
.dots i:nth-child(3) { animation-delay: 0.4s; }
@keyframes blink { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 1; } }

.composer { flex-shrink: 0; padding: 8px 20px 16px; }

.composer__box {
	min-height: 48px;
	border: 1px solid var(--border-strong);
	border-radius: var(--r-lg);
	display: flex;
	align-items: flex-end;
	gap: 8px;
	padding: 6px 8px 6px 14px;
	background: var(--bg);
}

.composer__box:focus-within { border-color: var(--brand); }

.composer__input {
	flex-grow: 1;
	border: none;
	outline: none;
	resize: none;
	background: transparent;
	color: var(--text);
	font: inherit;
	font-size: 16px;
	line-height: 22px;
	padding-block: 7px;
	max-height: 140px;
}

.composer__hint { font-size: 11px; color: var(--text-muted); padding-block-start: 6px; padding-inline-start: 4px; }

/* ================================================== generic panes */
.toolbar {
	flex-shrink: 0;
	min-height: 48px;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 20px;
	border-block-end: 1px solid var(--border);
	flex-wrap: wrap;
}

.scrollpane { flex-grow: 1; min-height: 0; overflow: auto; padding: 16px 20px; }

.crumbs { display: flex; align-items: center; gap: 4px; font-size: 13px; color: var(--text-muted); flex-wrap: wrap; min-width: 0; }
.crumbs button { background: none; border: none; padding: 3px 5px; border-radius: var(--r-sm); }
.crumbs button:hover { background: var(--bg-hover); color: var(--text); }
.crumbs .sep { opacity: 0.5; }

.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.tbl th {
	text-align: start;
	font-size: 12px;
	font-weight: 700;
	color: var(--text-muted);
	letter-spacing: 0.4px;
	text-transform: uppercase;
	padding: 8px 12px;
	border-block-end: 1px solid var(--border);
}
.tbl td { padding: 11px 12px; border-block-end: 1px solid var(--border); vertical-align: middle; }
.tbl tbody tr:hover { background: var(--bg-hover); cursor: pointer; }
.tbl .num { text-align: end; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }

.card {
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	padding: 12px 14px;
	display: flex;
	align-items: center;
	gap: 12px;
	background: var(--bg);
}

.switch {
	width: 38px;
	height: 22px;
	border-radius: 100px;
	background: var(--border-strong);
	border: none;
	padding: 3px;
	display: flex;
	flex-shrink: 0;
	transition: background 140ms ease;
}

.switch i { width: 16px; height: 16px; border-radius: 100px; background: #fff; transition: transform 140ms ease; }
.switch[aria-pressed="true"] { background: var(--brand); }
.switch[aria-pressed="true"] i { transform: translateX(16px); }

.board { display: flex; gap: 12px; align-items: flex-start; }
.board__col { width: 260px; flex-shrink: 0; border: 1px solid var(--border); border-radius: var(--r-lg); padding: 12px; background: var(--bg-subtle); }
.board__h { display: flex; align-items: center; gap: 8px; margin-block-end: 10px; font-size: 14px; font-weight: 600; }
.board__card {
	width: 100%;
	text-align: start;
	padding: 10px;
	border: 1px solid var(--border);
	border-radius: var(--r);
	background: var(--bg);
	margin-block-end: 8px;
	font-size: 14px;
	display: block;
}
.board__card:hover { border-color: var(--brand-line); }
.board__tag { display: inline-block; margin-block-start: 6px; font-size: 11px; font-weight: 700; letter-spacing: 0.3px; text-transform: uppercase; color: var(--text-muted); }

.doc { max-width: 68ch; }
.doc h2 { font-family: var(--display); font-size: 20px; margin: 24px 0 8px; text-wrap: balance; }
.doc h2:first-child { margin-block-start: 0; }
.doc h3 { font-size: 15px; margin: 18px 0 6px; }
.doc p, .doc li { font-size: 15px; color: var(--text); }
.doc ol, .doc ul { padding-inline-start: 20px; }
.doc code { background: var(--bg-subtle); padding: 1px 5px; border-radius: var(--r-sm); font-size: 13px; }

/* ======================================================= sidebar */
.side {
	width: 300px;
	flex-shrink: 0;
	border-inline-start: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	min-height: 0;
}

.side__head { padding: 14px 14px 8px; display: flex; align-items: center; gap: 8px; }
.side__title { font-size: 15px; font-weight: 600; flex-grow: 1; }
.side__scroll { overflow-y: auto; padding-inline: 8px; padding-block-end: 12px; min-height: 0; }

.mem { min-height: 44px; display: flex; align-items: center; gap: 10px; padding-inline: 8px; border-radius: var(--r); }
.mem:hover { background: var(--bg-hover); }
.mem__t { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; }
.mem__n { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mem__r { font-size: 12px; color: var(--text-muted); }

.dot { width: 9px; height: 9px; border-radius: 100px; flex-shrink: 0; }

/* ======================================================= controls */
.btn {
	min-height: var(--tap);
	padding-inline: 14px;
	border-radius: var(--r);
	border: 1px solid var(--border-strong);
	background: var(--bg);
	font-size: 13px;
	font-weight: 600;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	white-space: nowrap;
}

/* A link dressed as a button (the contact card's tel: Call) keeps the button
   look: no browser-blue text, no underline, visited or not. */
a.btn { text-decoration: none; }
a.btn:not(.btn--primary):not(.btn--danger),
a.btn:not(.btn--primary):not(.btn--danger):visited { color: inherit; }

.btn:hover:not(:disabled) { background: var(--bg-hover); }
.btn:disabled { opacity: 0.45; cursor: default; }
.btn--primary { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }
.btn--primary:hover:not(:disabled) { filter: brightness(1.08); background: var(--brand); }
.btn--quiet { border-color: transparent; background: transparent; }
.btn--danger { background: var(--danger); border-color: var(--danger); color: #fff; }

/* New file — a soft, half-filled accent that sits a step below the solid
   primary Upload and a step above the plain New folder, so the three read as
   a clear hierarchy rather than three equal buttons. */
.fnewwrap { position: relative; display: inline-flex; }
.btn--newfile {
	background: var(--brand-soft);
	border-color: color-mix(in srgb, var(--brand) 40%, transparent);
	color: var(--brand);
}
.btn--newfile:hover:not(:disabled),
.btn--newfile.is-open { background: color-mix(in srgb, var(--brand) 26%, transparent); }

.fnew {
	position: absolute;
	top: calc(100% + 8px);
	inset-inline-start: 0;
	z-index: 90;
	width: 246px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 18px 48px rgba(6, 17, 14, .3);
	padding: 6px;
	text-align: start;
}
.fnew__item {
	width: 100%;
	min-height: 38px;
	border: none;
	background: transparent;
	border-radius: var(--r);
	display: flex;
	align-items: center;
	gap: 11px;
	padding-inline: 10px;
	font-size: 13.5px;
	font-weight: 500;
	color: var(--text);
	text-align: start;
}
.fnew__item:hover { background: var(--bg-hover); }
.fnew__item svg { color: var(--brand); flex-shrink: 0; }
/* The import section is deliberately a different shape: a labelled group with
   its items on a subtle tray, so "bring something in" reads apart from "make
   something new". */
.fnew__imports { margin-block-start: 6px; padding-block-start: 4px; border-block-start: 1px solid var(--border); }
.fnew__l { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--text-muted); padding: 6px 10px 4px; }
.fnew__imports .fnew__item { background: var(--bg-subtle); margin-block-start: 2px; }
.fnew__imports .fnew__item:hover { background: var(--bg-hover); }
.fnew__imports .fnew__item svg { color: var(--text-muted); }

.ibtn {
	width: var(--tap);
	height: var(--tap);
	border-radius: var(--r);
	border: none;
	background: transparent;
	color: var(--text-muted);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.ibtn:hover { background: var(--bg-hover); color: var(--text); }

.input, .select, .textarea {
	min-height: var(--tap);
	width: 100%;
	border-radius: var(--r);
	border: 1px solid var(--border-strong);
	background: var(--bg);
	color: var(--text);
	padding: 6px 10px;
	font: inherit;
	font-size: 16px;
}

.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.textarea { resize: vertical; min-height: 70px; }

/* Event notes: one quiet toolbar row, one bright near-white writing surface
   (deliberately the same in both themes). */
.ev-notes__bar { display: flex; gap: 2px; margin-block-end: 6px; }
.ev-notes__bar .ibtn { width: 28px; height: 28px; border-radius: 6px; color: var(--text-muted); }
.ev-notes__bar .ibtn:hover { background: var(--bg-hover); color: var(--text); }
.ev-notes {
	min-height: 180px;
	max-height: 40vh;
	overflow: auto;
	resize: vertical;
	padding: 12px 14px;
	border: 2px solid #19C37D;
	border-radius: var(--r);
	background: #F7FBF8;
	color: #10221B;
	font: inherit;
	line-height: 1.5;
	overflow-wrap: anywhere;
}
.ev-notes:focus { outline: none; box-shadow: 0 0 0 3px rgba(25, 195, 125, .25); }
.ev-notes:empty::before { content: attr(data-placeholder); color: #7b8a83; pointer-events: none; }
.ev-notes a { color: #0f7a5a; }
.ev-notes ul, .ev-notes ol { padding-inline-start: 22px; margin: 4px 0; }
.ev-notes p { margin: 0 0 6px; }
.ev-notes h1, .ev-notes h2, .ev-notes h3 { margin: 10px 0 6px; line-height: 1.25; font-weight: 700; }
.ev-notes h1 { font-size: 1.55em; }
.ev-notes h2 { font-size: 1.3em; }
.ev-notes h3 { font-size: 1.12em; }
.ev-notes hr { border: 0; border-block-start: 1px solid #c9d6d0; margin: 12px 0; }
.ev-notes pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; background: #eef3f0; border-radius: 8px; padding: 10px 12px; white-space: pre-wrap; margin: 6px 0; }
.ev-notes blockquote, .ev-notes-view blockquote {
	margin: 6px 0;
	padding-inline-start: 12px;
	border-inline-start: 3px solid color-mix(in srgb, currentColor 25%, transparent);
	opacity: .78;
}
.ev-notes-view { color: var(--text); white-space: normal; line-height: 1.5; }
.ev-notes-view a { color: var(--brand); }
.ev-notes-view ul, .ev-notes-view ol { padding-inline-start: 22px; margin: 4px 0; }
.ev-notes-view p { margin: 0 0 6px; }
.ev-att { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.ev-att__chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	max-width: 100%;
	padding: 4px 6px 4px 10px;
	border: 1px solid var(--border);
	border-radius: 999px;
	background: var(--bg-raised);
	font-size: 13px;
}
.ev-att__chip > svg { color: var(--brand); flex-shrink: 0; }
.ev-att__n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ev-att__chip .ibtn { width: 22px; height: 22px; border-radius: 50%; }
.ev-att__open { font: inherit; color: var(--text); text-align: start; cursor: pointer; }
.ev-att__open:hover { border-color: var(--brand-line); }

.field { display: flex; flex-direction: column; gap: 6px; }
.field__l { font-size: 13px; font-weight: 600; }
.field__h { font-size: 12px; color: var(--text-muted); }
/* An inline field error: red text under the field and a red ring on the
   input, in both themes through --danger. A toast would vanish before the
   person finds which field it meant. */
.field__e { font-size: 12px; font-weight: 600; color: var(--danger); }
.field__e[hidden] { display: none; }
.input[aria-invalid="true"], .input[aria-invalid="true"]:focus { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger); }

/* ========================================================== modal */
.backdrop {
	position: fixed;
	inset: 0;
	background: rgba(6, 17, 14, 0.46);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
	z-index: 100;
}

.modal {
	background: var(--bg);
	border-radius: var(--r-xl);
	border: 1px solid var(--border);
	box-shadow: 0 24px 64px rgba(6, 17, 14, 0.28);
	width: 100%;
	max-width: 560px;
	max-height: 88dvh;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.modal--wide { max-width: 880px; }
.modal__h { padding: 20px 24px 12px; display: flex; align-items: flex-start; gap: 16px; flex-shrink: 0; }
.modal__t { font-family: var(--display); font-size: 20px; font-weight: 600; letter-spacing: -0.3px; }
.modal__s { font-size: 13px; color: var(--text-muted); }
.modal__b { padding: 4px 24px 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; min-height: 0; }
.modal__f { padding: 16px 24px; display: flex; justify-content: flex-end; gap: 10px; border-block-start: 1px solid var(--border); flex-shrink: 0; }

.pgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }

.prov {
	min-height: 94px;
	border-radius: var(--r-lg);
	border: 1px solid var(--border-strong);
	background: var(--bg);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 12px;
	text-align: center;
}

.prov:hover { background: var(--bg-hover); }
.prov[aria-pressed="true"] { border-color: var(--brand); border-width: 2px; background: var(--brand-soft); }
.prov__n { font-size: 13px; font-weight: 600; }

/* ===================================================== call strip */
.callbar {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 20px;
	background: var(--brand-soft);
	border-block-end: 1px solid var(--brand-line);
}

.callbar__t { font-family: var(--display); font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }

.rec-dot { width: 8px; height: 8px; border-radius: 100px; background: var(--danger); animation: pulse 1.6s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

@keyframes badge-pop {
	0% { transform: scale(1); }
	35% { transform: scale(1.4); }
	100% { transform: scale(1); }
}

.pill-count--pop { animation: badge-pop 460ms ease; }

/* ========================================================= misc */
.empty {
	flex-grow: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: 40px;
	text-align: center;
	color: var(--text-muted);
}

.empty__t { font-size: 17px; font-weight: 600; color: var(--text); }
.empty__x { max-width: 44ch; font-size: 14px; }

.toast {
	position: fixed;
	inset-block-end: 20px;
	inset-inline-start: 50%;
	transform: translateX(-50%);
	background: var(--text);
	color: var(--bg);
	padding: 10px 18px;
	border-radius: 100px;
	font-size: 13px;
	font-weight: 600;
	z-index: 200;
	box-shadow: 0 8px 24px rgba(6, 17, 14, 0.28);
}

/* A toast that offers to take something back (toastUndo): the same pill with
   one quiet button in it. */
.toast--act { display: inline-flex; align-items: center; gap: 6px; padding-inline-end: 6px; }
.toast__b { border: 0; background: transparent; color: inherit; font: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; padding: 4px 12px; border-radius: 100px; cursor: pointer; }
.toast__b:hover, .toast__b:focus-visible { background: color-mix(in oklab, var(--bg) 18%, transparent); }

.stack { display: flex; flex-direction: column; gap: 8px; }
.grow { flex-grow: 1; }
.muted { color: var(--text-muted); }

/* ========================================================= files */
.fapp, .capp { flex-grow: 1; display: flex; min-height: 0; min-width: 0; }

.appnav {
	width: 260px;
	flex-shrink: 0;
	background: var(--bg-subtle);
	border-inline-end: 1px solid var(--border);
	padding: 14px 8px;
	display: flex;
	flex-direction: column;
	gap: 2px;
	overflow-y: auto;
}

.appnav__t { font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -0.2px; padding: 0 10px 10px; }

.appnav__item {
	min-height: 36px;
	border-radius: var(--r);
	border: none;
	background: transparent;
	display: flex;
	align-items: center;
	gap: 10px;
	padding-inline: 10px;
	font-size: 14px;
	width: 100%;
	text-align: start;
}

.appnav__item:hover { background: var(--bg-hover); }
.appnav__item[aria-current="true"] { background: var(--brand); color: var(--brand-text); font-weight: 600; }
.appnav__count { margin-inline-start: auto; font-size: 12px; opacity: 0.7; font-variant-numeric: tabular-nums; }

.appmain { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; }

/* Photos -> Files "save as" bar: a soft brand-tinted band above the breadcrumbs. */
.sendto { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.sendto__t { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg-subtle); color: inherit; text-align: start; font: inherit; cursor: pointer; }
.sendto__t:hover { border-color: var(--brand); background: var(--brand-soft); }
.sendto__n { font-weight: 600; }
.sendto__d { font-size: 12.5px; color: var(--text-muted); }
.sendto__hd { display: flex; align-items: center; gap: 10px; margin-block-end: 12px; }
.fpick {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
	padding: 14px 20px;
	background: var(--brand-soft);
	border-block-end: 1px solid var(--border);
}
.fpick__th {
	width: 40px; height: 40px; border-radius: 8px; flex-shrink: 0;
	background-size: cover; background-position: center;
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
	display: flex; align-items: center; justify-content: center; color: var(--brand);
}
.fpick__t { font-weight: 600; }
.fpick__where {
	font-size: 12px; color: var(--text-muted);
	background: var(--bg-subtle); border: 1px solid var(--border);
	border-radius: 100px; padding: 3px 10px; max-width: 340px;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Photos -> Talk channel/chat picker (modal). */
.phpick__subs { display: flex; align-items: center; gap: 6px; }
.phpick__th {
	width: 40px; height: 40px; border-radius: 8px; flex-shrink: 0;
	background-size: cover; background-position: center;
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
}
.phpick__th--more {
	display: flex; align-items: center; justify-content: center;
	background: var(--bg-subtle); color: var(--text-muted); font-size: 12px; font-weight: 600;
}
.phpick__ghead {
	display: flex; align-items: center; gap: 8px;
	font-size: 12px; font-weight: 600; color: var(--text-muted);
	padding: 8px 8px 4px;
}
.phpick__dot { width: 10px; height: 10px; border-radius: 100px; flex-shrink: 0; }
.phpick__hash {
	width: 26px; height: 26px; flex-shrink: 0;
	display: flex; align-items: center; justify-content: center;
	border-radius: 7px; background: var(--bg-subtle); color: var(--text-muted); font-weight: 700;
}
.phpick__row:hover { background: var(--bg-hover) !important; }

.appbar {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 12px 20px;
	border-block-end: 1px solid var(--border);
	flex-wrap: wrap;
}

.fstar { background: none; border: none; padding: 2px; color: var(--border-strong); display: flex; }
.fstar:hover { color: #a37200; }
.fstar[aria-pressed="true"] { color: #a37200; }

.fsel {
	width: 17px;
	height: 17px;
	border-radius: var(--r-sm);
	border: 1.5px solid var(--border-strong);
	background: var(--bg);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	color: transparent;
	flex-shrink: 0;
}

.fsel[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }

.tbl th.sortable { cursor: pointer; user-select: none; }
.tbl th.sortable:hover { color: var(--text); }
.tbl tr[data-sel="1"] { background: var(--brand-soft); }

.fside { width: 300px; flex-shrink: 0; border-inline-start: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
.fside__h { padding: 16px 16px 10px; display: flex; align-items: flex-start; gap: 10px; }
.fside__b { padding: 0 16px 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
.fmeta { display: flex; flex-direction: column; gap: 2px; }
.fmeta__l { font-size: 12px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.fmeta__v { font-size: 14px; overflow-wrap: anywhere; }

/* ===================================================== files app (2026-10-01)
   The Files app and the channel Files tab (016-files-app.js), the upload
   tray (016-files-upload.js), the folder picker and the "already exists"
   question. Colours are tokens, written for light and in BOTH dark places. */
:root {
	--fs-doc: #2f63c4;
	--fs-sheet: #1d7f47;
	--fs-slides: #b8531c;
	--fs-pdf: #b5322c;
	--fs-image: #7d4bb3;
	--fs-video: #a2386f;
	--fs-audio: #0f7b7b;
	--fs-archive: #7c6219;
	--fs-text: #55665e;
	--fs-team: #0f6b8a;
	--fs-ext: #55665e;
	--fs-star: #a37200;
	--fs-lock: var(--warn);
	--fs-shadow: rgba(6, 17, 14, 0.24);
	--fs-scrim: rgba(6, 17, 14, 0.32);
	--fs-glass: rgba(255, 255, 255, 0.86);
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--fs-doc: #78a6f2;
		--fs-sheet: #4fc78b;
		--fs-slides: #f29b62;
		--fs-pdf: #f08079;
		--fs-image: #bb98ea;
		--fs-video: #e683b9;
		--fs-audio: #55cccc;
		--fs-archive: #d9b75e;
		--fs-text: #a2b5ad;
		--fs-team: #6cc3e0;
		--fs-ext: #a2b5ad;
		--fs-star: #f0c24b;
		--fs-shadow: rgba(0, 0, 0, 0.5);
		--fs-scrim: rgba(0, 0, 0, 0.5);
		--fs-glass: rgba(15, 27, 24, 0.86);
	}
}
:root[data-theme="dark"] {
	--fs-doc: #78a6f2;
	--fs-sheet: #4fc78b;
	--fs-slides: #f29b62;
	--fs-pdf: #f08079;
	--fs-image: #bb98ea;
	--fs-video: #e683b9;
	--fs-audio: #55cccc;
	--fs-archive: #d9b75e;
	--fs-text: #a2b5ad;
	--fs-team: #6cc3e0;
	--fs-ext: #a2b5ad;
	--fs-star: #f0c24b;
	--fs-shadow: rgba(0, 0, 0, 0.5);
	--fs-scrim: rgba(0, 0, 0, 0.5);
	--fs-glass: rgba(15, 27, 24, 0.86);
}

/* top/left 0: without them the box keeps its static place deep in a long
   list, and with no positioned ancestor that place made the whole page
   scrollable (seen on Dev, 2026-10-01: 191 px of empty band). */
.fs-sr {
	position: absolute !important;
	top: 0; left: 0;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0 0 0 0);
	white-space: nowrap; border: 0;
}

/* ---- bars ---- */
.fs-bar { gap: 8px; min-height: 58px; }
.fs-title { margin: 0; font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -0.2px; display: inline-flex; align-items: baseline; gap: 8px; min-width: 0; }
.fs-title__s { font-family: var(--body); font-size: 13px; font-weight: 500; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs-crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 2px; min-width: 0; }
.fs-crumbs li { display: inline-flex; align-items: center; gap: 2px; min-width: 0; }
.fs-crumbs button { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: inherit; }
.fs-crumbs button[aria-current="location"] { color: var(--text); font-weight: 600; }
.fs-crumbs button.is-drop { background: var(--brand-soft); color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); }
.fs-bar > .fs-crumbs { font-size: 14px; }
.fs-ro { flex-shrink: 0; }

.fs-search { position: relative; display: inline-flex; align-items: center; color: var(--text-muted); }
.fs-search svg { position: absolute; inset-inline-start: 10px; pointer-events: none; }
.fs-search .input { width: 220px; min-height: 34px; padding-inline-start: 32px; font-size: 14px; }

.fs-seg { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--r); overflow: hidden; flex-shrink: 0; }
.fs-seg__b { width: 34px; height: 32px; border: none; background: transparent; color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; padding: 0; }
.fs-seg__b + .fs-seg__b { border-inline-start: 1px solid var(--border-strong); }
.fs-seg__b:hover { background: var(--bg-hover); color: var(--text); }
.fs-seg__b[aria-pressed="true"] { background: var(--brand-soft); color: var(--brand); }
.fs-sortsel { display: inline-flex; align-items: center; gap: 2px; }
.fs-sortsel .select { width: auto; min-height: 34px; font-size: 13px; padding-block: 4px; }

.fs-selbar {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
	padding: 8px 20px;
	background: var(--brand-soft);
	border-block-end: 1px solid var(--brand-line);
}
.fs-selbar__n { font-weight: 700; color: var(--brand); margin-inline-end: 6px; font-variant-numeric: tabular-nums; }
.fs-selbar .btn { background: var(--bg); }
.fs-selbar .btn--primary { background: var(--brand); }
.fs-danger { color: var(--danger); }
.fs-selbar .btn.fs-danger { background: transparent; }

.fs-tabs { display: flex; gap: 4px; padding: 10px 20px 2px; flex-wrap: wrap; }
.fs-tabs__b { border: none; background: transparent; color: var(--text-muted); border-radius: 100px; padding: 6px 14px; font-size: 13px; font-weight: 600; }
.fs-tabs__b:hover { background: var(--bg-hover); color: var(--text); }
.fs-tabs__b[aria-pressed="true"] { background: var(--brand-soft); color: var(--brand); }

.fs-teamq { padding: 8px 20px 10px; border-block-end: 1px solid var(--border); max-width: 560px; }

/* ---- quota ---- */
.fs-nav__foot { margin-block-start: auto; padding: 12px 10px 0; border-block-start: 1px solid var(--border); }
.fs-quota { display: grid; gap: 4px; font-size: 12px; }
.fs-quota__l { font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-muted); }
.fs-quota__t { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fs-quota__bar { display: block; height: 6px; border-radius: 100px; background: var(--border); overflow: hidden; }
.fs-quota__bar i { display: block; height: 100%; background: var(--brand); border-radius: inherit; }
.fs-quota.is-full .fs-quota__bar i { background: var(--warn); }
.appnav__count.fs-pend { background: var(--brand); color: var(--brand-text); opacity: 1; border-radius: 100px; padding: 0 7px; font-weight: 700; }
.appnav__item[aria-current="page"] { background: var(--brand); color: var(--brand-text); font-weight: 600; }
.appnav__item[aria-current="page"] .appnav__count.fs-pend { background: var(--brand-text); color: var(--brand); }

/* ---- Personal / Spaces groups (2026-10-07) ---- */
.appnav__group { padding: 14px 10px 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-muted); }
.appnav__group:first-of-type { padding-block-start: 2px; }
.appnav__tile { width: 20px; height: 20px; flex-shrink: 0; border-radius: var(--r-sm); color: #fff; font: 600 10px var(--display); display: flex; align-items: center; justify-content: center; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14); }
.appnav__item[aria-current="page"] .appnav__tile { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .3), 0 0 0 1px var(--brand-text); }

/* ---- list ---- */
.fs-pane { padding: 0 20px 28px; }
.fs-tbl { table-layout: fixed; }
.fs-tbl thead th { position: sticky; top: 0; z-index: 1; background: var(--bg); }
.fs-tbl .fs-c-sel { width: 40px; padding-inline: 8px 4px; }
.fs-tbl .fs-c-size { width: 96px; }
.fs-tbl .fs-c-when { width: 156px; }
.fs-tbl .fs-c-act { width: 92px; text-align: end; padding-inline-end: 6px; }
.fs-sortb { display: inline-flex; align-items: center; gap: 4px; padding: 0; border: none; background: none; color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; }
.fs-sortb:hover { color: var(--text); }
th[aria-sort] .fs-sortb { color: var(--text); }
.fs-tbl .fs-row { cursor: default; }
.fs-row:focus { outline: none; }
.fs-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.fs-tbl tbody .fs-row.is-sel { background: var(--brand-soft); }
.fs-tbl tbody .fs-row.is-sel:hover { background: color-mix(in oklab, var(--brand) 16%, var(--bg)); }
.fs-row.is-drop { background: var(--brand-soft); box-shadow: inset 0 0 0 2px var(--brand); }
.fs-row.is-dragging { opacity: 0.5; }
.fs-cell { display: flex; align-items: center; gap: 12px; min-width: 0; }
.fs-nm { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.fs-name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs-sub, .fs-pmeta { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs-pmeta { display: none; }
.fs-acts { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
.fs-acts .ibtn { width: 32px; height: 32px; }

/* type icons */
.fs-ic { position: relative; display: inline-flex; flex-shrink: 0; color: var(--text-muted); }
.fs-k-folder { color: var(--brand); }
.fs-k-doc { color: var(--fs-doc); }
.fs-k-sheet { color: var(--fs-sheet); }
.fs-k-slides { color: var(--fs-slides); }
.fs-k-pdf { color: var(--fs-pdf); }
.fs-k-image { color: var(--fs-image); }
.fs-k-video { color: var(--fs-video); }
.fs-k-audio { color: var(--fs-audio); }
.fs-k-archive { color: var(--fs-archive); }
.fs-k-text { color: var(--fs-text); }
.fs-ic--team { color: var(--fs-team); }
.fs-ic--ext { color: var(--fs-ext); }
.fs-ic--shared::after { content: ''; position: absolute; inset-inline-end: -2px; inset-block-end: 1px; width: 8px; height: 8px; border-radius: 100px; background: var(--brand); box-shadow: 0 0 0 2px var(--bg); }

/* badges */
.fs-badges { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
.fs-b { display: inline-flex; align-items: center; gap: 2px; color: var(--text-muted); }
.fs-b--lock { color: var(--fs-lock); }
.fs-b--share, .fs-b--team { color: var(--brand); }
.fs-b--cmt i { font-style: normal; font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }
.fs-b--cmt.is-unread { color: var(--brand); }
.fs-tag { font-size: 11px; font-weight: 600; line-height: 18px; padding: 0 7px; border-radius: 100px; background: var(--bg-subtle); border: 1px solid var(--border); color: var(--text-muted); max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* favourite star */
.fs-star { color: var(--border-strong); }
.fs-star:hover, .fs-star[aria-pressed="true"] { color: var(--fs-star); }

/* row tools appear on hover and focus where there is hover; always on touch */
@media (hover: hover) {
	.fs-row .fs-more, .fs-row .fs-star[aria-pressed="false"] { opacity: 0; }
	.fs-row:hover .fs-more, .fs-row:focus-within .fs-more, .fs-row.is-sel .fs-more, .fs-more[aria-expanded="true"],
	.fs-row:hover .fs-star, .fs-row:focus-within .fs-star { opacity: 1; }
}

/* ---- grid ---- */
.fs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(172px, 1fr)); gap: 14px; padding-block: 16px; }
.fs-card { position: relative; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg); overflow: hidden; cursor: default; transition: border-color 0.12s ease, box-shadow 0.12s ease; }
.fs-card:hover { border-color: var(--border-strong); box-shadow: 0 2px 12px var(--fs-shadow); }
.fs-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fs-card.is-sel { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); background: var(--brand-soft); }
.fs-card.is-drop { box-shadow: 0 0 0 2px var(--brand); }
.fs-card__cell { display: flex; flex-direction: column; height: 100%; }
.fs-card__media { position: relative; aspect-ratio: 4 / 3; background: var(--bg-subtle); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.fs-card__media.is-folder { background: color-mix(in oklab, var(--brand) 7%, var(--bg)); }
.fs-thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--bg-subtle); }
.fs-thumb--page { object-position: center top; }
.fs-card__t { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px 12px; min-width: 0; }
.fs-card__t .fs-name { font-size: 13.5px; }
.fs-card__s { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs-card .fs-badges { margin-block-start: 4px; }
.fs-card__sel { position: absolute; inset-block-start: 8px; inset-inline-start: 8px; }
.fs-card__acts { position: absolute; inset-block-start: 6px; inset-inline-end: 6px; display: flex; gap: 2px; }
.fs-card__acts .ibtn { width: 30px; height: 30px; background: var(--fs-glass); }
@media (hover: hover) {
	.fs-card .fs-card__sel { opacity: 0; }
	.fs-card:hover .fs-card__sel, .fs-card:focus-within .fs-card__sel, .fs-card.is-sel .fs-card__sel { opacity: 1; }
}

/* ---- empty, loading ---- */
.fs-empty { padding: 64px 24px; }
.fs-more-res { display: flex; justify-content: center; padding: 16px 0 4px; }
.fs-empty__b { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-block-start: 6px; }
.fs-tab { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.fs-tabbar .fs-crumbs { font-size: 13px; }

/* ---- the action menu (a sheet on phones) ---- */
.fs-menu {
	position: fixed;
	z-index: 120;
	min-width: 230px;
	max-width: 300px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 18px 48px var(--fs-shadow);
	padding: 6px;
}
.fs-menu__i { width: 100%; min-height: 38px; border: none; background: transparent; border-radius: var(--r); display: flex; align-items: center; gap: 11px; padding-inline: 10px; font-size: 13.5px; font-weight: 500; color: var(--text); text-align: start; }
.fs-menu__i svg { color: var(--text-muted); flex-shrink: 0; }
.fs-menu__i:hover, .fs-menu__i:focus { background: var(--bg-hover); outline: none; }
.fs-menu__i:focus-visible { box-shadow: inset 0 0 0 2px var(--brand); }
.fs-menu__i.is-danger, .fs-menu__i.is-danger svg { color: var(--danger); }
.fs-menu__sep { height: 1px; background: var(--border); margin: 4px 6px; }
.fs-menu-scrim { position: fixed; inset: 0; z-index: 119; background: var(--fs-scrim); }
.fs-menu.is-sheet { left: 0; right: 0; top: auto; bottom: 0; max-width: none; border-radius: var(--r-xl) var(--r-xl) 0 0; padding: 8px 8px calc(10px + var(--sab, 0px)); max-height: 80dvh; overflow-y: auto; }
.fs-menu.is-sheet .fs-menu__i { min-height: 48px; font-size: 15px; }

/* ---- dialogs ---- */
.fs-dlg .modal { max-width: 500px; }
.backdrop.fs-dlg { z-index: 160; } /* above the share/details panels (150): an upload may ask while one is open */
.fs-dlg__left { margin-inline-end: auto; display: inline-flex; }
.fs-pick .modal__b { gap: 10px; }
.fs-pick__crumbs { font-size: 13px; }
.fs-pick__list { list-style: none; margin: 0; padding: 0; max-height: 320px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--r-lg); }
.fs-pick__row { width: 100%; display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border: none; border-block-end: 1px solid var(--border); background: transparent; color: var(--text); font-size: 14px; text-align: start; }
.fs-pick__list li:last-child .fs-pick__row { border-block-end: none; }
.fs-pick__row:hover:not([disabled]) { background: var(--bg-hover); }
.fs-pick__row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.fs-pick__row[disabled] { opacity: 0.45; cursor: default; }
.fs-pick__row .fs-name { min-width: 0; }
.fs-pick__msg { padding: 18px 4px; text-align: center; font-size: 14px; margin: 0; }
.fs-pick__mk { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.fs-pick__mk .input { flex: 1 1 180px; width: auto; }
.fs-pick__mk .field__e { flex-basis: 100%; }
.fs-pick__why { min-height: 1.3em; margin: 0; font-size: 12.5px; color: var(--text-muted); }

.fs-ex { display: flex; flex-direction: column; gap: 8px; }
.fs-ex__c { display: flex; align-items: flex-start; gap: 12px; width: 100%; padding: 12px 14px; border: 1px solid var(--border-strong); border-radius: var(--r-lg); background: var(--bg); color: inherit; font: inherit; text-align: start; cursor: pointer; }
.fs-ex__c:hover { background: var(--bg-hover); }
.fs-ex__c:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fs-ex__c--keep { border-color: var(--brand-line); background: var(--brand-soft); }
.fs-ex__c--keep:hover { background: color-mix(in oklab, var(--brand) 16%, var(--bg)); }
.fs-ex__i { display: inline-flex; color: var(--brand); flex-shrink: 0; margin-block-start: 1px; }
.fs-ex__c--replace .fs-ex__i { color: var(--warn); }
.fs-ex__c--skip .fs-ex__i { color: var(--text-muted); }
.fs-ex__t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fs-ex__t b { font-size: 14px; }
.fs-ex__t span { font-size: 12.5px; color: var(--text-muted); overflow-wrap: anywhere; }
.fs-ex__all { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-block-start: 4px; cursor: pointer; }
.fs-ex__all input { width: 16px; height: 16px; accent-color: var(--brand); margin: 0; }

/* ---- the upload tray ---- */
.fsu {
	position: fixed;
	z-index: 96;
	inset-inline-end: 20px;
	inset-block-end: 20px;
	width: 360px;
	max-width: calc(100vw - 32px);
	max-height: min(60vh, 480px);
	display: flex;
	flex-direction: column;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 18px 48px var(--fs-shadow);
	overflow: hidden;
}
.fsu[hidden] { display: none; }
.fsu__h { display: flex; align-items: center; gap: 10px; padding: 12px 8px 10px 14px; }
.fsu__ic { width: 30px; height: 30px; border-radius: 100px; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; background: var(--brand-soft); color: var(--brand); }
.fsu__ic.is-err { background: var(--warn-bg); color: var(--warn); }
.fsu__tt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.fsu__tt b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fsu__s { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fsu__bar { height: 3px; background: var(--border); flex-shrink: 0; }
.fsu__bar i { display: block; height: 100%; background: var(--brand); transition: width 0.2s ease; }
.fsu__list { list-style: none; margin: 0; padding: 4px 0; overflow-y: auto; flex: 1 1 auto; min-height: 0; }
.fsu__it { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 14px; }
.fsu__in { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.fsu__n { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fsu__st { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
.fsu__it.is-failed .fsu__st { color: var(--danger); white-space: normal; }
.fsu__it.is-done .fsu__st { color: var(--here-fg); }
.fsu__it.is-canceled .fsu__n, .fsu__it.is-skipped .fsu__n { color: var(--text-muted); }
.fsu__pb { display: block; height: 3px; border-radius: 100px; background: var(--border); overflow: hidden; }
.fsu__pb i { display: block; height: 100%; background: var(--brand); transition: width 0.2s ease; }
.fsu__x { width: 30px; height: 30px; }
.fsu__more { padding: 6px 14px; font-size: 12px; color: var(--text-muted); }
.fsu__f { display: flex; gap: 8px; justify-content: flex-end; padding: 8px 10px; border-block-start: 1px solid var(--border); flex-shrink: 0; }
.fsu__f:empty { display: none; }
@media (prefers-reduced-motion: reduce) {
	.fsu__bar i, .fsu__pb i, .fs-card { transition: none; }
}

/* ---- phones ---- */
@media (max-width: 767.98px) {
	.fs-bar { padding: 10px var(--gutter, 14px); }
	.fs-bar .fs-search { flex: 1 1 100%; order: 3; }
	.fs-bar .fs-search .input { width: 100%; }
	.fs-pane { padding: 0 var(--gutter, 14px) calc(24px + var(--sab, 0px)); }
	.fs-selbar { padding: 8px var(--gutter, 14px); gap: 6px; }
	.fs-selbar .btn span, .fs-hide-s {
		position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
		overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
	}
	.fs-selbar .btn { min-width: 44px; padding-inline: 10px; }
	.fs-tabs { padding: 10px var(--gutter, 14px) 2px; }
	.fs-teamq { padding: 8px var(--gutter, 14px) 10px; }
	.fs-tbl .fs-c-size, .fs-tbl .fs-c-when { display: none; }
	.fs-tbl .fs-c-act { width: 50px; }
	.fs-tbl .fs-c-sel { width: 36px; padding-inline: 2px; }
	.fs-tbl th, .fs-tbl td { padding-inline: 6px; }
	.fs-tbl .fs-star { display: none; }
	.fs-pmeta { display: block; }
	.fs-badges .fs-tag { display: none; }
	.fs-cell { gap: 10px; }
	.fs-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
	.fs-tabbar { padding: 8px var(--gutter, 14px); gap: 6px; }
	.fs-tabbar .fs-crumbs { flex: 1 1 100%; }
	.fsu {
		inset-inline: 8px;
		inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + 8px);
		width: auto;
		max-width: none;
		max-height: 50dvh;
	}
	.fs-dlg .modal__f { flex-wrap: wrap; }
}
/* ============================================ files panels: share & details */
/* The Sharing dialog and the Details side panel of Files (016-files-panels.js).
   Desktop: Share is a centred dialog, Details a calm drawer on the inline end;
   Share opens over Details with a scrim of its own. Phone: both are bottom
   sheets that clear the notch, the home indicator and the keyboard (--kb).
   Colours are the shell's tokens; the three of our own (scrim, lift, pop) are
   written in the light :root and in both dark places. */

:root {
	--fsp-scrim: rgba(6, 17, 14, 0.36);
	--fsp-lift: 0 24px 64px rgba(6, 17, 14, 0.24), 0 2px 6px rgba(6, 17, 14, 0.06);
	--fsp-pop: 0 10px 28px rgba(6, 17, 14, 0.12);
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--fsp-scrim: rgba(0, 0, 0, 0.56);
		--fsp-lift: 0 24px 64px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.3);
		--fsp-pop: 0 10px 28px rgba(0, 0, 0, 0.45);
	}
}
:root[data-theme="dark"] {
	--fsp-scrim: rgba(0, 0, 0, 0.56);
	--fsp-lift: 0 24px 64px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.3);
	--fsp-pop: 0 10px 28px rgba(0, 0, 0, 0.45);
}

/* ---- the layer ---- */
.fsp-layer {
	position: fixed;
	inset: 0;
	z-index: 150;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
}
.fsp-layer--details { justify-content: flex-end; padding: 0; }
.fsp-layer--over { z-index: 151; }
.fsp-scrim { position: absolute; inset: 0; background: var(--fsp-scrim); animation: fsp-fade 180ms ease both; }
.fsp-layer--details .fsp-scrim { opacity: 0.7; }
.fsp-box {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 100%;
	max-width: 560px;
	max-height: min(780px, calc(100dvh - 48px));
	background: var(--bg);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: var(--fsp-lift);
	overflow: hidden;
	overflow: clip; /* focus and scrollIntoView may scroll .fsp-b, never the box */
	animation: fsp-rise 220ms cubic-bezier(.2, .8, .2, 1) both;
}
.fsp-box:focus { outline: none; }
.fsp-box--details {
	max-width: 420px;
	height: 100dvh;
	max-height: none;
	border-radius: 0;
	border-block: none;
	border-inline-end: none;
	animation-name: fsp-slide;
}

/* ---- header, body, footer ---- */
.fsp-h { position: relative; display: flex; align-items: center; gap: 12px; padding: 18px 14px 12px 22px; flex-shrink: 0; }
.fsp-h--det { padding-block: 14px 4px; }
.fsp-h__ic {
	display: grid;
	place-items: center;
	width: 38px;
	height: 38px;
	border-radius: var(--r-lg);
	background: var(--brand-soft);
	color: var(--brand);
	flex-shrink: 0;
}
.fsp-h__t { flex: 1 1 auto; min-width: 0; }
.fsp-title { margin: 0; font-family: var(--display); font-size: 19px; font-weight: 600; letter-spacing: -0.3px; line-height: 1.25; }
.fsp-h--det .fsp-title { font-size: 15px; color: var(--text-muted); font-family: var(--body); font-weight: 700; letter-spacing: 0; }
/* the title takes the focus only so screen readers start there */
.fsp-title:focus, .fsp-title:focus-visible { outline: none; }
.fsp-sub { font-size: 13px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsp-grab { display: none; }
.fsp-b {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: 4px 22px 22px;
	display: flex;
	flex-direction: column;
	gap: 22px;
}
.fsp-f { display: flex; align-items: center; gap: 10px; padding: 12px 22px; border-block-start: 1px solid var(--border); flex-shrink: 0; }
.fsp-f--quiet { padding: 0; border: none; }
.fsp-f--quiet .fsp-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.fsp-f--ask { background: var(--warn-bg); border-block-start-color: var(--warn-border); flex-wrap: wrap; }
.fsp-f__q { flex: 1 1 auto; font-size: 14px; font-weight: 600; color: var(--warn); }
.fsp-status { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600; color: var(--ok); }
.fsp-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ---- sections and rows ---- */
.fsp-sec { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.fsp-sec__h { margin: 0; font-size: 12px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.fsp-list { display: flex; flex-direction: column; gap: 2px; }
.fsp-row { display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 6px; border-radius: var(--r-lg); transition: background 140ms ease; }
.fsp-row.is-open { background: var(--bg-subtle); border-end-start-radius: 0; border-end-end-radius: 0; }
.fsp-row.is-busy { opacity: 0.6; }
.fsp-row > .av { flex-shrink: 0; }
.fsp-row__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.fsp-row__n { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsp-row__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsp-role { width: auto; max-width: 172px; min-width: 0; flex: 0 1 auto; min-height: 34px; padding: 4px 8px; }
.fsp-role-t { flex-shrink: 0; font-size: 13px; color: var(--text-muted); white-space: nowrap; }
.fsp-more { flex-shrink: 0; }
.fsp-more[aria-expanded="true"] { background: var(--bg-hover); color: var(--text); }
.fsp-copy { flex-shrink: 0; }
.fsp-ic {
	display: grid;
	place-items: center;
	width: 30px;
	height: 30px;
	border-radius: 100px;
	background: var(--brand-soft);
	color: var(--brand);
	flex-shrink: 0;
}
.fsp-ic--warn { background: var(--warn-bg); color: var(--warn); }
.fsp-empty { padding: 6px; font-size: 13px; color: var(--text-muted); }
.fsp-danger { color: var(--danger); }
.fsp-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 10%, transparent); }

/* ---- notices ---- */
.fsp-notice {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	padding: 36px 12px;
	text-align: center;
	font-size: 14px;
	line-height: 1.45;
	color: var(--text-muted);
}
.fsp-notice b { font-size: 16px; color: var(--text); }
.fsp-notice > span:not(.fsp-notice__ic) { max-width: 40ch; }
.fsp-notice__ic {
	display: grid;
	place-items: center;
	width: 54px;
	height: 54px;
	margin-block-end: 4px;
	border-radius: 100px;
	background: var(--brand-soft);
	color: var(--brand);
}
.fsp-notice .btn { margin-block-start: 8px; }
.fsp-info, .fsp-warn {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 12px 14px;
	border-radius: var(--r-lg);
	font-size: 13px;
	line-height: 1.45;
}
.fsp-info { background: var(--bg-subtle); color: var(--text); }
.fsp-info svg { color: var(--text-muted); }
.fsp-warn { background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn); font-weight: 600; }
.fsp-info svg, .fsp-warn svg { flex-shrink: 0; margin-block-start: 1px; }
.fsp-ask {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
	padding: 10px 12px;
	border-radius: var(--r);
	background: var(--warn-bg);
	border: 1px solid var(--warn-border);
	color: var(--warn);
	font-size: 13px;
	font-weight: 600;
	line-height: 1.45;
}
.fsp-ask > span:first-child { flex: 1 1 220px; }
.fsp-ask__b { display: flex; gap: 8px; margin-inline-start: auto; }

/* ---- skeleton ---- */
.fsp-skel { display: flex; flex-direction: column; gap: 16px; padding-block: 6px; }
.fsp-skel__row { display: flex; align-items: center; gap: 12px; }
.fsp-skel__row i, .fsp-skel__row b { display: block; background: var(--bg-subtle); animation: fsp-pulse 1.3s ease-in-out infinite; }
.fsp-skel__row i { width: 30px; height: 30px; border-radius: 100px; flex-shrink: 0; }
.fsp-skel__row b { height: 12px; width: 58%; border-radius: 100px; }
.fsp-skel__row:nth-child(2) b { width: 42%; }
.fsp-skel__row:nth-child(3) b { width: 66%; }

/* ---- people search ---- */
.fsp-search { display: flex; flex-direction: column; gap: 8px; }
.fsp-search__box { position: relative; display: flex; align-items: center; gap: 8px; }
.fsp-search__box > svg { position: absolute; inset-inline-start: 12px; color: var(--text-muted); pointer-events: none; }
.fsp-search__box .input { flex: 1 1 auto; min-width: 0; min-height: 42px; padding-inline-start: 36px; border-radius: var(--r-lg); }
.fsp-res {
	display: flex;
	flex-direction: column;
	gap: 2px;
	max-height: 264px;
	overflow-y: auto;
	padding: 4px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg);
	box-shadow: var(--fsp-pop);
}
.fsp-res[hidden] { display: none; }
.fsp-optn { display: flex; align-items: center; gap: 10px; min-height: 46px; padding: 4px 8px; border-radius: var(--r); cursor: pointer; }
.fsp-optn:hover, .fsp-optn[aria-selected="true"] { background: var(--bg-hover); }
.fsp-optn[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--brand); }
.fsp-optn__t { display: flex; flex-direction: column; min-width: 0; }
.fsp-optn__n { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsp-optn__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- the new-share card and chips ---- */
.fsp-pend { display: flex; flex-direction: column; gap: 12px; padding: 14px; border-radius: var(--r-lg); background: var(--brand-soft); }
.fsp-pend__row .fsp-role { width: 100%; max-width: none; }
.fsp-pend__f { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fsp-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.fsp-chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	max-width: 100%;
	height: 34px;
	padding-inline: 4px 2px;
	border-radius: 100px;
	border: 1px solid var(--border);
	background: var(--bg);
	color: var(--text);
	font-size: 13px;
	font-weight: 600;
}
.fsp-chip .av, .fsp-chip .fsp-ic { width: 26px; height: 26px; font-size: 10px; }
.fsp-chip__n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fsp-chip .ibtn { width: 28px; height: 28px; border-radius: 100px; }
.fsp-chip--tag { padding-inline-start: 12px; background: var(--bg-subtle); }
.fsp-chip--add {
	padding-inline: 10px 12px;
	border-style: dashed;
	background: transparent;
	color: var(--text-muted);
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}
.fsp-chip--add:hover { color: var(--brand); border-color: var(--brand-line); }
.fsp-search--tag { margin-block-start: 4px; }

/* ---- the options of one share ---- */
.fsp-ed {
	display: flex;
	flex-direction: column;
	gap: 14px;
	margin-block: -2px 6px;
	padding: 14px 14px 12px;
	border-radius: 0 0 var(--r-lg) var(--r-lg);
	background: var(--bg-subtle);
}
.fsp-ed--new { margin-block: 4px 0; border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--bg-raised); }
.fsp-ed .field { gap: 6px; }
.fsp-ed__f { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-block-start: 2px; }
.fsp-opt { display: flex; align-items: center; gap: 12px; }
.fsp-opt__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; font-size: 14px; font-weight: 600; }
.fsp-opt__h { font-size: 12px; font-weight: 400; color: var(--text-muted); line-height: 1.4; }
.fsp-opt .switch:disabled { opacity: 0.5; cursor: default; }
.fsp-sub-field { margin-block-start: -6px; }
.fsp-perms { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; border: 0; min-width: 0; }
.fsp-perms legend { padding: 0; margin-block-end: 4px; }
.fsp-check { display: flex; align-items: center; gap: 10px; min-height: 32px; font-size: 14px; cursor: pointer; }
.fsp-check input { width: 18px; height: 18px; margin: 0; accent-color: var(--brand); flex-shrink: 0; }
.fsp-check input:disabled + span { color: var(--text-muted); }
.fsp-pw { display: flex; align-items: center; gap: 8px; }
.fsp-pw .input { flex: 1 1 auto; min-width: 0; }
.fsp-num { max-width: 150px; }
.fsp-note { min-height: 62px; }
.fsp-url { display: flex; gap: 8px; }
.fsp-url .input { flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--text-muted); }
.fsp-url .input:focus { color: var(--text); }
.fsp-add {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	min-height: 56px;
	padding: 8px 6px;
	border: none;
	border-radius: var(--r-lg);
	background: transparent;
	color: inherit;
	text-align: start;
	font: inherit;
	cursor: pointer;
}
.fsp-add:hover:not(:disabled) { background: var(--bg-hover); }
.fsp-add:disabled { opacity: 0.6; cursor: default; }
.fsp-add__t { display: flex; flex-direction: column; min-width: 0; }
.fsp-add__t b { font-size: 14px; color: var(--brand); }
.fsp-add__t span { font-size: 12px; color: var(--text-muted); }
.fsp-ilink {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 14px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg-raised);
}
.fsp-ilink__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.fsp-ilink__t b { font-size: 14px; }
.fsp-ilink__t span { font-size: 12px; color: var(--text-muted); }

/* ---- details ---- */
.fsd-hero { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
.fsd-prev {
	position: relative;
	display: grid;
	place-items: center;
	width: 100%;
	aspect-ratio: 16 / 10;
	max-height: 230px;
	margin-block-end: 12px;
	border-radius: var(--r-xl);
	background: var(--bg-subtle);
	color: var(--text-muted);
	overflow: hidden;
}
.fsd-prev img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: var(--bg-subtle); }
.fsd-prev.has-img .fsd-prev__ic { visibility: hidden; }
/* nothing to preview: a quiet tile, not an empty stage */
.fsd-prev:not(.has-img) { width: 88px; max-height: none; aspect-ratio: 1; margin-block-end: 8px; border-radius: 22px; color: var(--brand); background: var(--brand-soft); }
.fsd-name { font-family: var(--display); font-size: 19px; font-weight: 600; letter-spacing: -0.2px; line-height: 1.3; overflow-wrap: anywhere; }
.fsd-path { font-size: 13px; color: var(--text-muted); overflow-wrap: anywhere; }
.fsd-facts { display: flex; flex-direction: column; margin: 0; }
.fsd-fact { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 9px 0; border-block-end: 1px solid var(--border); }
.fsd-fact:first-child { border-block-start: 1px solid var(--border); }
.fsd-fact dt { flex-shrink: 0; font-size: 13px; color: var(--text-muted); }
.fsd-fact dd { margin: 0; min-width: 0; font-size: 13px; font-weight: 600; text-align: end; overflow-wrap: anywhere; }
.fsd-share, .fsd-line { display: flex; align-items: center; gap: 12px; }
.fsd-share__t { flex: 1 1 auto; min-width: 0; font-size: 14px; line-height: 1.4; }
.fsd-share .btn { flex-shrink: 0; }
.fsd-line__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.fsd-line__t b { font-size: 14px; font-weight: 600; }
.fsd-line__t span { font-size: 12px; color: var(--text-muted); line-height: 1.4; }
.fsd-line .btn { flex-shrink: 0; }
.fsd-picks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.fsd-pick {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	min-width: 0;
	padding: 10px 12px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg);
	color: inherit;
	text-align: start;
	font: inherit;
	cursor: pointer;
}
.fsd-pick:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--brand-line); }
.fsd-pick:disabled { opacity: 0.6; cursor: default; }
.fsd-pick[aria-expanded="true"] { background: var(--brand-soft); border-color: var(--brand); }
.fsd-pick b { font-size: 13px; }
.fsd-pick span { max-width: 100%; font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsd-custom { margin-block-start: 2px; }
.fsd-sec--disc { gap: 4px; }
.fsd-disc {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	min-height: 36px;
	padding: 4px 0;
	border: none;
	background: transparent;
	color: var(--text-muted);
	font: inherit;
	cursor: pointer;
}
.fsd-disc:hover { color: var(--text); }
.fsd-disc__t { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }
.fsd-disc__c { display: inline-flex; }
.fsd-disc__c svg { transition: transform 160ms ease; }
.fsd-disc[aria-expanded="true"] .fsd-disc__c svg { transform: rotate(90deg); }
.fsd-count {
	display: inline-grid;
	place-items: center;
	min-width: 20px;
	height: 18px;
	margin-inline-start: 6px;
	padding: 0 6px;
	border-radius: 100px;
	background: var(--bg-subtle);
	color: var(--text-muted);
	font-size: 11px;
	letter-spacing: 0;
}
.fsd-new {
	display: inline-block;
	margin-inline-start: 6px;
	padding: 1px 7px;
	border-radius: 100px;
	background: var(--brand);
	color: var(--brand-text);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0;
	text-transform: none;
}
.fsd-vers, .fsd-coms { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.fsd-ver { border-radius: var(--r-lg); }
.fsd-ver.is-open { background: var(--bg-subtle); }
.fsd-ver__b {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	min-height: 50px;
	padding: 6px;
	border: none;
	border-radius: var(--r-lg);
	background: transparent;
	color: inherit;
	text-align: start;
	font: inherit;
	cursor: pointer;
}
.fsd-ver__b:hover { background: var(--bg-hover); }
.fsd-ver__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.fsd-ver__n { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsd-ver__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsd-ver__a { display: flex; flex-wrap: wrap; gap: 2px; padding: 0 6px 8px 48px; }
.fsd-ver .fsp-ask, .fsd-vl { margin: 0 6px 8px; }
.fsd-compose { display: flex; flex-direction: column; gap: 8px; }
.fsd-compose__f { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.fsd-com { display: flex; gap: 10px; padding: 10px 6px; border-radius: var(--r-lg); }
.fsd-com.is-new { background: var(--brand-soft); }
.fsd-com > .av { flex-shrink: 0; }
.fsd-com__b { flex: 1 1 auto; min-width: 0; }
.fsd-com__h { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; font-size: 13px; }
.fsd-com__h span { font-size: 12px; color: var(--text-muted); }
.fsd-com__h .fsd-new { margin: 0; color: var(--brand-text); }
.fsd-com__t { margin-block-start: 2px; font-size: 14px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }

/* a refusal too long for the pill toast reads as a card */
.toast.fsp-toast { width: max-content; max-width: min(460px, calc(100vw - 32px)); padding: 12px 16px; border-radius: var(--r-lg); line-height: 1.45; text-align: start; }

/* ---- motion ---- */
@keyframes fsp-fade { from { opacity: 0; } }
@keyframes fsp-rise { from { opacity: 0; transform: translateY(8px) scale(0.985); } }
@keyframes fsp-slide { from { opacity: 0; transform: translateX(28px); } }
@keyframes fsp-up { from { opacity: 0.4; transform: translateY(48px); } }
@keyframes fsp-pulse { 50% { opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) {
	.fsp-scrim, .fsp-box, .fsp-skel__row i, .fsp-skel__row b { animation: none; }
	.fsd-disc__c svg, .fsp-row { transition: none; }
}

/* ---- desktop type sizes (phones keep 16px so focusing never zooms) ---- */
@media (min-width: 768px) {
	.fsp-b .input, .fsp-b .select, .fsp-b .textarea { font-size: 14px; }
	.fsp-search__box .input { font-size: 15px; }
}

/* ---- phone: bottom sheets ---- */
@media (max-width: 767.98px) {
	.fsp-layer, .fsp-layer--details {
		align-items: flex-end;
		justify-content: stretch;
		padding: calc(12px + var(--sat, 0px)) 0 var(--kb, 0px);
	}
	.fsp-box, .fsp-box--details {
		width: 100%;
		max-width: none;
		height: auto;
		max-height: 100%;
		border: none;
		border-radius: var(--r-xl) var(--r-xl) 0 0;
		animation-name: fsp-up;
	}
	.fsp-box--details { height: 100%; }
	.fsp-layer--details .fsp-scrim { opacity: 1; }
	.fsp-grab {
		display: block;
		position: absolute;
		top: 7px;
		inset-inline-start: 50%;
		width: 38px;
		height: 4px;
		margin-inline-start: -19px;
		border-radius: 100px;
		background: var(--border-strong);
	}
	.fsp-h { padding: 20px 8px 10px 16px; }
	.fsp-h--det { padding-block: 18px 0; }
	.fsp-b { padding: 4px 16px 18px; gap: 20px; }
	.fsp-f { padding: 10px 16px calc(10px + var(--sab, 0px)); }
	.fsp-f--quiet { padding: 0 0 var(--sab, 0px); }
	.fsp-row { gap: 10px; padding-inline: 4px; }
	.fsp-role { max-width: 128px; padding-inline: 6px; }
	.fsp-copy span { display: none; }
	.fsp-copy { padding-inline: 10px; }
	.fsp-ed { padding: 12px 12px 10px; }
	.fsp-ed__f .btn--primary, .fsp-pend__f .btn--primary { flex: 1 1 auto; }
	.fsd-prev { max-height: 180px; }
	.fsd-ver__a { padding-inline-start: 6px; }
	.fsd-picks { gap: 6px; }
}
/* ====================================================== calendar */
/* calendar editor + all-day band */
.cal-allday {
	display: grid;
	grid-template-columns: 58px repeat(var(--cols), minmax(90px, 1fr));
	border-block-end: 1px solid var(--border);
	min-width: 100%;
	background: var(--bg);
	/* Stays pinned just under the (also-sticky) day headers, so all-day events
	   remain visible while scrolling the hour grid down to midnight. --chead-h is
	   set by renderCalendar from the header's measured height. */
	position: sticky;
	top: var(--chead-h, 56px);
	z-index: 2;
	/* Corporate green (#15916B), darkened over the surface so the all-day band
	   reads as a distinct dark-green lane in both themes. */
	background: color-mix(in oklab, var(--brand-light) 30%, var(--bg));
}

.cal-allday__l { font-size: 11px; color: color-mix(in oklab, var(--brand-light) 30%, var(--text)); padding: 6px 8px; text-align: end; }
.cal-allday__c {
	position: relative;
	border-inline-start: 1px solid color-mix(in oklab, var(--brand-light) 22%, var(--border));
	padding: 4px; display: flex; flex-direction: column; gap: 3px; min-height: 30px;
	cursor: pointer;
}
.cal-allday__c:hover { background: color-mix(in oklab, var(--brand-light) 16%, transparent); }
/* Hover affordance: a "+" makes clear an empty cell adds an all-day event. */
.cal-allday__c::after {
	content: '+';
	position: absolute; top: 50%; inset-inline-end: 8px; transform: translateY(-50%);
	font-weight: 600; font-size: 15px; line-height: 1; color: var(--brand);
	opacity: 0; transition: opacity 0.12s; pointer-events: none;
}
.cal-allday__c:hover::after { opacity: 0.95; }

.cal-ad {
	border: none;
	border-radius: var(--r-sm);
	padding: 2px 7px;
	font-size: 11px;
	font-weight: 600;
	color: #fff;
	text-align: start;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.cev__meet { display: inline-flex; align-items: center; gap: 3px; opacity: .9; }

.ed { display: flex; flex-direction: column; gap: 14px; }
.ed__row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.ed__row > .field { flex: 1 1 140px; min-width: 120px; }

.ed__more {
	border: none;
	background: none;
	color: var(--brand);
	font-size: 13px;
	font-weight: 600;
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 4px 0;
	align-self: flex-start;
}

.ed__more svg { transition: transform 140ms ease; }
.ed__more[aria-expanded="true"] svg { transform: rotate(90deg); }

.ed__meet {
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	padding: 12px 14px;
	display: flex;
	flex-direction: column;
	gap: 12px;
	transition: border-color 160ms ease, background 160ms ease;
}

.ed__meet[data-on="1"] { border-color: var(--brand-line); background: var(--brand-soft); }
.ed__meet__top { display: flex; align-items: center; gap: 12px; }

.ed__chips { display: flex; gap: 6px; flex-wrap: wrap; }

.ed__chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	height: 30px;
	padding-inline: 10px;
	border-radius: 100px;
	border: 1px solid var(--border-strong);
	background: var(--bg);
	font-size: 13px;
}

.ed__chip[aria-pressed="true"] { border-color: var(--brand); background: var(--brand-soft); color: var(--brand); font-weight: 600; }

.cal-dot { width: 10px; height: 10px; border-radius: 100px; flex-shrink: 0; }


.cal-item { min-height: 34px; display: flex; align-items: center; gap: 10px; padding-inline: 10px; border-radius: var(--r); border: none; background: transparent; width: 100%; text-align: start; font-size: 14px; }
.cal-item:hover { background: var(--bg-hover); }

/* One calendar row: the toggle fills the row, the ⋯ sits at the end and only
   shows on hover / while its menu is open, so the list stays quiet. */
.cal-row { display: flex; align-items: center; gap: 2px; }
.cal-row .cal-item { flex: 1 1 auto; min-width: 0; }
.cal-row .cal-item .grow { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-row__more { opacity: 0; flex-shrink: 0; }
.cal-row:hover .cal-row__more, .cal-row__more[aria-expanded="true"], .cal-row__more:focus-visible { opacity: 1; }
.cal-row .dd { min-width: 200px; }
.cal-sub { color: var(--text-muted); display: inline-flex; flex-shrink: 0; }
.cal-tools { display: flex; flex-wrap: wrap; gap: 2px; padding: 6px 4px 0; }
.cal-tools .btn { font-size: 12px; padding-inline: 8px; min-height: 30px; }

/* The line under the Talk+ meeting switch: "created when you save" or the
   live link with a copy button. */
.ed__meet__line { display: flex; align-items: center; gap: 8px; font-size: 13px; min-width: 0; }
.ed__meet__url { color: var(--brand); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }
.ed__meet__url:hover { text-decoration: underline; }
.cal-ro { border: 1px solid var(--border); background: var(--bg-subtle); border-radius: var(--r-lg); padding: 10px 12px; font-size: 13px; color: var(--text-muted); }

.cal-chk {
	width: 16px;
	height: 16px;
	border-radius: var(--r-sm);
	border: 2px solid currentColor;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	color: var(--text-muted);
}

.cal-chk[data-on="1"] { background: currentColor; }
.cal-chk svg { color: #fff; }
.cal-chk[data-on="0"] svg { display: none; }

.cwrap { flex-grow: 1; min-height: 0; overflow: auto; }

/* ===== split week: two week panes with a draggable divider =====
   --split is the first pane's share (20–80 %). Side by side (--h) splits the
   width, stacked (--v) splits the height; each pane scrolls on its own. */
.csplit { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; }
.csplit--h { flex-direction: row; }
.csplit--v { flex-direction: column; }
.csplit > .cwrap { flex: 1 1 0; min-width: 0; min-height: 0; }
.csplit--h > .cwrap:first-child { flex: 0 0 calc(var(--split, 50%) - 5px); }
.csplit--v > .cwrap:first-child { flex: 0 0 calc(var(--split, 50%) - 5px); }
.csplit__bar { flex: 0 0 10px; position: relative; background: var(--bg-subtle); border-inline: 1px solid var(--border); cursor: col-resize; touch-action: none; user-select: none; display: flex; align-items: center; justify-content: center; }
.csplit--v > .csplit__bar { border-inline: none; border-block: 1px solid var(--border); cursor: row-resize; }
.csplit__bar i { display: block; width: 3px; height: 34px; border-radius: 3px; background: var(--border-strong, var(--border)); transition: background .15s ease, transform .15s ease; }
.csplit--v > .csplit__bar i { width: 34px; height: 3px; }
.csplit__bar:hover i, .csplit__bar:focus-visible i, .csplit.is-drag > .csplit__bar i { background: var(--brand); }
.csplit__bar:hover, .csplit.is-drag > .csplit__bar { background: var(--brand-soft, var(--bg-subtle)); }
.csplit__bar:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.csplit.is-drag > .cwrap { pointer-events: none; user-select: none; }
.chead__corner { font-size: 11px; font-weight: 700; color: var(--text-muted); display: flex; align-items: flex-end; justify-content: center; padding: 0 4px 8px; text-align: center; line-height: 1.15; font-variant-numeric: tabular-nums; }
.csplit-wrap { display: inline-flex; }
.csplit-menu { inset-inline-end: 0; inset-inline-start: auto; min-width: 260px; padding: 6px; }
.csplit-menu__opt { display: flex !important; align-items: center; gap: 12px; width: 100%; text-align: start; }
.csplit-menu__opt span { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.csplit-menu__opt b { font-size: 13.5px; font-weight: 600; }
.csplit-menu__opt small { font-size: 12px; color: var(--text-muted); }
.csplit-menu__opt[aria-checked="true"] { color: var(--brand); }
.csplit-menu__opt[aria-checked="true"] small { color: var(--brand); opacity: .8; }
.cgrid { display: grid; grid-template-columns: 58px repeat(var(--cols), minmax(90px, 1fr)); min-width: 100%; }

.chead {
	position: sticky;
	top: 0;
	z-index: 3;
	background: var(--bg);
	display: grid;
	grid-template-columns: 58px repeat(var(--cols), minmax(90px, 1fr));
	border-block-end: 1px solid var(--border);
	min-width: 100%;
}

.chead__c { padding: 8px 6px; text-align: center; border-inline-start: 1px solid var(--border); }
.chead__d { font-size: 12px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.chead__n { font-family: var(--display); font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }
.chead__c[data-today="1"] .chead__n { color: var(--brand-text); background: var(--brand); border-radius: 100px; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; }

.cgutter { position: relative; }
.cgutter__h { height: 48px; font-size: 11px; color: var(--text-muted); text-align: end; padding-inline-end: 8px; transform: translateY(-7px); font-variant-numeric: tabular-nums; }
.cgutter__h--end { height: 0; }

.ccol { border-inline-start: 1px solid var(--border); position: relative; }
.ccol__slot { height: 48px; border-block-end: 1px solid var(--border); position: relative; }
.ccol__slot:hover { background: var(--bg-hover); cursor: pointer; }
/* Hover affordance: a "+" makes clear that clicking a time slot adds an event. */
.ccol__slot::after {
	content: '+';
	position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
	font-weight: 600; font-size: 16px; line-height: 1; color: var(--brand);
	opacity: 0; transition: opacity 0.12s; pointer-events: none;
}
.ccol__slot:hover::after { opacity: 0.9; }


/* ---- month: every day is a door to that day (2026-09-28) ---- */
.cmonth__d[data-act="c-day"] { cursor: pointer; transition: background 120ms ease; }
.cmonth__d[data-act="c-day"]:hover { background: var(--bg-hover); }
.cmonth__d[data-act="c-day"]:hover .cmonth__n { background: var(--brand-soft); color: var(--brand); }
.cmonth__d[data-today="1"]:hover .cmonth__n { background: var(--brand); color: var(--brand-text); }
/* ---- day / week / 2-week: the range being dragged ---- */
.ccol__slot { touch-action: pan-y; }
.cdrag {
	position: absolute;
	inset-inline: 3px;
	z-index: 4;
	pointer-events: none;
	border-radius: 8px;
	background: color-mix(in oklab, var(--brand) 22%, transparent);
	border: 1.5px dashed var(--brand);
	color: var(--brand);
	font-size: 11px;
	font-weight: 600;
	padding: 4px 6px;
	line-height: 1.2;
	white-space: nowrap;
	overflow: hidden;
	box-sizing: border-box;
}
.cgrid.is-dragging, .cgrid.is-dragging * { user-select: none; cursor: ns-resize; }
/* ===== mini NuvoCloud dial — a thing that is being created, shown where it will land ===== */
.nuvo-mini { position: relative; width: 22px; height: 22px; display: inline-grid; place-items: center; flex: none; }
.nuvo-mini__ring {
	position: absolute; inset: 0; border-radius: 50%;
	background: conic-gradient(from 0deg, transparent 18deg, currentColor 320deg, transparent 360deg);
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 1.5px));
	mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 1.5px));
	animation: nuvo-spin 1.1s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}
.nuvo-mini__logo { width: 62%; height: 62%; display: block; animation: nuvo-spin 3.4s linear infinite; }
.nuvo-mini__logo svg { width: 100%; height: 100%; display: block; }
/* A space on its way: its tile, already in its colour, with the dial in place of the initials. */
.rail__tile--pending { color: #fff; opacity: .92; cursor: progress; display: grid; place-items: center; animation: nuvo-content-in .25s ease-out both; }
.rail__tile--pending:hover { transform: none; }
.rail__tile--pending .nuvo-mini { width: 24px; height: 24px; }
/* A channel on its way: its row, name already readable, dial where the badge sits. */
.chan--pending { cursor: progress; color: var(--text-muted); animation: nuvo-content-in .25s ease-out both; }
.chan--pending .chan__name { opacity: .8; }
.chan--pending .nuvo-mini { margin-inline-start: auto; width: 18px; height: 18px; color: var(--brand); }
@media (prefers-reduced-motion: reduce) {
	.nuvo-mini__logo { animation: none; }
	.nuvo-mini__ring { animation: nuvo-spin 1.4s linear infinite; }
}

/* ===== NuvoCloud loading dial ===== */
.nuvo-loader {
	/* Covers ONLY the app content pane — its rect (left/top/width/height) is
	   measured in nuvoLoaderFit so the top nav and the app's own left sidebar
	   stay visible and clickable through a slow load. z-index 50 keeps it above
	   content (≤5) but below the header's dropdowns (60) and menus (90), so the
	   brand, settings, theme and presence menus still open over it. */
	position: fixed; z-index: 50;
	display: grid; place-items: center;
	/* Opaque: while loading, ONLY the dial shows over the content — which fades
	   back in (see .nuvo-fade-in) once the load finishes. */
	background: var(--bg);
	animation: nuvo-loader-in 0.18s ease-out both;
}
/* el.hidden must win over display:grid — a class selector beats the UA
   [hidden] rule, so without this the "hidden" overlay stays on screen. */
.nuvo-loader[hidden] { display: none; }
@keyframes nuvo-loader-in { from { opacity: 0; } to { opacity: 1; } }
/* The freshly-loaded content fades in as the veil lifts. */
.nuvo-fade-in { animation: nuvo-content-in 0.34s ease-out both; }
@keyframes nuvo-content-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .nuvo-fade-in { animation: none; } }
.nuvo-loader__dial {
	position: relative; width: 104px; height: 104px;
	display: grid; place-items: center;
	filter: drop-shadow(0 0 18px color-mix(in oklab, var(--brand) 42%, transparent));
	animation: nuvo-dial-pulse 1.8s ease-in-out infinite;
}
@keyframes nuvo-dial-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
/* The sweeping arc — a masked conic gradient reads as a progress dial. */
.nuvo-loader__ring {
	position: absolute; inset: 0; border-radius: 50%;
	background: conic-gradient(from 0deg, transparent 18deg,
		color-mix(in oklab, var(--brand) 92%, transparent) 320deg, transparent 360deg);
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
	mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
	animation: nuvo-spin 1.1s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}
/* The brand mark itself, turning slowly so its orange spoke sweeps like a hand. */
.nuvo-loader__logo { width: 62%; height: 62%; display: block; animation: nuvo-spin 3.4s linear infinite; }
.nuvo-loader__logo svg { width: 100%; height: 100%; display: block; }
@keyframes nuvo-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
	.nuvo-loader__dial, .nuvo-loader__logo { animation: none; }
	.nuvo-loader__ring { animation: nuvo-spin 1.4s linear infinite; }
}

/* ===== drag & drop upload overlay =====
   Covers the Files app pane while a file is dragged over it. pointer-events:none so
   it never swallows the drag events (the window listeners handle everything). */
.nuvo-drop {
	position: fixed; z-index: 55; pointer-events: none;
	display: grid; place-items: center; padding: 24px;
	background: color-mix(in oklab, var(--brand) 12%, var(--bg) 74%);
	-webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
	animation: nuvo-drop-in 0.16s ease-out both;
}
.nuvo-drop[hidden] { display: none; }
.nuvo-drop__card {
	display: grid; justify-items: center; gap: 12px;
	padding: 34px 56px; border-radius: 20px;
	background: var(--bg-raised); color: var(--text);
	border: 2px dashed color-mix(in oklab, var(--brand) 60%, var(--border));
	box-shadow: 0 26px 64px -20px rgba(4, 16, 13, 0.5);
	animation: nuvo-drop-pop 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.nuvo-drop__ic { display: flex; color: var(--brand); animation: nuvo-drop-bob 1.1s ease-in-out infinite; }
.nuvo-drop__t { font-family: var(--display, inherit); font-size: 18px; font-weight: 600; }
.nuvo-drop__s { font-size: 13px; color: var(--text-muted); }
@keyframes nuvo-drop-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes nuvo-drop-pop { from { opacity: 0; transform: scale(0.96) translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes nuvo-drop-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@media (prefers-reduced-motion: reduce) { .nuvo-drop, .nuvo-drop__card, .nuvo-drop__ic { animation: none; } }

/* ===== the fancy document popup (Files → open a file) =====
   Nextcloud opens Office docs full-screen; NuvoCloud opens them in this window,
   which the user can maximise (⤢) or keep floating. Office docs embed the real
   Collabora editor through the gateway proxy (same-origin, so framing is
   allowed) and autosave; PDFs/images render from the download proxy; text and
   markdown open in an editor that saves on close. z-index 130 sits above the
   modal backdrop (100) and photo lightbox (120), below the toast (200). */
.nuvo-doc {
	position: fixed; inset: 0; z-index: 130;
	display: grid; place-items: center; padding: 28px;
	background: color-mix(in oklab, #04100d 62%, transparent);
	-webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
	animation: nuvo-doc-fade 0.18s ease-out both;
}
.nuvo-doc[hidden] { display: none; }
@keyframes nuvo-doc-fade { from { opacity: 0; } to { opacity: 1; } }
.nuvo-doc__win {
	display: flex; flex-direction: column;
	width: min(1180px, 100%); height: min(820px, 100%);
	background: var(--bg); color: var(--text);
	border: 1px solid var(--border-strong); border-radius: 16px; overflow: hidden;
	box-shadow: 0 24px 70px -12px rgba(4, 16, 13, 0.55);
	animation: nuvo-doc-rise 0.22s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes nuvo-doc-rise { from { opacity: 0; transform: translateY(10px) scale(0.99); } to { opacity: 1; transform: none; } }
/* Maximised: fill the viewport, drop the rounding. */
.nuvo-doc--full { padding: 0; }
.nuvo-doc--full .nuvo-doc__win { width: 100%; height: 100%; border-radius: 0; border: none; }
@media (prefers-reduced-motion: reduce) { .nuvo-doc, .nuvo-doc__win { animation: none; } }
.nuvo-doc__bar {
	display: flex; align-items: center; gap: 10px; flex: 0 0 auto;
	padding: 10px 12px 10px 16px;
	background: var(--bg-raised); border-block-end: 1px solid var(--border);
}
.nuvo-doc__ic { color: var(--brand); display: flex; flex: 0 0 auto; }
.nuvo-doc__name { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nuvo-doc__hint { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.nuvo-doc__sp { flex: 1 1 auto; min-width: 8px; }
.nuvo-doc__btn {
	display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
	width: 34px; height: 34px; border-radius: 9px;
	background: transparent; border: 1px solid transparent; color: var(--text-muted); cursor: pointer;
}
.nuvo-doc__btn:hover { background: var(--bg-hover); color: var(--text); }
.nuvo-doc__btn--close:hover { background: color-mix(in oklab, var(--danger) 16%, transparent); color: var(--danger); }
.nuvo-doc__body { flex: 1 1 auto; position: relative; background: var(--bg-subtle); overflow: auto; }
.nuvo-doc__frame { width: 100%; height: 100%; border: 0; display: block; background: #fff; }
.nuvo-doc__img { display: block; margin: auto; max-width: 100%; max-height: 100%; border-radius: 4px; box-shadow: 0 10px 34px -12px rgba(4, 16, 13, 0.4); }
.nuvo-doc__text {
	width: 100%; height: 100%; border: 0; resize: none; display: block; box-sizing: border-box;
	padding: 22px 26px; background: var(--bg); color: var(--text);
	font: 14px/1.6 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
.nuvo-doc__center { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 12px; padding: 24px; text-align: center; color: var(--text-muted); }
.nuvo-doc__btn[disabled] { opacity: .32; cursor: default; pointer-events: none; }
/* ‹ › segment reads as one control */
.nuvo-doc__seg { display: inline-flex; align-items: center; margin-inline-end: 2px; }
.nuvo-doc__share { position: relative; display: inline-flex; }
.nuvo-doc__menu {
	position: absolute; inset-block-start: calc(100% + 6px); inset-inline-end: 0; z-index: 5;
	min-width: 196px; padding: 6px; display: flex; flex-direction: column; gap: 2px;
	background: var(--bg-raised); border: 1px solid var(--border); border-radius: 12px;
	box-shadow: 0 16px 40px -12px rgba(4, 16, 13, 0.5);
}
/* An id/class display rule beats the bare [hidden] rule here, so hidden needs
   equal specificity to actually hide the menu (same gotcha as .nuvo-loader). */
.nuvo-doc__menu[hidden] { display: none; }
.nuvo-doc__menu button {
	display: flex; align-items: center; gap: 10px; width: 100%;
	padding: 9px 10px; border: 0; border-radius: 8px; cursor: pointer;
	background: transparent; color: var(--text); font: inherit; font-size: 14px; text-align: start;
}
.nuvo-doc__menu button:hover { background: var(--bg-hover); }
.nuvo-doc__menu button svg { color: var(--brand); flex: 0 0 auto; }
/* Opaque cover over the office iframe while Collabora boots (kills the NC-blue flash) */
.nuvo-doc__cover {
	position: absolute; inset: 0; z-index: 2;
	display: grid; place-items: center; align-content: center; gap: 14px;
	background: var(--bg); color: var(--text-muted); transition: opacity 0.2s ease;
}
.nuvo-doc__cover--out { opacity: 0; pointer-events: none; }
/* The popup body keeps ONE warm Collabora frame across opens (see
   nuvoOfficeFrame); everything else — covers, viewers, the proxy-mode preview —
   renders in the pane laid over it. An empty pane is display:none so it never
   swallows clicks meant for the editor beneath. */
.nuvo-doc__pane { position: absolute; inset: 0; z-index: 1; }
.nuvo-doc__pane:empty { display: none; }
.nuvo-doc__frame[hidden] { display: none; }
/* Direct-mode cover: the NuvoCloud dial, the document, and a progress feel —
   all on the popup's own ground so the fade reveals the editor in place. */
.nuvo-doc__cover--office { gap: 10px; }
.nuvo-doc__cover-dial { width: 76px; height: 76px; margin-block-end: 8px; }
.nuvo-doc__cover-doc { display: flex; align-items: center; gap: 8px; max-width: min(520px, 90%); color: var(--text); font-weight: 600; font-size: 15px; }
.nuvo-doc__cover-doc svg { color: var(--brand); flex: 0 0 auto; }
.nuvo-doc__cover-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nuvo-doc__cover-kind { font-size: 12px; color: var(--text-muted); }
.nuvo-doc__cover-bar { position: relative; width: 168px; height: 3px; margin-block-start: 8px; border-radius: 3px; overflow: hidden; background: var(--border); }
.nuvo-doc__cover-bar i {
	position: absolute; inset-block: 0; inset-inline-start: 0; width: 40%; border-radius: 3px;
	background: var(--brand); animation: nuvo-doc-slide 1.4s ease-in-out infinite;
}
@keyframes nuvo-doc-slide { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
/* A failed open: an honest message with a way forward, on the same cover. */
.nuvo-doc__cover-fail { display: grid; justify-items: center; gap: 6px; max-width: 440px; padding: 0 24px; text-align: center; }
.nuvo-doc__cover-fail svg { color: var(--danger); margin-block-end: 4px; }
.nuvo-doc__cover-fail b { color: var(--text); font-size: 15px; overflow-wrap: anywhere; }
.nuvo-doc__cover-fail p { margin: 0; font-size: 13px; color: var(--text-muted); }
.nuvo-doc__cover-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-block-start: 12px; }
@media (prefers-reduced-motion: reduce) { .nuvo-doc__cover-bar i { animation-duration: 3s; } }
.nuvo-doc__spin {
	width: 34px; height: 34px; border-radius: 50%;
	border: 3px solid var(--border); border-top-color: var(--brand);
	animation: nuvo-doc-spin 0.8s linear infinite;
}
@keyframes nuvo-doc-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .nuvo-doc__spin { animation-duration: 2.4s; } }

/* ===== office preview stage (opens instantly; editor warms up behind it) ===== */
/* The real editor loads here, occluded by the stage — so it truly loads, and the
   reveal on Open is instant. */
.nuvo-doc__frame--bg { position: absolute; inset: 0; z-index: 0; }
.nuvo-doc__stage {
	position: absolute; inset: 0; z-index: 1; background: var(--bg);
	display: grid; grid-template-columns: minmax(0, 1fr) 340px; min-height: 0;
	animation: nuvo-doc-fade 0.2s ease-out both;
}
.nuvo-doc__stage--out { opacity: 0; transition: opacity 0.25s ease; }
.nuvo-doc__stage--cover { display: grid; grid-template-columns: none; place-items: center; align-content: center; gap: 14px; color: var(--text-muted); }
/* left: the page-1 preview on a paper card */
.nuvo-doc__pv { min-width: 0; overflow: auto; display: grid; place-items: center; padding: 28px; background: var(--bg-subtle); }
.nuvo-doc__pv-paper {
	position: relative; max-width: 100%;
	border-radius: 6px; overflow: hidden; background: #fff;
	box-shadow: 0 10px 34px -10px rgba(4, 16, 13, 0.42), 0 0 0 1px rgba(4, 16, 13, 0.06);
}
.nuvo-doc__pv-img { display: block; max-width: min(560px, 100%); max-height: calc(100vh - 220px); width: auto; height: auto; }
.nuvo-doc__pv-ph { display: none; padding: 60px; color: var(--text-muted); }
.nuvo-doc__pv-paper--noimg { background: var(--bg-raised); }
.nuvo-doc__pv-paper--noimg .nuvo-doc__pv-ph { display: block; }
/* the live image viewer — image left, the shared details panel right (no stage,
   no iframe: images load instantly) */
.nuvo-doc__view { display: grid; grid-template-columns: minmax(0, 1fr) 340px; height: 100%; min-height: 0; }
.nuvo-doc__view-img { min-width: 0; overflow: auto; display: grid; place-items: center; padding: 28px; background: var(--bg-subtle); }
/* right: the details panel */
.nuvo-doc__pv-side { display: flex; flex-direction: column; gap: 18px; padding: 24px 22px; border-inline-start: 1px solid var(--border); overflow: auto; }
.nuvo-doc__pv-head { display: flex; align-items: flex-start; gap: 12px; }
.nuvo-doc__pv-badge { display: inline-flex; padding: 9px; border-radius: 12px; background: var(--brand-soft, var(--bg-hover)); color: var(--brand); flex: 0 0 auto; }
.nuvo-doc__pv-title { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nuvo-doc__pv-name { font-size: 15px; line-height: 1.3; overflow-wrap: anywhere; }
.nuvo-doc__pv-kind { font-size: 12px; color: var(--text-muted); }
.nuvo-doc__meta { display: flex; flex-direction: column; }
.nuvo-doc__mrow { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-block-end: 1px solid var(--border); font-size: 13px; }
.nuvo-doc__mrow:last-child { border-block-end: 0; }
.nuvo-doc__ml { color: var(--text-muted); flex: 0 0 auto; }
.nuvo-doc__mv { color: var(--text); text-align: end; overflow-wrap: anywhere; }
.nuvo-doc__pv-actions { display: flex; flex-direction: column; gap: 8px; margin-block-start: auto; }
.nuvo-doc__pv-open { justify-content: center; }
.nuvo-doc__pv-warm { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); }
.nuvo-doc__pv-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); animation: nuvo-doc-pulse 1.2s ease-in-out infinite; }
.nuvo-doc__pv-warm--ready { color: var(--brand); }
.nuvo-doc__pv-warm--ready .nuvo-doc__pv-dot { background: var(--brand); animation: none; }
.nuvo-doc__pv-warm--err { color: var(--danger); }
@keyframes nuvo-doc-pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .nuvo-doc__pv-dot, .nuvo-doc__stage { animation: none; } }
/* narrow: stack preview/image over details */
@media (max-width: 720px) {
	.nuvo-doc__stage, .nuvo-doc__view { grid-template-columns: none; grid-template-rows: minmax(0, 1fr) auto; }
	.nuvo-doc__pv-side { border-inline-start: 0; border-block-start: 1px solid var(--border); }
}

.cev {
	position: absolute;
	border-radius: var(--r-sm);
	padding: 3px 6px;
	font-size: 11px;
	line-height: 1.3;
	overflow: hidden;
	color: #fff;
	border: none;
	text-align: start;
	z-index: 2;
	box-shadow: 0 1px 2px rgba(6, 17, 14, 0.2);
}

.cev:hover { filter: brightness(1.1); }
.cev b { font-weight: 700; display: block; }
.cev[aria-pressed="true"] { outline: 2px solid var(--text); outline-offset: 1px; }

.cnow { position: absolute; inset-inline: 0; height: 2px; background: var(--danger); z-index: 4; pointer-events: none; }
.cnow::before { content: ''; position: absolute; inset-inline-start: -4px; top: -3px; width: 8px; height: 8px; border-radius: 100px; background: var(--danger); }

.cmonth { display: grid; grid-template-columns: repeat(var(--mcols, 7), minmax(0, 1fr)); grid-auto-rows: minmax(108px, auto); }
.cchip__meet { display: inline-flex; vertical-align: -1px; margin-inline-end: 3px; }
.cmonth__d { border-inline-start: 1px solid var(--border); border-block-end: 1px solid var(--border); padding: 6px; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cmonth__d[data-off="1"] { background: var(--bg-subtle); }
.cmonth__n { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; align-self: flex-start; padding: 2px 6px; border-radius: 100px; }
.cmonth__d[data-today="1"] .cmonth__n { background: var(--brand); color: var(--brand-text); }

.cchip {
	border-radius: var(--r-sm);
	padding: 2px 6px;
	font-size: 11px;
	color: #fff;
	text-align: start;
	border: none;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	display: block;
	width: 100%;
}

/* ================================================== app launcher */
.launch { position: relative; display: flex; }
/* Scrims exist only as mobile modal backdrops (see the compact block); on a
   pointer-sized screen the launcher and presence menu are dropdowns and need none. */
.launch__scrim, .pm__scrim { display: none; }

.launch__btn {
	height: var(--tap);
	padding-inline: 10px 12px;
	border-radius: var(--r);
	border: none;
	background: transparent;
	color: var(--chrome-muted);
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 13px;
	font-weight: 500;
	transition: color 200ms ease, background 200ms ease;
}

.launch__btn:hover { background: color-mix(in srgb, var(--chrome-text) 8%, transparent); color: var(--chrome-text); }
.launch__btn[aria-expanded="true"] { background: var(--chrome-active); color: var(--chrome-active-text); }

/* The hub: the logo's centre and its ring of dots, six of them, the top one
   in the logo's orange. Opening turns the ring a sixth and swells the centre. */
.launch__hub { flex-shrink: 0; display: block; overflow: visible; }
.launch__hub-c, .launch__hub-r { transform-origin: 12px 12px; transition: transform 460ms cubic-bezier(.2, 1.25, .3, 1); }
.launch__btn[aria-expanded="true"] .launch__hub-r { transform: rotate(60deg); }
.launch__btn[aria-expanded="true"] .launch__hub-c { transform: scale(1.45); }

.launch__panel {
	position: absolute;
	top: calc(100% + 12px);
	inset-inline-start: 0;
	z-index: 90;
	width: 420px;
	max-width: calc(100vw - 32px);
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 20px 52px rgba(6, 17, 14, .3);
	padding: 14px;
	transform-origin: top left;
	animation: launch-panel 320ms cubic-bezier(.2, 1.1, .3, 1);
}

@keyframes launch-panel {
	from { opacity: 0; transform: translateY(-10px) scale(.96); }
	to { opacity: 1; transform: none; }
}

.launch__panel::before {
	content: '';
	position: absolute;
	top: -6px;
	inset-inline-start: 20px;
	width: 11px;
	height: 11px;
	background: var(--bg);
	border-inline-start: 1px solid var(--border);
	border-block-start: 1px solid var(--border);
	transform: rotate(45deg);
}

.launch__t { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--text-muted); padding: 2px 4px 10px; }
.launch__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }

/* A hairline, not a rule: it separates two groups inside one panel, so it
   should be felt rather than read. */
.launch__sep {
	border: none;
	border-block-start: 1px solid var(--border);
	margin: 16px 4px 12px;
	opacity: .65;
}

.launch__t--beta { display: flex; align-items: center; gap: 8px; }

/* Warn tokens, not brand: this marks something you cannot rely on yet, and
   the mint is spoken for by things that work. */
.launch__badge {
	font-size: 9.5px;
	font-weight: 700;
	letter-spacing: .04em;
	text-transform: none;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--warn-bg);
	color: var(--warn);
	border: 1px solid var(--warn-border);
}

.launch__app {
	border: none;
	background: transparent;
	border-radius: var(--r-lg);
	padding: 14px 6px 12px;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 9px;
	text-align: center;
	opacity: 0;
	transform: translateY(12px) scale(.94);
	animation: launch-app 480ms cubic-bezier(.2, 1.2, .3, 1) forwards;
}

@keyframes launch-app { to { opacity: 1; transform: none; } }

.launch__app:hover { background: var(--bg-hover); }

.launch__ic {
	width: 46px;
	height: 46px;
	border-radius: 15px;
	background: var(--brand-soft);
	color: var(--brand);
	display: flex;
	align-items: center;
	justify-content: center;
	position: relative;
	transition: transform 300ms cubic-bezier(.2, 1.3, .3, 1), box-shadow 300ms ease;
}

.launch__app:hover .launch__ic { transform: translateY(-4px); box-shadow: 0 10px 20px rgba(6, 17, 14, .16); }
.launch__app[aria-current="true"] .launch__ic { background: var(--brand); color: var(--brand-text); }

/* The drawer draws the top bar's duotone glyphs: the soft fill sits a little
   stronger than in the bar because the tile is bigger and the icon larger. */
.launch__ic .nav-ic__fill { opacity: .22; }
.launch__app[aria-current="true"] .launch__ic .nav-ic__fill { opacity: .32; }

/* Tap feedback: an orange ring on the tile's own edge, lit as a travelling
   arc — the loading-ring feel — until the drawer folds away. The angle is a
   registered custom property so the arc itself moves while the ring stays put. */
@property --launch-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.launch__ic::after {
	content: '';
	position: absolute;
	inset: -5px;
	border-radius: 19px;
	padding: 2.5px;
	background: conic-gradient(from var(--launch-a, 0deg), #FF8A3D 0 26%, rgba(255, 138, 61, .18) 26% 100%);
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	opacity: 0;
	transition: opacity .15s ease;
	pointer-events: none;
}
.launch__ic.is-launching { transform: translateY(-2px) scale(1.04); }
.launch__ic.is-launching::after { opacity: 1; animation: launch-ring .9s linear infinite; }
@keyframes launch-ring { to { --launch-a: 360deg; } }
@media (prefers-reduced-motion: reduce) {
	.launch__ic.is-launching::after { animation: none; background: rgba(255, 138, 61, .9); }
}

.launch__n { font-size: 12.5px; font-weight: 600; line-height: 1.2; }
.launch__d { font-size: 10.5px; color: var(--text-muted); line-height: 1.3; }
.launch__ic .wip-badge { position: absolute; top: -5px; inset-inline-end: -8px; }

@media (max-width: 900px) { .launch__btn span { display: none; } }

/* ================================================= profile menu */
.me { position: relative; display: flex; }

.me__btn {
	position: relative;
	width: 32px;
	height: 32px;
	border-radius: 100px;
	border: none;
	padding: 0;
	background: #22b98a;
	color: #08231c;
	font-size: 12px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: visible;
}

.me__btn img { width: 100%; height: 100%; border-radius: 100px; object-fit: cover; display: block; }
.me__btn:hover { box-shadow: 0 0 0 2px rgba(255, 255, 255, .35); }

.me__dot {
	position: absolute;
	inset-block-end: -1px;
	inset-inline-end: -1px;
	width: 11px;
	height: 11px;
	border-radius: 100px;
	box-shadow: 0 0 0 2px var(--chrome);
}

.pm {
	position: absolute;
	top: calc(100% + 10px);
	inset-inline-end: 0;
	z-index: 90;
	width: 328px;
	max-height: 78dvh;
	overflow-y: auto;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 18px 48px rgba(6, 17, 14, .3);
	color: var(--text);
	padding: 6px;
	/* The Today sheet's quiet scrollbar, not the app-wide mint column. */
	scrollbar-width: thin;
	scrollbar-color: color-mix(in srgb, var(--text) 16%, transparent) transparent;
}
.pm::-webkit-scrollbar { width: 8px; background: transparent; }
.pm::-webkit-scrollbar-track, .pm::-webkit-scrollbar-button { background: transparent; height: 0; }
.pm::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--text) 16%, transparent); border: 2px solid transparent; background-clip: padding-box; border-radius: 8px; }
/* The picture's own menu, tucked under the picture. */
.pm__avmenu { inset-inline-end: auto; inset-inline-start: 0; top: calc(100% + 6px); min-width: 190px; }

.pm__id { display: flex; gap: 12px; align-items: center; padding: 12px 12px 14px; }
.pm__av { width: 46px; height: 46px; border-radius: 100px; flex-shrink: 0; background: #22b98a; color: #08231c; font-weight: 700; font-size: 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.pm__av img { width: 100%; height: 100%; object-fit: cover; }
/* The picture doubles as the "change picture" button: a small camera badge on
   its rim says so, and the whole tile lifts on hover. */
.pm__avbtn { position: relative; border: none; background: none; padding: 0; margin: 0; cursor: pointer; border-radius: 100px; flex-shrink: 0; color: inherit; font: inherit; }
.pm__avbtn .pm__av { transition: transform .15s ease, box-shadow .15s ease; }
.pm__avbtn:hover .pm__av, .pm__avbtn:focus-visible .pm__av { transform: scale(1.04); box-shadow: 0 0 0 3px var(--brand-soft, rgba(34, 185, 138, .25)); }
.pm__avbtn:focus-visible { outline: none; }
.pm__avcam { position: absolute; inset-block-end: -2px; inset-inline-end: -2px; width: 20px; height: 20px; border-radius: 100px; background: var(--bg); color: var(--text); display: flex; align-items: center; justify-content: center; box-shadow: 0 1px 4px rgba(0, 0, 0, .28); pointer-events: none; }
.pm__photo { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 12px 12px; }
.pm__photo .pm__preset { display: inline-flex; align-items: center; gap: 6px; }

/* ===== Today overlay: pull tab, liquid-glass sheet, widgets, feeds ===== */
/* The Today clock. The time, set quietly in the header beside you, is the way
   into the Today overlay (notifications, weather, widgets), the way the menu
   bar clock opens Notification Center. No box, no chevron, no number: a 6px
   orange dot above the digits says something is new. Ctrl+Shift+Space and a
   swipe down from the top edge (touch) open the same overlay. */
.nv-today-btn { position: relative; height: var(--tap); padding: 0 10px; border: none; border-radius: var(--r); background: transparent; color: var(--chrome-muted); font: inherit; font-size: 13px; font-weight: 500; letter-spacing: .03em; font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; cursor: pointer; flex-shrink: 0; transition: color .18s ease, background .18s ease; }
.nv-today-btn:hover, .nv-today-btn:focus-visible { color: var(--chrome-text); background: color-mix(in srgb, var(--chrome-text) 8%, transparent); outline: none; }
.nv-today-btn[aria-expanded="true"] { color: var(--chrome-active-text); }
.nv-today-btn__n { position: absolute; top: 8px; right: 4px; width: 6px; height: 6px; border-radius: 50%; background: #FF8A3D; box-shadow: 0 0 0 2px var(--chrome); }
.nv-today-btn__n[hidden] { display: none; }
.nv-today-btn.is-hint .nv-today-btn__n { animation: nv-dot-breathe 1.2s ease-in-out 2; }
@keyframes nv-dot-breathe { 50% { transform: scale(1.7); box-shadow: 0 0 0 2px var(--chrome), 0 0 10px rgba(255, 138, 61, .9); } }
.hdr { position: relative; }

.nv-today { position: fixed; inset: 0; z-index: 150; display: flex; flex-direction: column; overflow: hidden; color: var(--text); background: color-mix(in srgb, var(--bg) 58%, transparent); backdrop-filter: blur(22px) saturate(1.35); -webkit-backdrop-filter: blur(22px) saturate(1.35); opacity: 0; transform: translateY(-3%); transition: opacity .32s ease, transform .42s cubic-bezier(.2, .9, .25, 1); }
.nv-today.is-in { opacity: 1; transform: none; }
/* A sheet that is not shown (before its first frame, or fading out after
   Esc) never takes a click: it is fixed over the whole app, and an
   invisible layer that swallows every click is the worst bug a shell can
   have. */
.nv-today:not(.is-in) { pointer-events: none; }
/* Liquid background: three soft colour blobs drifting under the glass. */
.nv-today__bg { position: absolute; inset: -10%; pointer-events: none; overflow: hidden; }
.nv-today__bg i { position: absolute; width: 46vmax; height: 46vmax; border-radius: 50%; filter: blur(70px); opacity: .55; mix-blend-mode: screen; animation: nv-blob 26s ease-in-out infinite alternate; }
.nv-today__bg i:nth-child(1) { background: radial-gradient(circle at 40% 40%, var(--brand), transparent 62%); top: -8%; left: -6%; }
.nv-today__bg i:nth-child(2) { background: radial-gradient(circle at 50% 50%, #FF8A3D, transparent 62%); top: 30%; right: -12%; animation-duration: 33s; animation-delay: -9s; }
.nv-today__bg i:nth-child(3) { background: radial-gradient(circle at 50% 50%, #5AB6E8, transparent 62%); bottom: -14%; left: 28%; animation-duration: 29s; animation-delay: -17s; }
@keyframes nv-blob { 0% { transform: translate(0, 0) scale(1); } 50% { transform: translate(6vw, 4vh) scale(1.12); } 100% { transform: translate(-4vw, 7vh) scale(.96); } }
:root[data-theme="light"] .nv-today__bg i, :root:not([data-theme="dark"]) .nv-today__bg i { opacity: .38; mix-blend-mode: multiply; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .nv-today__bg i { opacity: .55; mix-blend-mode: screen; } }

.nv-today__sheet { position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: clamp(22px, 4vh, 44px) clamp(16px, 4vw, 56px) 48px; max-width: 1240px; width: 100%; margin: 0 auto; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--text) 16%, transparent) transparent; }
/* The app-wide mint scrollbar is a 14px green column down a sheet that is
   trying to be quiet. Here it is a hairline that shows up when it is used. */
.nv-today__sheet::-webkit-scrollbar { width: 8px; background: transparent; }
.nv-today__sheet::-webkit-scrollbar-track, .nv-today__sheet::-webkit-scrollbar-button { background: transparent; height: 0; }
.nv-today__sheet::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--text) 16%, transparent); border: 2px solid transparent; background-clip: padding-box; border-radius: 8px; }
.nv-today__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 30px; }
.nv-today__hello { font-family: var(--display); font-size: clamp(26px, 3.2vw, 38px); font-weight: 500; letter-spacing: -.8px; line-height: 1.05; }
.nv-today__date { font-size: 15px; color: var(--text-muted); margin-top: 8px; text-transform: capitalize; }
.nv-today__close { display: inline-flex; align-items: center; gap: 8px; border: 1px solid color-mix(in srgb, var(--text) 18%, transparent); background: color-mix(in srgb, var(--bg) 40%, transparent); color: var(--text); border-radius: 100px; padding: 8px 12px 8px 10px; cursor: pointer; font: inherit; font-size: 12.5px; }
.nv-today__close span { opacity: .6; font-weight: 600; }
.nv-today__close:hover { background: color-mix(in srgb, var(--bg) 70%, transparent); }
/* ---- one grid ----
   Every card on the sheet is a child of this grid and sits where its `order`
   says (see nvLayoutOrder). The two painted wrappers inside it are
   display:contents, so their cards are grid items too. Dense packing lets a
   4-column card fill the gap an 8-column one leaves after a rearrangement. */
.nv-today__cards { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-flow: dense; gap: 16px; margin-bottom: 16px; }
.nv-today__apps, .nv-today__ibx { display: contents; }
.nvw--pits { grid-column: span 8; }
.nvw--log { grid-column: span 12; }
/* ---- arrange mode ---- */
.nv-today__arr { display: inline-flex; align-items: center; gap: 6px; border: 1px solid color-mix(in srgb, var(--text) 18%, transparent); background: color-mix(in srgb, var(--bg) 40%, transparent); color: var(--text); border-radius: 100px; padding: 8px 12px; cursor: pointer; font: inherit; font-size: 12.5px; margin-inline-end: 8px; }
.nv-today__arr:hover { background: color-mix(in srgb, var(--bg) 70%, transparent); }
.nv-today__arr--on { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }
.nv-today__arr--on:hover { background: var(--brand); }
.nv-today__arrhint { font-size: 13px; color: var(--text-muted); margin: -14px 0 16px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.nv-today__arrhint .nvw__link { margin-inline-start: 0; }
.nv-today.is-arrange .nvw { cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; outline: 1.5px dashed color-mix(in srgb, var(--brand) 55%, transparent); outline-offset: 3px; }
.nv-today.is-arrange .nvw * { pointer-events: none; }
.nv-today.is-arrange .nvw .pit__ta { pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
	.nv-today.is-arrange .nvw { animation: nv-wobble 1.4s ease-in-out infinite alternate; }
	.nv-today.is-arrange .nvw:nth-child(2n), .nv-today.is-arrange .nv-today__apps > .nvw:nth-child(2n) { animation-delay: -.7s; }
}
/* `rotate`, not `transform`: the drag and the slide own `transform`, and an
   animation on the same property would silently override them. */
@keyframes nv-wobble { from { rotate: -.35deg; } to { rotate: .35deg; } }
.nv-today.is-arrange .nvw.is-lift { animation: none; cursor: grabbing; z-index: 60; transition: none; box-shadow: 0 30px 70px -20px rgba(0, 0, 0, .55); outline-color: var(--brand); }
.nv-today.is-arrange .nvw.is-flip { transition: transform .22s cubic-bezier(.2, .8, .2, 1); }
/* ---- the app cards ----
   Talk+, Mail and the Calendar, and the two that are only there when they hold
   something: Files and Account. Each card is one app's business, and what that
   app wants from you sits at the top of it. A third each; their wrapper is
   display:contents (see .nv-today__cards), so they sit in the one grid. */
.nv-today__pull { margin: 26px auto 0; width: 60px; height: 6px; border-radius: 6px; background: color-mix(in srgb, var(--text) 22%, transparent); cursor: pointer; }

/* Frosted cards. */
/* Quiet glass. The edge is a hairline at 7%, the top highlight is barely
   there and the shadow is a soft, close one: a card should read as a surface
   the content rests on, not as an object competing with it. */
.nvw { position: relative; border-radius: 24px; padding: 20px 22px; background: color-mix(in srgb, var(--bg) 50%, transparent); border: 1px solid color-mix(in srgb, var(--text) 7%, transparent); box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 9%, transparent), 0 10px 32px rgba(0, 0, 0, .1); backdrop-filter: blur(26px) saturate(1.3); -webkit-backdrop-filter: blur(26px) saturate(1.3); min-width: 0; display: flex; flex-direction: column; gap: 10px; }
/* Sentence case, regular weight: a title names the card, it does not shout it. */
.nvw__t { display: flex; align-items: center; gap: 8px; min-height: 22px; font-size: 13px; font-weight: 600; letter-spacing: .01em; color: var(--text-muted); }
.nvw__t .nav-ic { color: var(--text-muted); opacity: .85; }
.nvw__count { margin-inline-start: auto; background: color-mix(in srgb, var(--brand) 16%, transparent); color: var(--brand); border-radius: 100px; padding: 2px 9px; font-size: 11.5px; font-weight: 600; letter-spacing: 0; font-variant-numeric: tabular-nums; }
.nvw__sub { font-size: 12.5px; color: var(--text-muted); }
.nvw__link { margin-inline-start: auto; border: none; background: none; color: var(--text); font: inherit; font-size: 12px; font-weight: 600; text-transform: none; letter-spacing: 0; cursor: pointer; display: inline-flex; align-items: center; gap: 2px; padding: 2px 6px; border-radius: 8px; }
.nvw__link:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.nvw--clock { grid-column: span 4; }
/* Eight, not five: this card carries the conditions, the feels-like line,
   wind, sunrise, sunset and a row of hours, and it was the one being
   squeezed while a game sat beside it. */
.nvw--wx { grid-column: span 8; }
/* The snake's default place is the second row, beside the post-its; like every
   card it can be dragged elsewhere (see .nv-today__cards and nvLayoutOrder). */
.nvw--snake { grid-column: span 4; align-items: center; }
/* The app tiles: four across on a desktop (Talk+, Mail, Calendar, Photos),
   twice as wide when expanded. Files and Account, when something waits in
   them, take the same size. */
.nvw--feed { grid-column: span 3; min-height: 200px; }
.nvw--feed.is-big { grid-column: span 12; }
.nv-today__apps[data-compact="3"] > .nvw--feed:not(.is-big) { grid-column: span 4; }
.nv-today__apps[data-compact="2"] > .nvw--feed:not(.is-big) { grid-column: span 6; }
.nv-today__apps[data-compact="1"] > .nvw--feed:not(.is-big) { grid-column: span 12; }
/* The card holding an open snooze menu comes over the ones beside it: every
   .nvw is a stacking context of its own, so source order alone would clip that
   menu behind the next card. */
.nvw--feed.is-menu { z-index: 10; }

.nv-clock { font-family: var(--display); font-size: clamp(56px, 6.2vw, 80px); font-weight: 500; letter-spacing: -2.5px; line-height: 1; font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: 8px; }
.nv-clock__s { font-size: .32em; color: var(--text-muted); letter-spacing: 0; font-weight: 500; }
.nv-clock__row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
/* Next up, inside the clock: the next two appointments of today. It sits at
   the foot of the card under a hairline, so the time stays the headline. */
.nv-clock__next { margin-top: auto; padding-top: 12px; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); display: flex; flex-direction: column; gap: 4px; }
.nv-clock__next > small { font-size: 12px; font-weight: 600; color: var(--text-muted); padding: 0 8px; }
.nv-clock__next .nv-feed__i { padding: 6px 8px; }
.nv-clock__next .nv-feed__bar { height: 26px; width: 3px; }
.nv-clock__next .nv-feed__empty { padding: 4px 8px 2px; }

.nv-wx__now { display: flex; align-items: center; gap: 14px; }
.nv-wx__glyph { color: #FF8A3D; display: flex; }
.nv-wx__temp { font-family: var(--display); font-size: 52px; font-weight: 500; letter-spacing: -1.5px; line-height: 1; }
.nv-wx__meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nv-wx__meta b { font-size: 15px; }
.nv-wx__meta small { font-size: 12px; color: var(--text-muted); }
.nv-wx__hours { display: flex; gap: 4px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
.nv-wx__h { flex: 1 0 52px; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 4px; border-radius: 12px; font-size: 12px; }
.nv-wx__h--now { background: color-mix(in srgb, var(--brand) 16%, transparent); }
.nv-wx__h small { color: var(--text-muted); font-size: 11px; }
.nv-wx__h svg { color: var(--text); }
.nv-wx__h em { font-style: normal; font-size: 10.5px; color: #5AB6E8; min-height: 13px; }
/* The days ahead, under the hours: the day, its sky, the high over the low.
   Same cell shape as an hour so the two rows read as one forecast. */
/* The line under the hours: the sun on the left, the fold on the right. */
.nv-wx__foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; min-height: 26px; }
.nv-wx__more { display: inline-flex; align-items: center; gap: 5px; border: none; background: none; color: var(--text-muted); font: inherit; font-size: 12.5px; font-weight: 600; padding: 4px 8px; margin-inline-end: -8px; border-radius: 8px; cursor: pointer; transition: color .18s ease, background .18s ease; }
.nv-wx__more:hover, .nv-wx__more:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); outline: none; }
.nv-wx__more svg { transform: rotate(90deg); transition: transform .36s cubic-bezier(.2, .9, .25, 1); }
.nvw--wx.is-days .nv-wx__more svg { transform: rotate(-90deg); }
/* The fold itself. A grid row going from 0fr to 1fr animates to the height
   of whatever is inside without anyone measuring it; visibility follows so a
   folded forecast is out of the tab order and the reading order too. The
   negative margin takes back the card gap a zero-height row would still cost. */
.nv-wx__fold { display: grid; grid-template-rows: 0fr; margin-top: -10px; transition: grid-template-rows .36s cubic-bezier(.2, .9, .25, 1), margin-top .36s cubic-bezier(.2, .9, .25, 1); }
.nv-wx__fold > div { overflow: hidden; min-height: 0; visibility: hidden; opacity: 0; transition: opacity .24s ease, visibility 0s linear .36s; }
.nvw--wx.is-days .nv-wx__fold { grid-template-rows: 1fr; margin-top: 0; }
.nvw--wx.is-days .nv-wx__fold > div { visibility: visible; opacity: 1; transition: opacity .3s ease .08s, visibility 0s; }
@media (prefers-reduced-motion: reduce) { .nv-wx__fold, .nv-wx__fold > div, .nv-wx__more svg { transition: none; } }
.nv-wx__days { display: flex; gap: 4px; padding-top: 10px; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); }
.nv-wx__d { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 6px 2px; border-radius: 12px; font-size: 12px; }
.nv-wx__d small { color: var(--text-muted); font-size: 11px; text-transform: capitalize; }
.nv-wx__d svg { color: var(--text); }
.nv-wx__d b { font-weight: 600; }
.nv-wx__d i { font-style: normal; color: var(--text-muted); font-size: 11.5px; }
.nv-wx__loading { display: flex; align-items: center; gap: 10px; color: var(--text-muted); font-size: 13px; padding: 14px 0; }
.nv-wx__pick { display: flex; flex-direction: column; gap: 8px; }
.nv-wx__hits { display: flex; flex-direction: column; gap: 2px; }
.nv-wx__hit { display: flex; justify-content: space-between; gap: 10px; border: none; background: transparent; color: var(--text); font: inherit; text-align: start; padding: 8px 10px; border-radius: 10px; cursor: pointer; }
.nv-wx__hit small { color: var(--text-muted); }
.nv-wx__hit:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }

.nv-sn { position: relative; display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; }
.nv-sn canvas { width: min(100%, 240px); aspect-ratio: 1; border-radius: 16px; background: color-mix(in srgb, var(--bg) 55%, transparent); border: 1px solid color-mix(in srgb, var(--text) 10%, transparent); touch-action: none; outline: none; cursor: pointer; }
.nv-sn canvas:focus-visible { box-shadow: 0 0 0 2px var(--brand); }
.nv-sn__hint { position: absolute; inset-inline: 0; bottom: 34px; margin: 0 auto; width: fit-content; max-width: 90%; text-align: center; font-size: 12px; padding: 6px 10px; border-radius: 100px; background: color-mix(in srgb, var(--bg) 82%, transparent); border: 1px solid color-mix(in srgb, var(--text) 12%, transparent); pointer-events: none; }
.nv-sn__scores { margin-inline-start: auto; font-variant-numeric: tabular-nums; letter-spacing: 0; text-transform: none; }

.nv-feed { display: flex; flex-direction: column; gap: 2px; }
.nv-feed__i { display: flex; align-items: center; gap: 10px; width: 100%; border: none; background: transparent; color: var(--text); font: inherit; text-align: start; padding: 7px 8px; border-radius: 12px; cursor: pointer; }
.nv-feed__i:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.nv-feed__i--now { background: color-mix(in srgb, var(--brand) 14%, transparent); }
.nv-feed__b { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.nv-feed__b b { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-feed__b small { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-feed__bar { width: 4px; height: 30px; border-radius: 4px; flex-shrink: 0; }
.nv-feed__meet { color: var(--brand); display: flex; }
.nv-feed__imp { width: 18px; height: 18px; border-radius: 100px; background: color-mix(in srgb, #FF8A3D 16%, transparent); color: #FF8A3D; font-size: 11.5px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.nv-feed__empty { font-size: 13px; color: var(--text-muted); padding: 10px 4px; }
/* The demands, at the top of the card and not part of the list under them: one
   asks for an answer, the other only says what is unread. A hairline is the
   whole separation -- the rows already look different, because they carry
   buttons and the rows below them do not. */
.nvw__dem { gap: 2px; padding-bottom: 8px; border-bottom: 1px solid color-mix(in srgb, var(--text) 12%, transparent); }
.nvw__dem:empty { display: none; }
.nvw__dem:last-child { padding-bottom: 0; border-bottom: none; }
.nvw__dem .nvib__r { flex-wrap: wrap; row-gap: 6px; gap: 10px; padding: 8px; }
.nvw__dem .nvib__ic { width: 28px; height: 28px; border-radius: 9px; }
/* A zero basis, so the title shrinks and ellipsises on the row instead of
   claiming its full width and pushing everything onto separate lines. */
.nvw__dem .nvib__b { flex: 1 1 0; }
/* Accept / Decline is the exception: four buttons would leave about 90px
   for the title, so that row gives the text a line of its own. */
.nvw__dem .nvib__r:has(.nvib__x--act) .nvib__b { flex-basis: 100%; }
/* The age lives in the subtitle of the rows beside this one; a column of
   its own costs the width the buttons need in a third-width card. */
.nvw__dem .nvib__ts { display: none; }
/* A card is a third of the sheet wide and the actions do not fit beside the
   text, so they take a line of their own, indented to the text above them.
   They are always visible: an answer that only appears under the pointer is
   not an answer anybody finds. */
.nvw__dem .nvib__acts { opacity: 1; justify-content: flex-end; margin-inline-start: auto; }

@media (max-width: 1023.98px) {
	.nvw--clock { grid-column: span 5; }
	.nvw--wx { grid-column: span 7; }
	.nvw--pits, .nvw--snake { grid-column: span 12; }
	.nvw--feed, .nvw--talk, .nv-today__apps[data-compact] > .nvw--feed:not(.is-big) { grid-column: span 6; }
	.nvw--feed.is-big { grid-column: span 12; }
}
@media (max-width: 640px) {
	.nvw--clock, .nvw--wx { grid-column: span 12; }
	.nvw--feed, .nvw--talk, .nv-today__apps[data-compact] > .nvw--feed:not(.is-big) { grid-column: span 6; min-height: 0; }
	.nvw--feed.is-big { grid-column: span 12; }
	.nv-today__arr span { display: none; }
	.nv-today__sheet { padding-top: 16px; }
	.nv-today-btn { padding: 0 8px; }
}
@media (prefers-reduced-motion: reduce) {
	.nv-today, .nv-today__bg i, .nv-today-btn.is-hint .nv-today-btn__n { transition: none; animation: none; }
}

/* ---- the Activity log: the last thing on the sheet ----
   What happened, under everything that wants something. This used to be half
   of a pair at the top of the sheet; the other half -- the demands -- now sits
   in the card of the app that raised each one, which is where an answer
   belongs. What is left here is context, and it is treated as context: no
   count, no snooze, no done, three rows deep until someone asks for more.

   Inside the section nothing has changed: generous rows, the time
   right-aligned, one ellipsised line of body, and a removed row collapses
   instead of yanking the rows below up. Every colour is a theme token, so
   light and dark need no rules of their own. */
/* The end of the sheet: what happened, full width and on its own. #nv-inbox is
   a plain column that the inbox painter rewrites wholesale, so nothing else
   may ever be put inside it -- the snake was, once, and the first repaint
   deleted the game. */
.nvw--log { gap: 6px; }
.nvw--log .nvib__hic { color: var(--text-muted); }
/* The fold. Quiet until it is wanted, like the row actions. */
.nvib__more { margin-inline-start: 0; padding: 3px 6px; color: var(--text-muted); }
.nvib__more:hover, .nvib__more:focus-visible { color: var(--text); outline: none; }
.nvib__hic { display: inline-flex; color: var(--brand); }
.nvib__hd { margin-inline-start: auto; display: flex; align-items: center; gap: 2px; }
.nvib { display: flex; flex-direction: column; }
.nvib:empty { display: none; }
.nvib--scroll { max-height: 320px; overflow-y: auto; overscroll-behavior: contain; padding-inline-end: 4px; }
.nvib__day { padding: 12px 10px 4px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.nvib__day:first-child { padding-top: 2px; }
.nvib__msg { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); padding: 14px 10px; }
.nvib__msg .tf-spin { width: 16px; height: 16px; border-width: 2px; flex-shrink: 0; }
.nvib__msg .nvw__link { margin-inline-start: 0; }

.nvib__r { position: relative; display: flex; align-items: center; gap: 12px; min-width: 0; padding: 10px; border-radius: 14px; }
.nvib__r[data-act] { cursor: pointer; }
.nvib__r:hover { background: color-mix(in srgb, var(--text) 7%, transparent); }
.nvib__r:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--brand); }
/* Going: the height is pinned in JS first, because a transition out of 'auto'
   does not run. */
.nvib__r.is-gone { overflow: hidden; opacity: 0; padding-block: 0; pointer-events: none; transition: height .2s ease, opacity .16s ease, padding .2s ease; }
.nvib__ic { flex-shrink: 0; width: 34px; height: 34px; border-radius: 11px; display: flex; align-items: center; justify-content: center; background: color-mix(in srgb, var(--brand) 15%, transparent); color: var(--brand); }
/* Activity is context, not a demand: the same row, a quieter mark. */
.nvib__r--a .nvib__ic { background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text-muted); }
.nvib__b { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nvib__t { font-size: 14px; font-weight: 600; line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nvib__s { font-size: 12.5px; line-height: 1.4; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nvib__s:empty { display: none; }
.nvib__ts { flex-shrink: 0; font-size: 12px; color: var(--text-muted); text-align: end; white-space: nowrap; font-variant-numeric: tabular-nums; }
.nvib__acts { flex-shrink: 0; display: flex; align-items: center; gap: 4px; opacity: 0; transition: opacity .16s ease; }
.nvib__r:hover .nvib__acts, .nvib__r:focus-within .nvib__acts { opacity: 1; }
.nvib__x { flex-shrink: 0; height: 30px; min-width: 30px; padding: 0 7px; display: inline-flex; align-items: center; justify-content: center; gap: 4px; border: 1px solid color-mix(in srgb, var(--text) 14%, transparent); border-radius: 9px; background: color-mix(in srgb, var(--bg) 55%, transparent); color: var(--text); font: inherit; font-size: 12.5px; cursor: pointer; transition: background .16s ease, border-color .16s ease; }
.nvib__x:hover, .nvib__x:focus-visible { background: color-mix(in srgb, var(--text) 10%, transparent); border-color: color-mix(in srgb, var(--text) 30%, transparent); outline: none; }
.nvib__x--act { font-weight: 600; }
/* Nextcloud puts its primary action first; it is the only one that is loud. */
.nvib__x--act:first-child { border-color: var(--brand); color: var(--brand); }

/* The snooze menu, inside the row it belongs to: the same glass as the
   post-it share popover, so the two read as one language. */
.nvib__menu { position: absolute; z-index: 9000; inset-inline-end: 8px; top: calc(100% - 8px); width: 224px; display: flex; flex-direction: column; gap: 1px; padding: 6px; border-radius: 14px; background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(20px) saturate(1.2); -webkit-backdrop-filter: blur(20px) saturate(1.2); border: 1px solid color-mix(in srgb, var(--text) 14%, transparent); box-shadow: 0 18px 50px rgba(0, 0, 0, .28); animation: pit-pop-in .16s ease; cursor: default; }
.nvib__mi { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; border: none; background: none; color: var(--text); font: inherit; font-size: 13px; text-align: start; padding: 8px 9px; border-radius: 9px; cursor: pointer; }
.nvib__mi small { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.nvib__mi:hover, .nvib__mi:focus-visible { background: color-mix(in srgb, var(--text) 8%, transparent); outline: none; }

/* A finger cannot hover, so the actions are simply there. */
@media (hover: none) {
	.nvib__acts { opacity: 1; }
}
@media (max-width: 640px) {
	.nvib--scroll { max-height: 260px; }
	.nvib__r { gap: 9px; padding: 9px 6px; }
	.nvib__ic { width: 30px; height: 30px; border-radius: 10px; }
	.nvib__x { padding: 0 6px; }
	.nvib__menu { left: 6px; inset-inline-end: 6px; width: auto; }
}
@media (prefers-reduced-motion: reduce) {
	.nvib__r, .nvib__acts, .nvib__x, .nvib__menu { transition: none; animation: none; }
}

/* ---- Post-its + Next up: the row above the widgets ----
   Real sticky notes. The paper is always light (the four fixed colours, ink
   #2a2a1e) so a note reads the same in both themes; everything around it
   uses the app's tokens. A note is absolutely placed on a lined board in
   percent, tilted a hair from its file id, and held down by a strip of tape. */
.nv-today__wxline { margin-inline-start: auto; align-self: flex-start; margin-top: 8px; font-size: 13px; color: var(--text-muted); white-space: nowrap; letter-spacing: .01em; }
.nv-today__wxline:empty { display: none; }
.nv-today__wxline span { display: block; }
.nv-today__wxplace { color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
/* What is waiting, in one line under the greeting: a dot, a count, and the one
   action that clears it all. Absent when nothing is waiting. */
.nv-today__needs { display: inline-flex; align-items: center; gap: 8px; margin-top: 12px; padding: 4px 12px 4px 10px; border-radius: 100px; background: color-mix(in srgb, #FF8A3D 14%, transparent); font-size: 13px; font-weight: 600; }
.nv-today__needs:empty { display: none; }
.nv-today__needs i { width: 7px; height: 7px; border-radius: 50%; background: #FF8A3D; }
.nv-today__needs .nvw__link { margin-inline-start: 2px; color: var(--brand); }
.nvw__t .nvw__link--done { margin-inline-start: 6px; color: var(--brand); }
/* Above phone width the weather card sits directly under this line and says
   the same thing, larger. Saying it once is calmer. */
@media (min-width: 640.02px) { .nv-today__wxline { display: none; } }
/* The second row: what you wrote down, and something to do with your hands.
   The board takes eight columns -- wider than it has ever been, and its notes
   are placed in percentages, so they simply spread out. */
.nvw--snake { justify-content: flex-start; }
/* Every card's title starts at the same left edge; the board under it is what
   is centred. */
.nvw--snake .nvw__t { align-self: stretch; }
.nvw--snake .nv-sn { margin-block: auto; }
.nvw--pits { --hand: 'Caveat', 'Segoe Print', 'Bradley Hand', cursive; z-index: 1; } /* above the cards below it, so the share popover can hang over them (every .nvw is a stacking context) */
.pits__btn { width: 22px; height: 22px; flex-shrink: 0; border-radius: 7px; border: 1.5px dashed color-mix(in srgb, var(--text) 38%, transparent); background: transparent; color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; padding: 0; cursor: pointer; transition: color .18s ease, border-color .18s ease, background .18s ease; }
.pits__btn:hover, .pits__btn:focus-visible { color: var(--text); border-color: color-mix(in srgb, var(--text) 70%, transparent); background: color-mix(in srgb, var(--text) 6%, transparent); outline: none; }
.pits__btn:disabled { opacity: .4; cursor: default; }
.pits__btn--share { border-color: transparent; }
.pits__btn--share:hover, .pits__btn--share:focus-visible { border-color: transparent; }
.pits { position: relative; min-height: 300px; border-radius: 14px; background: repeating-linear-gradient(0deg, transparent 0 23px, color-mix(in srgb, var(--text) 5%, transparent) 23px 24px); }
.pits__msg { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 13px; color: var(--text-muted); text-align: center; padding: 20px; }
.pits__msg .nvw__link { margin-inline-start: 0; }
.pits__msg .tf-spin { width: 16px; height: 16px; border-width: 2px; }

.pit { position: absolute; width: 150px; min-height: 130px; padding: 14px 14px 18px; box-sizing: border-box; color: #2a2a1e; font: 500 19px/1.15 var(--hand); background: var(--paper, #ffe873); background-image: linear-gradient(180deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, 0) 45%); border-radius: 2px; box-shadow: 0 10px 20px -8px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(0, 0, 0, .08); transform: rotate(var(--rot, 0deg)); cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; transition: box-shadow .2s ease; overflow-wrap: anywhere; }
.pit:hover, .pit:focus-within { box-shadow: 0 16px 28px -10px rgba(0, 0, 0, .6), inset 0 1px 0 rgba(0, 0, 0, .08); }
.pit.is-drag { cursor: grabbing; transition: none; box-shadow: 0 24px 40px -14px rgba(0, 0, 0, .65), inset 0 1px 0 rgba(0, 0, 0, .08); }
.pit.is-edit { cursor: text; user-select: text; -webkit-user-select: text; }
.pit--yellow { --paper: #ffe873; }
.pit--pink { --paper: #ffb9c9; }
.pit--mint { --paper: #bdefd9; }
.pit--blue { --paper: #c3dcff; }
/* Tape: a translucent strip over the top edge. */
.pit::before { content: ''; position: absolute; top: -7px; left: 50%; width: 46px; height: 14px; margin-left: -23px; background: rgba(255, 255, 255, .5); box-shadow: 0 1px 2px rgba(0, 0, 0, .1), inset 0 0 0 1px rgba(255, 255, 255, .25); transform: rotate(-2deg); pointer-events: none; }
.pit__h { font-weight: 600; font-size: 21px; line-height: 1.1; margin-bottom: 4px; min-height: 1.1em; }
.pit__l { min-height: 1.15em; }
.pit__gap { height: 8px; }
.pit__body { cursor: text; }
.pit__tick { display: flex; align-items: flex-start; gap: 7px; width: 100%; border: none; background: none; padding: 0; margin: 0; color: inherit; font: inherit; text-align: start; cursor: pointer; }
.pit__tick i { flex-shrink: 0; width: 12px; height: 12px; margin-top: 5px; border: 1.5px solid #2a2a1e; border-radius: 3px; background: rgba(255, 255, 255, .35); transition: background .16s ease; }
.pit__tick:hover i { background: rgba(255, 255, 255, .75); }
.pit__tick.on i { background: #2a2a1e; box-shadow: inset 0 0 0 2px var(--paper, #ffe873); }
.pit__tick.on span { text-decoration: line-through; opacity: .6; }
.pit__tick:focus-visible { outline: none; }
.pit__tick:focus-visible i { box-shadow: 0 0 0 2px rgba(42, 42, 30, .35); }
.pit__ta { display: block; width: 100%; min-height: 96px; border: none; background: transparent; resize: none; overflow: hidden; padding: 0; margin: 0; color: inherit; font: inherit; line-height: inherit; outline: none; }
.pit__ta::placeholder { color: rgba(42, 42, 30, .4); font-weight: 600; font-size: 21px; }
.pit__x, .pit__share { position: absolute; border: none; background: none; padding: 4px; margin: 0; color: #2a2a1e; display: inline-flex; cursor: pointer; border-radius: 6px; transition: opacity .18s ease, background .18s ease; }
.pit__x { top: 3px; right: 4px; opacity: .35; }
.pit__x:hover, .pit__x:focus-visible { opacity: 1; background: rgba(0, 0, 0, .07); outline: none; }
.pit__share { right: 5px; bottom: 3px; opacity: 0; }
.pit__dots { position: absolute; top: 5px; left: 8px; display: flex; gap: 5px; opacity: 0; transition: opacity .18s ease; }
.pit:hover .pit__dots, .pit:focus-within .pit__dots, .pit:hover .pit__share, .pit:focus-within .pit__share { opacity: 1; }
.pit__share:hover, .pit__share:focus-visible { background: rgba(0, 0, 0, .07); outline: none; }
.pit__dot { width: 11px; height: 11px; border-radius: 50%; border: 1px solid rgba(0, 0, 0, .28); padding: 0; cursor: pointer; transition: transform .16s ease, box-shadow .16s ease; }
.pit__dot:hover, .pit__dot:focus-visible { transform: scale(1.25); outline: none; }
.pit__dot.is-on { box-shadow: 0 0 0 2px var(--paper, #ffe873), 0 0 0 3px rgba(42, 42, 30, .55); }
.pit__dot--yellow { background: #ffe873; }
.pit__dot--pink { background: #ffb9c9; }
.pit__dot--mint { background: #bdefd9; }
.pit__dot--blue { background: #c3dcff; }
.pit.is-drag .pit__dots, .pit.is-drag .pit__share { opacity: 0; }

/* The share popover: lives inside the sheet (the Today overlay sits above the
   app's modal layer), anchored under a note or under the card's header. */
.pit-pop { position: absolute; z-index: 9000; width: 250px; max-height: 300px; display: flex; flex-direction: column; gap: 6px; padding: 8px; border-radius: 14px; background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(20px) saturate(1.2); -webkit-backdrop-filter: blur(20px) saturate(1.2); border: 1px solid color-mix(in srgb, var(--text) 14%, transparent); box-shadow: 0 18px 50px rgba(0, 0, 0, .28); font-family: inherit; font-size: 13px; animation: pit-pop-in .16s ease; transition: opacity .18s ease; }
@keyframes pit-pop-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.pit-pop.is-busy { pointer-events: none; opacity: .6; }
.pit-pop__hd { display: flex; align-items: center; gap: 8px; }
.pit-pop__hd .input { flex: 1 1 auto; min-width: 0; height: 32px; font-size: 13px; }
.pit-pop__hd .tf-spin { width: 16px; height: 16px; border-width: 2px; flex-shrink: 0; }
.pit-pop__hd .tf-spin[hidden] { display: none; }
.pit-pop__list { overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 1px; scrollbar-width: thin; }
.pit-pop__g { flex-shrink: 0; display: flex; align-items: center; gap: 6px; padding: 7px 8px 3px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.pit-pop__g i { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.pit-pop__row { flex-shrink: 0; display: block; width: 100%; border: none; background: none; color: var(--text); font: inherit; text-align: start; padding: 7px 8px; border-radius: 8px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: background .16s ease; }
.pit-pop__row:hover, .pit-pop__row:focus-visible { background: color-mix(in srgb, var(--text) 8%, transparent); outline: none; }
.pit-pop__g[hidden], .pit-pop__row[hidden] { display: none; }
.pit-pop .nv-feed__empty { padding: 8px; }

/* Phone: still a board, not a list.
   Only the one thing that cannot survive a narrow screen is dropped --
   the absolute x/y a note is pinned at, and the dragging that sets it.
   Everything that makes a post-it read as a post-it stays: the paper, the
   tape, the tilt and the shadow. Two columns, because that shows four
   notes in a screenful where full-width rows showed one and a half and
   looked like a form. The tilt is halved so neighbours in a tight grid
   lean without touching, and the controls are always visible because a
   finger cannot hover. */
@media (max-width: 760px) {
	.pits { min-height: 0 !important; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 10px; background: none; align-items: start; padding: 6px 2px 2px; }
	.pits__msg { position: static; grid-column: 1 / -1; min-height: 120px; }
	.pit { position: static; width: auto; min-height: 124px; transform: rotate(calc(var(--rot, 0deg) * .5)); cursor: default; touch-action: auto; padding: 22px 12px 14px; font-size: 17px; }
	/* A note being edited straightens up and takes the full width, so the
	   keyboard is not fighting a tilted 46%-wide card. */
	.pit.is-edit { grid-column: 1 / -1; transform: none; min-height: 150px; }
	.pit__dots, .pit__share { opacity: 1; }
	.pit__x { opacity: .55; }
}
/* One note on its own would sit in a half-width column looking cut off. */
@media (max-width: 420px) {
	.pits { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 8px; }
	.pit { font-size: 16px; padding: 20px 10px 12px; min-height: 112px; }
}
@media (prefers-reduced-motion: reduce) {
	.pit, .pit__dots, .pit__x, .pit__share, .pit__dot, .pit-pop, .pit-pop__row, .pits__btn { transition: none; animation: none; }
}

/* ---- Next up / While you were away (2026-09-28) ----
   Next up takes the clock-and-weather row's wide side, Away the narrow
   one; both are plain .nvw cards and follow the sheet's one-column rule
   on a phone. .nvw is display:flex, which would beat the hidden
   attribute, so an empty card is hidden by rule. */
.nvw--next { grid-column: span 8; }
.nvw--away { grid-column: span 4; }
.nvw--next[hidden], .nvw--away[hidden] { display: none; }
.nv-next__head { display: flex; gap: 12px; align-items: stretch; }
.nv-next__head .nv-feed__bar { height: auto; align-self: stretch; }
.nv-next__b { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.nv-next__title { font-size: 18px; font-weight: 600; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; }
.nv-next__cd { font-size: 13px; font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.nv-next__cd.is-soon { color: var(--warn); }
.nv-next__who { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.nv-next__p { position: relative; display: inline-flex; }
.nv-next__p.is-no .av { opacity: .45; }
.nv-next__dot { position: absolute; inset-inline-end: -1px; inset-block-end: -1px; width: 10px; height: 10px; border-radius: 100px; box-shadow: 0 0 0 2px var(--bg); }
.nv-next__mark { position: absolute; inset-inline-start: -3px; inset-block-start: -3px; width: 14px; height: 14px; border-radius: 100px; background: var(--bg); color: var(--text-muted); font-style: normal; font-size: 10px; font-weight: 700; line-height: 14px; text-align: center; box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 12%, transparent); }
.nv-next__mark--no { color: var(--danger); }
.nv-next__more { font-size: 12px; font-weight: 600; color: var(--text-muted); padding-inline-start: 2px; }
.nv-next__files { gap: 0; }
.nv-next__fic { display: flex; color: var(--text-muted); flex-shrink: 0; }
.nv-next__msg { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; padding: 7px 10px; border-radius: 12px; background: color-mix(in srgb, var(--text) 5%, transparent); }
.nv-next__msg svg { flex-shrink: 0; align-self: center; color: var(--text-muted); }
.nv-next__msgb { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-next__msg small { color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.nv-next__acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 4px; }
.nv-away__since { margin-top: -6px; }
.nv-away__i .pill-count { flex-shrink: 0; }
.nv-away__foot { display: flex; justify-content: flex-end; margin-top: auto; padding-top: 4px; }
.nv-away__foot .nvw__link { margin-inline-start: 0; gap: 4px; color: var(--brand); }
@media (max-width: 1023.98px) {
	.nvw--next { grid-column: span 7; }
	.nvw--away { grid-column: span 5; }
}
@media (max-width: 640px) {
	.nvw--next, .nvw--away { grid-column: span 12; }
}
.nv-away__quiet { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); padding: 2px 2px 4px; }
.nv-away__quiet svg { color: var(--brand); flex-shrink: 0; }
/* ===== profile page (modal) =====
   A hero band with the picture and the name, four tabs underneath, one
   footer. Everything editable lives in the tabs; the hero only reflects. */
.prof { max-width: 760px; padding: 0; overflow: hidden; }
.prof__hero { position: relative; display: flex; gap: 18px; align-items: center; padding: 26px 24px 20px; background: linear-gradient(135deg, var(--brand-soft, rgba(34, 185, 138, .18)) 0%, var(--bg-subtle) 70%); border-block-end: 1px solid var(--border); }
.prof__avbtn { position: relative; border: none; background: none; padding: 0; margin: 0; cursor: pointer; border-radius: 100px; flex-shrink: 0; font: inherit; color: inherit; }
.prof__avbtn .av { width: 96px; height: 96px; font-size: 34px; box-shadow: 0 0 0 4px var(--bg), 0 10px 30px rgba(0, 0, 0, .18); transition: transform .15s ease; }
.prof__avbtn:hover .av, .prof__avbtn:focus-visible .av { transform: scale(1.03); }
.prof__avbtn:focus-visible { outline: none; }
.prof__avbtn .pm__avcam { width: 28px; height: 28px; inset-block-end: 2px; inset-inline-end: 2px; }
.prof__id { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 3px; }
.prof__name { font-family: var(--display); font-size: 22px; font-weight: 600; letter-spacing: -0.3px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.prof__headline { font-size: 14px; color: var(--text); }
.prof__headline--empty { color: var(--text-muted); font-style: italic; }
.prof__meta { font-size: 12.5px; color: var(--text-muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.prof__close { position: absolute; inset-block-start: 12px; inset-inline-end: 12px; }
.prof__tabs { display: flex; gap: 2px; padding: 8px 16px 0; border-block-end: 1px solid var(--border); flex-shrink: 0; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.prof__tab { border: none; background: none; font: inherit; font-size: 13.5px; font-weight: 600; color: var(--text-muted); padding: 10px 12px 12px; cursor: pointer; position: relative; white-space: nowrap; }
.prof__tab:hover { color: var(--text); }
.prof__tab[aria-selected="true"] { color: var(--brand); }
.prof__tab[aria-selected="true"]::after { content: ''; position: absolute; inset-inline: 10px; inset-block-end: -1px; height: 2px; background: var(--brand); border-radius: 2px; }
.prof__body { padding: 18px 24px 22px; gap: 14px; max-height: min(58vh, 560px); }
.prof__row { display: flex; gap: 12px; align-items: flex-start; }
.prof__row > .field { min-width: 0; }
.prof__scopef { flex: 0 0 176px; }
.prof__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.prof__grid > .field, .prof__grid > .prof__row { min-width: 0; }
.prof__span { grid-column: 1 / -1; }
.prof__sect { font-size: 11.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); margin: 6px 0 -4px; }
.prof__card { display: flex; gap: 12px; align-items: center; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r); background: var(--bg-subtle); }
.prof__card__t { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.prof__card__t b { font-size: 13.5px; }
.prof__card__t span { font-size: 12.5px; color: var(--text-muted); }
.prof__spaces { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }
.prof__space { display: flex; gap: 10px; align-items: center; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--r); background: var(--bg); text-align: start; cursor: pointer; font: inherit; color: inherit; }
.prof__space:hover { border-color: var(--brand-line); background: var(--brand-soft); }
.prof__space__tile { width: 30px; height: 30px; border-radius: 8px; color: #fff; font-weight: 700; font-size: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.prof__space__n { font-weight: 600; font-size: 13px; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prof__space__r { font-size: 11.5px; color: var(--text-muted); }
.prof__kv { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; font-size: 13px; align-items: center; }
.prof__kv dt { color: var(--text-muted); margin: 0; }
.prof__kv dd { margin: 0; min-width: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.prof__code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; background: var(--bg-subtle); border: 1px solid var(--border); border-radius: 6px; padding: 2px 7px; }
.prof__bar { height: 8px; border-radius: 100px; background: var(--border); overflow: hidden; flex: 1 1 auto; min-width: 120px; }
.prof__bar i { display: block; height: 100%; background: var(--brand); border-radius: inherit; }
.prof__foot { align-items: center; }
.prof__hint { margin-inline-end: auto; font-size: 12.5px; color: var(--text-muted); }
.prof__hint--dirty { color: var(--warn); }
.prof__err { font-size: 13px; color: var(--danger); padding: 10px 12px; border: 1px solid var(--danger); border-radius: var(--r); background: color-mix(in srgb, var(--danger) 8%, transparent); }
/* Settings > Mail: one row per mailbox, its actions side by side. */
.macc-acts { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.macc-acts .btn { padding-inline: 10px; }
/* Where to find a calendar link, under the field. */
.macc-hints { margin: 8px 0 0; padding-inline-start: 18px; color: var(--text-muted); font-size: 12.5px; line-height: 1.45; }
.macc-hints li { margin: 2px 0; }
.appnav__acct-n { margin-inline-start: auto; font-size: 11.5px; font-weight: 700; color: var(--brand); }
.prof__pw { position: absolute; inset: 0; background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(3px); display: flex; align-items: center; justify-content: center; padding: 24px; z-index: 2; }
.prof__pw__box { width: min(380px, 100%); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-lg, 14px); box-shadow: 0 20px 60px rgba(0, 0, 0, .25); padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.prof__pw__box h3 { margin: 0; font-family: var(--display); font-size: 17px; font-weight: 600; }
.prof__pw__box p { margin: 0; font-size: 13px; color: var(--text-muted); }
.prof__skel { height: 220px; display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 13px; }
@media (max-width: 640px) {
	.prof__hero { padding: 20px 16px 16px; gap: 14px; }
	.prof__avbtn .av { width: 72px; height: 72px; font-size: 26px; }
	.prof__grid { grid-template-columns: 1fr; }
	.prof__row { flex-direction: column; gap: 8px; }
	.prof__scopef { flex-basis: auto; }
	.prof__body { padding: 14px 16px 18px; max-height: none; }
}
.pm__n { font-size: 15px; font-weight: 600; }
.pm__m { font-size: 12px; color: var(--text-muted); }
.pm__now { font-size: 12px; margin-block-start: 3px; display: flex; align-items: center; gap: 6px; }

.pm__sep { border: none; border-block-start: 1px solid var(--border); margin: 6px 0; }
.pm__l { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--text-muted); padding: 8px 12px 6px; }
/* A section header that folds: label, the current value when closed, a chevron
   that points right when closed and down when open. */
.pm__fold { display: flex; align-items: center; gap: 8px; width: 100%; border: none; background: none; font: inherit; color: inherit; padding: 8px 8px 8px 12px; cursor: pointer; border-radius: 8px; text-align: start; }
.pm__fold:hover { background: var(--bg-hover, var(--bg-subtle)); }
.pm__fold__now { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm__fold__chev { margin-inline-start: auto; color: var(--text-muted); display: flex; transition: transform .15s ease; }
.pm__fold__chev--open { transform: rotate(90deg); }

/* ===== working hours (week editor) + out-of-office picker ===== */
.wh { display: flex; flex-direction: column; gap: 4px; }
.wh__row { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 8px; }
.wh__row--off { color: var(--text-muted); }
.wh__day { display: flex; align-items: center; gap: 8px; width: 132px; flex-shrink: 0; font-size: 13.5px; font-weight: 600; cursor: pointer; }
.wh__day input { accent-color: var(--brand); width: 16px; height: 16px; margin: 0; }
.wh__t { width: 132px; flex: 0 0 auto; } /* room for 12-hour locales ("08:00 AM") */
.wh__dash { color: var(--text-muted); }
.wh__na { font-size: 13px; color: var(--text-muted); font-style: italic; }
.wh__tools { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; padding: 2px 0; }
.oo__who { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--r); background: var(--bg-subtle); }
.oo__results { display: flex; flex-direction: column; gap: 2px; max-height: 190px; overflow-y: auto; }
.oo__results:empty { display: none; }
.oo__hit { width: 100%; text-align: start; border: none; background: transparent; cursor: pointer; }
.oo__hit:hover, .oo__hit:focus-visible { background: var(--bg-hover, var(--bg-subtle)); }
.oo__none { font-size: 12.5px; color: var(--text-muted); padding: 6px 8px; }
@media (max-width: 480px) {
	.wh__day { width: 96px; }
	.wh__t { width: 96px; }
}

.pm__states { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; padding-inline: 6px; }

.pm__state {
	min-height: 34px;
	border-radius: var(--r);
	border: none;
	background: transparent;
	display: flex;
	align-items: center;
	gap: 9px;
	padding-inline: 9px;
	font-size: 13px;
	text-align: start;
}

.pm__state:hover { background: var(--bg-hover); }
.pm__state[aria-pressed="true"] { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.pm__state .dot { width: 9px; height: 9px; }

.pm__auto { margin: 8px 6px 0; padding: 10px 11px; border-radius: var(--r-lg); background: var(--bg-subtle); border: 1px solid var(--border); display: flex; gap: 10px; align-items: flex-start; }
.pm__auto b { font-size: 12.5px; display: block; }
.pm__auto span { font-size: 11.5px; color: var(--text-muted); }

.pm__row { display: flex; gap: 8px; align-items: center; padding: 0 6px; }
.pm__presets { display: flex; flex-wrap: wrap; gap: 5px; padding: 8px 6px 0; }

.pm__preset {
	height: 26px;
	padding-inline: 10px;
	border-radius: 100px;
	border: 1px solid var(--border-strong);
	background: var(--bg);
	font-size: 12px;
}

.pm__preset:hover { border-color: var(--brand); color: var(--brand); }

.pm__item {
	width: 100%;
	min-height: 38px;
	border-radius: var(--r);
	border: none;
	background: transparent;
	display: flex;
	align-items: center;
	gap: 11px;
	padding-inline: 12px;
	font-size: 14px;
	text-align: start;
}

.pm__item:hover { background: var(--bg-hover); }
.pm__item small { margin-inline-start: auto; font-size: 11px; color: var(--text-muted); font-weight: 600; }
.pm__item--warn { color: var(--warn); }

.pm__quota { padding: 10px 12px 12px; }
.pm__quota__t { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-muted); margin-block-end: 6px; }
.pm__quota__bar { height: 6px; border-radius: 100px; background: var(--border); overflow: hidden; }
.pm__quota__fill { height: 100%; background: var(--brand); }

.pm__ooo { margin: 0 6px 4px; padding: 10px 11px; border-radius: var(--r-lg); background: var(--warn-bg); border: 1px solid var(--warn-border); font-size: 12px; display: flex; gap: 9px; align-items: flex-start; }
.pm__ooo b { display: block; font-size: 12.5px; color: var(--warn); }

/* ====================================================== the film
   Paced and staged the way a good product page is: one idea on screen,
   the picture settles before the words arrive, and nothing snaps. */
.mk {
	position: fixed;
	inset: 0;
	z-index: 300;
	background: #040d0b;
	color: #f4f3ee;
	overflow: hidden;
	font-family: var(--body);
	--ease: cubic-bezier(.16, 1, .3, 1);
}

.mk::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: radial-gradient(ellipse 70% 55% at 50% 45%, transparent 40%, rgba(4, 13, 11, .82) 100%);
	z-index: 3;
}

.mk__stage { position: absolute; inset: 0; z-index: 1; }

.mk__scene {
	position: absolute;
	inset: 0;
	display: grid;
	grid-template-rows: 1fr auto;
	align-items: center;
	justify-items: center;
	padding: 56px 32px 128px;
	opacity: 0;
	visibility: hidden;
	transition: opacity 900ms ease;
}

.mk__scene[data-on="1"] { opacity: 1; visibility: visible; }

.mk__art { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.mk__words { display: flex; flex-direction: column; align-items: center; max-width: 62ch; }

.mk__eyebrow {
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 3px;
	text-transform: uppercase;
	color: #3fd6a6;
	opacity: 0;
	transform: translateY(14px);
	transition: opacity 900ms ease, transform 1100ms var(--ease);
}

.mk__h {
	font-family: var(--display);
	font-size: clamp(2.2rem, 6.4vw, 4.8rem);
	font-weight: 700;
	letter-spacing: -0.035em;
	line-height: 1.03;
	text-align: center;
	text-wrap: balance;
	margin: 16px 0 0;
	opacity: 0;
	transform: translateY(22px);
	transition: opacity 1000ms ease 120ms, transform 1200ms var(--ease) 120ms;
}

.mk__sub {
	font-size: clamp(1rem, 1.75vw, 1.22rem);
	line-height: 1.55;
	color: rgba(244, 243, 238, .66);
	text-align: center;
	text-wrap: pretty;
	margin: 20px 0 0;
	max-width: 48ch;
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 1000ms ease 320ms, transform 1200ms var(--ease) 320ms;
}

.mk__kicker {
	margin: 26px 0 0;
	font-size: clamp(1rem, 1.6vw, 1.15rem);
	color: #ffb070;
	font-weight: 600;
	opacity: 0;
	transform: translateY(12px);
	transition: opacity 900ms ease, transform 1000ms var(--ease);
}

.mk__scene[data-step="1"] .mk__eyebrow, .mk__scene[data-step="2"] .mk__eyebrow, .mk__scene[data-step="3"] .mk__eyebrow,
.mk__scene[data-step="1"] .mk__h, .mk__scene[data-step="2"] .mk__h, .mk__scene[data-step="3"] .mk__h,
.mk__scene[data-step="1"] .mk__sub, .mk__scene[data-step="2"] .mk__sub, .mk__scene[data-step="3"] .mk__sub {
	opacity: 1;
	transform: translateY(0);
}

.mk__scene[data-step="3"] .mk__kicker { opacity: 1; transform: translateY(0); }

/* Scene 2 keeps its punchline until the shove lands. */
.mk__scene[data-i="1"][data-step="1"] .mk__h,
.mk__scene[data-i="1"][data-step="1"] .mk__sub { opacity: 0; transform: translateY(22px); }

/* ---------------- scene 1 · one question ---------------- */
.mk-line { position: relative; width: min(860px, 92vw); height: 120px; }

.mk-line__rail {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	height: 1px;
	background: linear-gradient(to right, rgba(63,214,166,.5), rgba(244,243,238,.14));
}

.mk-here, .mk-there {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 1.6px;
	text-transform: uppercase;
}

.mk-here { left: 0; color: #3fd6a6; padding-inline-start: 18px; }
.mk-there { right: 0; color: rgba(244,243,238,.45); padding-inline-end: 18px; text-align: end; }

.mk-here::before, .mk-there::before {
	content: '';
	position: absolute;
	top: 50%;
	width: 9px;
	height: 9px;
	border-radius: 100px;
	transform: translateY(-50%);
}

.mk-here::before { left: 0; background: #3fd6a6; box-shadow: 0 0 18px rgba(63,214,166,.8); }
.mk-there::before { right: 0; background: rgba(244,243,238,.4); }

.mk-parcel {
	position: absolute;
	left: 0;
	top: 50%;
	width: 34px;
	height: 44px;
	margin-top: -22px;
	border-radius: 5px;
	background: linear-gradient(150deg, #ffffff, #d5dad6);
	box-shadow: 0 10px 26px rgba(0,0,0,.55);
	display: flex;
	flex-direction: column;
	gap: 3.5px;
	padding: 7px 6px;
	transition: transform 3600ms cubic-bezier(.5,0,.3,1);
}

.mk-parcel i { display: block; height: 2.5px; border-radius: 2px; background: #b9c2bd; }
.mk-parcel i:nth-child(2) { width: 66%; }

.mk__scene[data-step="1"] .mk-parcel, .mk__scene[data-step="2"] .mk-parcel,
.mk__scene[data-step="3"] .mk-parcel { transform: translateX(calc(min(860px, 92vw) - 34px)); }

.mk-stamp {
	position: absolute;
	right: 4%;
	top: -18%;
	padding: 9px 14px;
	border: 3px solid #ff6b5a;
	color: #ff6b5a;
	border-radius: 5px;
	font-weight: 800;
	font-size: 11px;
	letter-spacing: 1.5px;
	line-height: 1.3;
	text-align: center;
	transform: rotate(-12deg) scale(3);
	opacity: 0;
	transition: opacity 200ms ease, transform 420ms cubic-bezier(.2,1.6,.4,1);
}

.mk__scene[data-step="2"] .mk-stamp, .mk__scene[data-step="3"] .mk-stamp { opacity: 1; transform: rotate(-12deg) scale(1); }

/* ---------------- scene 2 · the monoliths ---------------- */
.mk-hall { position: relative; width: min(1000px, 94vw); height: min(400px, 50dvh); perspective: 1400px; }

.mk-floor {
	position: absolute;
	inset-inline: -20%;
	bottom: -2px;
	height: 42%;
	background: linear-gradient(to bottom, rgba(63, 214, 166, .07), transparent 70%);
	border-top: 1px solid rgba(244, 243, 238, .09);
}

.mk-mono {
	position: absolute;
	bottom: 0;
	width: 190px;
	height: 100%;
	border-radius: 8px 8px 2px 2px;
	background: linear-gradient(158deg, #2b3238 0%, #171c20 42%, #0d1114 100%);
	box-shadow: inset 1px 1px 0 rgba(255,255,255,.14), inset -1px 0 0 rgba(0,0,0,.5), 0 40px 70px rgba(0,0,0,.6);
	overflow: hidden;
	opacity: 0;
	transition: transform 1600ms var(--ease), opacity 1200ms ease;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: 18px 16px;
}

.mk-mono::before {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,.07) 45%, transparent 60%);
}

.mk-mono__n { position: relative; font-family: var(--display); font-size: 17px; font-weight: 700; color: #e7ebee; line-height: 1.15; }
.mk-mono__sub { position: relative; font-size: 11px; color: rgba(231,235,238,.5); margin-block-start: 6px; line-height: 1.45; }

.mk-tiers {
	position: absolute;
	inset-inline: 0;
	top: 0;
	height: 62%;
	overflow: hidden;
	opacity: .3;
	mask-image: linear-gradient(to bottom, transparent, #000 25%, #000 60%, transparent);
}

.mk-tiers span { display: block; font-size: 10px; line-height: 1.9; text-align: center; color: #9fb3ad; font-family: ui-monospace, monospace; letter-spacing: .4px; }
.mk-tiers__roll { animation: mk-roll 14s linear infinite; }
@keyframes mk-roll { from { transform: translateY(0); } to { transform: translateY(-50%); } }

.mk-mono--a { left: 8%; transform: translate3d(-40px, 46px, -260px) rotateY(16deg); }
.mk-mono--b { right: 8%; transform: translate3d(40px, 46px, -260px) rotateY(-16deg); }

.mk__scene[data-step="1"] .mk-mono, .mk__scene[data-step="2"] .mk-mono, .mk__scene[data-step="3"] .mk-mono { opacity: 1; }
.mk__scene[data-step="1"] .mk-mono--a { transform: translate3d(0,0,0) rotateY(11deg); }
.mk__scene[data-step="1"] .mk-mono--b { transform: translate3d(0,0,0) rotateY(-11deg); }
.mk__scene[data-step="2"] .mk-mono--a, .mk__scene[data-step="3"] .mk-mono--a { transform: translate3d(-135%, 22px, -140px) rotateY(46deg) rotate(-9deg); opacity: .12; }
.mk__scene[data-step="2"] .mk-mono--b, .mk__scene[data-step="3"] .mk-mono--b { transform: translate3d(135%, 22px, -140px) rotateY(-46deg) rotate(9deg); opacity: .12; }

.mk-rise {
	position: absolute;
	left: 50%;
	bottom: 8%;
	width: 170px;
	height: 170px;
	margin-inline-start: -85px;
	opacity: 0;
	transform: translateY(120px) scale(.4);
	transition: transform 1500ms cubic-bezier(.18,1.3,.32,1), opacity 700ms ease;
}

.mk-rise svg { width: 100%; height: 100%; filter: drop-shadow(0 0 44px rgba(63,214,166,.5)); }
.mk__scene[data-step="2"] .mk-rise, .mk__scene[data-step="3"] .mk-rise { opacity: 1; transform: translateY(0) scale(1); }

.mk-bloom {
	position: absolute;
	left: 50%;
	bottom: 8%;
	width: 520px;
	height: 520px;
	margin-inline-start: -260px;
	border-radius: 100%;
	background: radial-gradient(circle, rgba(63,214,166,.3), transparent 62%);
	opacity: 0;
	transform: scale(.2);
	transition: opacity 1400ms ease, transform 1600ms var(--ease);
	pointer-events: none;
}

.mk__scene[data-step="2"] .mk-bloom, .mk__scene[data-step="3"] .mk-bloom { opacity: 1; transform: scale(1); }

/* ---------------- scene 3 · it stays here ---------------- */
.mk-plane { position: relative; width: min(760px, 92vw); height: min(300px, 38dvh); perspective: 800px; }

.mk-grid {
	position: absolute;
	inset-inline: -30%;
	bottom: 0;
	height: 78%;
	transform: rotateX(74deg);
	transform-origin: bottom center;
	background-image: linear-gradient(rgba(63,214,166,.22) 1px, transparent 1px), linear-gradient(90deg, rgba(63,214,166,.22) 1px, transparent 1px);
	background-size: 46px 46px;
	mask-image: radial-gradient(ellipse 55% 70% at 50% 100%, #000 20%, transparent 75%);
	opacity: 0;
	transition: opacity 1600ms ease;
}

.mk__scene[data-step="1"] .mk-grid, .mk__scene[data-step="2"] .mk-grid { opacity: 1; }

.mk-ring {
	position: absolute;
	left: 50%;
	bottom: 16%;
	width: 44px;
	height: 44px;
	margin-inline-start: -22px;
	border-radius: 100px;
	border: 1.5px solid rgba(63,214,166,.6);
	opacity: 0;
}

.mk__scene[data-step="1"] .mk-ring, .mk__scene[data-step="2"] .mk-ring { animation: mk-pulse 3400ms ease-out infinite; }
.mk-ring:nth-of-type(2) { animation-delay: 1130ms !important; }
.mk-ring:nth-of-type(3) { animation-delay: 2260ms !important; }

@keyframes mk-pulse { 0% { opacity: .85; transform: scale(.4); } 100% { opacity: 0; transform: scale(6); } }

.mk-beacon {
	position: absolute;
	left: 50%;
	bottom: 16%;
	margin-inline-start: -19px;
	color: #3fd6a6;
	opacity: 0;
	transform: translateY(-170px) scale(.6);
	transition: transform 1300ms cubic-bezier(.2,1.5,.35,1), opacity 600ms ease;
	filter: drop-shadow(0 0 22px rgba(63,214,166,.7));
}

.mk__scene[data-step="1"] .mk-beacon, .mk__scene[data-step="2"] .mk-beacon { opacity: 1; transform: translateY(0) scale(1); }

/* ---------------- scene 4 · the product, alive ---------------- */
.mk-win {
	width: min(760px, 94vw);
	height: min(430px, 52dvh);
	border-radius: 16px;
	overflow: hidden;
	background: #ffffff;
	box-shadow: 0 40px 90px rgba(0,0,0,.6), 0 0 0 1px rgba(244,243,238,.16);
	display: flex;
	flex-direction: column;
	opacity: 0;
	transform: translateY(40px) scale(.94);
	transition: opacity 900ms ease, transform 1300ms var(--ease);
	position: relative;
}

.mk__scene[data-step="1"] .mk-win, .mk__scene[data-step="2"] .mk-win, .mk__scene[data-step="3"] .mk-win {
	opacity: 1;
	transform: translateY(0) scale(1);
}

.mk-win__bar { height: 34px; background: #08231c; display: flex; align-items: center; gap: 8px; padding-inline: 12px; flex-shrink: 0; }
.mk-win__bar svg { width: 17px; height: 17px; }
.mk-win__brand { font-family: var(--display); font-size: 12px; font-weight: 600; color: #fff; }
.mk-win__tabs { display: flex; gap: 3px; margin-inline-start: 10px; }
.mk-win__tab { font-size: 10px; color: rgba(255,255,255,.55); padding: 3px 7px; border-radius: 5px; }
.mk-win__tab--on { background: rgba(63,214,166,.18); color: #7cf0cc; font-weight: 700; }

.mk-win__body { flex-grow: 1; display: flex; min-height: 0; }
.mk-win__side { width: 148px; flex-shrink: 0; background: #f4f3ee; border-inline-end: 1px solid #e7e5de; padding: 10px 8px; display: flex; flex-direction: column; gap: 3px; }
.mk-win__sh { font-size: 8.5px; font-weight: 800; letter-spacing: .7px; text-transform: uppercase; color: #8a968f; padding: 6px 6px 2px; }
.mk-win__ch { font-size: 11px; color: #08231c; padding: 5px 7px; border-radius: 5px; display: flex; align-items: center; gap: 5px; }
.mk-win__ch--on { background: #15916b; color: #fff; font-weight: 700; }
.mk-win__ch i { opacity: .55; font-style: normal; }

.mk-win__main { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; position: relative; }
.mk-win__head { height: 32px; border-block-end: 1px solid #ededed; display: flex; align-items: center; gap: 7px; padding-inline: 12px; font-size: 11px; font-weight: 700; color: #08231c; flex-shrink: 0; }
.mk-win__chat { flex-grow: 1; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; justify-content: flex-end; overflow: hidden; }

.mk-msg { display: flex; gap: 7px; opacity: 0; transform: translateY(10px); transition: opacity 500ms ease, transform 600ms var(--ease); }
.mk__scene[data-step="1"] .mk-msg, .mk__scene[data-step="2"] .mk-msg, .mk__scene[data-step="3"] .mk-msg { opacity: 1; transform: translateY(0); }

.mk-msg__a { width: 22px; height: 22px; border-radius: 100px; flex-shrink: 0; font-size: 8px; font-weight: 800; display: flex; align-items: center; justify-content: center; color: #fff; }
.mk-msg__b { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mk-msg__n { font-size: 9.5px; font-weight: 700; color: #08231c; }
.mk-msg__x { font-size: 11px; color: #2c3a35; line-height: 1.35; }

.mk-win__composer { height: 34px; margin: 0 12px 10px; border: 1px solid #dcdcdc; border-radius: 9px; display: flex; align-items: center; padding-inline: 10px; font-size: 10.5px; color: #8a968f; gap: 8px; flex-shrink: 0; }
.mk-win__send { margin-inline-start: auto; width: 22px; height: 22px; border-radius: 6px; background: #15916b; display: flex; align-items: center; justify-content: center; color: #fff; }

.mk-call {
	position: absolute;
	inset: 0;
	background: #0c2a22;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 5px;
	padding: 5px;
	opacity: 0;
	transform: scale(1.04);
	transition: opacity 700ms ease, transform 900ms var(--ease);
	pointer-events: none;
}

.mk__scene[data-step="2"] .mk-call, .mk__scene[data-step="3"] .mk-call { opacity: 1; transform: scale(1); }

.mk-tile {
	position: relative;
	border-radius: 8px;
	overflow: hidden;
	background: #143029 center/cover no-repeat;
	opacity: 0;
	transform: scale(.86);
	transition: opacity 520ms ease, transform 700ms cubic-bezier(.2,1.35,.35,1);
}

.mk__scene[data-step="2"] .mk-tile, .mk__scene[data-step="3"] .mk-tile { opacity: 1; transform: scale(1); }
.mk-tile__n { position: absolute; left: 7px; bottom: 6px; font-size: 9.5px; font-weight: 700; color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.8); }

.mk-tile--me { display: flex; align-items: center; justify-content: center; background: #143029; }
.mk-tile--me span { width: 40px; height: 40px; border-radius: 100px; background: #22b98a; color: #08231c; font-weight: 800; font-size: 14px; display: flex; align-items: center; justify-content: center; }

.mk-live {
	position: absolute;
	top: 8px;
	inset-inline-end: 8px;
	z-index: 2;
	height: 18px;
	padding-inline: 8px;
	border-radius: 100px;
	background: rgba(6,17,14,.6);
	color: #fff;
	font-size: 9px;
	font-weight: 800;
	letter-spacing: .6px;
	display: flex;
	align-items: center;
	gap: 5px;
}

.mk-live i { width: 6px; height: 6px; border-radius: 100px; background: #ff6b5a; display: block; }

/* ---------------- scene 5 · the price ---------------- */
.mk-price { width: min(700px, 92vw); display: flex; flex-direction: column; gap: 20px; }

.mk-bar__row { display: flex; align-items: center; gap: 14px; }
.mk-bar__l { width: 132px; flex-shrink: 0; text-align: end; font-size: 12px; font-weight: 700; color: rgba(244,243,238,.62); line-height: 1.3; }
.mk-bar__track { flex-grow: 1; height: 40px; border-radius: 8px; background: rgba(244,243,238,.06); overflow: hidden; }

.mk-bar__fill {
	height: 100%;
	width: 0;
	border-radius: 8px;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	padding-inline-end: 14px;
	font-family: var(--display);
	font-size: 17px;
	font-weight: 700;
	transition: width 1600ms var(--ease);
}

.mk-bar__fill--them { background: linear-gradient(90deg, #3a4249, #545e66); color: #eef1f3; }
.mk-bar__fill--us { background: linear-gradient(90deg, #15916b, #3fd6a6); color: #06110e; }

.mk__scene[data-step="1"] .mk-bar__fill--them, .mk__scene[data-step="2"] .mk-bar__fill--them,
.mk__scene[data-step="3"] .mk-bar__fill--them { width: 100%; }
.mk__scene[data-step="1"] .mk-bar__fill--us, .mk__scene[data-step="2"] .mk-bar__fill--us,
.mk__scene[data-step="3"] .mk-bar__fill--us { width: 45%; transition-delay: 420ms; }

.mk-tiles { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-block-start: 4px; }

.mk-tier {
	border: 1px solid rgba(244,243,238,.16);
	border-radius: 10px;
	padding: 9px 13px;
	display: flex;
	flex-direction: column;
	gap: 1px;
	opacity: 0;
	transform: translateY(12px);
	transition: opacity 700ms ease, transform 800ms var(--ease);
}

.mk__scene[data-step="2"] .mk-tier, .mk__scene[data-step="3"] .mk-tier { opacity: 1; transform: translateY(0); }
.mk-tier b { font-family: var(--display); font-size: 16px; color: #3fd6a6; }
.mk-tier span { font-size: 10px; color: rgba(244,243,238,.5); letter-spacing: .3px; }

.mk-note { font-size: 11px; color: rgba(244,243,238,.36); text-align: center; max-width: 60ch; margin: 0 auto; }

/* ---------------- scene 5 · the close ---------------- */
/* ---------------- scene 5 · the close ---------------- */
.mk-lock { display: flex; align-items: center; gap: 18px; position: relative; }
.mk-lock svg { width: 78px; height: 78px; filter: drop-shadow(0 0 32px rgba(63, 214, 166, .35)); }
.mk-word { font-family: var(--display); font-size: clamp(2.1rem, 5.4vw, 3.6rem); font-weight: 700; letter-spacing: -.035em; position: relative; }
.mk-word .c { color: #3fd6a6; font-weight: 500; }
.mk-word .e { color: #ff8a3d; font-size: .5em; font-weight: 600; vertical-align: .16em; }

.mk-cta { display: flex; gap: 12px; margin-block-start: 34px; flex-wrap: wrap; justify-content: center; opacity: 0; transition: opacity 900ms ease; }
.mk__scene[data-step="2"] .mk-cta, .mk__scene[data-step="3"] .mk-cta { opacity: 1; }

.mk-btn {
	height: 48px;
	padding-inline: 26px;
	border-radius: 100px;
	border: 1px solid rgba(244, 243, 238, .26);
	background: transparent;
	color: #f4f3ee;
	font-size: 15px;
	font-weight: 700;
	display: inline-flex;
	align-items: center;
	gap: 9px;
	transition: background 200ms ease, border-color 200ms ease;
}

.mk-btn:hover { background: rgba(244, 243, 238, .1); border-color: rgba(244, 243, 238, .5); }
.mk-btn--go { background: #3fd6a6; border-color: #3fd6a6; color: #040d0b; }
.mk-btn--go:hover { background: #5be3b8; border-color: #5be3b8; }

/* ---------------- chrome ---------------- */
.mk__ctl {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	z-index: 4;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 16px;
	padding: 18px 24px 22px;
}

.mk__dots { display: flex; gap: 9px; }

.mk__dot {
	width: 34px;
	height: 4px;
	border-radius: 100px;
	border: none;
	padding: 0;
	background: rgba(244, 243, 238, .2);
	overflow: hidden;
	position: relative;
}

.mk__dot[aria-current="true"] { background: rgba(244, 243, 238, .28); }
.mk__dot i { position: absolute; inset: 0; width: 0; background: #3fd6a6; border-radius: 100px; }
.mk__dot[data-done="1"] i { width: 100%; }

.mk__ibtn {
	width: 38px;
	height: 38px;
	border-radius: 100px;
	border: 1px solid rgba(244, 243, 238, .22);
	background: transparent;
	color: rgba(244, 243, 238, .8);
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

.mk__ibtn:hover { color: #fff; border-color: rgba(244, 243, 238, .5); }

.mk__skip {
	position: absolute;
	top: 24px;
	inset-inline-end: 26px;
	z-index: 5;
	height: 38px;
	padding-inline: 18px;
	border-radius: 100px;
	border: 1px solid rgba(244, 243, 238, .22);
	background: rgba(4, 13, 11, .5);
	color: rgba(244, 243, 238, .8);
	font-size: 13px;
	font-weight: 600;
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.mk__skip:hover { color: #fff; border-color: rgba(244, 243, 238, .5); }
.mk__note { position: absolute; bottom: 26px; inset-inline-start: 26px; z-index: 4; font-size: 11px; color: rgba(244, 243, 238, .3); }

@media (max-width: 780px) {
	.mk__note { display: none; }
	.mk-mono { width: 132px; }
	.mk-app { width: 72px; height: 72px; }
}

@media (prefers-reduced-motion: reduce) {
	.mk__scene, .mk__h, .mk__sub, .mk__eyebrow, .mk__kicker,
	.mk-doc, .mk-mono, .mk-rise, .mk-app, .mk-beacon, .mk-stamp, .mk-bloom, .mk-far {
		transition: opacity 260ms ease !important;
		transform: none !important;
	}
	.mk-ring, .mk-tiers__roll { animation: none !important; }
	.mk-orbit path { transition: none !important; stroke-dashoffset: 0 !important; }
}

/* about page */
.ab { display: flex; flex-direction: column; gap: 18px; }
.ab__hero { display: flex; align-items: center; gap: 16px; }
.ab__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.ab__cell { border: 1px solid var(--border); border-radius: var(--r-lg); padding: 12px 14px; }
.ab__k { font-size: 12px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .4px; }
.ab__v { font-size: 14px; margin-block-start: 3px; }

/* ====================================================== settings */
.modal--tall { height: 660px; max-height: 88dvh; }

.set { display: flex; flex-grow: 1; min-height: 0; }

.set__rail {
	width: 246px;
	flex-shrink: 0;
	border-inline-end: 1px solid var(--border);
	padding: 6px 8px 12px;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	gap: 2px;
	background: var(--bg-subtle);
}

.set__grp {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	color: var(--text-muted);
	padding: 14px 10px 5px;
	display: flex;
	flex-direction: column;
	gap: 1px;
}

.set__grp:first-child { padding-block-start: 8px; }
.set__grp small { font-size: 11px; font-weight: 500; letter-spacing: 0; text-transform: none; opacity: 0.85; }

.set__item {
	min-height: 36px;
	border-radius: var(--r);
	border: none;
	background: none;
	display: flex;
	align-items: center;
	gap: 9px;
	padding-inline: 10px;
	width: 100%;
	text-align: start;
	font-size: 14px;
}

.set__item:hover { background: var(--bg-hover); }
.set__item[aria-current="true"] { background: var(--brand); color: var(--brand-text); font-weight: 600; }
.set__item > span:not(.set__marks) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.set__marks { margin-inline-start: auto; flex-shrink: 0; display: flex; align-items: center; gap: 5px; }

.set__here {
	flex-shrink: 0;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.3px;
	text-transform: uppercase;
	color: var(--here-fg);
}

/* On the selected row the ground is the brand colour, so the marker
   borrows that row's own text colour instead. */
.set__item[aria-current="true"] .set__here { color: inherit; opacity: 0.85; }

.set__body {
	flex-grow: 1;
	min-width: 0;
	overflow-y: auto;
	padding: 18px 22px 24px;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.set__banner {
	display: flex;
	gap: 10px;
	align-items: flex-start;
	padding: 12px 14px;
	border-radius: var(--r-lg);
	font-size: 13px;
	line-height: 1.5;
}
/* The text sits in the second child; min-width:0 lets this flex item shrink so
   the sentence wraps instead of being clipped. */
.set__banner > span:last-child { min-width: 0; overflow-wrap: break-word; }
.set__banner--narrow { background: var(--brand-soft); border: 1px solid var(--brand-line); }
.set__banner--wide { background: var(--bg-subtle); border: 1px solid var(--border); }
/* Inline emphasis inside the sentence — NOT a block (which stacked each bold
   word on its own line and shattered the copy). */
.set__banner b { font-weight: 600; }

.set__row { display: flex; gap: 16px; align-items: center; padding-block: 13px; border-block-end: 1px solid var(--border); }
.set__row:last-child { border-block-end: none; }
.set__l { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set__t { font-size: 14px; font-weight: 600; }
.set__d { font-size: 13px; color: var(--text-muted); }
.set__c { flex-shrink: 0; display: flex; align-items: center; gap: 8px; justify-content: flex-end; }
.set__c .select, .set__c .input { width: auto; min-width: 168px; }
.set__copy { display: flex; align-items: center; gap: 6px; max-width: min(420px, 100%); }
.set__copy .input { min-width: 0; width: 260px; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.set__c .input--short { min-width: 96px; }

.who {
	height: 18px;
	padding-inline: 7px;
	border-radius: 100px;
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.3px;
	text-transform: uppercase;
	display: inline-flex;
	align-items: center;
	flex-shrink: 0;
}

.who--you { background: var(--bg-subtle); color: var(--text-muted); border: 1px solid var(--border); }
.who--all { background: var(--brand-soft); color: var(--brand); border: 1px solid var(--brand-line); }
.set__t { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.set__swatches { display: flex; gap: 6px; }
.set__sw { width: 26px; height: 26px; border-radius: 100px; border: 2px solid transparent; padding: 0; }
.set__sw[aria-pressed="true"] { border-color: var(--text); }

/* Settings → Spaces & channels: the spaces you may manage on the left, the
   selected one on the right. Same tokens as the rest of the panel, so it
   follows the theme. */
.setsp { display: flex; gap: 16px; align-items: flex-start; min-width: 0; }
.setsp__list { flex: 0 0 216px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.setsp__item {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 44px;
	padding: 6px 10px;
	width: 100%;
	text-align: start;
	border-radius: var(--r);
	border: 1px solid transparent;
	background: none;
	color: var(--text);
}
.setsp__item:hover { background: var(--bg-hover); }
.setsp__item[aria-current="true"] { background: var(--brand-soft); border-color: var(--brand-line); }
.setsp__dot { width: 12px; height: 12px; border-radius: 100px; flex-shrink: 0; }
.setsp__t { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.setsp__n { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.setsp__s { font-size: 12px; color: var(--text-muted); }
.setsp__main { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.setsp__card {
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg);
	padding: 12px 14px;
	display: flex;
	flex-direction: column;
	gap: 6px;
}
.setsp__head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-height: 32px; }
.setsp__head .setsp__n { font-size: 15px; }
.setsp__head .input { flex: 1 1 160px; min-width: 0; }
.setsp__card .mem { padding-inline: 0; min-height: 40px; }
.setsp__card .mem .select { width: auto; min-width: 120px; }
.setsp__ch { border-block-start: 1px solid var(--border); padding-block: 6px; }
.setsp__ch:first-of-type { border-block-start: none; }
.setsp__chrow { display: flex; align-items: center; gap: 8px; min-height: 40px; }
.setsp__chrow > .setsp__t { flex-grow: 1; }
.setsp__sub {
	margin: 4px 0 6px 10px;
	padding-inline-start: 12px;
	border-inline-start: 2px solid var(--brand-line);
	display: flex;
	flex-direction: column;
	gap: 10px;
}
.setsp__k { font-size: 11px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-muted); }
.setsp__tab { display: flex; align-items: center; gap: 8px; min-height: 34px; font-size: 14px; }
.setsp__tab > span:first-of-type { flex-grow: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.setsp__empty { font-size: 13px; color: var(--text-muted); margin: 0; padding: 4px 0; }

@media (max-width: 760px) {
	.set { flex-direction: column; }
	.set__rail { width: 100%; border-inline-end: none; border-block-end: 1px solid var(--border); max-height: 180px; }
	.setsp { flex-direction: column; }
	.setsp__list { flex-basis: auto; width: 100%; }
}

/* ======================================================== photos */
/* real photographs */
.ph-grid { grid-auto-flow: dense; }
.ph-tile img, .ph-card__art img, .ph-view__stage img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ph-tile img { transition: transform 320ms cubic-bezier(.2,.7,.3,1), filter 320ms ease; }
.ph-tile:hover img { transform: scale(1.05); filter: brightness(1.04); }
.ph-tile::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(6,17,14,.28) 0%, rgba(6,17,14,0) 34%, rgba(6,17,14,0) 62%, rgba(6,17,14,.3) 100%);
	opacity: 0;
	transition: opacity 240ms ease;
	pointer-events: none;
}
.ph-tile:hover::after, .ph-tile[data-sel="1"]::after, .ph-tile[data-fav="1"]::after { opacity: 1; }
.ph-tile--hero { grid-column: span 2; grid-row: span 2; }

/* memories cover */
.ph-hero {
	position: relative;
	border-radius: var(--r-xl);
	overflow: hidden;
	min-height: 208px;
	display: flex;
	align-items: flex-end;
	margin-block-end: 4px;
	border: none;
	padding: 0;
	width: 100%;
	text-align: start;
}

.ph-hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 600ms cubic-bezier(.2,.7,.3,1); }
.ph-hero:hover img { transform: scale(1.04); }
.ph-hero__veil { position: absolute; inset: 0; background: linear-gradient(to top, rgba(6,17,14,.82) 0%, rgba(6,17,14,.25) 52%, rgba(6,17,14,.1) 100%); }
.ph-hero__b { position: relative; padding: 20px 22px; display: flex; align-items: flex-end; gap: 16px; width: 100%; }
.ph-hero__t { font-family: var(--display); font-size: 24px; font-weight: 600; letter-spacing: -0.4px; color: #fff; }
.ph-hero__s { font-size: 13px; color: rgba(255,255,255,.78); }
.ph-hero__play {
	flex-shrink: 0;
	height: 40px;
	padding-inline: 18px;
	border-radius: 100px;
	border: none;
	background: rgba(255,255,255,.94);
	color: #08231c;
	font-size: 14px;
	font-weight: 700;
	display: inline-flex;
	align-items: center;
	gap: 8px;
}
.ph-hero:hover .ph-hero__play { background: #fff; }

/* filmstrip */
.ph-strip {
	flex-shrink: 0;
	height: 74px;
	display: flex;
	gap: 6px;
	padding: 8px 14px;
	overflow-x: auto;
	align-items: center;
	background: rgba(0,0,0,.28);
}
.ph-strip button { width: 58px; height: 58px; border-radius: var(--r-sm); overflow: hidden; border: 2px solid transparent; padding: 0; flex-shrink: 0; opacity: .55; }
.ph-strip button img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ph-strip button:hover { opacity: .85; }
.ph-strip button[aria-current="true"] { border-color: #fff; opacity: 1; }

.ph-view__stage img { border-radius: var(--r-lg); box-shadow: 0 20px 60px rgba(0,0,0,.5); width: auto; height: auto; max-width: 100%; max-height: 100%; }
.ph-view__stage { padding: 16px 70px 16px; }

.ph-credit { font-size: 11px; color: var(--text-muted); }


.ph-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	gap: 4px;
}

.ph-tile {
	position: relative;
	aspect-ratio: 1;
	border: none;
	padding: 0;
	background: var(--bg-subtle);
	overflow: hidden;
	border-radius: var(--r-sm);
	display: block;
}

.ph-tile svg { width: 100%; height: 100%; display: block; }
.ph-tile:hover .ph-pick, .ph-tile:hover .ph-fav { opacity: 1; }
.ph-tile[data-sel="1"] { outline: 3px solid var(--brand); outline-offset: -3px; }
.ph-tile[data-sel="1"] svg { transform: scale(0.92); transition: transform 120ms ease; }

.ph-pick {
	position: absolute;
	top: 7px;
	inset-inline-start: 7px;
	width: 21px;
	height: 21px;
	border-radius: 100px;
	border: 2px solid #fff;
	background: rgba(6, 17, 14, 0.32);
	display: flex;
	align-items: center;
	justify-content: center;
	color: transparent;
	opacity: 0;
	transition: opacity 120ms ease;
}

.ph-tile[data-sel="1"] .ph-pick { opacity: 1; background: var(--brand); border-color: var(--brand); color: var(--brand-text); }

.ph-fav {
	position: absolute;
	inset-block-end: 7px;
	inset-inline-end: 7px;
	color: #fff;
	opacity: 0;
	filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
	transition: opacity 120ms ease;
	background: none;
	border: none;
	padding: 0;
	display: flex;
}

.ph-tile[data-fav="1"] .ph-fav { opacity: 1; color: #ffd166; }

.ph-vid {
	position: absolute;
	top: 7px;
	inset-inline-end: 7px;
	height: 18px;
	padding-inline: 6px;
	border-radius: 100px;
	background: rgba(6, 17, 14, 0.55);
	color: #fff;
	font-size: 10px;
	font-weight: 700;
	display: flex;
	align-items: center;
	font-variant-numeric: tabular-nums;
}

.ph-day {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 20px 0 8px;
	position: sticky;
	top: 0;
	background: var(--bg);
	z-index: 2;
}

.ph-day__t { font-size: 15px; font-weight: 600; }
.ph-day__s { font-size: 13px; color: var(--text-muted); }

.ph-day__sel {
	border: none;
	background: none;
	color: var(--brand);
	font-size: 12px;
	font-weight: 600;
	padding: 4px 8px;
	border-radius: var(--r);
}

.ph-day__sel:hover { background: var(--brand-soft); }

.ph-bar {
	flex-shrink: 0;
	min-height: 52px;
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 20px;
	border-block-end: 1px solid var(--border);
	flex-wrap: wrap;
	background: var(--brand-soft);
}

.ph-scrub {
	width: 62px;
	flex-shrink: 0;
	padding-block: 16px;
	display: flex;
	flex-direction: column;
	gap: 2px;
	border-inline-start: 1px solid var(--border);
}

.ph-scrub button {
	border: none;
	background: none;
	font-size: 11px;
	font-weight: 600;
	color: var(--text-muted);
	padding: 3px 6px;
	border-radius: var(--r-sm);
	text-align: end;
}

.ph-scrub button:hover { background: var(--bg-hover); color: var(--text); }
.ph-scrub button[aria-current="true"] { color: var(--brand); }

.ph-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }

.ph-card {
	border: none;
	background: none;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
	text-align: start;
}

.ph-card__art {
	aspect-ratio: 1;
	border-radius: var(--r-lg);
	overflow: hidden;
	position: relative;
	background: var(--bg-subtle);
	display: grid;
	grid-template-columns: 1fr 1fr;
	grid-template-rows: 1fr 1fr;
	gap: 2px;
}

.ph-card:hover .ph-card__art { outline: 2px solid var(--brand); outline-offset: 2px; }
.ph-card__art svg { width: 100%; height: 100%; display: block; }
.ph-card__art--one { display: block; }
.ph-card__n { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-card__s { font-size: 12px; color: var(--text-muted); }

.ph-face { border-radius: 100px; }
.ph-face .ph-card__art { border-radius: 100px; }

/* ---- lightbox ---- */
.ph-view {
	position: fixed;
	inset: 0;
	z-index: 120;
	background: rgba(6, 17, 14, 0.94);
	display: flex;
	flex-direction: column;
}

.ph-view__top {
	height: 56px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 8px;
	padding-inline: 14px;
	color: #fff;
}

.ph-view__top .ibtn { color: rgba(255, 255, 255, 0.75); }
.ph-view__top .ibtn:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.ph-view__name { font-size: 14px; font-weight: 600; }
.ph-view__meta { font-size: 12px; color: rgba(255, 255, 255, 0.6); }

.ph-view__body { flex-grow: 1; min-height: 0; display: flex; }
/* touch-action: pan-y lets a vertical scroll through but hands horizontal
   drags to the swipe handler instead of the browser's own gesture. */
.ph-view__stage { flex-grow: 1; min-width: 0; display: flex; align-items: center; justify-content: center; padding: 12px 8px 24px; position: relative; touch-action: pan-y; }
.ph-view__stage img { will-change: transform; }
/* Set while a horizontal swipe is in progress so the drag never selects the
   surrounding chrome; removed the moment the gesture ends. */
.ph-view.is-swiping, .ph-view.is-swiping * { user-select: none; -webkit-user-select: none; }
.ph-view__stage svg { max-width: 100%; max-height: 100%; width: min(74dvh, 100%); aspect-ratio: 1; border-radius: var(--r-lg); }

.ph-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 44px;
	height: 44px;
	border-radius: 100px;
	border: none;
	background: rgba(255, 255, 255, 0.14);
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
}

.ph-nav:hover { background: rgba(255, 255, 255, 0.26); }
.ph-nav--prev { inset-inline-start: 18px; }
.ph-nav--next { inset-inline-end: 18px; }

.ph-info {
	width: 320px;
	flex-shrink: 0;
	background: var(--bg);
	border-inline-start: 1px solid var(--border);
	overflow-y: auto;
	padding: 18px;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.ph-kv { display: flex; flex-direction: column; gap: 2px; }
.ph-kv__k { font-size: 12px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.ph-kv__v { font-size: 14px; overflow-wrap: anywhere; }

.ph-chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	height: 24px;
	padding-inline: 9px;
	border-radius: 100px;
	background: var(--bg-subtle);
	border: 1px solid var(--border);
	font-size: 12px;
	font-weight: 600;
}

.ph-used { border: 1px solid var(--brand-line); background: var(--brand-soft); border-radius: var(--r-lg); padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; }

@media (max-width: 900px) { .ph-info { display: none; } .ph-scrub { display: none; } }

/* ---- photo editor ----
   A full-screen dark overlay above the lightbox (120). The Save dialog is a
   normal .backdrop modal, so it is lifted above this while the editor is open
   (see html.phed-open .backdrop below) -- otherwise the modal, at z-index 100,
   would open behind the editor. */
.phed {
	position: fixed;
	inset: 0;
	z-index: 140;
	background: rgba(6, 17, 14, 0.97);
	display: flex;
	flex-direction: column;
	color: #fff;
}
html.phed-open .backdrop { z-index: 160; }

.phed__top {
	height: 56px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: 8px;
	padding-inline: 12px;
}
.phed__top .ibtn { color: rgba(255, 255, 255, 0.78); min-width: 44px; height: 44px; }
.phed__top .ibtn:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.phed__name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.phed__top .btn { min-height: 40px; }

.phed__body { flex-grow: 1; min-height: 0; display: flex; flex-direction: column; }
@media (min-width: 720px) { .phed__body { flex-direction: row-reverse; } }

.phed__stage {
	flex-grow: 1;
	min-height: 0;
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 12px;
	position: relative;
}
/* Sized to the image's natural pixels in JS; CSS scales it to fit the stage. */
.phed__canvas { max-width: 100%; max-height: 100%; width: auto; height: auto; border-radius: var(--r-md); box-shadow: 0 20px 60px rgba(0,0,0,.5); touch-action: none; cursor: crosshair; background: rgba(255,255,255,.04); }
.phed__load { display: flex; align-items: center; gap: 10px; color: rgba(255,255,255,.8); font-size: 14px; }

/* The text tool's keyboard catcher: a visually invisible <input> parked at the
   tap point. The text itself is drawn straight onto the canvas as you type;
   this input only captures keystrokes (mobile keyboards need a focused,
   on-screen input). 16px avoids iOS zoom; pointer-events off so it never
   swallows the next tap. */
.phed__text { position: fixed; z-index: 2; width: 1px; height: 1px; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; background: transparent; color: transparent; font-size: 16px; }
/* The faint one-line hint shown in the toolbar while the text tool is armed. */
.phed__hint { align-self: center; color: rgba(255,255,255,.6); font-size: 13px; padding: 0 4px; }

/* One flex bar that wraps: a column on the left on wide screens, a wrapping
   row along the bottom on phones. Every target is at least 44px. */
.phed__tools {
	flex-shrink: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px 14px;
	padding: 12px;
	background: rgba(0, 0, 0, 0.35);
	border-block-start: 1px solid rgba(255, 255, 255, 0.12);
}
@media (min-width: 720px) {
	.phed__tools {
		flex-direction: column;
		align-items: stretch;
		width: 76px;
		border-block-start: none;
		border-inline-end: 1px solid rgba(255, 255, 255, 0.12);
		overflow-y: auto;
	}
}
.phed__group { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@media (min-width: 720px) { .phed__group { justify-content: center; } }
.phed__sep { width: 1px; height: 30px; background: rgba(255,255,255,.14); }
@media (min-width: 720px) { .phed__sep { width: auto; height: 1px; margin-block: 2px; } }

.phed__tool {
	width: 44px; height: 44px;
	border-radius: var(--r-md);
	border: 1px solid rgba(255, 255, 255, 0.18);
	background: rgba(255, 255, 255, 0.06);
	color: #fff;
	display: flex; align-items: center; justify-content: center;
	font-size: 20px; font-weight: 700;
}
.phed__tool:hover { background: rgba(255, 255, 255, 0.16); }
.phed__tool[aria-pressed="true"] { background: #fff; color: #111; border-color: #fff; }

.phed__sw {
	width: 30px; height: 30px; border-radius: 100px; padding: 0;
	border: 2px solid transparent; box-shadow: 0 0 0 1px rgba(255,255,255,.35);
}
.phed__sw[aria-pressed="true"] { box-shadow: 0 0 0 2px rgba(6,17,14,.97), 0 0 0 4px #fff; }

.phed__w {
	width: 40px; height: 40px; border-radius: var(--r-md);
	border: 1px solid rgba(255, 255, 255, 0.18);
	background: rgba(255, 255, 255, 0.06);
	display: flex; align-items: center; justify-content: center;
}
.phed__w[aria-pressed="true"] { background: rgba(255,255,255,.18); border-color: #fff; }
.phed__w i { display: block; border-radius: 100px; background: #fff; }

/* The two big Save choice cards. */
.phed__choice {
	display: flex; align-items: flex-start; gap: 12px; text-align: start; width: 100%;
	padding: 14px; border-radius: var(--r-lg);
	border: 1px solid var(--border); background: var(--bg-subtle);
	margin-block-end: 10px;
}
.phed__choice:hover { border-color: var(--brand); }
.phed__choice--primary { border-color: var(--brand); background: var(--brand-soft); }
.phed__choice--danger { border-inline-start: 4px solid var(--danger); }
.phed__choice svg { flex-shrink: 0; margin-block-start: 2px; }
.phed__choice b { display: block; font-size: 15px; }
.phed__choice span { display: block; font-size: 13px; color: var(--text-muted); margin-block-start: 2px; }



/* ---- library: Years / Months / Days / All Photos ---------------------- */
/* One seamless mosaic, the way a phone shows a library: a 2px seam, no
   rounded tiles, the group's own corners rounded on a desktop. */
#phapp .ph-grid {
	grid-template-columns: repeat(auto-fill, minmax(var(--phmin, 150px), 1fr));
	gap: 2px;
	border-radius: 12px;
	overflow: hidden;
}
#phapp .ph-tile { border-radius: 0; }
#phapp .ph-tile:hover img { transform: none; filter: brightness(1.07); }
#phapp .phl[data-fit="1"] .ph-tile img,
#phapp .phl[data-fit="1"] .ph-tile .ph-tile__v { object-fit: contain; }
#phapp .ph-tile.is-broken img { visibility: hidden; }

.phl-bar { gap: 10px; }
.phl-when { display: flex; flex-direction: column; min-width: 0; }
.phl-when__t {
	font-family: var(--display);
	font-size: 19px;
	font-weight: 700;
	letter-spacing: -0.3px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	text-transform: capitalize;
}
.phl-when__s { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.phl-zoom {
	display: inline-flex;
	gap: 2px;
	padding: 2px;
	border-radius: 100px;
	background: var(--bg-subtle);
	border: 1px solid var(--border);
}
.phl-zoom .ibtn { width: 30px; height: 30px; border-radius: 100px; font-size: 18px; font-weight: 600; line-height: 1; }
.phl-zoom .ibtn:disabled { opacity: 0.35; pointer-events: none; }
.phl-wrap { position: relative; display: flex; flex-grow: 1; min-height: 0; }
.phl-foot { height: 76px; }
.phl-more { height: 1px; grid-column: 1 / -1; }

#phapp .ph-day { padding: 18px 2px 8px; }
#phapp .ph-day__t { font-size: 16px; font-weight: 700; letter-spacing: -0.2px; }

/* video tiles: the length bottom-right over a soft scrim, the favourite
   star bottom-left, the moving picture fading in over the poster */
#phapp .ph-vid {
	top: auto;
	bottom: 6px;
	inset-inline-end: 7px;
	height: auto;
	padding: 0;
	background: none;
	font-size: 11px;
	font-weight: 600;
	gap: 3px;
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65);
}
#phapp .ph-vid svg { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55)); }
#phapp .ph-fav { inset-inline-end: auto; inset-inline-start: 7px; }
#phapp .ph-tile[data-video="1"]::after {
	opacity: 1;
	background: linear-gradient(to top, rgba(6, 17, 14, 0.42) 0%, rgba(6, 17, 14, 0) 36%);
}
.ph-tile__v, .ph-still {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	pointer-events: none;
}
.ph-tile__v { opacity: 0; transition: opacity 280ms ease; }
.ph-tile .ph-still { position: static; }
.is-live > .ph-tile__v { opacity: 1; }

/* Months and Years: big covers, a video cover moves */
.phl-sec {
	font-family: var(--display);
	font-size: 26px;
	font-weight: 700;
	letter-spacing: -0.6px;
	padding: 22px 2px 12px;
}
.phl-sec:first-child { padding-block-start: 6px; }
.phl-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 14px; }
.phl-cards--years { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 18px; padding-block-start: 6px; }
.phl-card {
	position: relative;
	display: block;
	border: none;
	padding: 0;
	overflow: hidden;
	border-radius: 18px;
	aspect-ratio: 4 / 3;
	background: var(--bg-subtle);
	text-align: start;
	isolation: isolate;
	box-shadow: 0 1px 2px rgba(6, 17, 14, 0.08), 0 8px 24px rgba(6, 17, 14, 0.1);
	transition: transform 240ms cubic-bezier(.2, .7, .3, 1), box-shadow 240ms ease;
}
.phl-card--year { aspect-ratio: 16 / 10; }
.phl-card:hover { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(6, 17, 14, 0.1), 0 16px 40px rgba(6, 17, 14, 0.18); }
.phl-card:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; }
.phl-card img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.phl-card__veil {
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgba(6, 17, 14, 0.74) 0%, rgba(6, 17, 14, 0.14) 46%, rgba(6, 17, 14, 0) 70%);
}
.phl-card__b {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	padding: 16px 18px;
	display: flex;
	flex-direction: column;
	gap: 3px;
	color: #fff;
}
.phl-card__t {
	font-family: var(--display);
	font-size: 22px;
	font-weight: 700;
	letter-spacing: -0.4px;
	text-transform: capitalize;
}
.phl-card--year .phl-card__t { font-size: 46px; letter-spacing: -1.4px; line-height: 1; }
.phl-card__s { font-size: 13px; color: rgba(255, 255, 255, 0.84); }
.ph-hero .ph-tile__v { z-index: 0; }

/* the Years / Months / Days / All Photos switch floats over the library */
.phl-seg {
	position: absolute;
	left: 50%;
	bottom: 18px;
	transform: translateX(-50%);
	z-index: 5;
	display: flex;
	gap: 2px;
	padding: 4px;
	border-radius: 100px;
	background: var(--bg);
	background: color-mix(in srgb, var(--bg) 74%, transparent);
	-webkit-backdrop-filter: blur(18px) saturate(1.6);
	backdrop-filter: blur(18px) saturate(1.6);
	border: 1px solid var(--border);
	box-shadow: 0 8px 30px rgba(6, 17, 14, 0.18);
}
.phl-seg button {
	border: none;
	background: none;
	height: 34px;
	padding-inline: 16px;
	border-radius: 100px;
	font-size: 13px;
	font-weight: 600;
	color: var(--text);
	white-space: nowrap;
	transition: background 160ms ease, color 160ms ease;
}
.phl-seg button:hover { background: var(--bg-hover); }
.phl-seg button[aria-selected="true"] { background: var(--text); color: var(--bg); }

/* the month scrubber down the side */
.phl-scrub { overflow-y: auto; scrollbar-width: none; padding-block-end: 80px; }
.phl-scrub::-webkit-scrollbar { display: none; }
.phl-scrub__y { font-size: 11px; font-weight: 700; color: var(--text); padding: 10px 6px 2px; text-align: end; }
.phl-scrub button { text-transform: capitalize; }

/* an empty library invites the first photos */
.phl-empty {
	max-width: 460px;
	margin: 10vh auto 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 12px;
}
.phl-empty__art {
	width: 76px;
	height: 76px;
	border-radius: 22px;
	display: grid;
	place-items: center;
	background: var(--brand-soft);
	color: var(--brand);
}
.phl-empty__t { font-family: var(--display); font-size: 24px; font-weight: 700; letter-spacing: -0.4px; text-wrap: balance; }
.phl-empty__x { color: var(--text-muted); font-size: 14px; line-height: 1.5; text-wrap: pretty; }

/* dropping files on the view */
#phapp.is-drop { position: relative; }
#phapp.is-drop::after {
	content: attr(data-drop);
	position: absolute;
	inset: 10px;
	z-index: 20;
	display: grid;
	place-items: center;
	border: 2px dashed var(--brand);
	border-radius: 18px;
	background: var(--brand-soft);
	font-family: var(--display);
	font-size: 20px;
	font-weight: 700;
	color: var(--brand);
	pointer-events: none;
}

/* adding photos: one quiet pill with a progress ring */
.phl-up {
	position: fixed;
	z-index: 130;
	inset-inline-end: 20px;
	bottom: calc(20px + env(safe-area-inset-bottom, 0px));
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 10px 10px 12px;
	min-width: 280px;
	max-width: calc(100vw - 32px);
	border-radius: 16px;
	background: var(--bg);
	color: var(--text);
	border: 1px solid var(--border);
	box-shadow: 0 12px 40px rgba(6, 17, 14, 0.22);
	animation: phl-up-in 260ms cubic-bezier(.2, .7, .3, 1);
}
.phl-up__ring {
	--p: 0;
	position: relative;
	width: 34px;
	height: 34px;
	flex-shrink: 0;
	border-radius: 50%;
	background: conic-gradient(var(--brand) calc(var(--p) * 1%), var(--bg-subtle) 0);
	display: grid;
	place-items: center;
	color: var(--brand-text);
}
.phl-up__ring::before { content: ''; position: absolute; inset: 4px; border-radius: 50%; background: var(--bg); }
.phl-up[data-done="1"] .phl-up__ring::before { display: none; }
.phl-up__ring svg { position: relative; }
.phl-up__txt { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.phl-up__txt b { font-size: 14px; color: var(--text); }
.phl-up__txt span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@keyframes phl-up-in { from { transform: translateY(12px); opacity: 0; } }

/* the viewer plays a video in place of the picture */
.ph-view__stage video.ph-stage__v {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	border-radius: var(--r-lg);
	box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
	background: #000;
	outline: none;
	will-change: transform;
}
.ph-stage__err {
	position: absolute;
	left: 50%;
	bottom: 40px;
	transform: translateX(-50%);
	max-width: min(420px, 90%);
	padding: 10px 14px;
	border-radius: 12px;
	background: rgba(0, 0, 0, 0.74);
	color: #fff;
	font-size: 13px;
	text-align: center;
}
.ph-strip button[data-video="1"] { position: relative; }
.ph-strip button[data-video="1"]::after {
	content: '';
	position: absolute;
	right: 5px;
	bottom: 5px;
	border-style: solid;
	border-width: 5px 0 5px 8px;
	border-color: transparent transparent transparent #fff;
	filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.6));
}

@media (prefers-reduced-motion: reduce) {
	.phl-up { animation: none; }
	.phl-card, .ph-tile__v, .phl-seg button { transition: none; }
	.phl-card:hover { transform: none; }
}

.ph-info a.btn { text-decoration: none; }
/* ================================================ photos albums & sharing */
/* Albums, Shared albums, People, Places and Tags as calm cover cards, and the
   album dialogs (add to album, new album, album details, share, add photos,
   tags). Colours are the shell's tokens only, so light and both dark modes
   follow without a dark block of their own; the only fixed colours sit on top
   of a photograph (the shared badge), where the picture is the background. */

.pha-title { font-family: var(--display); font-size: 17px; font-weight: 600; }
.pha-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ---- cover cards ---- */
.pha-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: 22px 18px; }
.pha-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
	padding: 0;
	border: none;
	background: none;
	color: inherit;
	text-align: start;
	border-radius: var(--r-xl);
}
.pha-card__art {
	position: relative;
	display: grid;
	place-items: center;
	aspect-ratio: 1;
	margin-block-end: 6px;
	border-radius: var(--r-xl);
	overflow: hidden;
	background: var(--bg-subtle);
	color: var(--text-muted);
	box-shadow: 0 1px 2px rgba(6, 17, 14, 0.06), 0 6px 18px rgba(6, 17, 14, 0.06);
	transition: transform 220ms cubic-bezier(.2, .7, .3, 1), box-shadow 220ms ease;
}
.pha-card__art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.pha-card__art img[hidden] { display: none; }
.pha-card:hover .pha-card__art { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(6, 17, 14, 0.08), 0 14px 32px rgba(6, 17, 14, 0.14); }
.pha-card:focus-visible { outline: none; }
.pha-card:focus-visible .pha-card__art { outline: 3px solid var(--brand); outline-offset: 3px; }
.pha-card--round { align-items: center; text-align: center; }
.pha-card--round .pha-card__art { width: 100%; border-radius: 100px; }
.pha-card__n { max-width: 100%; font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pha-card__s { max-width: 100%; font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pha-card__badge {
	position: absolute;
	top: 8px;
	inset-inline-end: 8px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	border-radius: 100px;
	background: rgba(6, 17, 14, 0.56);
	color: #fff;
}

/* skeletons hold the place while a list or an album loads: nothing jumps
   when the answer lands */
.pha-skel { background: var(--bg-subtle); animation: pha-pulse 1.3s ease-in-out infinite; }
.pha-skel--line { display: block; height: 12px; width: 70%; border-radius: 100px; margin-block-start: 4px; }
.pha-skel--tile { aspect-ratio: 1; }
@keyframes pha-pulse { 50% { opacity: 0.5; } }

/* ---- the album header ---- */
/* one row at every width: the title gives way (ellipsis), the actions stay */
#phapp .pha-bar { gap: 8px; flex-wrap: nowrap; }
.pha-head { display: flex; flex-direction: column; min-width: 0; flex: 1 1 0; }
.pha-head__t:focus { outline: none; }
.pha-head__t {
	font-family: var(--display);
	font-size: 19px;
	font-weight: 700;
	letter-spacing: -0.3px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.pha-head__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pha-acts { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.pha-avs { display: inline-flex; align-items: center; }
.pha-avs .av { width: 22px; height: 22px; font-size: 9px; box-shadow: 0 0 0 2px var(--bg); }
.pha-avs .av + .av { margin-inline-start: -6px; }
/* a shared album shows who has it on Share; a phone shows the plain icon */
.pha-share--avs > svg { display: none; }
.pha-wrap { position: relative; display: flex; flex-direction: column; flex-grow: 1; min-height: 0; }

/* ---- dialogs ---- */
.pha-dlg .modal__f { flex-wrap: wrap; align-items: center; }
.pha-grp { display: flex; flex-direction: column; gap: 2px; }
.pha-grp + .pha-grp { margin-block-start: 4px; }
.pha-grp__h { padding: 0 8px 4px; font-size: 12px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.4px; }
.pha-pick {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	min-height: 52px;
	padding: 6px 8px;
	border: none;
	border-radius: var(--r-lg);
	background: transparent;
	color: inherit;
	text-align: start;
}
.pha-pick:hover { background: var(--bg-hover); }
.pha-pick[aria-pressed="true"], .pha-pick[aria-pressed="mixed"] { background: var(--brand-soft); }
.pha-pick:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.pha-pick__th {
	position: relative;
	flex-shrink: 0;
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border-radius: var(--r);
	overflow: hidden;
	background: var(--bg-subtle);
	color: var(--text-muted);
}
.pha-pick__th img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pha-pick__th img[hidden] { display: none; }
.pha-pick--new .pha-pick__th { background: var(--brand-soft); color: var(--brand); }
.pha-pick__t { display: flex; flex-direction: column; flex-grow: 1; min-width: 0; }
.pha-pick__n { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pha-pick__s { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pha-check {
	flex-shrink: 0;
	display: grid;
	place-items: center;
	width: 22px;
	height: 22px;
	border-radius: 100px;
	border: 2px solid var(--border-strong);
	color: transparent;
}
.pha-pick[aria-pressed="true"] .pha-check { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }
.pha-pick[aria-pressed="mixed"] .pha-check { border-color: var(--brand); background: linear-gradient(var(--brand), var(--brand)) center / 10px 2px no-repeat; }
.pha-muted { font-size: 13px; color: var(--text-muted); }
.pha-danger { color: var(--danger); }
.pha-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 10%, transparent); }
.pha-list { display: flex; flex-direction: column; gap: 2px; }

/* share: search, chips, the public link */
.pha-res {
	display: flex;
	flex-direction: column;
	gap: 2px;
	max-height: 236px;
	overflow-y: auto;
	padding: 4px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg);
	box-shadow: 0 8px 24px rgba(6, 17, 14, 0.1);
}
.pha-res[hidden] { display: none; }
.pha-opt { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 4px 8px; border-radius: var(--r); cursor: pointer; }
.pha-opt:hover, .pha-opt[aria-selected="true"] { background: var(--bg-hover); }
.pha-opt[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--brand); }
.pha-ic {
	flex-shrink: 0;
	display: grid;
	place-items: center;
	width: 30px;
	height: 30px;
	border-radius: 100px;
	background: var(--brand-soft);
	color: var(--brand);
}
.pha-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.pha-chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	max-width: 100%;
	height: 36px;
	padding-inline: 4px 2px;
	border-radius: 100px;
	background: var(--bg-subtle);
	border: 1px solid var(--border);
	font-size: 13px;
	font-weight: 600;
}
.pha-chip .av, .pha-chip .pha-ic { width: 26px; height: 26px; font-size: 10px; }
.pha-chip__n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pha-chip .ibtn { width: 30px; height: 30px; border-radius: 100px; flex-shrink: 0; }
.pha-link {
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding: 12px 14px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	background: var(--bg-raised);
}
.pha-link__row { display: flex; align-items: center; gap: 12px; }
.pha-link__t { display: flex; flex-direction: column; flex-grow: 1; min-width: 0; }
.pha-link__t b { font-size: 14px; }
.pha-link__t span { font-size: 12px; color: var(--text-muted); }
.pha-link .switch:disabled { opacity: 0.45; }
.pha-url { display: flex; gap: 8px; }
.pha-url .input { flex-grow: 1; min-width: 0; font-size: 13px; }
.pha-warn {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 10px 12px;
	border-radius: var(--r);
	background: var(--warn-bg);
	border: 1px solid var(--warn-border);
	color: var(--warn);
	font-size: 13px;
	font-weight: 600;
	line-height: 1.45;
}
.pha-warn svg { flex-shrink: 0; margin-block-start: 1px; }
.pha-trunc { margin: 0; padding-block-start: 18px; text-align: center; font-size: 12px; color: var(--text-muted); }
.pha-warn .btn { margin-inline-start: auto; flex-shrink: 0; }
.pha-status { min-height: 18px; font-size: 13px; font-weight: 600; color: var(--ok); }

/* add photos: the library as a picking grid */
.pha-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 4px; }
.pha-ptile { position: relative; aspect-ratio: 1; padding: 0; border: none; border-radius: var(--r-sm); overflow: hidden; background: var(--bg-subtle); }
.pha-ptile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 160ms ease; }
.pha-ptile .pha-check { position: absolute; top: 6px; inset-inline-start: 6px; border-color: #fff; background: rgba(6, 17, 14, 0.32); }
.pha-ptile[aria-pressed="true"] { outline: 3px solid var(--brand); outline-offset: -3px; }
.pha-ptile[aria-pressed="true"] img { transform: scale(0.94); }
.pha-ptile[aria-pressed="true"] .pha-check { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }
.pha-ptile:disabled { cursor: default; }
.pha-ptile:disabled img { opacity: 0.42; }
.pha-ptile:disabled .pha-check { background: var(--text-muted); border-color: transparent; color: var(--bg); }
.pha-ptile:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.pha-more { align-self: center; }

/* ---- grid tiles: open, select and star are sibling buttons ---- */
.ph-open {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: inherit;
	background: transparent;
	cursor: pointer;
}
.ph-open:focus-visible { outline: 3px solid var(--brand); outline-offset: -3px; }
/* always overlays (a touch rule in 018 makes them relative for its hit area) */
.ph-tile > .ph-pick, .ph-tile > .ph-fav { position: absolute; cursor: pointer; font: inherit; }
.ph-tile > .ph-pick { padding: 0; }
.ph-tile:focus-within .ph-pick, .ph-tile:focus-within .ph-fav { opacity: 1; }
.ph-tile > .ph-pick:focus-visible, .ph-tile > .ph-fav:focus-visible { opacity: 1; outline: 2px solid #fff; outline-offset: 2px; box-shadow: 0 0 0 4px var(--brand); border-radius: 100px; }

/* the backdrop above the photo viewer, so a dialog opened from it shows */
html.ph-viewing .backdrop { z-index: 130; }
html.phed-open .backdrop { z-index: 160; }

/* a message too long for the pill toast reads as a card */
.toast.pha-toast { border-radius: var(--r-lg); max-width: min(440px, calc(100vw - 32px)); width: max-content; text-align: start; line-height: 1.45; padding: 12px 16px; }

@media (prefers-reduced-motion: reduce) {
	.pha-skel { animation: none; }
	.pha-card__art, .pha-ptile img { transition: none; }
	.pha-card:hover .pha-card__art { transform: none; }
}

@media (max-width: 767.98px) {
	.pha-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 12px; }
	#phapp .pha-bl { display: none; }
	/* the selection bar wraps instead of scrolling actions off-screen */
	#phapp .ph-bar { flex-wrap: wrap; overflow-x: visible; row-gap: 6px; }
	#phapp .ph-bar .btn { padding-inline: 10px; }
	#phapp .pha-bar .btn, #phapp .pha-acts .btn { flex: 0 0 auto; padding-inline: 10px; }
	.pha-head__t { font-size: 17px; }
	.pha-avs { display: none; }
	.pha-share--avs > svg { display: inline-block; }
	.pha-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px; }
	.pha-ptile { border-radius: 0; }
	.pha-dlg .modal__f { gap: 8px; }
}
/* ========================================================== mail */
.mlist {
	width: 380px;
	flex-shrink: 0;
	border-inline-end: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	min-height: 0;
}

.mlist__scroll { flex-grow: 1; overflow-y: auto; min-height: 0; }

.msec {
	padding: 12px 14px 6px;
	font-size: 12px;
	font-weight: 700;
	color: var(--text-muted);
	letter-spacing: 0.4px;
	text-transform: uppercase;
	display: flex;
	align-items: center;
	gap: 8px;
	position: sticky;
	top: 0;
	background: var(--bg);
	z-index: 1;
}

.mrow {
	display: flex;
	gap: 10px;
	padding: 11px 14px;
	border-block-end: 1px solid var(--border);
	width: 100%;
	text-align: start;
	background: none;
	border-inline: none;
	border-block-start: none;
	align-items: flex-start;
}

.mrow:hover { background: var(--bg-hover); }
.mrow[aria-current="true"] { background: var(--brand-soft); }
.mrow__dot { width: 8px; height: 8px; border-radius: 100px; background: var(--brand); flex-shrink: 0; margin-block-start: 7px; }
.mrow__dot--read { background: transparent; }
.mrow__b { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mrow__top { display: flex; align-items: baseline; gap: 8px; }
.mrow__from { font-size: 14px; font-weight: 600; flex-grow: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mrow__date { font-size: 12px; color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.mrow__subj { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mrow--unread .mrow__subj { font-weight: 700; }
.mrow__prev { font-size: 13px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mrow__meta { display: flex; gap: 6px; align-items: center; margin-block-start: 5px; flex-wrap: wrap; }

.mtag {
	height: 20px;
	padding-inline: 8px;
	border-radius: 100px;
	font-size: 11px;
	font-weight: 600;
	color: #fff;
	display: inline-flex;
	align-items: center;
	white-space: nowrap;
}

.mstar { background: none; border: none; padding: 2px; color: var(--border-strong); display: flex; flex-shrink: 0; }
.mstar:hover { color: #a37200; }
.mstar[aria-pressed="true"] { color: #a37200; }

/* Conversations in the list: message count after the names, account chip in "All inboxes". */
.mrow__n { display: inline-block; vertical-align: 1px; min-width: 18px; padding: 0 5px; border-radius: 100px; background: var(--bg-hover); color: var(--text-muted); font-size: 11px; font-weight: 600; line-height: 16px; text-align: center; font-variant-numeric: tabular-nums; }
.mrow--unread .mrow__n { color: var(--text); }
.mrow__acct { flex-shrink: 0; font-size: 10px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-muted); border: 1px solid var(--border); border-radius: 4px; padding: 0 4px; line-height: 15px; max-width: 9ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Account switcher in the folder nav (two or more accounts). */
.appnav__acct { display: flex; align-items: center; gap: 6px; width: 100%; min-height: 30px; margin-block-start: 8px; padding: 4px 10px 2px; border: 0; background: transparent; color: var(--text-muted); font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; text-align: start; border-radius: var(--r); }
.appnav__acct:hover { background: var(--bg-hover); color: var(--text); }
.appnav__acct[aria-expanded="true"] { color: var(--text); }
.appnav__acct-chev { display: flex; transition: transform 0.15s; }
.appnav__acct[aria-expanded="true"] .appnav__acct-chev { transform: rotate(90deg); }
.appnav__acct-a { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-transform: none; letter-spacing: 0; }
/* Conversation view: one card per message, oldest first. */
.mread__h--thread { gap: 6px; }
.mthread__meta { display: flex; align-items: center; gap: 8px; font-size: 13px; }
/* Conversation-wide actions in the thread header, next to full screen. */
.mthread__acts { display: inline-flex; align-items: center; gap: 2px; }
.mthread__acts .ddwrap { position: relative; }
.mthread { gap: 10px; }
.mthread__m { border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-raised); flex-shrink: 0; }
.mthread__m--open { border-color: var(--brand-line); }
.mthread__hd { display: flex; align-items: center; gap: 10px; padding: 10px 14px; cursor: pointer; border-radius: inherit; }
.mthread__hd:hover { background: var(--bg-hover); }
.mthread__hd .mrow__dot { margin-block-start: 0; }
.mthread__from { font-size: 14px; font-weight: 600; flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mthread__m--unread .mthread__from { font-weight: 700; }
.mthread__prev { flex-grow: 1; min-width: 0; font-size: 13px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mthread__date { flex-shrink: 0; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.mthread__hd--open { padding: 12px 14px; border-block-end: 1px solid var(--border); border-end-start-radius: 0; border-end-end-radius: 0; }
.mthread__hd--open .mread__who { flex-grow: 1; min-width: 0; }
.mthread__m .mread__acts { padding: 10px 14px 0; }
.mthread__body { padding: 12px 14px 16px; display: flex; flex-direction: column; gap: 16px; }
.mthread__body .mbody { flex: 0 0 auto; }
.mthread__body .mhtml { min-height: 200px; border-radius: 8px; }
#app .mread--full .mthread__body .mhtml { min-height: 200px; }
.mread { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; }
/* Full-screen reading: the pane alone over the whole app, header and tab bar
   included; edge-to-edge with safe-area padding on phones. Wins over the
   compact depth rules (which only toggle display) because it is fixed. */
/* z-index 95: above the app, below the modal backdrop (100). It used to be
   120 — above it — so Reply opened the composer *behind* the full-screen
   message and every button looked dead. */
#app .mread--full { position: fixed; inset: 0; z-index: 95; display: flex !important; background: var(--bg); padding-block-start: env(safe-area-inset-top, 0px); padding-block-end: env(safe-area-inset-bottom, 0px); }
#app .mread--full .mread__body { padding-inline: clamp(16px, 4vw, 48px); padding-block-end: 16px; }
#app .mread--full .mbody:not(:has(> .mhtml)) { max-width: 80ch; margin-inline: auto; width: 100%; }
#app .mread--full .mread__h { padding-inline: clamp(16px, 4vw, 48px); }
.mread__h { padding: 18px 24px 14px; border-block-end: 1px solid var(--border); display: flex; flex-direction: column; gap: 12px; }
.mread__subj { font-family: var(--display); font-size: 22px; font-weight: 600; letter-spacing: -0.3px; text-wrap: balance; }
.mread__who { display: flex; align-items: center; gap: 12px; }
.mread__acts { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.mread__body { flex-grow: 1; overflow-y: auto; padding: 20px 24px 28px; display: flex; flex-direction: column; gap: 16px; }
/* Live mail is one rendered document in a frame, so the frame — not the pane —
   is what has to grow: the message gets every pixel under the header, and
   scrolls inside itself like every other mail client. The demo's paragraph
   list keeps its comfortable measure. */
.mbody { display: flex; flex-direction: column; gap: 12px; font-size: 15px; flex: 1 1 auto; min-height: 0; }
.mbody:not(:has(> .mhtml)) { max-width: 70ch; flex-grow: 0; }
.mhtml { flex: 1 1 auto; width: 100%; min-height: 420px; border: 0; border-radius: 10px; background: var(--bg); }
#app .mread--full .mhtml { min-height: 0; }

.matt {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	padding: 8px 12px;
	background: var(--bg-raised);
	text-align: start;
}

.matt:hover { border-color: var(--brand-line); }

.mcard { border: 1px solid var(--brand-line); background: var(--brand-soft); border-radius: var(--r-xl); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; max-width: 70ch; }
.mwarn { border: 1px solid var(--warn-border); background: var(--warn-bg); border-radius: var(--r-lg); padding: 10px 14px; display: flex; gap: 10px; align-items: flex-start; max-width: 70ch; }

.ddwrap { position: relative; }

.dd {
	position: absolute;
	inset-inline-end: 0;
	top: calc(100% + 6px);
	z-index: 60;
	min-width: 246px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: 0 12px 32px rgba(6, 17, 14, 0.24);
	padding: 6px;
	display: flex;
	flex-direction: column;
	gap: 1px;
	max-height: 70dvh;
	overflow-y: auto;
}

.dd button {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 34px;
	padding-inline: 10px;
	border: none;
	background: none;
	border-radius: var(--r);
	font-size: 14px;
	text-align: start;
	width: 100%;
}

.dd button:hover { background: var(--bg-hover); }
.dd__sep { border: none; border-block-start: 1px solid var(--border); margin: 4px 0; }
.dd__l { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted); padding: 6px 10px 2px; }

@media (max-width: 1280px) { .mlist { width: 320px; } }
@media (max-width: 1000px) { .mlist { width: 280px; } }

/* ---- mail, 2026-09: the second look ----
   Rows carry less chrome and more hierarchy: the unread state is a brand bar
   and weight, not a dot; the date sits quiet; quick actions appear where the
   date was when the pointer is on the row. The message is paper on a desk --
   a white sheet in both themes. The toolbar is one row, the folder nav has
   a menu per folder and a way to add one. */
.mlist { width: 400px; background: var(--bg); }
.mlist .appbar { padding: 10px 12px !important; border-block-end: 1px solid var(--border); }
.mlist .input[type=search] { border-radius: 100px; background: var(--bg-subtle); padding-inline: 14px; }
.msec { padding: 14px 16px 6px; font-size: 11px; letter-spacing: .08em; color: var(--text-muted); }
.mrow { position: relative; gap: 12px; padding: 12px 14px 12px 18px; border-block-end: 1px solid color-mix(in oklab, var(--border) 60%, transparent); align-items: flex-start; transition: background .12s ease; }
.mrow::before { content: ''; position: absolute; inset-inline-start: 0; inset-block: 10px; width: 3px; border-radius: 0 3px 3px 0; background: transparent; }
.mrow--unread::before { background: var(--brand); }
.mrow[aria-current="true"] { background: var(--brand-soft); }
.mrow[aria-current="true"]::before { background: var(--brand); inset-block: 0; border-radius: 0; }
.mrow__dot { display: none; }
.mrow .av--sm { width: 36px; height: 36px; font-size: 13px; margin-block-start: 1px; }
.mrow__from { font-size: 14px; font-weight: 500; }
.mrow--unread .mrow__from { font-weight: 700; }
.mrow__date { font-size: 12px; opacity: .85; }
.mrow__subj { font-size: 14px; color: var(--text); }
.mrow--unread .mrow__subj { font-weight: 650; }
.mrow__prev { font-size: 13px; opacity: .8; }
.mrow .mstar { position: absolute; inset-inline-end: 12px; inset-block-end: 10px; opacity: 0; transition: opacity .12s ease; }
.mrow:hover .mstar, .mrow:focus-within .mstar, .mrow .mstar[aria-pressed="true"] { opacity: 1; }
.mrow__quick { position: absolute; inset-inline-end: 10px; inset-block-start: 8px; display: none; gap: 2px; padding: 2px; border-radius: 10px; background: var(--bg-raised); border: 1px solid var(--border); box-shadow: 0 6px 18px -8px rgba(0, 0, 0, .35); }
.mrow:hover .mrow__quick, .mrow:focus-within .mrow__quick { display: inline-flex; }
.mrow:hover .mrow__date, .mrow:focus-within .mrow__date { visibility: hidden; }
.mrow__q { width: 28px; height: 28px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; color: var(--text-muted); cursor: pointer; }
.mrow__q:hover { background: var(--bg-hover); color: var(--text); }
.mrow__q--danger:hover { color: var(--danger); }
@media (hover: none) { .mrow__quick { display: none !important; } .mrow .mstar { opacity: 1; } .mrow:hover .mrow__date { visibility: visible; } }
/* the reading pane */
.mread { background: var(--bg-subtle); }
.mread__h { padding: 16px 24px 12px; background: var(--bg); gap: 10px; }
.mread__subj { font-size: 21px; line-height: 1.25; }
.mread__who .av { width: 40px; height: 40px; font-size: 14px; }
.mread__acts { gap: 6px; padding-block-start: 2px; }
.mread__acts .btn { min-height: 34px; padding-inline: 12px; font-size: 13px; }
.mread__body { padding: 18px 24px 28px; gap: 14px; }
.mhtml { background: #fff; border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 1px 2px rgba(0, 0, 0, .04), 0 14px 40px -24px rgba(0, 0, 0, .35); color-scheme: light; }
.mthread__body .mhtml { border-radius: 10px; }
.matts { display: flex; flex-direction: column; gap: 8px; }
.matts:empty { display: none; }
.matts__t { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
.matts__l { display: flex; gap: 8px; flex-wrap: wrap; }
.matt { gap: 10px; padding: 8px 10px 8px 8px; border-radius: 12px; max-width: 280px; cursor: pointer; }
.matt__ic { width: 34px; height: 34px; border-radius: 9px; background: var(--brand-soft); color: var(--brand); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.matt__b { display: flex; flex-direction: column; min-width: 0; text-align: start; }
.matt__b b { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.matt__b .muted { font-size: 12px; }
.matt__dl { color: var(--text-muted); margin-inline-start: 4px; flex-shrink: 0; }
.matt:hover .matt__dl { color: var(--brand); }
/* the folder nav */
.appnav__row { position: relative; display: flex; align-items: center; }
.appnav__row .appnav__item { flex: 1 1 auto; min-width: 0; }
.appnav__n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.appnav__count { font-size: 11px; font-weight: 700; min-width: 20px; padding: 0 6px; border-radius: 100px; background: color-mix(in oklab, var(--text) 8%, transparent); text-align: center; line-height: 18px; opacity: 1; }
.appnav__item[aria-current="true"] .appnav__count { background: rgba(255, 255, 255, .22); }
.appnav__more { position: absolute; inset-inline-end: 4px; width: 26px; height: 26px; border: 0; border-radius: 7px; background: transparent; color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; opacity: 0; cursor: pointer; }
.appnav__row:hover .appnav__more, .appnav__row.is-menu .appnav__more, .appnav__more:focus-visible { opacity: 1; }
.appnav__row:hover .appnav__count, .appnav__row.is-menu .appnav__count { visibility: hidden; }
.appnav__more:hover { background: var(--bg-hover); color: var(--text); }
.appnav__row.is-cur .appnav__more { color: var(--brand-text); }
.appnav__row.is-cur .appnav__more:hover { background: rgba(255, 255, 255, .18); }
.dd--nav { inset-inline-end: auto; inset-inline-start: 24px; top: calc(100% - 2px); min-width: 210px; }
.dd__danger { color: var(--danger) !important; }
.dd__k { margin-inline-start: auto; padding-inline-start: 14px; font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mread__acts .dd button { white-space: nowrap; }
.appnav__item--quiet { color: var(--text-muted); font-size: 13px; min-height: 32px; margin-block-start: 2px; }
.appnav__item--quiet:hover { color: var(--text); }
@media (hover: none) { .appnav__more { opacity: 1; } .appnav__row .appnav__count { display: none; } }


/* The message is loading (011 mailBodyHtml): a calm layer on the paper
   until the frame has its document. It fades in after 150 ms, so a quick
   open never flashes, and lifts on the frame's load event (.is-loaded).
   The paper is white in both themes, so its colours are fixed. */
.mbody:has(> .mhtml) { position: relative; }
.mbody__wait { position: absolute; inset: 0; z-index: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; border-radius: 14px; background: #fff; color: #5b6b64; font-size: 13px; font-weight: 500; pointer-events: none; animation: mbody-wait-in .25s ease .15s both; transition: opacity .25s ease, visibility 0s linear .25s; }
.mbody__spin { width: 26px; height: 26px; border-radius: 50%; border: 2.5px solid #e3e9e6; border-top-color: #15916B; animation: nuvo-spin .8s linear infinite; }
.mbody.is-loaded .mbody__wait { opacity: 0; visibility: hidden; animation: none; }
@keyframes mbody-wait-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
	.mbody__wait { animation: none; transition: none; }
	.mbody__spin { animation-duration: 2.4s; }
}

/* "Images are hidden to protect your privacy" + Load images (011). */
.mbody__imgs { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 8px 8px 12px; border-radius: 12px; background: color-mix(in srgb, var(--brand) 9%, var(--bg)); border: 1px solid color-mix(in srgb, var(--brand) 22%, transparent); font-size: 13px; color: var(--text); }
.mbody__imgs[hidden] { display: none; }
.mbody__imgs-ic { color: var(--brand); display: inline-flex; }
.mbody__imgs .btn { margin-inline-start: auto; min-height: 30px; padding-inline: 12px; font-size: 12.5px; color: var(--brand); font-weight: 600; }
/* ========================================================== flow */
.flcard { border: 1px solid var(--border); border-radius: var(--r-xl); padding: 14px 16px; display: flex; gap: 14px; align-items: flex-start; }
.flcard__b { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.flcard__n { font-size: 15px; font-weight: 600; }

.flsteps { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.flstep {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 24px;
	padding: 2px 9px;
	border-radius: 100px;
	font-size: 12px;
	font-weight: 600;
	background: var(--bg-subtle);
	color: var(--text-muted);
}

.flstep b { font-weight: 700; color: var(--text); }
.flstep--when { background: var(--brand-soft); color: var(--brand); }
.flstep--when b { color: var(--brand); }
.flstep--then { background: var(--warn-bg); color: var(--warn); }
.flstep--then b { color: var(--warn); }
.flarrow { color: var(--text-muted); display: flex; flex-shrink: 0; }

.builder { max-width: 840px; display: flex; flex-direction: column; gap: 16px; }
.bstage { border: 1px solid var(--border); border-radius: var(--r-xl); overflow: hidden; }
.bstage__h { display: flex; align-items: center; gap: 10px; padding: 11px 16px; background: var(--bg-subtle); border-block-end: 1px solid var(--border); }

.bstage__n {
	width: 24px;
	height: 24px;
	border-radius: 100px;
	background: var(--brand);
	color: var(--brand-text);
	font-size: 12px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.bstage__t { font-size: 14px; font-weight: 600; }
.bstage__b { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; }

.brow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.brow > .select, .brow > .input { width: auto; flex: 1 1 150px; min-width: 130px; }

.bsummary { padding: 12px 16px; border-radius: var(--r-lg); background: var(--brand-soft); font-size: 14px; line-height: 1.7; }
.bsummary b { color: var(--brand); }

.fltpl { border: 1px solid var(--border); border-radius: var(--r-lg); padding: 12px 14px; text-align: start; background: var(--bg); width: 100%; display: flex; flex-direction: column; gap: 4px; }
.fltpl:hover { border-color: var(--brand); background: var(--bg-hover); }

/* ======================================================== queues */
.qapp { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; background: var(--bg); }

.qhead { flex-shrink: 0; display: flex; align-items: center; gap: 16px; padding: 16px 24px 12px; flex-wrap: wrap; }
.qtitle { font-family: var(--display); font-size: 22px; font-weight: 600; letter-spacing: -0.4px; }

.seg { display: flex; gap: 2px; padding: 3px; background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--r); }
.seg button { min-height: 30px; padding-inline: 14px; border: none; background: transparent; border-radius: var(--r-sm); font-size: 13px; font-weight: 600; color: var(--text-muted); }
.seg button[aria-pressed="true"] { background: var(--bg); color: var(--text); box-shadow: 0 1px 2px rgba(6, 17, 14, 0.14); }

.wip { margin: 0 24px 14px; display: flex; gap: 12px; align-items: flex-start; padding: 12px 14px; border-radius: var(--r-lg); background: var(--warn-bg); border: 1px solid var(--warn-border); }
.wip__t { font-size: 12px; font-weight: 700; color: var(--warn); text-transform: uppercase; letter-spacing: 0.4px; }
.wip__x { font-size: 13px; max-width: 92ch; }

.wip-badge {
	height: 16px;
	padding-inline: 6px;
	border-radius: 100px;
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	display: inline-flex;
	align-items: center;
	background: var(--warn-bg);
	color: var(--warn);
	border: 1px solid var(--warn-border);
}

.hdr .wip-badge { background: rgba(255, 138, 61, 0.18); color: #ffb070; border-color: rgba(255, 138, 61, 0.36); }
.tab .wip-badge, .prov .wip-badge { transform: translateY(-1px); }

.qbody { flex-grow: 1; min-height: 0; overflow: auto; padding: 0 24px 24px; }
.qcols { display: flex; gap: 16px; align-items: flex-start; }
.qmain { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.qside { flex: 0 0 320px; display: flex; flex-direction: column; gap: 16px; }

.panel { border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--bg); }
.panel__h { padding: 14px 18px 8px; display: flex; align-items: center; gap: 10px; }
.panel__t { font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-muted); }
.panel__b { padding: 0 18px 16px; display: flex; flex-direction: column; gap: 8px; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 12px; }
.kpi { border: 1px solid var(--border); border-radius: var(--r-xl); padding: 14px 16px; display: flex; flex-direction: column; gap: 1px; }
.kpi--warn { background: var(--warn-bg); border-color: var(--warn-border); }
.kpi__l { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.kpi__v { font-family: var(--display); font-size: 29px; font-weight: 600; letter-spacing: -0.5px; line-height: 1.15; font-variant-numeric: tabular-nums; }
.kpi__x { font-size: 12px; color: var(--text-muted); }

.qcall { border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--bg-raised); padding: 18px 20px; display: flex; flex-direction: column; gap: 16px; }
.qcall__top { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.qcall__name { font-family: var(--display); font-size: 22px; font-weight: 600; letter-spacing: -0.3px; }
.qcall__timer { font-family: var(--display); font-size: 32px; font-weight: 600; letter-spacing: -0.5px; font-variant-numeric: tabular-nums; line-height: 1.1; }
.qcall__ctrls { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.qcall__ctrls .btn[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }

.tag { height: 22px; padding-inline: 9px; border-radius: 100px; font-size: 12px; font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.tag--brand { background: var(--brand-soft); color: var(--brand); }
.tag--mute { background: var(--bg-subtle); color: var(--text-muted); }
.tag--warn { background: var(--warn-bg); color: var(--warn); }

.qstate { display: flex; flex-direction: column; gap: 3px; }
.qstate button { min-height: 34px; border-radius: var(--r); border: none; background: transparent; display: flex; align-items: center; gap: 9px; padding-inline: 10px; font-size: 14px; text-align: start; width: 100%; }
.qstate button:hover { background: var(--bg-hover); }
.qstate button[aria-pressed="true"] { background: var(--brand); color: var(--brand-text); font-weight: 600; }

.qwait { border: 1px solid var(--border); border-radius: var(--r-lg); padding: 11px 12px; display: flex; align-items: center; gap: 12px; }
.qwait--sla { background: var(--warn-bg); border-color: var(--warn-border); }
.qwait__t { font-family: var(--display); font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }

.qtbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.qtbl th { text-align: start; font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-muted); padding: 10px 12px; border-block-end: 1px solid var(--border); }
.qtbl td { padding: 11px 12px; border-block-end: 1px solid var(--border); vertical-align: middle; }
.qtbl tr[data-mon="1"] { background: var(--brand-soft); }
.qtbl .num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }

.mon { display: flex; gap: 6px; justify-content: flex-end; }
.mon .btn { min-height: 32px; padding-inline: 11px; font-size: 12px; }
.mon .btn[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }

.rule { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; }
.rule > svg { flex-shrink: 0; margin-block-start: 2px; color: var(--brand); }

.alert { display: flex; gap: 10px; padding: 11px 12px; border-radius: var(--r-lg); border: 1px solid var(--border); }
.alert--warn { background: var(--warn-bg); border-color: var(--warn-border); }

@media (max-width: 1100px) {
	.qcols { flex-direction: column; }
	.qside { flex: 1 1 auto; width: 100%; }
}

/* ====================================================== contacts
   The vocabulary here is CardDAV's, because that is what Nextcloud
   Contacts actually is. Address books hold vCards. A "group" is a
   CATEGORIES value written on the card, never a container a card is
   moved into — so groups are derived from the cards on every render
   and the last card leaving a category takes the category with it.

   Structure classes are borrowed from Mail deliberately: .appnav,
   .mlist and .mread are the three names responsive-layout.css already
   maps onto data-depth 0/1/2, so the phone drill-down works here
   without one new media query. Everything below is skin, not layout. */

.ctlist { width: 340px; }

.ctrow {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 9px 14px;
	min-height: calc(var(--tap) + 12px);
	width: 100%;
	text-align: start;
	background: none;
	border: none;
	border-block-end: 1px solid var(--border);
}

.ctrow:hover { background: var(--bg-hover); }
.ctrow[aria-current="true"] { background: var(--brand-soft); }
.ctrow__b { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ctrow__n { font-size: 14.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctrow__s { font-size: 12.5px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The detail column. .mread supplies the column behaviour. */
.ctcard { padding: 26px 24px 20px; border-block-end: 1px solid var(--border); display: flex; flex-direction: column; gap: 18px; }
.ctcard__top { display: flex; gap: 16px; align-items: center; }
.ctcard__id { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ctcard__n { font-family: var(--display); font-size: 24px; font-weight: 600; letter-spacing: -0.3px; text-wrap: balance; }
.ctcard__o { font-size: 14px; color: var(--text-muted); }
.ctcard__p { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-muted); }
.ctcard__acts { display: flex; gap: 8px; flex-wrap: wrap; }

.av--lg { width: 68px; height: 68px; font-size: 24px; border-radius: 100px; }

.ctbody { flex-grow: 1; overflow-y: auto; padding: 6px 24px 28px; }

.ctf { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-block-end: 1px solid var(--border); }
.ctf:last-child { border-block-end: none; }
.ctf__ic { color: var(--text-muted); display: flex; flex-shrink: 0; }
.ctf__b { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ctf__l { font-size: 11px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.ctf__v { font-size: 15px; overflow-wrap: anywhere; }

.ctchips { display: flex; gap: 6px; flex-wrap: wrap; }

.ctchip {
	height: 25px;
	padding-inline: 11px;
	border-radius: 100px;
	background: var(--brand-soft);
	border: 1px solid var(--brand-line);
	font-size: 12px;
	font-weight: 600;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

.ctbadge {
	font-size: 10.5px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	padding: 2px 8px;
	border-radius: 100px;
	border: 1px solid var(--border-strong);
	color: var(--text-muted);
	white-space: nowrap;
}

.ctempty { padding: 48px 24px; text-align: center; color: var(--text-muted); display: flex; flex-direction: column; align-items: center; gap: 10px; }
.ctempty__t { font-family: var(--display); font-size: 17px; font-weight: 600; color: var(--text); }

/* The read-only notice on a system card. Quiet: it explains a missing
   affordance, it is not a warning about anything the user did. */
.ctro { display: flex; gap: 10px; align-items: flex-start; font-size: 12.5px; color: var(--text-muted); padding: 12px 14px; background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--r); }

/* On a phone you land on the list, not the address books, so the list
   needs its own way to add a card. Sits in the appbar next to search
   rather than floating: a FAB would have to clear the safe-area insets
   platform.css owns, and this needs no such coordination.

   Hidden on desktop, where .appnav is on screen already carrying a
   full-width New contact button. Two of them made .appbar wrap and put
   a stray + on a row of its own. */
.ctadd { display: none; flex-shrink: 0; }

@media (max-width: 767.98px) {
	.ctlist .appbar { flex-wrap: nowrap; }
	.ctlist .appbar .input { min-width: 0; }
	.ctadd { display: inline-flex; }
}

@media (max-width: 1180px) { .side { display: none; } }
@media (max-width: 900px) {
	.hdr__brand { width: auto; }
	.hdr__apps { display: none; }
	.list { width: 240px; }
}
/* ====================================================== drafts dock

   The docked cards for the universal draft system. Bottom-inline-end,
   the way a minimised composer sits in LinkedIn or Gmail, because that
   corner is the one place in this shell nothing else claims: the toast
   is bottom-centre, the modal is a centred backdrop, and there is no
   bottom nav on compact.

   z-index 95 is chosen, not inherited. It clears the dropdowns (60) and
   the launcher and profile menus (90), and stays under the modal
   backdrop (100), the photo lightbox (120), the film (300) and the
   toast (200) — so a draft card can never sit on top of something the
   user has deliberately opened.
*/

.dfdock {
	position: fixed;
	inset-block-end: 18px;
	inset-inline-end: 18px;
	z-index: 95;
	display: flex;
	align-items: flex-end;
	gap: 6px;
	flex-wrap: wrap-reverse;
	justify-content: flex-end;
	max-width: min(680px, calc(100vw - 36px));
	pointer-events: none;
}

.dfdock[hidden] { display: none; }

/* ---- the compact handle ----
   Hidden entirely on a pointer-sized screen: there the dock has room
   and a summary pill would be a lid on an open box. It exists for
   compact, where it is the whole dock until you ask for more. */
.dfdock__handle { display: none; }

.dfpip {
	width: 7px;
	height: 7px;
	border-radius: 100px;
	flex-shrink: 0;
}
.dfpip--chat { background: var(--df-chat); }
.dfpip--mail { background: var(--df-mail); }
.dfpip--cal { background: var(--df-cal); }
.dfpip--contact { background: var(--df-contact); }

/* The kind palette. Hues are borrowed from the shell's own avatar
   colours rather than invented, so the dock reads as part of the
   product. `-ink` is the same hue lifted for use as a mark on a dark
   surface; the base value is the filled-chip colour and needs no
   adjustment because it always carries white on top of it.

   Declared on bare :root first, then overridden in BOTH dark selectors
   — the media query for viewers on system-dark, and the attribute for
   an explicit toggle — which is the pattern the rest of this stylesheet
   follows. */
:root {
	--df-chat: var(--brand);
	--df-chat-ink: var(--brand);
	--df-mail: #3B5C8A;
	--df-mail-ink: #3B5C8A;
	--df-cal: #8A5A32;
	--df-cal-ink: #8A5A32;
	--df-contact: #6A4B8A;
	--df-contact-ink: #6A4B8A;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--df-mail-ink: #7FA6D9;
		--df-cal-ink: #D69C63;
		--df-contact-ink: #AC8CD6;
	}
}

:root[data-theme="dark"] {
	--df-mail-ink: #7FA6D9;
	--df-cal-ink: #D69C63;
	--df-contact-ink: #AC8CD6;
}

/* ---- one stack per kind ----

   Collapsed, the cards in a stack are absolutely placed and lifted by
   DF_STEP each, so the title row of every card behind stays readable —
   a deck you can read is browsable; a deck you can only see the top of
   is decoration. Expanded, the same cards become an ordinary column. */

.dfstack {
	pointer-events: auto;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 7px;
	width: 310px;
	max-width: 100%;
}

.dfstack__cards { position: relative; }

/* ---- the deck, and how it opens ----

   THE RULE THIS IS BUILT ON: a stack may overlap, but it must never
   slice content. At rest the cards are stepped by DF_CLOSED, which is
   chosen to clear the avatar chip completely — a peek that cuts an icon
   in half looks like a rendering fault, not a design.

   On hover the whole deck FANS OPEN rather than lifting one card out of
   it. That is the part that matters. Lifting a single card leaves the
   remaining cards in their resting order, so the one you are pointing at
   sits above its neighbour while that neighbour still sits above the
   front card — a layering sandwich the eye reads as broken. Separating
   every card removes the overlap entirely, so there is no z-order left
   to misread, and all three are legible at once.

   TWO STEPS, WRITTEN AS LITERALS — 33px closed, 45px open. The card is
   ~42px tall and its avatar chip ends ~33px in, so 33 is the smallest
   step that clears the icon, and 45 leaves a ~3px seam when open. Both
   follow the CARD height: shrink the card and these must be re-measured,
   or the peek starts slicing icons again.

   These were briefly a single `--step` custom property that the hover
   rule reassigned. Do not put it back. A custom property used inside
   calc() for a TRANSITIONED property does not reliably invalidate the
   value that depends on it: `--step` computed correctly as 54px on
   every card while `inset-block-end` stayed at the old 39px multiple,
   so the fan silently refused to open. It appeared to work under some
   timings and not others, which is worse than a clean failure.

   `--i` and `--n` stay as custom properties because they are STATIC —
   set once at render, never animated, never reassigned. That is the
   distinction that makes them safe here. */

.dfstack:not(.dfstack--open) .dfstack__cards {
	height: calc(42px + (var(--n) - 1) * 33px);
	transition: height 0.2s cubic-bezier(0.22, 0.8, 0.3, 1);
}

.dfstack:not(.dfstack--open) .dfstack__cards > .dfcard {
	position: absolute;
	inset-inline: 0;
	inset-block-end: calc(var(--i) * 33px);
	transition: transform 0.14s ease-out, box-shadow 0.14s ease-out;
}

/* THE DECK NO LONGER FANS ON HOVER, AND THAT IS A FIX, NOT A REGRESSION.

   A click needs mousedown and mouseup on the SAME element. The fan moved
   every card except the front one 12px upward the instant the pointer
   arrived, so aiming at a buried card slid it out from under the cursor
   between the two halves of the click — the event then resolved to a
   common ancestor with no data-act and nothing happened at all. The
   front card, which never moved, stayed clickable throughout, which is
   exactly why only the cards behind it felt dead.

   Never move the thing the user is aiming at. The fan was introduced to
   resolve a three-card layering sandwich; at DF_PEEK 2 there is a single
   overlap with an unambiguous order (front over back), so it has nothing
   left to solve and costs a broken click. Hover now only lifts the card
   in place. */

/* Cards behind the front one are tinted back so the front card reads
   as the live one. They stay fully clickable on their exposed strip. */
.dfcard--behind { filter: saturate(0.82); }
.dfcard--behind::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: var(--bg);
	opacity: 0.32;
	pointer-events: none;
	transition: opacity 0.14s ease-out;
}

/* Once the fan is open every card is fully visible, so the tint that
   marked them as "buried" has no job left and would only make the open
   deck look muddy. */
.dfstack:hover .dfcard--behind,
.dfstack:focus-within .dfcard--behind { filter: none; }
.dfstack:hover .dfcard--behind::after,
.dfstack:focus-within .dfcard--behind::after { opacity: 0; }

/* The card actually under the pointer still lifts a little — the fan
   says "here is everything", this says "and this is the one you are
   about to click". z-index is !important because the resting order is
   an inline style, which a normal rule cannot beat. */
.dfstack:not(.dfstack--open) .dfstack__cards > .dfcard:hover,
.dfstack:not(.dfstack--open) .dfstack__cards > .dfcard:focus-within {
	z-index: 40 !important;
	transform: translateY(-2px);
	box-shadow: 0 16px 38px rgba(6, 17, 14, 0.24), 0 3px 8px rgba(6, 17, 14, 0.12);
}

.dfstack--open .dfstack__cards {
	display: flex;
	flex-direction: column-reverse;
	gap: 7px;
	max-height: min(62vh, 620px);
	overflow-y: auto;
	overflow-x: hidden;
	padding: 2px;
	margin: -2px;
}

/* The "···  2 more emails" control, and its Collapse counterpart. */
.dfstack__more {
	pointer-events: auto;
	appearance: none;
	cursor: pointer;
	display: flex;
	align-items: center;
	gap: 8px;
	align-self: flex-end;
	background: var(--bg-raised);
	color: var(--text-muted);
	border: 1px solid var(--border);
	border-radius: 100px;
	padding: 5px 13px;
	font: inherit;
	font-size: 12px;
	font-weight: 600;
	box-shadow: 0 4px 14px rgba(6, 17, 14, 0.12);
}

/* The button tints to its own stack's colour too, so the control and
   the pile it opens are visibly one object. */
.dfstack__more:hover {
	color: var(--kind-ink, var(--brand));
	border-color: color-mix(in oklab, var(--kind-ink, var(--brand)) 40%, var(--border));
}
.dfstack__more:focus-visible {
	outline: 2px solid var(--kind-ink, var(--brand));
	outline-offset: 2px;
}

.dfstack__dots {
	letter-spacing: 0.1em;
	font-size: 13px;
	line-height: 1;
	color: var(--kind-ink, var(--brand));
}

.dfstack__more--less { color: var(--text-muted); }

.dfcard {
	pointer-events: auto;
	display: flex;
	align-items: stretch;
	background: var(--bg-raised);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: 0 10px 28px rgba(6, 17, 14, 0.16), 0 2px 6px rgba(6, 17, 14, 0.08);
	/* NOT overflow:hidden — the snooze menu opens outside the card and
	   would be clipped by it. The inner buttons round their own outer
	   corners instead, which is what the overflow was doing for them. */
	position: relative;
	max-width: 310px;
	animation: dfrise 0.34s cubic-bezier(0.16, 0.84, 0.44, 1) both;
}

/* The whole body of the card is the button — a small target for a
   feature whose entire promise is "one click back to your work" would
   be a poor joke. */
.dfcard__go {
	appearance: none;
	border: 0;
	background: transparent;
	font: inherit;
	color: inherit;
	cursor: pointer;
	display: flex;
	align-items: center;
	gap: 9px;
	padding: 6px 4px 6px 9px;
	min-width: 0;
	flex: 1 1 auto;
	text-align: start;
	min-height: var(--tap, 44px);
}

.dfcard__go:hover { background: var(--bg-hover); }
.dfcard__go:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

.dfcard__ic {
	flex-shrink: 0;
	width: 24px;
	height: 24px;
	border-radius: 7px;
	display: grid;
	place-items: center;
	color: #fff;
}

/* Kind is carried by colour as well as glyph, so the two draft types
   are told apart at a glance without reading anything. */
/* ---- one accent per kind ----

   Each stack carries its own colour, and BOTH the icon chip and the
   "···" of its more-button take it from the same custom property. That
   is the point: a green ··· sitting under a blue stack reads as a
   control that belongs to something else, and the eye has to work out
   which pile it opens.

   Two values per kind, not one. The chip is a filled swatch carrying
   white glyphs, so it wants the saturated colour on both themes. The
   dots are bare marks on the card's own surface, so on a dark ground
   they need the lifted variant or they disappear into it. Same hue,
   different job. */
.dfstack[data-kind="chat"] {
	--kind: var(--df-chat); --kind-ink: var(--df-chat-ink); --kind-fg: var(--brand-text);
}
.dfstack[data-kind="mail"] {
	--kind: var(--df-mail); --kind-ink: var(--df-mail-ink); --kind-fg: #fff;
}
.dfstack[data-kind="cal"] {
	--kind: var(--df-cal); --kind-ink: var(--df-cal-ink); --kind-fg: #fff;
}
.dfstack[data-kind="contact"] {
	--kind: var(--df-contact); --kind-ink: var(--df-contact-ink); --kind-fg: #fff;
}

/* Fallbacks keep a card correct if it is ever rendered outside a stack. */
.dfcard__ic {
	background: var(--kind, var(--brand));
	color: var(--kind-fg, var(--brand-text));
}

.dfcard__tx {
	display: flex;
	flex-direction: column;
	min-width: 0;
	gap: 1px;
}

.dfcard__t {
	font-size: 12.5px;
	font-weight: 700;
	line-height: 1.2;
	color: var(--text);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.dfcard__s {
	font-size: 11px;
	line-height: 1.25;
	color: var(--text-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Snooze and discard. Both quiet until hovered — the card's job is to
   be a way back to your work, not a control panel. */
.dfcard__b {
	pointer-events: auto;
	appearance: none;
	border: 0;
	border-inline-start: 1px solid var(--border);
	background: transparent;
	color: var(--text-muted);
	cursor: pointer;
	padding: 0 8px;
	display: grid;
	place-items: center;
	flex-shrink: 0;
}

.dfcard__b:hover { background: var(--bg-hover); color: var(--text); }
.dfcard__b:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.dfcard__x:hover { color: var(--danger); }
.dfcard--open .dfcard__b[data-act="df-snooze"] { background: var(--bg-hover); color: var(--brand); }

/* ---- the snooze menu ----
   Opens UPWARD out of the card, because the card is already at the
   bottom of the viewport and a downward menu would be off screen. */
.dfmenu {
	position: absolute;
	inset-block-end: calc(100% + 8px);
	inset-inline-end: 0;
	min-width: 210px;
	background: var(--bg-raised);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: 0 14px 36px rgba(6, 17, 14, 0.22), 0 2px 6px rgba(6, 17, 14, 0.1);
	padding: 5px;
	z-index: 2;
	animation: dfrise 0.16s ease-out both;
}

.dfmenu__h {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-muted);
	padding: 7px 10px 6px;
}

.dfmenu__o {
	appearance: none;
	border: 0;
	background: transparent;
	font: inherit;
	color: var(--text);
	cursor: pointer;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 14px;
	padding: 8px 10px;
	border-radius: var(--r-sm);
	text-align: start;
	font-size: 13.5px;
	min-height: 36px;
}

.dfmenu__o:hover { background: var(--brand-soft); color: var(--brand); }
.dfmenu__o:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* The landing time, in tabular figures so the column lines up. */
.dfmenu__t {
	font-size: 12px;
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
	flex-shrink: 0;
}

.dfmenu__o:hover .dfmenu__t { color: var(--brand); }

/* The corners the removed overflow:hidden used to handle. */
.dfcard__go {
	border-start-start-radius: var(--r-lg);
	border-end-start-radius: var(--r-lg);
}
.dfcard__x {
	border-start-end-radius: var(--r-lg);
	border-end-end-radius: var(--r-lg);
}

/* A quiet pulse on the card that was just updated, so a draft saved
   while you are elsewhere announces itself once rather than appearing
   silently and being missed. */
.dfcard--fresh { animation: dfrise 0.34s cubic-bezier(0.16, 0.84, 0.44, 1) both, dfglow 1.5s ease-out 0.34s 1; }

@keyframes dfrise {
	from { opacity: 0; transform: translateY(14px) scale(0.97); }
	to   { opacity: 1; transform: none; }
}

@keyframes dfglow {
	0%   { box-shadow: 0 10px 28px rgba(6, 17, 14, 0.16), 0 0 0 0 var(--brand-line); }
	40%  { box-shadow: 0 10px 28px rgba(6, 17, 14, 0.16), 0 0 0 3px var(--brand-line); }
	100% { box-shadow: 0 10px 28px rgba(6, 17, 14, 0.16), 0 0 0 0 transparent; }
}

@media (prefers-reduced-motion: reduce) {
	.dfcard, .dfcard--fresh { animation: none; }
	/* The fan still opens — it just snaps instead of sliding. Removing
	   the motion must not remove the behaviour. */
	.dfstack:not(.dfstack--open) .dfstack__cards,
	.dfstack:not(.dfstack--open) .dfstack__cards > .dfcard { transition: none; }
	.dfstack:not(.dfstack--open) .dfstack__cards > .dfcard:hover { transform: none; }
	.dfcard--behind::after { transition: none; }
	.dfdock__chev { transition: none; }
}

/* On a phone the dock spans the width and the cards stack, because two
   300px cards side by side do not fit and a horizontally scrolling
   dock is worse than a taller one. */
@media (max-width: 767.98px) {
	/* THE TAB BAR OUTRANKS THE DOCK.

	   `.hdr__apps` is the bottom navigation on compact and sits at
	   z-index 95 — the same as the dock, which meant the dock won on
	   source order and covered the way out of every screen. Losing
	   navigation to a draft card is a far worse failure than a draft
	   being one tap further away, so the dock drops to 94 AND clears the
	   bar's height outright. Two defences, because relying on the
	   z-index alone would still let a tall stack sit over the bar during
	   a transition. */
	.dfdock {
		z-index: 94;
		inset-inline: 10px;
		inset-block-end: calc(var(--tabbar-h) + var(--sab, 0px) + 10px);
		max-width: none;
		flex-direction: column;
		align-items: stretch;
		gap: 8px;
	}

	.dfcard { max-width: none; }
	.dfstack { width: auto; }

	/* Folded in, the dock is just the pill. Folded out, the stacks
	   appear above it and it becomes the way back. */
	.dfdock:not(.dfdock--open) .dfstack { display: none; }

	.dfdock__handle {
		display: flex;
		pointer-events: auto;
		align-self: flex-end;
		align-items: center;
		gap: 9px;
		appearance: none;
		cursor: pointer;
		background: var(--bg-raised);
		color: var(--text);
		border: 1px solid var(--border);
		border-radius: 100px;
		padding: 8px 14px;
		font: inherit;
		font-size: 13px;
		font-weight: 600;
		/* 44px outright rather than the shell's --tap (34px). This is the
		   only way to reach your drafts on a phone; it earns a full-size
		   touch target even though the surrounding chrome runs smaller. */
		min-height: 44px;
		box-shadow: 0 8px 24px rgba(6, 17, 14, 0.22);
	}

	.dfdock__handle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
	.dfdock__pips { display: flex; gap: 3px; align-items: center; }
	.dfdock__count { white-space: nowrap; }

	.dfdock__chev {
		display: grid;
		place-items: center;
		color: var(--text-muted);
		transition: transform 0.18s ease-out;
	}
	/* Chevron points the way the tap will move things: up to reveal,
	   down to put away. */
	.dfdock:not(.dfdock--open) .dfdock__chev { transform: rotate(-90deg); }
	.dfdock--open .dfdock__chev { transform: rotate(90deg); }

	.dfstack--open .dfstack__cards { max-height: 42vh; }
}
/* ============================================================
   Appended by _integrate.py. Order is load-bearing:
   app CSS -> responsive-layout.css -> platform.css
   ============================================================ */

/* ===================================================== language dropdown */
/* Built on the app's existing .dd idiom so it reads as native furniture:
   a .select-shaped trigger, a floating panel, brand-soft active row. */
.flag { display: block; flex-shrink: 0; border-radius: 3.2px; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .3)); }

.lang-wrap { position: relative; display: inline-flex; }

.lang-trigger {
	display: inline-flex; align-items: center; gap: 10px;
	min-height: var(--tap); min-width: 190px;
	padding: 6px 10px;
	border: 1px solid var(--border-strong); border-radius: var(--r);
	background: var(--bg); color: var(--text);
	font: inherit; font-size: 14px; font-weight: 500;
	cursor: pointer; text-align: start;
	transition: border-color 140ms ease, box-shadow 140ms ease, background 140ms ease;
}
.lang-trigger:hover { background: var(--bg-hover); border-color: var(--brand); }
.lang-trigger[aria-expanded="true"] { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.lang-trigger:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.lang-trigger__n { flex-grow: 1; }
.lang-caret { flex-shrink: 0; color: var(--text-muted); transition: transform 200ms cubic-bezier(.2, .7, .3, 1); }
.lang-trigger[aria-expanded="true"] .lang-caret { transform: rotate(180deg); color: var(--brand); }

.lang-dd {
	position: absolute; inset-inline-end: 0; top: calc(100% + 6px); z-index: 70;
	min-width: 232px; max-width: min(300px, calc(100vw - 32px));
	background: var(--bg);
	border: 1px solid var(--border); border-radius: var(--r-lg);
	box-shadow: 0 14px 38px rgba(6, 17, 14, .28);
	padding: 6px; display: flex; flex-direction: column; gap: 1px;
	transform-origin: top right;
	animation: langDrop 170ms cubic-bezier(.2, .7, .3, 1);
}
@keyframes langDrop {
	from { opacity: 0; transform: translateY(-6px) scale(.97); }
	to   { opacity: 1; transform: none; }
}

.lang-opt {
	display: flex; align-items: center; gap: 10px;
	min-height: var(--tap); padding: 4px 10px;
	border: none; background: none; border-radius: var(--r);
	font: inherit; font-size: 14px; color: var(--text);
	text-align: start; width: 100%; cursor: pointer;
}
.lang-opt:hover { background: var(--bg-hover); }
.lang-opt:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.lang-opt__n { flex-grow: 1; display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.lang-opt__s { font-size: 11px; color: var(--text-muted); font-weight: 400; }
.lang-opt[aria-selected="true"] { background: var(--brand-soft); font-weight: 600; }
.lang-opt__c { flex-shrink: 0; color: var(--brand); opacity: 0; }
.lang-opt[aria-selected="true"] .lang-opt__c { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
	.lang-dd { animation: none; }
	.lang-caret { transition: none; }
}

/* ---------- responsive-layout.css ---------- */
/* ------------------------------------------------------------------
   Base state for the compact-only affordances.
   Without this they render on desktop: .ibtn sets display:flex and the
   compact rule only ever turns them ON. Verified visible at 1386px.
   ------------------------------------------------------------------ */
.nav-back, .nav-info { display: none; }

/* ==========================================================================
   NuvoCloud Talk+ — responsive layout architecture
   --------------------------------------------------------------------------
   Paste at the END of the existing <style> block (after the current
   `@media (max-width: 900px)` rules on line 2718–2722). Everything here
   relies on source order to win, so specificity stays as low as possible
   and !important is used only where an inline style has to be beaten
   (three places, each flagged).

   DESKTOP IS NOT TOUCHED. Every rule below is gated on one of:
     • a max-width media query at or below 1180px, or
     • @media (pointer: coarse)   — a desktop mouse reports `fine`, so
       nothing in that layer applies to the approved desktop design, or
     • a @container query on .modal / .qbody, which only narrows layouts
       that were already overflowing at that container width.

   Class names used below all exist in talkplus-prototype-v2.html except
   the ones marked  *** NEW MARKUP *** — those need the DOM changes listed
   in responsive-notes.md. They are inert until that markup lands.

   --------------------------------------------------------------------------
   INTEROP WITH agent-out/platform.css (the safe-area / viewport layer)
   --------------------------------------------------------------------------
   That file styles ~18 of the same selectors at top level, unprefixed:
   .rail .chat__scroll .scrollpane .toolbar .cwrap .mread__body .qbody
   .composer .backdrop .toast .ph-view__top .modal .modal--tall .pm .dd
   .mk-hall .mk-plane .side.
   Every rule below that touches one of those carries a redundant `body `
   prefix. That is deliberate: it raises specificity from (0,1,0) to
   (0,1,1) so the two files compose regardless of which is pasted first,
   and each such rule folds the platform tokens back in itself —
   var(--sal, 0px) / --sar / --sat / --sab / --kb, always with a 0px
   fallback so this file also stands alone if platform.css is dropped.
   Nothing here sets a padding/inset SHORTHAND on a shared selector.
   ========================================================================== */


/* ==========================================================================
   0 · BREAKPOINT SCALE
   --------------------------------------------------------------------------
   CSS has no @custom-media, so the numbers are literal. The scale is:

     compact      ≤  767px   phone portrait + phone landscape + split view
       ├ xs        ≤  359px   iPhone SE / narrow Android
       └ sm       ≥  400px   large phone — one extra photo column, etc.
     medium    768 – 1023px   tablet portrait, phone landscape on big phones
     wide     1024 – 1180px   tablet landscape, small laptop
     full        ≥ 1181px    the approved desktop design — UNTOUCHED
                             (1181 because the existing `.side` rule already
                              draws the line at 1180)

   Orthogonal axes, deliberately NOT tied to width:
     @media (pointer: coarse)                       → touch sizing
     @media (hover: none)                           → reveal hover-only affordances
     @media (max-height: 520px) and (orientation: landscape) → short viewport
   ========================================================================== */


/* ==========================================================================
   1 · TOKENS
   --------------------------------------------------------------------------
   Layout tokens live on bare :root only — they carry no colour, so they do
   not need a per-theme variant. The one colour token added here
   (--nav-hairline) follows the project's three-state pattern exactly.
   ========================================================================== */

:root {
	/* height of the phone bottom tab bar (the repurposed .hdr__apps) */
	--tabbar-h: 56px;
	/* height of the Spaces rail when it lies down as a horizontal strip */
	--rail-h: 62px;
	/* one page gutter, so every pane breathes identically on phones */
	--gutter: 14px;
	/* the hairline between chrome surfaces (tab bar top edge, rail edge) */
	--nav-hairline: rgba(255, 255, 255, 0.10);
}

@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--nav-hairline: rgba(255, 255, 255, 0.07);
	}
}

:root[data-theme="dark"] {
	--nav-hairline: rgba(255, 255, 255, 0.07);
}


/* ==========================================================================
   2 · COARSE-POINTER LAYER — 44 × 44 minimum, without wrecking desktop
   --------------------------------------------------------------------------
   The whole design system already routes its clickable height through
   --tap (34px) and --header-h (44px). Re-pointing those two tokens does
   most of the work in one move; the rest of this block catches the controls
   that hard-code their own size.

   `pointer: coarse` describes the PRIMARY input device. A laptop with a
   touchscreen still reports `fine`, so this layer is invisible on the
   demo machine and on every reviewer's desktop.
   ========================================================================== */

@media (pointer: coarse) {
	:root {
		--tap: 44px;        /* .btn .ibtn .input .select .textarea .chan .hdr__app .launch__btn */
		--header-h: 52px;   /* the header has to grow to hold a 44px control */
	}

	/* --- iOS Safari auto-zooms any focused field below 16px. Never. ------ */
	input, textarea, select,
	.input, .select, .textarea,
	.composer__input,
	.set__c .input, .set__c .select {
		font-size: 16px;
	}
	/* the composer inherits `font: inherit` from body (15px) — pin it */
	.composer__input { font-size: 16px; line-height: 24px; }

	/* --- controls that size themselves rather than using --tap ---------- */
	.appnav__item,
	.set__item,
	.cal-item,
	.pm__item,
	.pm__state,
	.qstate button,
	.dd button { min-height: 44px; }

	.seg button { min-height: 38px; }          /* +3px seg padding each side = 44 */
	.pm__preset { height: 36px; }
	.ed__chip { height: 40px; }
	.ph-day__sel { min-height: 40px; padding-inline: 12px; }
	.crumbs button { min-height: 36px; padding-inline: 8px; }

	.rail__tile { width: 44px; height: 44px; }
	.rail__item { width: 52px; }

	.tabstrip { min-height: 52px; }
	.tab { padding-inline: 14px; }
	.tab__x { width: 40px; height: 40px; align-items: center; justify-content: center; margin-inline-start: 4px; }

	.sect { padding-block: 16px 4px; }
	.sect__toggle { min-height: 40px; }
	.sect__btn { width: 40px; height: 40px; align-items: center; justify-content: center; padding: 0; }

	.mstar, .fstar { width: 44px; height: 44px; align-items: center; justify-content: center; padding: 0; }

	.mk__ibtn { width: 44px; height: 44px; }
	.mk__skip { height: 44px; }

	/* denser tables get taller rows on touch — desktop density is untouched */
	.tbl td, .qtbl td { padding-block: 15px; }

	/* .chan carries an inline style="min-height:42px" on chat rows
	   (talkplus-prototype-v2.html line 3929). Inline styles can only be
	   beaten with !important. Removing that inline style is listed as an
	   optional JS clean-up in responsive-notes.md; until then, this. */
	.chan { min-height: 44px !important; }

	/* --- hit-area expansion: keep the DOT small, make the TARGET big ----
	   Used where growing the visible control would break the composition.
	   The pseudo-element is transparent, carries no content, and is
	   absolutely positioned — so on the controls below that are themselves
	   flex containers (.switch, .fsel, .ph-pick, .me__btn) it is removed
	   from flow and does NOT become a stray flex item. */
	.fsel,
	.swatch,
	.set__sw,
	.switch,
	.ph-pick,
	.ph-fav,
	.chip,
	.mk__dot,
	.me__btn { position: relative; }

	.fsel::after,
	.swatch::after,
	.set__sw::after,
	.switch::after,
	.ph-pick::after,
	.ph-fav::after,
	.chip::after,
	.mk__dot::after,
	.me__btn::after {
		content: '';
		position: absolute;
		inset-block-start: 50%;
		inset-inline-start: 50%;
		width: 44px;
		height: 44px;
		transform: translate(-50%, -50%);
	}
}

/* --- touch has no hover, so hover-only affordances must be visible ------- */
@media (hover: none) {
	.ph-pick { opacity: 1; }
	.ph-tile[data-fav="1"] .ph-fav { opacity: 1; }
	.ph-fav { opacity: 0.85; }
	.ph-tile::after { opacity: 1; }        /* the scrim that makes the icons legible */
	.tab__x { opacity: 0.85; }
}


/* ==========================================================================
   3 · COMPACT SHELL  (≤ 767px)
   --------------------------------------------------------------------------
   Two structural moves:

   A. The seven apps get a real home: .hdr__apps is lifted out of the header
      and pinned to the bottom of the viewport as an iOS-style tab bar.
      No new markup — the existing nav element is re-laid-out. The launcher
      ("Apps") is already the last child of that nav, so it becomes the
      5th tab and reaches the other three apps.

   B. The 3–4 column layouts become a drill-down stack driven by ONE
      attribute on #app:  data-depth="0" | "1" | "2".

        depth 0   the navigation level     .rail + .list        (Talk+)
                                           .appnav              (everything else)
        depth 1   the content level        .main                (Talk+)
                                           .mlist               (Mail)
                                           .appmain             (Files/Photos/Cal/Flow)
        depth 2   the detail level         .side                (Talk+)
                                           .mread               (Mail)
                                           .fside               (Files/Calendar)

      Only one level is in the layout at a time. Nothing is destroyed, so
      going back is instant and stateless — see responsive-notes.md.
   ========================================================================== */

@media (max-width: 767.98px) {

	/* ---------------------------------------------------- 3.1 the shell */
	/* the tab bar is fixed, so the shell has to reserve its height.
	   --sab is platform.css's bottom safe-area inset; folded in here so
	   the two layers cannot double-count or forget it. */
	.app { padding-block-end: calc(var(--tabbar-h) + var(--sab, 0px)); }

	.body { flex-direction: column; }
	.fapp, .capp { flex-direction: column; }

	/* every top-level column becomes a full-bleed page */
	.rail, .list, .main, .side,
	.appnav, .appmain, .mlist, .mread, .fside {
		width: 100%;
		max-width: none;
		min-width: 0;
		flex: 1 1 auto;
		border-inline: none;
	}

	/* -------------------------------------------- 3.2 the bottom tab bar */
	/* beats `@media (max-width:900px){ .hdr__apps{display:none} }` on source order */
	.hdr__apps {
		display: flex;
		position: fixed;
		inset-inline: 0;
		inset-block-end: 0;
		z-index: 95;
		/* box-sizing is border-box globally, so the inset lives inside the
		   height: the bar is --tabbar-h of touchable chrome plus a strip of
		   --chrome bleeding under the home indicator. */
		height: calc(var(--tabbar-h) + var(--sab, 0px));
		padding-block-end: var(--sab, 0px);
		padding-inline: calc(2px + var(--sal, 0px)) calc(2px + var(--sar, 0px));
		flex-grow: 0;
		align-items: stretch;
		justify-content: space-around;
		gap: 0;
		background: var(--chrome);
		border-block-start: 1px solid var(--nav-hairline);
	}

	/* the header keeps only brand + right-hand controls */
	.hdr__brand { flex-grow: 1; width: auto; }
	.proto-pill { display: none; }
	.brandpick { display: none; } /* the same swatches live in Settings → Appearance */

	.hdr__app,
	.launch,
	.launch__btn {
		flex: 1 1 0;
		min-width: 0;
		height: 100%;
	}

	.hdr__app,
	.launch__btn {
		position: relative;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 3px;
		border: none;
		border-radius: 0;
		background: transparent;
		padding-inline: 2px;
		font-size: 10px;
		font-weight: 600;
		line-height: 1.1;
		letter-spacing: 0.1px;
	}

	.hdr__app > svg,
	.launch__hub { width: 22px; height: 22px; flex-shrink: 0; }

	/* the active app gets a rounded pill behind icon + label (the full-height
	   block would read as a slab), plus the top indicator */
	.hdr__app { isolation: isolate; }
	.hdr__app[aria-current="true"] { background: transparent; color: var(--chrome-active-text); }
	.hdr__app[aria-current="true"]::after { content: ''; position: absolute; inset: 5px 3px; border-radius: 12px; background: var(--chrome-active); z-index: -1; }
	.hdr__app[aria-current="true"]::before {
		content: '';
		position: absolute;
		inset-block-start: 0;
		inset-inline: 22%;
		height: 2px;
		border-radius: 100px;
		background: var(--brand-dark);
	}
	.launch__btn[aria-expanded="true"] { background: transparent; color: var(--chrome-active-text); }

	/* the unread count rides the icon instead of sitting after the label */
	.hdr__app .pill-count {
		position: absolute;
		inset-block-start: 4px;
		inset-inline-start: 50%;
		margin-inline-start: 3px;
		min-width: 17px;
		height: 17px;
		font-size: 10px;
	}
	.hdr__app .wip-badge { display: none; }

	/* --- the launcher opens upward, as a sheet, not a dropdown ---------- */
	.launch__panel {
		position: fixed;
		inset-block-start: auto;
		inset-block-end: calc(var(--tabbar-h) + var(--sab, 0px) + 8px);
		inset-inline: 8px;
		z-index: 96;
		width: auto;
		max-width: none;
		transform-origin: bottom center;
	}
	.launch__panel::before { display: none; }
	.launch__grid { grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); }
	.launch__ic { width: 52px; height: 52px; }
	.launch__n { font-size: 13px; }
	.launch__d { display: none; }   /* the descriptions are desktop luxury */

	/* --- the profile menu becomes a sheet hung off the header ----------- */
	/* `body ` prefix: shared selector with platform.css — see header note */
	body .pm {
		position: fixed;
		inset-block-start: calc(var(--header-h) + var(--sat, 0px) + 6px);
		inset-inline: 8px;
		width: auto;
		max-height: calc(88vh - var(--header-h) - var(--tabbar-h));
	}
	.pm__states { grid-template-columns: 1fr; }

	/* --- launcher + presence menu are modal sheets on mobile -------------
	   Each gets a full-viewport scrim so it reads as a layer over ALL content,
	   and tapping the scrim closes it (the scrim carries the menu's own toggle
	   data-act, so no new JS is needed). Both panels are position:fixed but sit
	   inside a fixed chrome ancestor that forms its own stacking context — the
	   bottom tab bar for the launcher, the header-right cell for the presence
	   menu (which light theme even pins to z-index:3). A child's z-index can't
	   escape that, so :has() lifts the ancestor itself to the shared overlay
	   tier — but ONLY while its menu is open, so the call window (z-index 96) is
	   untouched the rest of the time. The two menus are mutually exclusive, so
	   they share one tier (97): above every app surface and all chrome, and just
	   below the modal backdrop (100), photo lightbox (120), toast (200) and
	   film (300). The scrim sits under its own panel but over the chrome behind. */
	.launch__scrim, body .pm__scrim {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 50;
		background: rgba(9, 15, 13, .5);
		-webkit-backdrop-filter: blur(2px);
		backdrop-filter: blur(2px);
		animation: nuvoScrimIn 180ms ease both;
		border: 0;
		cursor: default;
	}
	@keyframes nuvoScrimIn { from { opacity: 0 } to { opacity: 1 } }
	.hdr__apps:has(.launch__panel) { z-index: 97 !important; }
	.hdr__right:has(.pm) { z-index: 97 !important; }

	/* --- generic dropdowns become bottom sheets ------------------------- */
	body .dd {
		position: fixed;
		inset-block-start: auto;
		inset-block-end: calc(var(--tabbar-h) + var(--sab, 0px) + 10px);
		inset-inline: 10px;
		min-width: 0;
		max-height: 60vh;
	}

	/* --- the toast must clear the tab bar, the home indicator, and the
	       software keyboard (--kb, owned by platform.js) --------------- */
	body .toast {
		inset-block-end: calc(var(--tabbar-h) + 16px + var(--sab, 0px) + var(--kb, 0px));
	}

	/* ------------------------------------------- 3.3 the drill-down stack */
	/* *** NEW MARKUP *** — #app needs data-depth (see notes §3).
	   With no attribute present the first block below applies, which is the
	   correct pre-JS fallback: the navigation level shows. */

	/* depth 0 — and the no-attribute fallback, which is deliberately the
	   same thing: with JS not yet wired up you land on the nav level and
	   the app is still navigable rather than blank. */
	.main, .side, .mlist, .appmain, .mread, .fside { display: none; }

	#app[data-depth="1"] .rail,
	#app[data-depth="1"] .list,
	#app[data-depth="1"] .appnav,
	#app[data-depth="1"] .side,
	#app[data-depth="1"] .mread,
	#app[data-depth="1"] .fside { display: none; }

	#app[data-depth="1"] .main { display: flex; }
	#app[data-depth="1"] .appmain { display: flex; }
	#app[data-depth="1"] .mlist { display: flex; }

	#app[data-depth="2"] .rail,
	#app[data-depth="2"] .list,
	#app[data-depth="2"] .appnav,
	#app[data-depth="2"] .appmain,
	#app[data-depth="2"] .mlist,
	#app[data-depth="2"] .main { display: none; }

	#app[data-depth="2"] .side { display: flex; }
	#app[data-depth="2"] .mread { display: flex; }
	#app[data-depth="2"] .fside { display: flex; }

	/* .side is display:none from the existing 1180px rule — the attribute
	   selectors above are specificity (1,1,0) and beat it comfortably. */

	/* --- the back / forward affordances ---------------------------------
	   *** NEW MARKUP *** — .nav-back and .nav-info (see notes §4).
	   Hidden everywhere except compact, so adding them is desktop-safe. */
	.nav-back, .nav-info { display: inline-flex; flex-shrink: 0; }

	/* ----------------------------------------------- 3.4 shared spacing
	   Longhands, never the `padding` shorthand, on any selector
	   platform.css also owns — and the landscape safe-area insets are
	   folded back in on the inline axis. */
	body .scrollpane {
		padding-block: 12px;
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
	}
	body .toolbar,
	body .appbar {
		padding-block: 8px;
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
		gap: 8px;
	}
	.modal__h { padding: 16px 18px 10px; }
	.modal__b { padding: 4px 18px 16px; }
	.modal__f { padding: 12px 18px; }
	/* .modal / .modal--tall are shared with platform.css's dvh block */
	body .modal {
		max-width: none;
		max-height: none;
		height: 100%;
		border: none;
		border-radius: 0;
		box-shadow: none;
	}
	body .modal--tall { height: 100%; max-height: none; }
	.modal__t { font-size: 18px; }
	.doc h2 { font-size: 18px; }
	.empty { padding: 32px 20px; }
	.empty__x { font-size: 13px; }
}

/* the tightest phones: shave the tab-bar labels rather than truncate them */
@media (max-width: 359.98px) {
	.hdr__app, .launch__btn { font-size: 0; gap: 0; }
	.hdr__app > svg, .launch__hub { width: 24px; height: 24px; }
	.hdr__app .pill-count { font-size: 10px; }
	.wordmark { font-size: 16px; }
}


/* ==========================================================================
   4 · TALK+   (≤ 767px)
   --------------------------------------------------------------------------
   Four columns → Spaces strip + channel list (depth 0) → conversation
   (depth 1) → about-this-channel (depth 2).

   The Spaces rail LIES DOWN rather than disappearing: on a phone it is a
   horizontal avatar strip above the channel list, the pattern Slack and
   Teams both use. No markup change — the same .rail element, rotated.
   ========================================================================== */

@media (max-width: 767.98px) {

	/* `body ` prefix: platform.css sets .rail width + padding-inline-start
	   for the landscape notch. Both are folded back in here. */
	body .rail {
		flex: 0 0 auto;
		width: 100%;
		height: var(--rail-h);
		flex-direction: row;
		align-items: center;
		gap: 8px;
		padding-block: 0;
		padding-inline: calc(10px + var(--sal, 0px)) calc(10px + var(--sar, 0px));
		overflow-x: auto;
		overflow-y: hidden;
		border-block-end: 1px solid var(--nav-hairline);
	}

	/* the active marker moves from the leading edge to the bottom edge */
	.rail__marker {
		inset-inline: 6px;
		inset-inline-start: 6px;
		inset-block-start: auto;
		inset-block-end: -7px;
		width: auto;
		height: 3px;
	}
	.rail__sep { width: 1px; height: 26px; margin-block: 0; margin-inline: 4px; }

	/* --- the channel list ------------------------------------------------ */
	.list { background: var(--bg-subtle); }
	.list__head { padding: 12px var(--gutter) 8px; }
	.list__title { font-size: 16px; }
	.list__search { padding-inline: var(--gutter); }

	/* --- the conversation ------------------------------------------------ */
	.topbar { height: 52px; gap: 8px; padding-inline: 8px 10px; }
	/* The channel's "..." (rename, delete) lives in About this channel on a
	   phone; the topbar ends in the panel icon, the same as on a desktop. */
	.topbar > span:has(> [data-act="ch-menu"]) { display: none !important; } /* the wrapper carries an inline display */
	.topbar__name { font-size: 15px; }
	.topbar__desc { font-size: 12px; }

	/* Meet / Call collapse to their glyphs. font-size:0 keeps the text node
	   in the accessibility tree, so the accessible name survives; the SVGs
	   carry explicit width/height attributes so they do not shrink. */
	.topbar > .btn {
		font-size: 0;
		gap: 0;
		padding-inline: 0;
		width: var(--tap);
		flex-shrink: 0;
	}

	.tabstrip { padding-inline: 6px; scrollbar-width: none; }
	.tabstrip::-webkit-scrollbar { display: none; }

	body .chat__scroll {
		padding-block: 14px 6px;
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
		gap: 12px;
	}
	.msg { gap: 10px; }
	.msg__text { font-size: 15px; }
	.msg--system { padding-inline-start: 0; font-size: 12.5px; }
	.callcard { margin-inline-start: 0; width: 100%; }
	.filecard { width: 100%; }

	/* platform.css owns .composer's block-end padding (home indicator +
	   software keyboard). Its `:root[data-kb="1"] .composer` rule is
	   (0,3,0) and still outranks this, so the keyboard case is untouched.
	   No --kb term here either, for the reason spelled out in platform.css
	   section 3: the shell is already sized to the visible viewport. */
	body .composer {
		padding-block: 6px calc(10px + var(--sab, 0px));
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
	}
	.composer__box { padding: 5px 6px 5px 12px; }
	.composer__input { max-height: 108px; }
	.composer__hint { display: none; }   /* Enter-to-send is not a phone idiom */

	.callbar { padding: 8px var(--gutter); flex-wrap: wrap; }
	.callbar .btn { flex: 1 1 auto; }

	/* --- about this channel (depth 2) ------------------------------------ */
	.side { background: var(--bg); }
	.side__head { padding: 12px var(--gutter) 8px; }

	/* --- boards and docs inside a channel tab ---------------------------- */
	.board { flex-direction: column; }
	.board__col { width: 100%; }
	.doc { max-width: none; }

	/* the Files tab table inside a channel: drop "Modified by" and "Modified" */
	.pane .tbl th:nth-child(3), .pane .tbl td:nth-child(3),
	.pane .tbl th:nth-child(5), .pane .tbl td:nth-child(5) { display: none; }
}


/* ==========================================================================
   5 · CALENDAR   (≤ 767px)
   --------------------------------------------------------------------------
   The week grid is the hardest surface in the product. Seven columns at a
   usable minimum (78px) plus the hour gutter is ~590px — it cannot fit a
   phone, and squeezing it produces unreadable 45px columns.

   The decision: on compact, DAY is the default view (JS, see notes §5).
   Week stays reachable and stays honest — it scrolls horizontally inside
   .cwrap, with the hour gutter and the day header travelling together
   because both grids live inside the same scroller.

   Critically: the slot height stays 48px. JS positions .cev absolutely from
   HOUR_H = 48 (line 3255); changing it in CSS would desynchronise every
   event from its time.
   ========================================================================== */

@media (max-width: 767.98px) {

	/* narrower hour gutter, tighter day columns — vertical rhythm untouched */
	.cgrid, .chead, .cal-allday {
		grid-template-columns: 58px repeat(var(--cols), minmax(78px, 1fr));
	}
	.cgutter__h { font-size: 10px; padding-inline-end: 6px; }

	.chead__c { padding: 6px 4px; }
	.chead__d { font-size: 11px; }
	.chead__n { font-size: 16px; }
	.chead__c[data-today="1"] .chead__n { width: 28px; height: 28px; }

	/* in day view there is one column — let it use the whole width */
	body .cwrap { overscroll-behavior-x: contain; }

	/* --- month view: chips become dots, the way iOS Calendar does it ----- */
	/* six rows should fill the viewport rather than stopping two thirds down */
	.cmonth { grid-auto-rows: minmax(64px, 1fr); min-height: 100%; }
	/* block flow, not column flex: the day number must hug its digits (the
	   today pill is a background on that element) while the event dots run
	   inline underneath it and wrap on their own */
	.cmonth__d { display: block; padding: 4px; }
	.cmonth__n {
		display: block;
		width: max-content;
		font-size: 12px;
		padding: 1px 6px;
		margin-block-end: 3px;
	}
	.cchip {
		display: inline-block;
		width: 6px;
		height: 6px;
		min-width: 6px;
		padding: 0;
		margin: 0 3px 3px 0;
		border-radius: 100px;
		font-size: 0;
		line-height: 0;
		vertical-align: middle;
	}
	.cmonth__d .muted { display: none; }   /* the "+3 more" line */

	/* --- the calendar picker column becomes depth 0 ---------------------- */
	.cal-item { font-size: 15px; }

	/* --- the event editor -------------------------------------------------
	   .ed__row already wraps at flex-basis 140px, which is the right
	   behaviour; just stop the two-up date/time pair from going 1-up
	   unnecessarily on a 390px phone. */
	.ed__row > .field { flex: 1 1 132px; min-width: 108px; }
}


/* ==========================================================================
   6 · MAIL   (≤ 767px)
   --------------------------------------------------------------------------
   Mailboxes → message list → message. Exactly iOS Mail. The app opens at
   depth 1 (the Inbox list), and the back button from there reveals the
   folder/tag column — nobody wants to pick a mailbox before reading mail.
   ========================================================================== */

@media (max-width: 767.98px) {

	.mlist { border-inline-end: none; }
	.mlist .appbar { padding: 8px var(--gutter); }

	.mrow { padding: 12px var(--gutter); gap: 10px; }
	.mrow__from { font-size: 15px; }
	.mrow__subj { font-size: 14px; }
	.mrow__prev {
		font-size: 13px;
		/* two lines of preview, the way a phone inbox reads */
		white-space: normal;
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}

	.msec { padding: 10px var(--gutter) 6px; }

	.mread__h { padding: 12px var(--gutter) 12px; gap: 10px; }
	.mread__subj { font-size: 19px; }
	body .mread__body {
		padding-block: 16px 24px;
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
	}
	.mbody { font-size: 15px; max-width: none; }
	.mcard, .mwarn { max-width: none; }

	/* the reply/forward/archive row scrolls rather than stacking four deep */
	.mread__acts {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
		padding-block-end: 2px;
	}
	.mread__acts::-webkit-scrollbar { display: none; }
	.mread__acts .btn { flex-shrink: 0; }

	.matt { max-width: 100%; }
}


/* ==========================================================================
   7 · FILES   (≤ 767px)
   --------------------------------------------------------------------------
   Nav → file table → detail. The table keeps its shape (a phone file
   manager IS a list) but sheds the two columns nobody reads on a phone:
   "Modified by" (4th) and "Modified" (6th).

   Scoped to #fapp so the identical .tbl in a Talk+ Files tab — which has a
   different column order — is not hit. That one is handled in §4.
   ========================================================================== */

@media (max-width: 767.98px) {

	/* Since 2026-10-01 the Files list (.fs-tbl, styles/005-files-app.css)
	   hides Size and Modified itself and shows them under the name. */

	.scrollpane .tbl { font-size: 14px; }

	/* the search field carries style="width:200px" inline (line ~5938) —
	   inline styles need !important. Removing it is listed as an optional
	   JS clean-up in the notes. */
	#fq { width: 100% !important; }

	.appbar .crumbs { flex: 1 1 100%; order: -1; }
	.appbar .btn { flex: 1 1 auto; }

	.fside__h { padding: 14px var(--gutter) 10px; }
	.fside__b { padding: 0 var(--gutter) 16px; }
}


/* ==========================================================================
   8 · PHOTOS   (≤ 767px)
   --------------------------------------------------------------------------
   The target is Apple Photos: a seamless, edge-to-edge, square mosaic with
   a 2px seam and sticky date headers — not a card grid with rounded corners
   floating in 20px of padding.
   ========================================================================== */

@media (max-width: 767.98px) {

	/* full-bleed: cancel the .scrollpane gutter for the grid only */
	#phapp .ph-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 2px;
		margin-inline: calc(var(--gutter) * -1);
	}
	#phapp .ph-tile { border-radius: 0; }
	#phapp .ph-tile[data-sel="1"] { outline-width: 2px; outline-offset: -2px; }

	.ph-day { padding: 16px 0 6px; }
	.ph-day__t { font-size: 14px; }
	.ph-day__s { font-size: 12px; }

	.ph-hero { min-height: 168px; }
	.ph-hero__b { padding: 16px; gap: 12px; }
	.ph-hero__t { font-size: 20px; }
	.ph-hero__play { height: 38px; padding-inline: 14px; font-size: 13px; }

	.ph-cards { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }

	/* the selection bar keeps every action, on one scrolling line */
	.ph-bar {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
		padding: 8px var(--gutter);
		gap: 8px;
	}
	.ph-bar::-webkit-scrollbar { display: none; }
	.ph-bar .btn, .ph-bar .ibtn, .ph-bar .tag { flex-shrink: 0; }
	.ph-bar .grow { display: none; }

	/* --- the lightbox --------------------------------------------------- */
	body .ph-view__top {
		height: calc(52px + var(--sat, 0px));
		padding-block-start: var(--sat, 0px);
		padding-inline: calc(6px + var(--sal, 0px)) calc(6px + var(--sar, 0px));
	}
	.ph-view__stage { padding: 6px 6px 16px; }
	.ph-nav { width: 40px; height: 40px; }
	.ph-nav--prev { inset-inline-start: 6px; }
	.ph-nav--next { inset-inline-end: 6px; }
	.ph-strip { height: 66px; padding: 6px 10px; }
	.ph-strip button { width: 50px; height: 50px; }
}

/* four columns once the phone is wide enough to keep the thumbs legible */
@media (min-width: 400px) and (max-width: 767.98px) {
	#phapp .ph-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}


/* ==========================================================================
   9 · QUEUES   (≤ 767px)
   --------------------------------------------------------------------------
   Queues is already a single column and already stacks .qcols below 1100px.
   What it needs on a phone is gutters, smaller display numerals, and a
   two-up KPI grid instead of a four-up one that produces 80px cards.
   The wide supervisor table already ships inside an overflow-x wrapper,
   so it scrolls honestly rather than being folded into cards.
   ========================================================================== */

@media (max-width: 767.98px) {

	.qhead { padding: 12px var(--gutter) 10px; gap: 10px; }
	.qtitle { font-size: 19px; }
	.qhead .seg { flex: 1 1 100%; }
	.qhead .seg button { flex: 1 1 0; padding-inline: 8px; }
	.qhead .grow { display: none; }

	.wip { margin: 0 var(--gutter) 12px; padding: 10px 12px; }
	body .qbody {
		padding-block: 0 20px;
		padding-inline: calc(var(--gutter) + var(--sal, 0px)) calc(var(--gutter) + var(--sar, 0px));
	}

	.kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
	.kpi { padding: 12px; }
	.kpi__v { font-size: 24px; }
	.kpi__x { font-size: 11px; }

	.qcall { padding: 14px var(--gutter); }
	.qcall__name { font-size: 19px; }
	.qcall__timer { font-size: 26px; }
	.qcall__ctrls .btn { flex: 1 1 calc(50% - 4px); }

	.panel__h { padding: 12px 14px 6px; }
	.panel__b { padding: 0 14px 14px; }

	.qwait { flex-wrap: wrap; }
	.mon { justify-content: flex-start; }
}




/* ---- Photos library on a phone (<= 767px) ----------------------------- */
@media (max-width: 767.98px) {
	#phapp .phl .ph-grid,
	#phapp .ph-grid { grid-template-columns: repeat(var(--phcols, 4), minmax(0, 1fr)); border-radius: 0; }
	.phl-scrub { display: none; }
	.phl-zoom { display: none; }
	.phl-add span { display: none; }
	.phl-when__t { font-size: 17px; }
	.phl-seg { bottom: 12px; max-width: calc(100% - 24px); }
	.phl-seg button { height: 32px; padding-inline: 11px; }
	.phl-cards, .phl-cards--years { grid-template-columns: minmax(0, 1fr); gap: 12px; }
	.phl-card { border-radius: 14px; }
	.phl-card--year .phl-card__t { font-size: 38px; }
	.phl-sec { font-size: 22px; padding-block: 16px 10px; }
	.phl-up { inset-inline: 16px; bottom: calc(84px + env(safe-area-inset-bottom, 0px)); min-width: 0; }
	.phl-empty { margin-block-start: 6vh; padding-inline: 8px; }
}
/* ==========================================================================
   10 · FLOW   (≤ 767px)
   ========================================================================== */

@media (max-width: 767.98px) {
	.builder { max-width: none; }
	.brow > .select, .brow > .input { flex: 1 1 100%; min-width: 0; }
	.flcard { flex-direction: column; align-items: stretch; }
	.bsummary { font-size: 13.5px; line-height: 1.6; }
	.bstage__b { padding: 12px 14px; }
}


/* ==========================================================================
   11 · OVERLAYS — modals, settings, the film   (≤ 767px)
   ========================================================================== */

@media (max-width: 767.98px) {

	/* --- modals become full-height sheets -------------------------------
	   The sheet fills the screen; only the safe-area insets stay outside
	   it, so nothing lands under the notch or the home indicator.
	   (.modal / .modal--tall themselves are set in §3.4.) */
	body .backdrop {
		align-items: stretch;
		padding-block: var(--sat, 0px) var(--sab, 0px);
		padding-inline: var(--sal, 0px) var(--sar, 0px);
	}
	.modal__f { flex-direction: column-reverse; }
	.modal__f .btn { width: 100%; }

	.pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.prov { min-height: 84px; }

	/* --- settings: the rail is a scrolling first level ------------------ */
	/* the existing 760px rule already stacks .set; this tunes the split so
	   the body, not the rail, owns most of the height */
	.set__rail { max-height: 38vh; padding: 4px 8px 10px; }
	.set__body { padding: 14px var(--gutter) 20px; }
	.set__grp { padding: 12px 10px 4px; }

	/* --- the film ------------------------------------------------------- */
	.mk__scene { padding: 40px 20px 104px; }
	.mk__sub { margin-block-start: 14px; }
	.mk__skip { inset-block-start: 14px; inset-inline-end: 14px; padding-inline: 14px; }
	.mk__ctl { padding: 12px 16px 16px; gap: 12px; }
	.mk__dot { width: 24px; }

	.mk-bar__row { gap: 10px; }
	.mk-bar__l { width: 84px; font-size: 11px; }
	.mk-bar__track { height: 34px; }
	.mk-bar__fill { font-size: 14px; padding-inline-end: 10px; }
	.mk-tier { padding: 8px 11px; }

	.mk-lock { flex-direction: column; gap: 12px; }
	.mk-lock svg { width: 60px; height: 60px; }
	.mk-cta { flex-direction: column; align-items: stretch; width: min(320px, 84vw); margin-block-start: 26px; }
	.mk-btn { width: 100%; justify-content: center; }

	.mk-win__side { width: 112px; }
	.mk-line { height: 96px; }
}


/* ==========================================================================
   12 · MEDIUM — tablet portrait  (768 – 1023px)
   --------------------------------------------------------------------------
   Two content columns fit comfortably, three do not. So:

     • the seven-app nav comes BACK into the header as glyphs. Today it is
       display:none below 900px, which is the bug called out in the brief —
       between 768 and 900 the apps are unreachable except via the launcher.
     • every .appnav (Mail/Files/Photos/Calendar/Flow) collapses to a 60px
       icon rail. Labels go, targets stay, nothing becomes unreachable.
     • Talk+ keeps rail + list + main; .side stays hidden by the existing
       1180px rule.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1023.98px) {

	/* --- header nav restored, as glyphs -------------------------------- */
	.hdr__apps { display: flex; }
	.hdr__app {
		padding-inline: 11px;
		gap: 0;
		font-size: 0;   /* label stays in the a11y tree, leaves the layout */
	}
	.hdr__app .pill-count { font-size: 11px; margin-inline-start: 4px; }
	.hdr__app .wip-badge { display: none; }

	/* --- .appnav becomes an icon rail ---------------------------------- */
	.appnav {
		width: 60px;
		padding: 10px 6px;
		align-items: stretch;
	}
	.appnav__t { display: none; }
	.appnav__item {
		justify-content: center;
		padding-inline: 0;
		gap: 0;
		font-size: 0;
	}
	.appnav__count { display: none; }
	.appnav__group { display: none; }
	.appnav .dd__l { display: none; }
	.appnav .appnav__acct { justify-content: center; padding-inline: 0; }
	.appnav .appnav__acct-a { display: none; }
	.appnav .btn {
		font-size: 0;
		gap: 0;
		padding-inline: 0;
		justify-content: center;
		margin-inline: 4px !important;   /* beats the inline margin on the "New …" button */
	}
	/* the storage-quota footer is a luxury at 60px wide */
	.appnav > div:last-child { display: none; }

	/* --- Talk+ --------------------------------------------------------- */
	.list { width: 264px; }

	/* --- Mail ---------------------------------------------------------- */
	.mlist { width: 296px; }
	.mread__h { padding: 16px 18px 12px; }
	body .mread__body {
		padding-block: 18px 24px;
		padding-inline: 18px calc(18px + var(--sar, 0px));
	}
	.mread__subj { font-size: 20px; }

	/* --- Files / Calendar detail sidebar -------------------------------- */
	.fside { width: 264px; }

	/* --- Calendar ------------------------------------------------------- */
	.cgrid, .chead, .cal-allday {
		grid-template-columns: 52px repeat(var(--cols), minmax(82px, 1fr));
	}

	/* --- Photos --------------------------------------------------------- */
	.ph-grid { grid-template-columns: repeat(auto-fill, minmax(126px, 1fr)); gap: 3px; }
	.ph-cards { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); }
}


/* ==========================================================================
   13 · WIDE — tablet landscape / small laptop  (1024 – 1180px)
   --------------------------------------------------------------------------
   The desktop layout is essentially correct here; .side is already hidden
   by the existing rule. Only the .appnav labels come back and the middle
   columns give a little width to the content.
   ========================================================================== */

@media (min-width: 1024px) and (max-width: 1180.98px) {
	.appnav { width: 216px; }
	.list { width: 268px; }
	.fside { width: 276px; }
}


/* ==========================================================================
   14 · SHORT VIEWPORTS — landscape phone
   --------------------------------------------------------------------------
   A 390 × 844 phone rotated is 844 × 390. Header (52 on coarse) + tab bar
   (56) + topbar (52) + tabstrip (52) + composer (~78) = 290 of 390 before a
   single message is drawn. Everything chrome-shaped gets thinner and the
   secondary lines go.

   Deliberately keyed on height + orientation, NOT width: a 844px-wide
   landscape phone otherwise falls into the medium band and gets the
   two-column tablet layout, which is the right layout — it just needs
   shorter chrome.
   ========================================================================== */

@media (max-height: 520px) and (orientation: landscape) {

	:root {
		--header-h: 42px;
		--tabbar-h: 46px;
		--rail-h: 52px;
	}

	.hdr__app, .launch__btn { font-size: 0; gap: 0; }
	.hdr__app > svg, .launch__hub { width: 21px; height: 21px; }
	.hdr__app[aria-current="true"]::before { inset-inline: 30%; }

	.topbar { height: 44px; }
	.topbar__desc { display: none; }
	.tabstrip { min-height: 42px; }
	.tab { padding-inline: 11px; }

	.callbar { padding-block: 6px; }
	.chat__scroll { padding-block: 10px 4px; gap: 10px; }

	.composer { padding-block: 4px 8px; }
	.composer__box { min-height: 40px; padding-block: 4px; }
	.composer__input { max-height: 72px; line-height: 20px; }
	.composer__hint { display: none; }

	.list__head { padding-block: 8px 6px; }
	.list__sub { display: none; }

	body .modal, body .modal--tall { max-height: 100%; height: 100%; }
	.modal__h { padding-block: 12px 8px; }
	body .pm { max-height: calc(94vh - var(--header-h)); }
	.set__rail { max-height: 30vh; }

	body .ph-view__top { height: calc(46px + var(--sat, 0px)); }
	.ph-strip { height: 58px; }
	.ph-strip button { width: 44px; height: 44px; }

	/* the film is a full-bleed piece — it must not overflow a 390px height */
	.mk__scene { padding: 26px 24px 76px; }
	.mk__h { font-size: clamp(1.5rem, 4.6vw, 2.4rem); margin-block-start: 8px; }
	.mk__sub { font-size: 0.9rem; margin-block-start: 10px; }
	.mk__kicker { margin-block-start: 14px; font-size: 0.95rem; }
	.mk__ctl { padding: 8px 20px 12px; }
	body .mk-hall { height: min(400px, 44vh); }
	body .mk-plane { height: min(300px, 34vh); }
	.mk-cta { margin-block-start: 16px; }
	.mk-note { display: none; }
}


/* ==========================================================================
   15 · CONTAINER QUERIES
   --------------------------------------------------------------------------
   Used only where the element's own width genuinely diverges from the
   viewport's, which is exactly two places in this app:

   (a) .modal — width is `min(880px, 100% - 40px)`, so a 900px viewport
       gives an 860px modal and a 780px viewport gives a 740px one. A
       viewport media query cannot express "the settings rail no longer
       fits"; a container query can, and it keeps the settings dialog
       correct inside any future modal width without a new breakpoint.

   (b) .qbody — the queues body sits inside a column whose width depends on
       whether .appnav is a rail, a full nav, or gone. Same argument.

   `container-type: inline-size` implies `contain: layout style inline-size`.
   Both elements have a definite inline size and neither hosts a
   fixed-position descendant, so containment is inert here.
   ========================================================================== */

.modal { container-type: inline-size; container-name: modal; }
.qbody { container-type: inline-size; container-name: qbody; }

@container modal (max-width: 620px) {
	/* the settings rail stops being a column and becomes a first level */
	.set { flex-direction: column; }
	.set__rail {
		width: 100%;
		/* vh, not cqh: .modal is an inline-size container, so cq block units
		   would silently fall back to the viewport anyway */
		max-height: 38vh;
		border-inline-end: none;
		border-block-end: 1px solid var(--border);
	}
}

@container modal (max-width: 520px) {
	/* label above control — .set__c hard-codes min-width:168px, which is
	   what actually breaks narrow settings rows */
	.set__row { flex-direction: column; align-items: stretch; gap: 8px; }
	.set__c { justify-content: flex-start; }
	.set__c .select, .set__c .input { width: 100%; min-width: 0; }
	.set__c .input--short { min-width: 0; }
	.ed__row { flex-direction: column; align-items: stretch; }
	.ed__row > .field { flex: 1 1 auto; min-width: 0; }
}

@container modal (max-width: 400px) {
	.pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@container modal (max-width: 300px) {
	.pgrid { grid-template-columns: 1fr; }
}

@container qbody (max-width: 560px) {
	.kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.qcall__top { gap: 10px; }
}

@container qbody (max-width: 360px) {
	.kpis { grid-template-columns: 1fr; }
}

/* ======================================================= end responsive */

/* ---------- platform.css ---------- */
/* ================================================================== *
 *  PLATFORM SUBSTRATE — NuvoCloud Talk+ prototype v2
 *  Paste VERBATIM at the very end of the existing style block, i.e.
 *  immediately before the closing style tag on line 2723.
 *
 *  NOTE TO ANY FUTURE EDITOR: nothing in this file may contain the
 *  literal sequence  <  /  s  t  y  l  e  (unspaced), not even inside
 *  a comment — the HTML parser ends the style block at that sequence
 *  and renders the remainder of the CSS as visible page text. That is
 *  why the closing tag is described in words here rather than written.
 *
 *  Everything here relies on being LAST in source order: several rules
 *  deliberately re-declare properties that earlier rules set, and win
 *  on source order rather than on specificity inflation.
 *
 *  Scope: viewport, safe areas, keyboard/input behaviour, scrolling,
 *  pointer/hover semantics, foldable viewport segments.
 *  NOT in scope (owned by the responsive-layout agent): breakpoints,
 *  column counts, the phone navigation pattern, component restyling.
 * ================================================================== */


/* ------------------------------------------------------------------ *
 *  1. SAFE-AREA TOKENS
 *
 *  env(safe-area-inset-*) evaluates to 0px unless the viewport meta
 *  carries `viewport-fit=cover`. platform.js injects that meta, so
 *  these are live on notched hardware and inert everywhere else.
 *
 *  Aliased into custom properties for three reasons:
 *   - `calc(20px + var(--sab))` reads better than nesting env() calls;
 *   - a single place to zero them out for a subtree if ever needed;
 *   - env() inside calc() inside a shorthand trips up older WebKit,
 *     the indirection sidesteps it.
 *
 *  These are PHYSICAL edges (left/right), not logical (start/end).
 *  The app uses logical properties throughout; in an RTL locale the
 *  mapping below would need flipping. Called out in platform-notes.md.
 * ------------------------------------------------------------------ */
:root {
	--sat: env(safe-area-inset-top, 0px);
	--sar: env(safe-area-inset-right, 0px);
	--sab: env(safe-area-inset-bottom, 0px);
	--sal: env(safe-area-inset-left, 0px);

	/* Keyboard overlap in px, maintained by platform.js from
	   visualViewport. 0 when no on-screen keyboard is showing. */
	--kb: 0px;
}


/* ------------------------------------------------------------------ *
 *  2. THE 100vh PROBLEM
 *
 *  `.app { height: 100vh }` (line 149) is wrong on mobile: 100vh is the
 *  LARGE viewport, measured as if the URL bar were hidden. With the bar
 *  visible the shell overflows the screen by the height of that bar and,
 *  because `.app` is `overflow: hidden`, the composer pinned at its
 *  bottom is simply pushed off-screen and unreachable.
 *
 *  Three-tier ladder, weakest first:
 *    a) 100vh          — ancient browsers, unchanged behaviour.
 *    b) 100dvh         — the dynamic viewport; correct on modern
 *                        Safari/Chrome, tracks the URL bar.
 *    c) var(--app-h)   — an exact pixel height written by platform.js
 *                        from visualViewport. Only engaged once JS has
 *                        actually measured, hence the [data-vv="1"]
 *                        gate on <html>.
 *
 *  (c) exists because iOS Safari does NOT shrink the LAYOUT viewport
 *  when the software keyboard appears — only the VISUAL viewport — so
 *  100dvh stays at full screen height and the composer ends up behind
 *  the keyboard. Chrome/Android solves this declaratively via
 *  `interactive-widget=resizes-content` in the viewport meta; Safari has
 *  no equivalent, so JS measurement is the only route.
 *
 *  Why the [data-vv] attribute gate instead of `height: var(--app-h, 100dvh)`:
 *  a browser that supports var() but not dvh would parse that
 *  declaration as valid (var() defers validation), then fail to resolve
 *  it at computed-value time and fall back to `height: auto` — NOT to
 *  the earlier 100vh declaration. That is the classic
 *  "invalid at computed-value time" footgun and it would collapse the
 *  entire shell. Keeping dvh out of the var() fallback avoids it.
 * ------------------------------------------------------------------ */
.app {
	height: 100vh;                 /* tier (a) — final fallback       */
	overscroll-behavior: none;     /* see §5, rubber-band suppression */
}

@supports (height: 100dvh) {
	.app { height: 100dvh; }       /* tier (b) */
}

:root[data-vv="1"] .app {
	height: var(--app-h);          /* tier (c) — JS-measured px */
}

/* iOS has a second way of revealing a focused field, and it is the one
   that put the composer near the top of the screen. When the document
   has nothing to scroll (it does not: .app is one viewport tall and
   `overflow: hidden`) Safari PANS THE VISUAL VIEWPORT instead. That pan
   is reported as visualViewport.offsetTop while window.scrollY stays 0,
   so `window.scrollTo(0, 0)` cannot undo it: the shell keeps rendering
   at layout y=0, which is now above the visible band, and its header
   slides off the top while the composer climbs.
   .app is already the right HEIGHT for that band (tier c); pinning it
   to --vv-top also puts it in the right PLACE.
   Gated on data-vvpan, which platform.js sets only while the pan is
   actually non-zero, so on Chrome/Android and on a desktop -- where it
   never happens -- the shell keeps the static layout it has today.
   `position: fixed` and NOT a transform: a transform would make .app
   the containing block for every nested `position: fixed` overlay (the
   modals, the toast, the call window) and move all of them with it. */
:root[data-vvpan="1"] .app {
	position: fixed;
	inset-inline: 0;
	inset-block-start: var(--vv-top, 0px);
}

/* ---- every other `vh` in the file, addressed individually ----------
   Each of these is a max-height on an overlay. On mobile with the URL
   bar showing, `88vh` can exceed the actual visible height, so a tall
   modal's footer (its action buttons) sits below the fold with no way
   to scroll to it — the modal itself is the scroll container. Switching
   to dvh and subtracting the safe-area insets fixes both at once.

   dvh is wrapped in @supports so the original vh value survives on
   browsers that lack it.                                             */
@supports (height: 100dvh) {
	/* line 805  — .modal          max-height: 88vh */
	.modal        { max-height: calc(88dvh - var(--sat) - var(--sab)); }
	/* line 1986 — .modal--tall    max-height: 88vh (height:660px kept) */
	.modal--tall  { max-height: calc(88dvh - var(--sat) - var(--sab)); }
	/* line 1302 — .pm             max-height: 78vh (profile menu)     */
	.pm           { max-height: calc(78dvh - var(--sat) - var(--sab)); }
	/* line 2544 — .dd             max-height: 70vh (dropdown menu)    */
	.dd           { max-height: calc(70dvh - var(--sat) - var(--sab)); }
	/* line 2380 — .ph-view__stage svg  width: min(74vh, 100%)         */
	.ph-view__stage svg { width: min(74dvh, 100%); }
	/* lines 1571 / 1665 / 1718 — the .mk film scenes.
	   These are decorative stage boxes inside a fixed full-screen
	   overlay; dvh keeps them from overflowing when the URL bar shows. */
	.mk-hall  { height: min(400px, 50dvh); }
	.mk-plane { height: min(300px, 38dvh); }
	.mk-win   { height: min(430px, 52dvh); }
}


/* ------------------------------------------------------------------ *
 *  3. SAFE AREAS — notch, Dynamic Island, home indicator, landscape
 *
 *  Principle: BACKGROUNDS bleed edge to edge, CONTENT is inset. A strip
 *  of page background beside the notch looks broken; a dark header that
 *  runs under the notch with its buttons pushed clear looks native.
 * ------------------------------------------------------------------ */

/* --- top: header runs under the status bar / Dynamic Island ---------
   `.hdr` is `height: var(--header-h)` (44px) and `flex-shrink: 0`.
   `* { box-sizing: border-box }` is global (line 120), so padding is
   drawn INSIDE the height — growing the height by exactly the inset
   keeps the 44px of usable chrome intact and lets --chrome paint the
   status bar area.                                                   */
.hdr {
	height: calc(var(--header-h) + var(--sat));
	padding-block-start: var(--sat);
	padding-inline-start: calc(8px + var(--sal));
	padding-inline-end: calc(8px + var(--sar));
}

/* --- left edge in landscape: the icon rail ---------------------------
   `.rail` is `width: 56px` with `background: var(--chrome-2)`. Widening
   it by the inset keeps chrome-2 bleeding into the notch strip while
   the 40px tiles stay thumb-reachable. `align-items: center` centres
   the tiles inside the padded box, which is the behaviour we want.   */
.rail {
	width: calc(56px + var(--sal));
	padding-inline-start: var(--sal);
}

/* --- right edge in landscape ----------------------------------------
   Rightmost element is `.side` when it is visible (>1180px, so iPad
   landscape and desktop) and `.main` otherwise (phones, foldables).
   Padding goes on the SCROLLING CHILDREN rather than on `.main`, so
   `.main`'s --bg keeps painting all the way to the glass.            */
.side          { padding-inline-end: var(--sar); }
.chat__scroll  { padding-inline-end: calc(20px + var(--sar)); }
.scrollpane    { padding-inline-end: calc(20px + var(--sar)); }
.toolbar       { padding-inline-end: calc(20px + var(--sar)); }
.cwrap         { padding-inline-end: var(--sar); }
.mlist__scroll { padding-inline-end: var(--sar); }
.mread__body   { padding-inline-end: calc(24px + var(--sar)); }
.qbody         { padding-inline-end: calc(24px + var(--sar)); }

/* When `.side` is on screen it, not `.main`, owns the right edge —
   so give the inset back to `.side` and take it off `.main`'s panes.
   1181px is the complement of the file's own `@media (max-width: 1180px)
   { .side { display: none } }` on line 2717. Kept in lockstep. */
@media (min-width: 1181px) {
	.chat__scroll  { padding-inline-end: 20px; }
	.scrollpane    { padding-inline-end: 20px; }
	.toolbar       { padding-inline-end: 20px; }
	.mread__body   { padding-inline-end: 24px; }
	.qbody         { padding-inline-end: 24px; }
}

/* --- bottom: composer clears the home indicator AND the keyboard -----
   Base rule is `.composer { padding: 8px 20px 16px }` (line 592).
   --kb is deliberately NOT added here. The composer lives inside
   .app, and .app is already sized to the VISIBLE viewport (section 2
   tier c) whenever a keyboard is up -- so the shell ends where the
   keyboard begins and its last child is on the keyboard by
   construction. Adding --kb on top of that is what pushed the input
   a full keyboard-height up the screen and squeezed the thread into
   the remainder. --kb stays where it belongs: on the things
   positioned against the LAYOUT viewport, which the shrink never
   touches (.toast, section 4).
   The home indicator inset is dropped while the keyboard is up — iOS
   hides the indicator behind the keyboard, so keeping it would leave
   a dead 34px gap.                                                   */
.composer {
	padding-inline-start: calc(20px + var(--sal));
	padding-inline-end: calc(20px + var(--sar));
	padding-block-end: calc(16px + var(--sab));
}

/* Keyboard up: the home indicator is behind it, so its inset goes, and
   the gap to the keyboard is one small breath of padding. */
:root[data-kb="1"] .composer {
	padding-block-end: 8px;
}

/* The keyboard eats the screen; the "Enter to send" affordance is the
   first thing worth sacrificing for message real estate. */
:root[data-kb="1"] .composer__hint { display: none; }

/* --- the composer's resting height on a touch device ----------------
   Two rows, not one. One row is a 34px tap target that shows a third
   of a sentence, and it is what the box snapped back to after every
   send. Two rows is comfortable to hit and honest about a line that
   wraps; the autogrow (the `#draft` input handler) still takes it to
   the 108px cap from there.
   `min-height` and not `height`: the autogrow writes an inline
   `height` from scrollHeight, and min-height outranks it, so the box
   can never fall below two rows however that measurement lands.
   62px = two 24px rows (section 4 raises the line-height on coarse
   pointers) + the input's own 14px of block padding. */
@media (pointer: coarse) {
	.composer__input { min-height: 62px; }
}

/* Landscape on a phone is a different bargain. A rotated iPhone is ~390px
   tall and the keyboard takes more than half of it, so two rows of
   composer would come straight out of the conversation -- which is the
   very trade the short-viewport block above already makes when it caps
   this box at 72px. (That block also asks for a 20px line-height, but the
   later (pointer: coarse) rule wins with 24px -- so a row is 24px here too,
   and a 62px floor under a 72px cap would leave under half a row of growth:
   an effectively fixed-height box. The other reason two rows is wrong in
   landscape.) One row there.
   Immediately after the rule it overrides: same specificity, so source
   order is what decides it. */
@media (pointer: coarse) and (max-height: 520px) and (orientation: landscape) {
	.composer__input { min-height: 0; }
}

/* --- fixed / absolutely positioned overlays --------------------------
   Every `position: fixed` in the file (lines 788, 879, 1389, 2355) plus
   the two absolutely positioned menus (lines 1296 `.pm`, 2530 `.dd`). */

/* line 788 — .backdrop, `inset: 0` with `padding: 20px`. */
.backdrop {
	padding-block-start: calc(20px + var(--sat));
	padding-block-end: calc(20px + var(--sab));
	padding-inline-start: calc(20px + var(--sal));
	padding-inline-end: calc(20px + var(--sar));
}

/* line 879 — .toast, pinned to the bottom centre. Must clear the home
   indicator, and ride above the keyboard when one is open. */
.toast {
	inset-block-end: calc(20px + var(--sab) + var(--kb));
	max-width: calc(100vw - 32px - var(--sal) - var(--sar));
}

/* line 2355 — .ph-view, the full-screen photo lightbox. Its top bar is
   `height: 56px; flex-shrink: 0`, same border-box trick as .hdr. */
.ph-view__top {
	height: calc(56px + var(--sat));
	padding-block-start: var(--sat);
	padding-inline-start: calc(14px + var(--sal));
	padding-inline-end: calc(14px + var(--sar));
}
.ph-view__body { padding-block-end: var(--sab); }

/* line 1389 — .mk, the marketing film. Fixed, inset: 0, z-index 300.
   Its chrome (skip button, prev/next) must not land under the notch. */
.mk {
	padding-block-start: var(--sat);
	padding-block-end: var(--sab);
	padding-inline-start: var(--sal);
	padding-inline-end: var(--sar);
}

/* Anchored popovers. Both are `position: absolute` inside the header
   region, so they inherit the header's inset for the top edge, but
   their own bottom edge can still run past the home indicator once
   they hit their max-height. */
.pm { margin-block-end: var(--sab); }
.dd { margin-block-end: var(--sab); }


/* ------------------------------------------------------------------ *
 *  4. iOS AUTO-ZOOM ON INPUT FOCUS
 *
 *  Mobile Safari zooms the page when a focused form control's computed
 *  font-size is under 16px, and it does NOT zoom back out. The app has
 *  exactly two rules that produce sub-16px controls:
 *
 *    line 767  .input, .select, .textarea  { font-size: 14px }
 *    line 607  .composer__input            { font: inherit }  -> 15px
 *                                          (inherited from body, line 127)
 *
 *  Every <input>/<select>/<textarea> the app renders carries one of
 *  those classes — verified by enumerating all 40+ control tags in the
 *  template strings. There are no bare/unclassed controls and no
 *  contenteditable regions.
 *
 *  Guarded by `pointer: coarse` so desktop typography is untouched:
 *  this must not regress the desktop demo.
 * ------------------------------------------------------------------ */
@media (pointer: coarse) {
	.input,
	.select,
	.textarea {
		font-size: 16px;
	}

	.composer__input {
		/* Overrides the `font: inherit` shorthand from line 607 purely on
		   source order. line-height is restated as a ratio so the 22px
		   rhythm is preserved at the new size (16 x 1.375 = 22px), which
		   keeps the JS auto-grow clamp (Math.min(scrollHeight, 140) near
		   line 9180) landing on whole lines. */
		font-size: 16px;
		line-height: 1.375;
	}

	/* Larger controls need a taller tap target to stay balanced.
	   --tap is the app's own token (line 96), so this stays on-system. */
	.input,
	.select,
	.textarea {
		min-height: max(var(--tap), 40px);
	}
	.textarea { min-height: 76px; }
}


/* ------------------------------------------------------------------ *
 *  5. SCROLLING — momentum, rubber band, scroll chaining
 *
 *  The document itself never scrolls: `.app` is a 100dvh flex column
 *  with `overflow: hidden`, and inner panes do the scrolling. Without
 *  overscroll-behavior, dragging past the end of a pane on iOS hands
 *  the gesture to the document and rubber-bands the whole app, which
 *  reads as a broken native app.
 *
 *  `contain` (not `none`) on the panes: it stops the scroll CHAINING to
 *  the document but keeps the pane's own bounce, which is the gesture
 *  iOS users read as "you're at the end". `none` on the document kills
 *  the page-level bounce and Chrome's pull-to-refresh.
 * ------------------------------------------------------------------ */
html,
body {
	overscroll-behavior: none;
	/* iOS bumps font sizes on rotation to portrait-optimised values
	   unless pinned. Pinning to 100% does NOT disable user zoom. */
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

/* Every overflow:auto / overflow-y:auto container in the file
   (lines 248, 328, 496, 634, 719, 815, 909, 970, 1074, 1303, 1995,
   2053, 2406, 2444, 2509, 2545, 2658). */
.rail,
.list__scroll,
.chat__scroll,
.scrollpane,
.side__scroll,
.modal__b,
.appnav,
.fside__b,
.cwrap,
.pm,
.dd,
.mlist__scroll,
.mread__body,
.qbody,
.ph-view__body {
	overscroll-behavior: contain;
	/* Legacy iOS < 13 momentum scrolling. Inert (and harmless) on every
	   current engine, where momentum is the default. */
	-webkit-overflow-scrolling: touch;
}

/* The message list is the one pane where new content arrives at the
   bottom while the user may be reading. `overflow-anchor` keeps the
   viewport pinned to the read position instead of jumping. */
.chat__scroll {
	overflow-anchor: auto;
	scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
	.chat__scroll { scroll-behavior: auto; }
}


/* ------------------------------------------------------------------ *
 *  6. TOUCH INPUT SEMANTICS
 *
 *  touch-action: manipulation removes the ~300ms click delay that
 *  WebKit still applies while it waits to see whether a tap is the
 *  first half of a double-tap-to-zoom. It disables DOUBLE-TAP zoom on
 *  these elements only; PINCH zoom is untouched, so this is WCAG-safe
 *  (contrast with `touch-action: none`, which is not, and which does
 *  not appear anywhere here).
 * ------------------------------------------------------------------ */
button,
a,
[role="button"],
[data-act],
.chan,
.tab,
.rail__tile,
.cal-item,
.appnav__item,
.launch__app,
.mrow,
.ph-tile,
.set__item,
.pm__item,
.input,
.select,
.textarea,
.composer__input {
	touch-action: manipulation;
	-webkit-tap-highlight-color: transparent;
}

/* Killing the tap highlight removes the only press feedback touch users
   get, so it has to be replaced rather than merely deleted. --press
   mirrors the ORIGINAL --bg-hover values per theme, because §7 is about
   to neutralise --bg-hover itself. Values copied verbatim from
   line 61 (light), line 61 in the dark media block, and line 82. */
:root            { --press: #f2f1ec; }
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) { --press: #172722; }
}
:root[data-theme="dark"]          { --press: #172722; }

@media (hover: none) {
	.chan:active,
	.tab:active,
	.mem:active,
	.appnav__item:active,
	.cal-item:active,
	.launch__app:active,
	.pm__item:active,
	.set__item:active,
	.mrow:active,
	.dd button:active,
	.btn:active:not(:disabled),
	.ibtn:active,
	.prov:active,
	.crumbs button:active,
	.qstate button:active,
	.ph-scrub button:active {
		background: var(--press);
	}
	.rail__tile:active { transform: scale(0.94); }
}


/* ------------------------------------------------------------------ *
 *  7. STICKY :hover ON TOUCH
 *
 *  The file has 51 `:hover` rules. On touch, WebKit and Blink apply
 *  :hover on tap and leave it applied until the user taps elsewhere —
 *  so the last-tapped channel keeps a highlight that reads as a
 *  selection state, directly competing with the real selection
 *  (`.chan[aria-current="true"]`, line 394).
 *
 *  The textbook fix is to wrap all 51 rules in `@media (hover: hover)`.
 *  That means 51 hand edits and it is what I would do with write access
 *  to the file (the notes list them). Without it, there is a cleaner
 *  lever available here specifically:
 *
 *    VERIFIED: `var(--bg-hover)` appears on 30 lines in the file and
 *    EVERY ONE of them is inside a `:hover` rule. Zero non-hover uses.
 *    VERIFIED: `--tab-fg-hover` (line 35) is referenced exactly once,
 *    in `.tab:hover` (line 473).
 *
 *  So neutralising those two tokens under `(hover: none)` disarms 31 of
 *  the 51 rules with no collateral damage and no hand edits. The
 *  remainder — the ones using transform/opacity/filter/border-color or
 *  hard-coded colours — are neutralised explicitly below.
 *
 *  Specificity note: the token overrides must beat
 *  `:root[data-theme="dark"]` (0,2,0), so `:root:root` (also 0,2,0)
 *  is used and wins on source order. A plain `:root` (0,1,0) would
 *  silently lose in the dark theme.
 * ------------------------------------------------------------------ */
@media (hover: none) {
	:root:root {
		--bg-hover: transparent;
		--tab-fg-hover: var(--tab-fg);
	}

	/* --- rules that do NOT route through those two tokens --- */

	.hdr__app:hover        { background: transparent; color: var(--chrome-muted); }  /* 204 */
	.rail__tile:hover      { transform: none; }                                      /* 281 */
	.sect__toggle:hover    { color: inherit; }                                        /* 360 */
	.sect__btn:hover       { background: transparent; color: inherit; }               /* 377 */
	.tab__x:hover          { opacity: 0.5; }                                          /* 487 */
	.filecard:hover        { border-color: var(--border); }                           /* 570 */
	.board__card:hover     { border-color: var(--border); }                           /* 696 */
	.btn--primary:hover:not(:disabled) { filter: none; }                              /* 748 */
	.fstar:hover           { color: inherit; }                                        /* 945 */
	.tbl th.sortable:hover { color: var(--text-muted); }                              /* 965 */
	.cev:hover             { filter: none; }                                          /* 1114 */
	.launch__btn:hover     { border-color: rgba(255,255,255,.22); color: inherit; }   /* 1159 */
	.launch__app:hover .launch__ic { transform: none; box-shadow: none; }             /* 1254 */
	.me__btn:hover         { box-shadow: none; }                                      /* 1284 */
	.pm__preset:hover      { border-color: var(--border); color: inherit; }           /* 1357 */
	.pm__state:hover       { background: transparent; }                               /* 1337 */
	.matt:hover            { border-color: var(--border); }                           /* 2523 */
	.fltpl:hover           { border-color: var(--border); }                           /* 2624 */
	.mstar:hover           { color: inherit; }                                        /* 2501 */
	.ph-day__sel:hover     { background: transparent; }                               /* 2282 */
	.ph-card:hover .ph-card__art { outline: none; }                                   /* 2344 */
	.ph-tile:hover img     { transform: none; filter: none; }                         /* 2113 */
	.ph-hero:hover img     { transform: none; }                                       /* 2142 */
	.ph-hero:hover .ph-hero__play { background: rgba(255,255,255,.82); }              /* 2161 */
	.ph-strip button:hover { opacity: 1; }                                            /* 2176 */
	.ph-view__top .ibtn:hover { background: transparent; color: rgba(255,255,255,.75); } /* 2374 */
	.ph-nav:hover          { background: rgba(255, 255, 255, 0.16); }                 /* 2397 */

	/* line 2123 mixes :hover with real state selectors in one list:
	   `.ph-tile:hover::after, .ph-tile[data-sel="1"]::after,
	    .ph-tile[data-fav="1"]::after { opacity: 1 }`
	   Neutralise only the hover arm, then re-assert the state arms so a
	   selected-and-just-tapped tile keeps its marker. Order matters. */
	.ph-tile:hover::after { opacity: 0; }
	.ph-tile[data-sel="1"]::after,
	.ph-tile[data-fav="1"]::after { opacity: 1; }

	/* line 2203, same shape. */
	.ph-tile:hover .ph-pick,
	.ph-tile:hover .ph-fav { opacity: 0; }
	.ph-tile[data-sel="1"] .ph-pick,
	.ph-tile[data-fav="1"] .ph-fav { opacity: 1; }

	/* The .mk film chrome (1892, 1894, 1938, 1958). */
	.mk-btn:hover     { background: transparent; border-color: rgba(244,243,238,.28); }
	.mk-btn--go:hover { background: #3FD6A6; border-color: #3FD6A6; }
	.mk__ibtn:hover,
	.mk__skip:hover   { color: inherit; border-color: rgba(244,243,238,.28); }

	/* Row-level cursor hints are meaningless without a pointer. */
	.tbl tbody tr:hover  { cursor: default; }
	.ccol__slot:hover    { cursor: default; }
}


/* ------------------------------------------------------------------ *
 *  8. iPad — Split View, Slide Over, Stage Manager
 *
 *  The window can be ANY width, independent of device. The app already
 *  gets this right: platform.js confirmed there is ZERO user-agent
 *  sniffing in the file (no navigator.userAgent / .platform / .vendor /
 *  maxTouchPoints, no /iPad|iPhone|Android/ tests anywhere in the
 *  ~6,400 lines of JS). All 15 existing media queries are width-based.
 *  Nothing to undo — this section only adds pointer semantics.
 *
 *  Pointer situation on iPad:
 *    - finger only          -> (pointer: coarse) (hover: none)
 *    - trackpad/Magic Mouse -> (pointer: fine)   (hover: hover)
 *    - trackpad attached but user still touching the screen: Safari
 *      reports the FINE pointer, because `pointer`/`hover` describe the
 *      PRIMARY input. So a paired-keyboard iPad gets desktop hover
 *      semantics AND finger taps.
 *
 *  Consequence: `(pointer: coarse)` alone is not a safe gate for
 *  touch-sized targets on iPad — an iPad with a Magic Keyboard reports
 *  fine/hover yet is still touched constantly. `any-pointer: coarse`
 *  ("at least one available input is coarse") is the correct test for
 *  "a finger might touch this", and it is what sizes tap targets below.
 *  `(pointer: coarse)` stays the gate for the 16px font fix, because
 *  the auto-zoom only fires for the primary touch case.
 * ------------------------------------------------------------------ */
/*  DELIBERATELY NOT DONE HERE: hit-target expansion.
 *
 *  The obvious move is to grow `.ibtn` / `.tab__x` / `.rail__tile` to
 *  the 44x44 (Apple HIG) / 48x48 (Material) minimum under
 *  (any-pointer: coarse), via a transparent ::after overlay. I built it,
 *  measured it against the live prototype, and removed it. Two reasons:
 *
 *  1. IT REGRESSES DESKTOP. Measured in the running app: `.ibtn` is
 *     34x34 and the toolbar packs them with a 10px gap (line 758 area).
 *     A 44px overlay extends 5px past each edge, so ADJACENT overlays
 *     overlap and the later one in DOM order swallows clicks meant for
 *     its neighbour. `(any-pointer: coarse)` matches any machine with a
 *     touchscreen — including Surface and ThinkPad Yoga laptops driven
 *     by trackpad, which is exactly the enterprise hardware this demo
 *     runs on. Verified: this very browser reports any-pointer: coarse.
 *     `.tab__x` is nested inside `.tab`, so an oversized overlay there
 *     turns "select tab" into "close tab".
 *
 *  2. IT IS NOT MY LAYER. Target sizing is a component/layout decision,
 *     and the brief assigns those to the second agent. Doing it here
 *     would also mean doing it blind to whatever phone layout they land
 *     on.
 *
 *  RECOMMENDATION for whoever owns the components: solve it with real
 *  box size (raise --tap from 34px, line 96) inside the phone
 *  breakpoint, not with overlays. That changes layout honestly instead
 *  of hiding a mismatch behind an invisible rectangle.
 */


/* ------------------------------------------------------------------ *
 *  9. FOLDABLES — CSS Viewport Segments
 *
 *  Standard: CSS Viewport Segments (W3C CSS WG). Two halves:
 *
 *    media features   horizontal-viewport-segments: <integer>
 *                     vertical-viewport-segments:   <integer>
 *    env() variables  viewport-segment-width  <i> <j>
 *                     viewport-segment-height <i> <j>
 *                     viewport-segment-top / -left / -bottom / -right
 *
 *  NOTE ON SYNTAX: the indices are SPACE separated, not comma
 *  separated — `env(viewport-segment-width 0 0, 0px)`. The trailing
 *  comma introduces the FALLBACK, exactly as in env(safe-area-inset-*).
 *  A comma between the indices is invalid and the whole declaration is
 *  dropped. (The brief wrote them comma-separated; flagged in the notes.)
 *
 *  A "segment" is a logically separate region of the viewport. A device
 *  with no fold reports ONE segment, so `horizontal-viewport-segments: 1`
 *  matches an ordinary phone and desktop — which is why all the fold
 *  behaviour is written as `: 2` and everything else is left alone.
 *  Nothing in this section can fire on a non-folding device.
 *
 *  --seam is the physical width of the hinge/gap: the left edge of the
 *  second segment minus the right edge of the first. On a seamless
 *  flexible display both edges coincide and --seam computes to 0, so
 *  the same rules degrade to a plain two-pane split for free. That
 *  property is what makes this defensive rather than device-specific.
 * ------------------------------------------------------------------ */

/* ---- 9a. VERTICAL HINGE, device unfolded (Z Fold-class open) --------
   Two side-by-side segments, ~840x1080 CSS px total on current Fold
   hardware. `.rail` (56px) + `.list` (300px) live in segment 0 and
   `.main` takes segment 1, so the seam falls exactly on the existing
   list/main boundary instead of slicing a message in half.

   Everything is derived from env() — no 840, no 360, no device width
   is hard-coded anywhere in this block.                              */
@media (horizontal-viewport-segments: 2) {
	/* FALLBACKS ARE MANDATORY, AND MUST BE SANE.
	   Verified empirically in Chromium: an env() whose variable cannot
	   be resolved and which has NO fallback is invalid at computed-value
	   time and the whole declaration is dropped — `width: env(...)` with
	   no fallback computes to 0px, not to the previous declaration.
	   So every one of these carries a fallback, and the fallback is a
	   HALF-VIEWPORT rather than 0px: if a future engine matches the
	   media feature but reports no geometry (the plausible failure mode
	   for a device nobody has tested against yet), the app degrades to
	   an even two-pane split instead of collapsing a pane to zero. */
	:root {
		--seg0-w: env(viewport-segment-width 0 0, 50vw);
		--seg1-w: env(viewport-segment-width 1 0, 50vw);
		--seam: calc(
			env(viewport-segment-left 1 0, 50vw) -
			env(viewport-segment-right 0 0, 50vw)
		);
	}

	/* `.list` fills whatever is left of segment 0 after the rail. The
	   file's own `@media (max-width: 900px) { .list { width: 240px } }`
	   (line 2720) would otherwise pin it to 240px and leave a ragged
	   gutter, so this restates the width; being later in source order
	   it wins at equal specificity. */
	.list {
		width: calc(var(--seg0-w) - 56px - var(--sal));
		flex-shrink: 0;
	}

	/* Push `.main` clear of the hinge. A margin (not padding) so the
	   seam shows the shell background rather than a stretched pane. */
	.main {
		margin-inline-start: var(--seam);
	}

	/* The right sidebar cannot coexist with a two-pane split on a
	   ~840px canvas; the conversation needs the whole second segment. */
	.side { display: none; }

	/* Modals must not straddle the hinge — a dialog with its buttons
	   split across a physical gap is the single most obvious foldable
	   bug. Clamp to the wider segment and centre within it. */
	.modal {
		max-width: min(560px, calc(max(var(--seg0-w), var(--seg1-w)) - 40px));
	}
	.backdrop {
		justify-content: flex-start;
		padding-inline-start: calc(
			20px + var(--sal) +
			max(0px, (var(--seg0-w) - min(560px, var(--seg0-w) - 40px)) / 2)
		);
	}
}

/* ---- 9b. HORIZONTAL HINGE — book / laptop posture -------------------
   Two stacked segments (a Flip-class device opened, or a Fold held
   book-wise). The natural mapping for a chat app is the laptop one:
   conversation in the top segment, composer in the bottom, hinge
   between them — physically the same gesture as a laptop screen and
   keyboard.                                                          */
@media (vertical-viewport-segments: 2) {
	/* Same reasoning as 9a. A 0px fallback here would compute
	   `max-height: calc(0px - 44px)` on `.chat__scroll`, clamp to 0 and
	   make the entire conversation invisible — the worst possible
	   failure in a sales demo. 50dvh degrades to an even split. */
	:root {
		--seg-top-h: env(viewport-segment-height 0 0, 50dvh);
		--vseam: calc(
			env(viewport-segment-top 0 1, 50dvh) -
			env(viewport-segment-bottom 0 0, 50dvh)
		);
	}

	/* Rail and list are horizontal chrome in this posture; the fold is
	   too short to carry a sidebar. Left to the layout agent to decide
	   the nav pattern — this only guarantees the SEAM lands correctly. */
	.chat__scroll {
		max-height: calc(var(--seg-top-h) - var(--header-h) - var(--sat));
	}

	.composer {
		margin-block-start: var(--vseam);
	}

	/* Keep dialogs inside the top segment rather than bridging the gap. */
	.modal { max-height: calc(var(--seg-top-h) - 40px); }
	.backdrop { align-items: flex-start; }
}

/* ---- 9c. JS FALLBACK for engines without the CSS media features -----
   platform.js sets data-segments="2" plus --js-seg0-w / --js-seam on
   <html> when it can read segment geometry through a non-CSS route
   (the older `visualViewport.segments` / `getWindowSegments()` shapes).
   Gated on `data-seg-css="0"` so it can never fight the real thing on
   a browser that supports both. */
:root[data-seg-css="0"][data-segments="2"][data-seg-axis="horizontal"] .list {
	width: calc(var(--js-seg0-w, 300px) - 56px);
	flex-shrink: 0;
}
:root[data-seg-css="0"][data-segments="2"][data-seg-axis="horizontal"] .main {
	margin-inline-start: var(--js-seam, 0px);
}
:root[data-seg-css="0"][data-segments="2"][data-seg-axis="horizontal"] .side {
	display: none;
}

/* ---- 9d. Z Fold-class FOLDED (cover screen) ------------------------
   ~360 CSS px wide and unusually tall (aspect ratio near 1:2.2). It
   reports ONE segment, so none of the above applies and it is simply a
   narrow phone — correctly the layout agent's territory, not mine.
   The only substrate concern is that the app is exceptionally tall, so
   the composer is a long way from the content the user is reading.
   Nothing to force here; noted so the boundary is explicit.

   ---- Apple's foldable ----
   There is NO published specification, no announced screen size, no
   confirmed segment reporting behaviour, and no shipping browser to
   test against. I have deliberately invented no numbers. The defence
   is structural: every rule above is driven by env(viewport-segment-*)
   and reduces to a no-op when the device reports a single segment. If
   Apple's device reports two segments through the standard API, 9a/9b
   apply unchanged; if it reports one segment (a seamless display
   presented as one canvas, which is the more likely choice given
   how Apple has handled Stage Manager), the app is a plain wide
   viewport and the layout agent's breakpoints carry it. Either way
   nothing breaks. See platform-notes.md for the honest limits. */


/* ------------------------------------------------------------------ *
 * 10. MISC PLATFORM HYGIENE
 * ------------------------------------------------------------------ */

/* iOS renders <select> and <input type=date|time> with its own control
   chrome and ignores several box properties unless appearance is reset.
   The app uses type=date and type=time in the event and out-of-office
   dialogs (lines 7154, 7156, 7174, 7176, 7213, 7216, 7218, 6931). */
.select {
	-webkit-appearance: none;
	appearance: none;
	/* Room for the native disclosure arrow iOS draws regardless. */
	padding-inline-end: 28px;
}
.input[type="date"],
.input[type="time"] {
	-webkit-appearance: none;
	appearance: none;
	/* Safari centres date/time text vertically only with an explicit
	   line-height; without it the value sits high in the box. */
	line-height: normal;
	min-width: 0;
}

/* iOS renders type=search with a native inset and a clear button that
   ignores the app's border radius. Four search fields: lines 3916
   (#filter), 5073 (#mq), 5938 (#fq), and the members lookup. */
.input[type="search"] {
	-webkit-appearance: none;
	appearance: none;
}
.input[type="search"]::-webkit-search-decoration,
.input[type="search"]::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
}

/* The composer textarea is resizable by default via `.textarea`, but
   `.composer__input` sets `resize: none` (line 610) — correct, since JS
   drives its height. Belt and braces for the drag handle on touch. */
.composer__input { resize: none; }

/* Prevent the long-press callout ("Copy / Look Up") on chrome that is
   not text content. Message text is deliberately excluded — users must
   still be able to select and copy what people wrote. */
.hdr,
.rail,
.tab,
.chan,
.appnav__item,
.launch__app {
	-webkit-touch-callout: none;
	-webkit-user-select: none;
	user-select: none;
}

/* ...and explicitly re-enable selection where it matters. */
.msg__text,
.doc,
.mread__body,
.fmeta__v {
	-webkit-touch-callout: default;
	-webkit-user-select: text;
	user-select: text;
}

/* Landscape phone: the header is 44px of a ~390px-tall viewport. Not a
   layout change (that is the other agent's call) — purely reclaiming
   the status-bar padding, which the browser chrome already covers in
   landscape on iOS. */
@media (orientation: landscape) and (max-height: 450px) {
	:root { --sat: 0px; }
}

/* ------------------------------------------------------------------ *
 * 11. COORDINATION WITH responsive-layout.css  (the other agent)
 *
 *  >>> PASTE-ORDER REQUIREMENT <<<
 *  This section must come AFTER responsive-layout.css in the stylesheet.
 *  Recommended final order inside the style block:
 *      [existing app CSS]  ->  responsive-layout.css  ->  platform.css
 *  Several rules below deliberately re-declare theirs and rely on
 *  winning by source order at equal specificity.
 *
 *  Their file turns `.hdr__apps` into a FIXED BOTTOM TAB BAR below
 *  768px and reserves room for it with `.app { padding-block-end:
 *  var(--tabbar-h) }`. That changes who owns the bottom edge of the
 *  screen, which is squarely a safe-area question — so it is mine.
 *
 *  They left an explicit request at their lines 249-252 asking the
 *  platform layer to add the bottom inset here. This honours it.
 *
 *  Every rule below is inert if responsive-layout.css is NOT pasted:
 *  --tabbar-h would be undefined, so the fallbacks in the var() calls
 *  keep the arithmetic valid and equal to the no-tab-bar case.
 * ------------------------------------------------------------------ */
@media (max-width: 767.98px) {

	/* The tab bar sits ON the home indicator. Grow it by the inset and
	   pad its contents clear, so --chrome bleeds to the glass while the
	   buttons stay above the indicator. Same border-box trick as .hdr. */
	.hdr__apps {
		height: calc(var(--tabbar-h, 56px) + var(--sab));
		padding-block-end: var(--sab);
	}

	/* ...and the shell must reserve the taller height, or the last row
	   of the conversation hides behind the bar. */
	.app {
		padding-block-end: calc(var(--tabbar-h, 56px) + var(--sab));
	}

	/* THE COMPOSER NO LONGER OWNS THE BOTTOM EDGE. The tab bar does, and
	   it is now carrying the home-indicator inset — so the composer must
	   STOP adding it or the gap is counted twice (~34px of dead space
	   above the tab bar on every notched iPhone). Overrides §3. */
	.composer {
		padding-block-end: 16px;
	}
	:root[data-kb="1"] .composer {
		padding-block-end: 8px;
	}

	/* When the keyboard is up, the tab bar is buried behind it. Reclaim
	   its reserved space — otherwise the shell keeps a 56px hole under
	   the keyboard and the composer floats absurdly high. */
	:root[data-kb="1"] .app { padding-block-end: 0; }
	:root[data-kb="1"] .hdr__apps { display: none; }

	/* Their line 352 sets `.toast { inset-block-end: calc(var(--tabbar-h)
	   + 16px) }`, which correctly clears the tab bar but drops both the
	   safe-area inset and the keyboard offset that §3 added. Restore
	   all three terms. */
	.toast {
		inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab) + var(--kb) + 16px);
	}
	:root[data-kb="1"] .toast {
		/* tab bar is hidden while typing, so only clear the keyboard */
		inset-block-end: calc(var(--kb) + 16px);
	}

	/* Their line 957 caps `.pm` at `calc(100dvh - var(--header-h) - 16px)`,
	   which ignores the status bar the header now extends under. */
	.pm {
		max-height: calc(100dvh - var(--header-h) - var(--sat) - var(--sab) - 16px);
	}
}

/*  ONE DUPLICATION BETWEEN THE TWO FILES, recorded so nobody "fixes"
 *  half of it later.
 *
 *  responsive-layout.css lines 98 and 101 also raise the form controls
 *  and `.composer__input` to 16px under (pointer: coarse) — same intent
 *  and same value as §4 here, so the duplication is harmless and either
 *  file alone is sufficient for the iOS auto-zoom fix. Keeping both is
 *  deliberate: neither file should depend on the other being pasted.
 *
 *  The one genuine disagreement is `.composer__input` line-height —
 *  theirs 24px, §4 here 22px. Under the recommended paste order this
 *  file is LAST, so §4 would silently win. Line-height is a component
 *  metric and therefore their call, not mine, so it is handed back
 *  explicitly below rather than won by accident of ordering.
 *
 *  (Either value is safe for the JS auto-grow near line 9180, which
 *  clamps at a flat 140px: 5 rows at 24px, 6 at 22px.) */
@media (pointer: coarse) {
	.composer__input { line-height: 24px; }
}

/* END PLATFORM SUBSTRATE ------------------------------------------- */

/* ---------- light-chrome.css ---------- */
/* ================================================================
   LIGHT-MODE CHROME · glass + the nuvocloud.eu arc motif
   ----------------------------------------------------------------
   In light mode the topbar and the Spaces rail were still deep ink
   (#08231c / #0c2a22), which is why the app read dark even with a
   white body. This lifts them to a pale mint glass and carries the
   arc motif from the marquee band under the homepage hero.

   The motif, lifted from .trust__arcs on nuvocloud.eu: ONE cubic arc
   stroked three times — 46px at .05, 16px at .09, 1.5px at .22 — so a
   line reads as light rather than as a stroke, plus a single faint
   orange arc and a soft radial bloom.

   Values are re-graded, not copied. The site's stack sits on deep ink
   where a 5% mint glow reads; on a pale ground the same numbers are
   invisible, so the glow steps are roughly doubled and the crisp
   hairline moves to mint-dark #15916B, which has the luminance to
   register on white.

   Scoped so DARK MODE IS UNTOUCHED. The dark blocks override only
   --chrome and --chrome-2; the text tokens are inherited from the
   bare :root, so setting them there would have put ink text on a
   near-black bar. Everything below is additive and light-only.
   ================================================================ */

@media (prefers-color-scheme: light) {
	:root:not([data-theme="dark"]) {
		--chrome:              rgba(247, 252, 250, 0.78);
		--chrome-2:            rgba(241, 249, 245, 0.72);
		--chrome-text:         #08231C;
		--chrome-muted:        rgba(8, 35, 28, 0.66);
		--chrome-active:       color-mix(in srgb, var(--brand-dark) 30%, transparent);
		--chrome-active-text:  color-mix(in srgb, var(--brand-light) 80%, #000000);
		--chrome-edge:         color-mix(in srgb, var(--brand-light) 16%, transparent);
		--chrome-glass:        saturate(150%) blur(14px);
		--nuvo-wash: radial-gradient(1200px 460px at 18% -8%,
			color-mix(in srgb, var(--brand-dark) 10%, transparent), transparent 68%);
		/* Only defined in light. The pseudo-elements and the list tint key off
		   these, so in dark mode they fall back and vanish entirely. */
		--nuvo-arc-on:  '';
		--chrome-list:  rgba(241, 249, 245, 0.72);
		/* backdrop-filter makes .hdr a stacking context, which traps the Apps
		   panel (z 90) and the profile menu inside the header. Lift the whole
		   header context above content but below .backdrop (100).
		   90 was not enough: it only tied with the panel's own z-index and
		   left no headroom over content. 99 clears every ordinary element
		   while still sitting under .backdrop (100) and .modal (200), so
		   dialogs still cover the bar as they should. */
		--nuvo-hdr-z:   99;
		--nuvo-child-z: 1;
	}
}

:root[data-theme="light"] {
	--chrome:              rgba(247, 252, 250, 0.78);
	--chrome-2:            rgba(241, 249, 245, 0.72);
	--chrome-text:         #08231C;
	--chrome-muted:        rgba(8, 35, 28, 0.66);
	--chrome-active:       color-mix(in srgb, var(--brand-dark) 22%, transparent);
	--chrome-active-text:  color-mix(in srgb, var(--brand-light) 80%, #000000);
	--chrome-edge:         color-mix(in srgb, var(--brand-light) 16%, transparent);
	--chrome-glass:        saturate(150%) blur(14px);
	--nuvo-wash: radial-gradient(1200px 460px at 18% -8%,
		color-mix(in srgb, var(--brand-dark) 10%, transparent), transparent 68%);
	--nuvo-arc-on:  '';
	--chrome-list:  rgba(241, 249, 245, 0.72);
	--nuvo-hdr-z:   99;
	--nuvo-child-z: 1;
}

/* The wash exists so the glass has something to pick up. Without it a
   translucent bar in a fixed-shell layout is just a lighter opaque bar:
   nothing scrolls underneath it to show through. */
.app { background-image: var(--nuvo-wash, none); }

/* ---------------------------------------------------------------- topbar */
.hdr {
	position: relative;
	background: var(--chrome);
	-webkit-backdrop-filter: var(--chrome-glass, none);
	        backdrop-filter: var(--chrome-glass, none);
	z-index: var(--nuvo-hdr-z, auto);
	box-shadow: inset 0 -1px 0 var(--chrome-edge, transparent);
}

/* ------------------------------------------------------------ spaces rail */
.rail {
	position: relative;
	background: var(--chrome-2);
	-webkit-backdrop-filter: var(--chrome-glass, none);
	        backdrop-filter: var(--chrome-glass, none);
	box-shadow: inset -1px 0 0 var(--chrome-edge, transparent);
}

/* The channel list sits directly against the rail; without a matching
   tint the two read as different materials meeting at a seam. */
.list { background-color: var(--chrome-list, var(--bg-subtle)); }

/* -------------------------------------------------------------- the arcs */
/* Inline SVG as a data URI: a strict CSP blocks external images, and this
   keeps the whole motif in one declaration with no extra request. */
.hdr::after,
.rail::after {
	content: var(--nuvo-arc-on, none);
	position: absolute;
	inset: 0 -6% 0 -6%;
	pointer-events: none;
	z-index: 0;
	background-repeat: no-repeat;
	background-size: cover;
	animation: nuvo-arc-drift 26s var(--e-inout, cubic-bezier(.65,0,.35,1)) infinite alternate;
}

/* Every direct child of the bar must clear the overlay.
   NOT `position: relative` -- .hdr__apps becomes a FIXED bottom tab bar
   below 768px, and this file lands after responsive-layout.css, so a
   blanket position here silently un-pinned it and folded it back into
   the header. Both bars are flex containers, and a flex item honours
   z-index while still position:static, so stacking alone is enough. */
.hdr > *, .rail > * { z-index: var(--nuvo-child-z, auto); }

/* ----------------------------------------------------------------
   Why the Apps panel could end up under content, in light mode only.

   The line above puts all three header children on z-index 1, and a flex
   item honours z-index while still position:static -- so each becomes a
   STACKING CONTEXT. .launch__panel's own z-index 90 is therefore inert:
   it resolves against its siblings inside .hdr__apps, not against the
   page. Two consequences, both light-only, because in dark mode neither
   --chrome-glass nor --nuvo-child-z is defined and the panel's 90 works
   at the root exactly as written:

     1. .hdr__brand / .hdr__apps / .hdr__right are TIED at 1, so DOM order
        decides. .hdr__right is last, so anything in it that reaches down
        into the panel's box paints over it.
     2. The panel can never beat .hdr's own z-index against page content.

   Fix 1: lift whichever header child currently owns an open menu above
   its siblings. Scoped with :has() so the two menus cannot fight each
   other -- a blanket lift on .hdr__apps would push the profile menu
   under the Apps panel instead, which is the same bug wearing a hat.

   LIGHT ONLY, and that scoping is load-bearing. In dark mode the header
   children have no z-index at all, so this rule would CREATE a stacking
   context where none existed and cap the panel at 3 -- below .dd (60),
   .lang-dd (70) and .pm (90). Measured: unscoped, the dark panel dropped
   from an effective 90 at the root to 3. The bug only exists in light,
   so the fix lives only in light.
   ---------------------------------------------------------------- */
@media (prefers-color-scheme: light) {
	:root:not([data-theme="dark"]) .hdr > *:has(.launch__panel),
	:root:not([data-theme="dark"]) .hdr > *:has(.pm) { z-index: 3; }
}
:root[data-theme="light"] .hdr > *:has(.launch__panel),
:root[data-theme="light"] .hdr > *:has(.pm) { z-index: 3; }

.hdr::after {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 120' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3CradialGradient id='a' cx='72%25' cy='42%25' r='46%25'%3E%3Cstop offset='0%25' stop-color='rgba(63,214,166,.20)'/%3E%3Cstop offset='100%25' stop-color='rgba(63,214,166,0)'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='1440' height='120' fill='url(%23a)'/%3E%3Cpath d='M -60,142 C 260,116 520,52 1500,-18' stroke='rgba(63,214,166,.10)' stroke-width='46' fill='none' stroke-linecap='round'/%3E%3Cpath d='M -60,142 C 260,116 520,52 1500,-18' stroke='rgba(63,214,166,.18)' stroke-width='16' fill='none' stroke-linecap='round'/%3E%3Cpath d='M -60,142 C 260,116 520,52 1500,-18' stroke='rgba(21,145,107,.34)' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3Cpath d='M -60,168 C 340,150 700,96 1500,26' stroke='rgba(255,138,61,.18)' stroke-width='1.2' fill='none' stroke-linecap='round'/%3E%3Ccircle cx='1104' cy='34' r='30' fill='rgba(63,214,166,.09)'/%3E%3Ccircle cx='1104' cy='34' r='11' fill='rgba(63,214,166,.16)'/%3E%3Ccircle cx='248' cy='92' r='18' fill='rgba(255,138,61,.09)'/%3E%3C/svg%3E");
}

/* The rail runs vertically, so the arc is transposed rather than rotated —
   a rotate would need a square box and would crop at both ends. */
.rail::after {
	inset: -4% 0 -4% 0;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 1440' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3CradialGradient id='b' cx='42%25' cy='72%25' r='46%25'%3E%3Cstop offset='0%25' stop-color='rgba(63,214,166,.20)'/%3E%3Cstop offset='100%25' stop-color='rgba(63,214,166,0)'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='120' height='1440' fill='url(%23b)'/%3E%3Cpath d='M 142,-60 C 116,260 52,520 -18,1500' stroke='rgba(63,214,166,.10)' stroke-width='46' fill='none' stroke-linecap='round'/%3E%3Cpath d='M 142,-60 C 116,260 52,520 -18,1500' stroke='rgba(63,214,166,.18)' stroke-width='16' fill='none' stroke-linecap='round'/%3E%3Cpath d='M 142,-60 C 116,260 52,520 -18,1500' stroke='rgba(21,145,107,.34)' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3Cpath d='M 168,-60 C 150,340 96,700 26,1500' stroke='rgba(255,138,61,.18)' stroke-width='1.2' fill='none' stroke-linecap='round'/%3E%3Ccircle cx='34' cy='1104' r='30' fill='rgba(63,214,166,.09)'/%3E%3Ccircle cx='34' cy='1104' r='11' fill='rgba(63,214,166,.16)'/%3E%3C/svg%3E");
}

/* A slow tidal drift, not a loop you can time. */
@keyframes nuvo-arc-drift {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(2.2%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
	.hdr::after, .rail::after { animation: none; }
}

/* Hover and active states were written for white-on-ink and go invisible
   on glass. */
@media (prefers-color-scheme: light) {
	:root:not([data-theme="dark"]) .hdr__app:hover { background: rgba(8, 35, 28, 0.06); }
	:root:not([data-theme="dark"]) .rail__tile { color: var(--chrome-text); }
}
:root[data-theme="light"] .hdr__app:hover { background: rgba(8, 35, 28, 0.06); }
:root[data-theme="light"] .rail__tile { color: var(--chrome-text); }

/* ----------------------------------------------------------------
   backdrop-filter establishes a containing block for position:fixed
   descendants. Below 768px .hdr__apps IS a fixed bottom tab bar and
   lives inside .hdr, so the blur re-anchored it to the header and it
   rendered at the TOP of the screen (measured: bottom 52px instead of
   812px). Drop the blur in the compact band only — on a phone nothing
   sits behind the bar to blur, so the tint and the arcs carry it.
   ---------------------------------------------------------------- */
@media (max-width: 767.98px) {
	.hdr {
		-webkit-backdrop-filter: none;
		        backdrop-filter: none;
	}
}

/* ---------- attention.css ---------- */
/* ================================================================
   ATTENTION · wake on approach
   ----------------------------------------------------------------
   The brief: the right sidebar sits muted until the pointer goes
   there, and more broadly the interface should be smart about what
   is active and what is not.

   The naive version of this is `opacity: .5` on the region. It is
   wrong three times over: it dims live state along with decoration,
   it makes text muddy rather than quiet, and a half-faded panel
   reads as DISABLED, which is a different message entirely.

   So instead of fading a region, the region re-mixes its own colour
   tokens toward the background, and every element that carries live
   state is explicitly exempt. Nothing is faded. Things step back.

   The mechanic: --wake is a registered <number>, 0 muted, 1 awake.
   Registering it means the browser can INTERPOLATE it, so the
   colour-mix percentages animate smoothly instead of snapping. That
   is the difference between a cross-fade and a switch.
   ================================================================ */

@property --wake {
	syntax: '<number>';
	inherits: true;
	initial-value: 0;
}

/* Fallback for engines without @property: no interpolation, but the
   two end states are still correct, so nothing looks broken. */
@supports not (background: paint(x)) {
	.side, .rail { --wake: 0; }
}

/* ----------------------------------------------------------------
   Only where hovering is a real thing.

   On a touchscreen there is no pointer to approach with, so a muted
   panel would simply be permanently dim. And below 1181px .side is
   display:none anyway — on a phone it is the whole screen at
   data-depth="2", where muting it would be absurd. One media query
   covers all of that honestly, rather than an IntersectionObserver
   that would have nothing to observe.

   prefers-reduced-motion and prefers-contrast are both requests for
   a plainer interface. Muting is the opposite of plainer, so both
   opt out entirely rather than getting a degraded version of it.
   ---------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {

	/* ---- the regions that participate ---------------------------
	   .side  — reference material. Muted hardest; you read it once.
	   .rail  — pure navigation chrome. Muted gently; it is a map,
	            and a map you cannot read is not a map.
	   .main and .list never mute. The conversation is the subject of
	   the screen, and the channel list is how you notice things. */

	.side {
		--wake: 0;
		transition: --wake 560ms cubic-bezier(.4, 0, .2, 1) 140ms;
	}
	.side:hover,
	.side:focus-within {
		--wake: 1;
		transition: --wake 150ms cubic-bezier(.16, 1, .3, 1) 0ms;
	}

	.rail {
		--wake: 0;
		transition: --wake 560ms cubic-bezier(.4, 0, .2, 1) 140ms;
	}
	.rail:hover,
	.rail:focus-within {
		--wake: 1;
		transition: --wake 150ms cubic-bezier(.16, 1, .3, 1) 0ms;
	}

	/* Asymmetric on purpose. Waking is near-instant because it must
	   feel like the panel was always ready; sleeping is slow and
	   delayed so that crossing the panel on the way somewhere else
	   never makes it strobe. */

	/* ---- what actually changes ----------------------------------
	   Text is mixed toward the background rather than made
	   transparent. A colour-mix keeps the type crisp at every step;
	   opacity would render it grey AND soft, which is what makes the
	   naive version look cheap. */

	.side .side__title,
	.side .mem__n {
		color: color-mix(in oklab, var(--text) calc(38% + 62% * var(--wake)), var(--bg));
	}

	.side .mem__r,
	.side .muted,
	.side .panel__t {
		color: color-mix(in oklab, var(--text-muted) calc(46% + 54% * var(--wake)), var(--bg));
	}

	/* Avatars are the loudest thing in the panel — six saturated
	   discs. Desaturating rather than fading keeps their shape and
	   their initials readable while removing the colour shouting. */
	.side .av {
		filter: saturate(calc(0.3 + 0.7 * var(--wake)));
		transition: filter 340ms cubic-bezier(.4, 0, .2, 1);
	}

	/* Buttons keep their label legible and lose only their edge, so
	   the panel does not read as three disabled controls. */
	.side .btn {
		border-color: color-mix(in oklab, var(--border) calc(30% + 70% * var(--wake)), transparent);
		color: color-mix(in oklab, var(--text) calc(52% + 48% * var(--wake)), var(--bg));
	}

	/* The divider that separates the panel from the conversation. */
	.side {
		border-inline-start-color: color-mix(in oklab, var(--border) calc(42% + 58% * var(--wake)), transparent);
	}

	/* The rail's tiles are navigation: presence steps back, identity does not.

	   Opacity only, deliberately. An earlier version also desaturated, and
	   that was wrong: a Space's colour IS its name at this size -- the tile
	   is 40px and the initials are two characters, so colour is what you
	   actually recognise it by. Draining it turns four distinct places into
	   four grey squares, which is a different and worse problem than being
	   too loud.

	   opacity() inside filter rather than the opacity property, so it
	   composes into the one declaration the exemptions already override
	   with `filter: none` -- one switch, not two.

	   This 0.52 is the single knob for how quiet the rail is. */
	.rail .rail__tile {
		filter: opacity(calc(0.52 + 0.48 * var(--wake)));
		transition: filter 340ms cubic-bezier(.4, 0, .2, 1);
	}

	/* ---- STATE IS NEVER MUTED ----------------------------------
	   Everything below is exempt, and the exemptions are the whole
	   reason this is a design and not a filter. A muted unread badge
	   is not a subtle interface, it is a missed message.

	   These win by being more specific than the rules above, and by
	   re-stating the colour rather than inheriting a mixed one. */

	.side .dot,
	.side .pill-count,
	.rail .pill-count,
	.rail__badge {
		filter: none !important;
		opacity: 1 !important;
	}

	/* .rail__badge is currently a SIBLING of .rail__tile, so the tile's
	   saturate() never reaches it — verified in the running app. The
	   exemption is here anyway: the day someone nests the badge inside
	   the tile for layout reasons, an unread count would silently go
	   grey, and nobody would connect that to a refactor of the rail. */

	/* A presence dot means someone is available, away or in a call.
	   That is live information and it keeps full colour at all times. */
	.side .dot { --wake: 1; }

	/* The typing indicator and any in-call marker are, by definition,
	   happening right now. */
	.side .dots,
	.side .dots i,
	.rail .dots i {
		filter: none !important;
		opacity: 1 !important;
	}

	/* The Space you are in keeps full strength -- it is the answer to
	   "where am I", and that survives everything.

	   Belt and braces on purpose. aria-current is now emitted by the
	   renderer, but :has(.rail__marker) matches the same tile through the
	   mint bar the markup has always drawn, so the exemption cannot be
	   silently lost again if either mechanism is refactored away. */
	.rail .rail__tile[aria-current="true"],
	.rail .rail__item:has(.rail__marker) .rail__tile {
		filter: none;
	}

	/* ---- the composer ------------------------------------------
	   It sits at full strength permanently today, which makes an
	   empty input the second loudest object on the screen. Quiet
	   until approached, full strength the moment it has focus.
	   The border only — never the typed text, which must always be
	   exactly as legible as what it will become once sent. */
	.composer__box {
		border-color: color-mix(in oklab, var(--border-strong) 46%, transparent);
		transition: border-color 220ms cubic-bezier(.4, 0, .2, 1);
	}
	.composer:hover .composer__box,
	.composer__box:focus-within {
		border-color: var(--border-strong);
	}
	.composer__box:focus-within {
		border-color: var(--brand);
	}

	/* The keystroke hint under the composer is instruction, not
	   content, and it is read exactly once in a user's lifetime. */
	.composer__hint {
		opacity: .55;
		transition: opacity 220ms cubic-bezier(.4, 0, .2, 1);
	}
	.composer:hover .composer__hint,
	.composer:focus-within .composer__hint { opacity: 1; }
}

/* ----------------------------------------------------------------
   Keyboard users must be able to reach a muted panel and have it
   wake. :focus-within above handles that, but the focus ring itself
   has to survive every colour-mix, so it is stated last and plainly.
   ---------------------------------------------------------------- */
.side :focus-visible,
.rail :focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}

/* ----------------------------------------------------------------
   The two opt-outs, expressed through the same variable rather than
   as clauses in the media query above.

   This is deliberate. `@media A and not B` is invalid syntax, and an
   invalid media query drops its entire block silently -- no warning,
   no partial application. Pinning --wake to 1 instead un-mutes
   everything through the mechanism that already exists, so there is
   only one code path to reason about and no second set of rules to
   keep in sync.

   Both settings are requests for a plainer, steadier interface, and
   muting is the opposite of that.
   ---------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
	.side, .rail { --wake: 1; transition: none; }
	.composer__hint { opacity: 1; }
}

@media (prefers-contrast: more) {
	.side, .rail { --wake: 1; transition: none; }
	.composer__hint { opacity: 1; }
	.side .btn { border-color: var(--border-strong); }
}

/* ================================================================
   THE RIGHT PANEL · collapsible
   ----------------------------------------------------------------
   Two controls, one state, so the panel can never be half-there:
     · an arrow inside the panel head that pushes it away
     · the topbar button that brings it back

   Scoped to >=1181px on purpose. Below that the panel is already
   display:none, and on a phone it IS the screen at data-depth="2" —
   collapsing it to zero width there would leave the user staring at
   nothing with no way back.
   ================================================================ */
@media (min-width: 1181px) {

	.side {
		/* width is not a cheap property to animate, but this is one
		   panel moving once on a deliberate click, not a per-frame
		   effect — and animating width is what lets .main actually
		   reflow into the space rather than have the panel slide over
		   the top of the conversation. */
		transition:
			width 320ms cubic-bezier(.4, 0, .2, 1),
			opacity 200ms cubic-bezier(.4, 0, .2, 1),
			border-inline-start-width 320ms cubic-bezier(.4, 0, .2, 1);
	}

	#app[data-side="0"] .side {
		width: 0;
		opacity: 0;
		border-inline-start-width: 0;
		overflow: hidden;
		pointer-events: none;
	}

	/* The topbar control is mobile-only in the base stylesheet, where it
	   drills down a level. On desktop it becomes the way back to a panel
	   you have hidden, so it has to be visible here. */
	.nav-info { display: inline-flex; }

	/* It is the one control that reflects a hidden thing, so it carries the
	   state rather than just firing an action.

	   Keyed off #app[data-side] rather than the button's own aria-expanded.
	   Both are set, but only the attribute on #app survives a re-render:
	   renderMain() rebuilds the topbar, so any attribute written onto that
	   button before the render is gone by the time it matters. aria-expanded
	   is still set for screen readers, on a microtask that lands after the
	   render pass -- but the CSS must not depend on that timing. */
	#app[data-side="0"] .nav-info { color: var(--text-muted); }
	#app[data-side="1"] .nav-info { color: var(--text); }

	/* "<" leads the panel's head; pulled a touch left so the glyph lines up
	   with the text below it. */
	.side__collapse { flex-shrink: 0; margin-inline-start: -8px; }

	/* Opening the panel is a deliberate request to read it, so it
	   arrives at full strength and settles to muted a beat later
	   rather than greeting you dimmed. --wake is already the whole
	   vocabulary for that, so this is one line rather than a second
	   system. */
	.side.side--awake { --wake: 1; }
}

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

/* ================================================================
   TAB-BAR FIT · six tabs on a narrow phone
   ----------------------------------------------------------------
   Not an attention rule; it lives here so the change travels with the
   nav change that caused it.

   The bottom tab bar went from five items to six when Files and Photos
   joined the bar. Measured at 360px, the widest labels -- "Calendario"
   and "Bestanden" -- come to 52px against 52.1px of available width.
   They fit, by a tenth of a pixel, which is not a margin: Manrope is
   loaded from a font host, and the moment it fails the fallback stack's
   metrics differ and both labels overflow.

   One point smaller between 360px and 400px buys about 5px of real
   cushion and keeps the labels, which matters more than the point size:
   below 360px the responsive layer already drops to icons only, and an
   icon-only bar is a worse experience for anyone who does not recognise
   the icons yet.
   ================================================================ */
@media (min-width: 360px) and (max-width: 400px) {
	.hdr__apps .hdr__app { font-size: 9px; }
}

/* ---------- nav-dock.css ---------- */
/* ================================================================
   NAV MARKS + THE NUVO DOCK
   ----------------------------------------------------------------
   Two briefs, one file, because they are the same surface:

     1. the app marks in the top bar should be fancier -- and
        especially better on the phone
     2. the phone's bottom bar reads as Microsoft Teams and should
        read as NuvoCloud

   On (2), the Teams tell is specific and worth naming, because it
   is what the fix has to remove: an edge-to-edge flat bar, sitting
   hard against the bottom of the screen, with a hairline along its
   top and a short accent RULE above the active tab. Tint the text
   and you have Teams; that is also, near enough, stock Fluent.

   So none of those survive here. The bar detaches from the edge and
   becomes a floating capsule on glass, the hairline becomes a ring
   around it, and the active tab is marked by a soft mint PEBBLE
   behind the icon rather than a rule above it. The one ornament is
   a mint highlight along the capsule's top edge -- the same "light
   catching a curve" as the arcs on nuvocloud.eu.

   Loads last, so it wins on source order over responsive-layout.css
   and platform.css, both of which style this same bar.
   ================================================================ */

/* ----------------------------------------------------------------
   1 · THE MARKS  (both bars)

   Duotone. Every mark carries a wash of its own body under the
   stroke, painted in currentColor at low opacity -- so it tints
   itself mint on the active tab and needs no second colour, no
   theme fork and no JS. At rest the wash is barely there and just
   gives the glyph some weight; on the active tab it blooms.
   ---------------------------------------------------------------- */
.nav-ic__fill {
	opacity: .10;
	transition: opacity 280ms cubic-bezier(.4, 0, .2, 1);
}
.hdr__app:hover .nav-ic__fill { opacity: .17; }
.hdr__app[aria-current="true"] .nav-ic__fill { opacity: .26; }

/* A wash behind a stroke is exactly what someone asking for more
   contrast does not want. */
@media (prefers-contrast: more) {
	.nav-ic__fill { opacity: 0; }
}

/* ----------------------------------------------------------------
   2 · THE DOCK  (<= 767px)
   ---------------------------------------------------------------- */
@media (max-width: 767.98px) {

	:root {
		--dock-gap: 10px;   /* breathing room on all three free sides */
		--dock-r: 22px;
	}

	/* The shell must reserve the bar AND the gap it floats above.
	   Overrides responsive-layout.css and platform.css, both of which
	   set this to the flush-to-edge height. */
	.app {
		padding-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + var(--dock-gap));
	}

	.hdr__apps {
		/* Off the edge on all three sides. The safe-area insets move from
		   padding (where they belonged when the bar was flush) into the
		   offsets, so the capsule clears the home indicator and the
		   landscape notch without growing. */
		inset-inline: calc(var(--dock-gap) + var(--sal, 0px)) calc(var(--dock-gap) + var(--sar, 0px));
		inset-block-end: calc(var(--dock-gap) + var(--sab, 0px));
		height: var(--tabbar-h, 56px);
		padding-block: 0;
		padding-inline: 4px;

		/* The surface itself is on ::before, not here -- see below. */
		background: transparent;
		border-block-start: none;
		border-radius: var(--dock-r);

		/* A dock stretched across an unfolded Fold or a small tablet in
		   portrait looks like a stretched phone UI. Cap it and centre it;
		   with both inline offsets set, auto margins do the centring. */
		max-width: 460px;
		margin-inline: auto;

		justify-content: space-between;
	}

	/* THE SURFACE LIVES ON A PSEUDO-ELEMENT, AND THAT IS LOAD-BEARING.

	   backdrop-filter establishes a containing block for position:fixed
	   descendants. .launch__panel is fixed and lives inside this bar, so
	   a blur on .hdr__apps itself would re-anchor the Apps sheet to the
	   dock instead of the viewport. light-chrome.css already documents
	   the same bug one level up, where a blur on .hdr re-anchored this
	   very bar to the header and rendered it at the top of the screen.

	   A pseudo-element has no descendants, so its containing block
	   traps nothing. Negative z-index puts it behind the buttons and
	   inside the bar's own stacking context. */
	.hdr__apps::before {
		content: '';
		position: absolute;
		inset: 0;
		z-index: -1;
		border-radius: inherit;
		background: var(--chrome);
		-webkit-backdrop-filter: var(--chrome-glass, saturate(160%) blur(20px));
		        backdrop-filter: var(--chrome-glass, saturate(160%) blur(20px));
		border: 1px solid var(--chrome-edge, rgba(255, 255, 255, 0.12));
		box-shadow:
			inset 0 1px 0 rgba(255, 255, 255, 0.05),
			0 2px 8px -2px rgba(3, 14, 11, 0.28),
			0 12px 32px -8px rgba(3, 14, 11, 0.45);
	}

	/* Without a blur the translucent --chrome would sit on whatever is
	   scrolling underneath and turn to mud. Stack it over an opaque page
	   colour so the tint survives and the legibility does too. */
	@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
		.hdr__apps::before {
			background: linear-gradient(var(--chrome), var(--chrome)), var(--bg);
		}
	}

	/* The single ornament: mint catching the top curve of the capsule,
	   the same gesture as the marquee arcs on the marketing site. */
	.hdr__apps::after {
		content: '';
		position: absolute;
		z-index: -1;
		inset-block-start: 0;
		inset-inline: 16%;
		height: 1px;
		border-radius: 100px;
		pointer-events: none;
		background: linear-gradient(90deg,
			transparent,
			rgba(63, 214, 166, 0.5) 35%,
			rgba(63, 214, 166, 0.5) 65%,
			transparent);
	}

	/* ---- the active tab ------------------------------------------
	   The Teams rule above the tab is replaced outright. Every inset
	   it set is re-stated, because ::before is one element and a
	   half-overridden absolute box is a worse bug than either design. */
	.hdr__app[aria-current="true"]::before {
		inset-block-start: 6px;
		inset-block-end: auto;
		inset-inline-start: 50%;
		inset-inline-end: auto;
		width: 46px;
		height: 28px;
		translate: -50% 0;
		border-radius: 11px;
		background: var(--chrome-active);
		box-shadow:
			inset 0 0 0 1px rgba(63, 214, 166, 0.20),
			0 4px 12px -5px rgba(63, 214, 166, 0.45);
	}

	/* A pebble alone is static. The icon lifting a pixel into it is what
	   makes the tab feel picked up rather than highlighted. */
	.hdr__app > svg {
		transition: translate 320ms cubic-bezier(.34, 1.4, .44, 1);
	}
	.hdr__app[aria-current="true"] > svg { translate: 0 -1px; }

	/* The unread count rides the icon, and the pebble sits behind both.
	   Nudged in to clear the pebble's rounded corner. */
	.hdr__app .pill-count {
		inset-block-start: 3px;
		margin-inline-start: 5px;
	}

	/* The Apps sheet has to clear the dock AND the gap under it. */
	.launch__panel {
		inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + var(--dock-gap) + 8px);
	}

	/* Same for toasts, which platform.css positions off the flush bar. */
	.toast {
		inset-block-end: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + var(--kb, 0px) + var(--dock-gap) + 16px);
	}

	/* The launcher is the fifth tab down here and must sit in the same
	   pebble geometry as the other four when its sheet is open. */
	.launch__btn[aria-expanded="true"]::before {
		content: '';
		position: absolute;
		inset-block-start: 6px;
		inset-inline-start: 50%;
		width: 46px;
		height: 28px;
		translate: -50% 0;
		border-radius: 11px;
		background: var(--chrome-active);
		z-index: -1;
	}
	.launch__btn { position: relative; }
}

/* The lift is decoration on top of a state that is already carried by
   colour and by the pebble, so it is the first thing to go. */
@media (prefers-reduced-motion: reduce) {
	.nav-ic__fill { transition: none; }
	.hdr__app > svg { transition: none; translate: none !important; }
}

/* ---------- film.css (must stay last in the cascade) ---------- */
/* =====================================================================
   NOBODY SAID ANYTHING — the film's visual layer
   Built to film-concept-b.md (script) and film-motion-system.md (craft).

   APPEND-AT-END SEMANTICS. Everything here is authored to win the cascade
   against the existing .mk-* block around lines 1388-1975 of
   _base-postnav.html. Two rules there cannot be overridden and must be
   deleted by hand — see film-build-notes.md.

   Naming: structural hooks the engine touches keep their .mk__ names.
   Every new art class is prefixed .mkf- so nothing collides with the old
   scene art (.mk-line, .mk-hall, .mk-mono, .mk-win, .mk-price, .mk-lock,
   .mk-app, .mk-ring ...), which the new mkScenes() no longer emits.

   Animate transform / opacity / filter only. No width, height, top, left.
   ===================================================================== */


/* ============================================================ 0 · TOKENS
   §2.1 of the motion system, verbatim, plus the film's palette and the
   one geometry the whole film is built on: the row pitch. */

.mk {
	/* ---- easing ---------------------------------------------------- */
	--e-out:      cubic-bezier(.16, 1, .3, 1);
	--e-out-soft: cubic-bezier(.22, .61, .36, 1);
	--e-inout:    cubic-bezier(.65, 0, .35, 1);
	--e-in:       cubic-bezier(.55, 0, 1, .45);
	--e-glide:    cubic-bezier(.33, 0, .12, 1);
	--e-snap:     cubic-bezier(.2, .9, .1, 1);
	--e-mass:     cubic-bezier(.34, 1.12, .5, 1);
	--ease:       var(--e-out);

	/* ---- durations ------------------------------------------------- */
	--t-1:  160ms;
	--t-2:  280ms;
	--t-3:  460ms;
	--t-4:  720ms;
	--t-5: 1100ms;
	--t-6: 1800ms;
	--t-7: 2800ms;

	/* ---- rhythm ---------------------------------------------------- */
	--stag:      90ms;
	--stag-word: 46ms;
	--stag-line: 130ms;

	/* ---- amplitude (reduced motion collapses this to 0) ------------- */
	--amp: 1;
	--lift:   calc(28px * var(--amp));
	--lift-s: calc(14px * var(--amp));
	--push:   calc(64px * var(--amp));

	/* ---- light ----------------------------------------------------- */
	--key-deg: 152deg;
	--rim-w:   1px;

	/* ---- palette · the one rule everything obeys -------------------- */
	--ink:      #08231C;
	--ink-deep: #041310;
	--ash:      #6B7B76;
	--ash-hi:   #93A49E;
	--ash-row:  #47574F;
	--ochre:    #C9A227;
	--mint:     #3FD6A6;
	--mint-hi:  #B4FFE8;
	--mint-mid: #2FAF83;
	--mint-lo:  #15916B;
	--paper:    #F4F3EE;

	/* ---- the spine · one pitch for every row in every scene --------- */
	--row-h:     clamp(9px, 1.55vh, 14px);
	--row-gap:   clamp(7px, 1.10vh, 10px);
	--row-pitch: calc(var(--row-h) + var(--row-gap));
	--stack-w:   clamp(178px, 25vw, 408px);
	--cross:     calc(var(--stack-w) + clamp(20px, 2.4vw, 46px));

	/* ---- type ------------------------------------------------------
	   The headline measure is in ch of the DISPLAY font, so it must live
	   on .mk__h itself — a ch cap on .mk__words would resolve against
	   Manrope and crush the headline to less than half its measure. */
	--h-lh: 1.055;
	--h-mw: 14ch;

	/* ---- grain (inline SVG, no external asset) ---------------------- */
	--mk-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='170' height='170' filter='url(%23g)'/%3E%3C/svg%3E");

	position: fixed;
	inset: 0;
	z-index: 300;
	background: var(--ink);
	color: var(--paper);
	overflow: hidden;
	font-family: var(--body);
}


/* ====================================================== 1 · THE GROUND
   Two global layers, both on .mk's own pseudo-elements so the film needs
   no extra markup inside paintFilm(): a drifting light field underneath
   everything, and a grain plate over everything but the chrome. §3.4, §3.6 */

.mk::before {
	content: '';
	position: absolute;
	inset: -25%;
	z-index: 0;
	pointer-events: none;
	mix-blend-mode: screen;
	opacity: .34;
	background:
		radial-gradient(ellipse 46% 38% at 28% 34%, rgba(63, 214, 166, .18), transparent 62%),
		radial-gradient(ellipse 38% 46% at 74% 66%, rgba(21, 145, 107, .20), transparent 66%);
	filter: blur(calc(46px * var(--amp)));
	animation: mkf-haze 31s var(--e-inout) infinite alternate;
	will-change: transform;
}

@keyframes mkf-haze {
	from { transform: translate3d(-2.5%, 1.5%, 0) scale(1); }
	to   { transform: translate3d(3%, -2%, 0) scale(1.09); }
}

/* Supersedes the old single dead-centre vignette on .mk::after.
   The vignette is now per-scene (§3.5); this slot becomes the grain. */
.mk::after {
	content: '';
	position: absolute;
	inset: -170px;
	z-index: 6;
	pointer-events: none;
	background: none;
	background-image: var(--mk-grain);
	background-repeat: repeat;
	opacity: .055;
	mix-blend-mode: overlay;
	animation: mkf-grain 900ms steps(1, end) infinite;
	will-change: transform;
}

@keyframes mkf-grain {
	0%   { transform: translate3d(0, 0, 0); }
	12%  { transform: translate3d(-13px, 9px, 0); }
	25%  { transform: translate3d(7px, -15px, 0); }
	37%  { transform: translate3d(-19px, -6px, 0); }
	50%  { transform: translate3d(11px, 13px, 0); }
	62%  { transform: translate3d(-5px, -11px, 0); }
	75%  { transform: translate3d(16px, 4px, 0); }
	87%  { transform: translate3d(-9px, 17px, 0); }
	100% { transform: translate3d(0, 0, 0); }
}

.mk__stage { position: absolute; inset: 0; z-index: 1; }


/* ============================================== 2 · THE SCENE TRANSITION
   BUG 1 — visibility is discrete. Without an explicit entry it flips on
   frame one and every scene change is a hard cut with a black gap. The
   outgoing scene now holds visible for the whole exit. §2.5

   Transition A · RACK-THROUGH. The departing scene defocuses toward the
   camera, the arriving one pulls into focus from behind. Opposite blur
   directions, so two sharp images never compete. */

.mk .mk__scene {
	position: absolute;
	inset: 0;
	display: grid;
	grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
	grid-template-rows: 1fr;
	align-items: center;
	justify-items: stretch;
	--pad-x: clamp(22px, 5vw, 84px);
	padding: 68px var(--pad-x) 112px;
	column-gap: clamp(20px, 3.6vw, 64px);

	perspective: 1200px;
	perspective-origin: 50% 46%;
	transform-origin: 50% 46%;
	contain: layout paint style;

	--vig-x: 50%;
	--vig-y: 46%;
	--vig-w: 74%;
	--vig-h: 58%;
	--wash: rgba(107, 123, 118, .07);

	opacity: 0;
	visibility: hidden;
	filter: blur(calc(9px * var(--amp)));
	transform: scale(calc(1 + .045 * var(--amp))) translate3d(0, calc(-.28 * var(--push)), 0);

	transition:
		opacity    var(--t-3) var(--e-in),
		transform  var(--t-6) var(--e-glide),
		filter     var(--t-4) var(--e-in),
		visibility 0s linear var(--t-6);
}

.mk .mk__scene[data-on="1"] {
	opacity: 1;
	visibility: visible;
	filter: blur(0);
	transform: none;
	transition:
		opacity    var(--t-3) var(--e-out-soft),
		transform  var(--t-6) var(--e-glide),
		filter     var(--t-5) var(--e-out),
		visibility 0s linear 0s;
}

/* Per-scene atmosphere wash — light never falls the same way twice. */
.mk__scene::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	background: radial-gradient(ellipse 120% 92% at 16% 6%, var(--wash), transparent 56%);
}

/* Per-scene vignette — a DP re-lights per shot. §3.5 */
.mk__scene::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 3;
	pointer-events: none;
	background: radial-gradient(
		ellipse var(--vig-w) var(--vig-h) at var(--vig-x) var(--vig-y),
		transparent 36%, rgba(3, 11, 9, .88) 100%);
	transition: background var(--t-7) var(--e-glide);
}

.mk__scene[data-i="0"] { --vig-x: 41%; --vig-y: 50%; --vig-w: 66%; --vig-h: 74%; }
.mk__scene[data-i="1"] { --vig-x: 40%; --vig-y: 58%; --vig-w: 72%; --vig-h: 66%; }
.mk__scene[data-i="2"] { --vig-x: 42%; --vig-y: 46%; --vig-w: 62%; --vig-h: 58%; --wash: rgba(201, 162, 39, .05); }
.mk__scene[data-i="3"] { --vig-x: 46%; --vig-y: 50%; --vig-w: 88%; --vig-h: 70%; --wash: rgba(63, 214, 166, .07); }
.mk__scene[data-i="4"] { --vig-x: 40%; --vig-y: 50%; --vig-w: 74%; --vig-h: 66%; --wash: rgba(63, 214, 166, .08); }
.mk__scene[data-i="5"] { --vig-x: 38%; --vig-y: 50%; --vig-w: 92%; --vig-h: 78%; --wash: rgba(63, 214, 166, .07); }
.mk__scene[data-i="6"] { --vig-x: 50%; --vig-y: 54%; --vig-w: 86%; --vig-h: 76%; --wash: rgba(63, 214, 166, .06); }

/* Transition B · THE BATON, used exactly once — scene 3 to scene 4, the
   moment the mint arrives. An animation, not a transition, so it re-fires
   reliably on every entry. §2.5 */
.mkf-baton {
	position: absolute;
	inset: -10% -40%;
	z-index: 4;
	pointer-events: none;
	background: linear-gradient(100deg,
		transparent 0 42%,
		rgba(63, 214, 166, .10) 46%,
		rgba(180, 255, 232, .58) 50%,
		rgba(63, 214, 166, .10) 54%,
		transparent 58% 100%);
	mix-blend-mode: plus-lighter;
	filter: blur(calc(6px * var(--amp)));
	opacity: 0;
	transform: translate3d(-62%, 0, 0);
}

.mk__scene[data-on="1"] .mkf-baton { animation: mkf-baton 1150ms var(--e-inout) both; }

@keyframes mkf-baton {
	0%   { opacity: 0; transform: translate3d(-62%, 0, 0); }
	14%  { opacity: 1; }
	86%  { opacity: 1; }
	100% { opacity: 0; transform: translate3d(62%, 0, 0); }
}


/* ================================================ 3 · SPLIT AND PARALLAX
   Artwork on the left ~55%, bleeding off the left edge. Words in a narrow
   column on the right, vertically centred. Art and words sit on different
   z-planes and travel at different rates, so the frame has depth. §3.8 */

.mk .mk__art {
	position: relative;
	z-index: 1;
	width: auto;
	height: 100%;
	display: block;
	margin-inline-start: calc(-1 * var(--pad-x) - clamp(8px, 4vw, 96px));
	transform: translate3d(0, calc(.55 * var(--push)), -140px);
	transition: transform var(--t-6) var(--e-glide);
}

.mk .mk__words {
	position: relative;
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
	text-align: start;
	/* No ch cap here: each child carries its own measure in its own
	   font. The grid column is the only outer bound. */
	max-width: none;
	transform: translate3d(0, calc(.22 * var(--push)), 0);
	transition: transform var(--t-6) var(--e-glide) 90ms;
}

.mk__scene[data-on="1"] .mk__art,
.mk__scene[data-on="1"] .mk__words { transform: none; }

/* §5.4 — will-change only while the element is actually animating, and
   never on .mk__scene itself (that would be seven full-screen layers). */
.mk__scene[data-on="1"] .mk__art,
.mk__scene[data-on="1"] .mk__words { will-change: transform, opacity, filter; }
.mk__scene:not([data-on="1"]) .mk__art,
.mk__scene:not([data-on="1"]) .mk__words,
.mk__scene:not([data-on="1"]) { will-change: auto; }


/* ========================================================= 4 · THE TYPE
   BUG 3 — opacity and transform shared one duration, so the headline was
   unreadable for the first ~1.1s of every scene. Opacity now resolves in
   280ms and the clip in 460ms, while the transform settles underneath for
   1100ms. Fully legible inside the 620ms read clock. §2.1, §4.4

   Every visible string is one clean text node. No per-line or per-word
   wrappers anywhere: the runtime i18n matches whole strings, so Tier A and
   Tier B of the type system are unusable here and Tier C is the right
   tool. §2.3 Tier C. */

.mk .mk__eyebrow {
	font-family: var(--body);
	font-size: 12px;
	font-weight: 700;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--ash-hi);
	margin: 0;
	opacity: 0;
	transform: translate3d(0, var(--lift-s), 0);
	transition:
		opacity   var(--t-2) var(--e-out-soft),
		transform var(--t-5) var(--e-out);
}

.mk .mk__h {
	font-family: var(--display);
	/* Sized so a 40-character English headline sets to three lines at
	   every breakpoint, and a German one to four — without the type ever
	   shrinking to fit. */
	font-size: clamp(2.2rem, 4.7vw, 4rem);
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: var(--h-lh);
	text-align: start;
	text-wrap: pretty;
	max-width: var(--h-mw);
	/* German runs ~40% longer. Three lines are reserved at every
	   breakpoint and the type never shrinks to fit. */
	min-block-size: calc(3 * var(--h-lh) * 1em);
	margin: 14px 0 0;
	color: var(--paper);

	clip-path: inset(-22% 0 110% 0);
	transform: translate3d(0, calc(.35 * var(--lift)), 0);
	opacity: 0;
	filter: blur(calc(4px * var(--amp)));
	transition:
		clip-path var(--t-3) var(--e-out),
		transform var(--t-5) var(--e-out),
		opacity   var(--t-2) var(--e-out-soft),
		filter    var(--t-3) var(--e-out-soft);
}

.mk .mk__sub {
	font-family: var(--body);
	font-size: clamp(1rem, 1.25vw, 1.05rem);
	font-weight: 500;
	line-height: 1.5;
	color: color-mix(in srgb, #fff 62%, transparent);
	text-align: start;
	text-wrap: pretty;
	max-width: 32ch;
	margin: 22px 0 0;
	opacity: 0;
	transform: translate3d(0, var(--lift), 0);
	transition:
		opacity   var(--t-3) var(--e-out-soft),
		transform var(--t-5) var(--e-out);
}

.mk .mk__kicker {
	font-family: var(--body);
	font-size: clamp(.95rem, 1.2vw, 1rem);
	font-weight: 600;
	line-height: 1.45;
	letter-spacing: -0.005em;
	color: var(--ash-hi);
	text-align: start;
	max-width: 30ch;
	margin: 26px 0 0;
	opacity: 0;
	transform: translate3d(0, var(--lift-s), 0);
	transition:
		opacity   var(--t-3) var(--e-out-soft),
		transform var(--t-5) var(--e-out);
}

/* The steps. data-step 1 = eyebrow + headline, 2 = sub, 3 = kicker. */
.mk .mk__scene[data-step="1"] .mk__eyebrow,
.mk .mk__scene[data-step="2"] .mk__eyebrow,
.mk .mk__scene[data-step="3"] .mk__eyebrow,
.mk .mk__scene[data-step="1"] .mk__clock,
.mk .mk__scene[data-step="2"] .mk__clock,
.mk .mk__scene[data-step="3"] .mk__clock {
	opacity: 1;
	transform: none;
}

.mk .mk__scene[data-step="1"] .mk__h,
.mk .mk__scene[data-step="2"] .mk__h,
.mk .mk__scene[data-step="3"] .mk__h {
	clip-path: inset(-22% 0 -22% 0);
	transform: none;
	opacity: 1;
	filter: blur(0);
	transition-delay: 90ms;
}

.mk .mk__scene[data-step="2"] .mk__sub,
.mk .mk__scene[data-step="3"] .mk__sub { opacity: 1; transform: none; }

.mk .mk__scene[data-step="3"] .mk__kicker { opacity: 1; transform: none; }

/* §5.6 — paintFilm() calls mkShow(0) after 40ms, which on a cold layout
   can be zero painted frames, and a transition with no computed "from"
   style silently does not run. Scene 0's hero reveal is an animation,
   which always plays from its 0% frame. */
.mk__scene[data-i="0"][data-step="1"] .mk__h,
.mk__scene[data-i="0"][data-step="2"] .mk__h,
.mk__scene[data-i="0"][data-step="3"] .mk__h {
	animation: mkf-head-in var(--t-5) var(--e-out) 90ms both;
}

@keyframes mkf-head-in {
	0% {
		clip-path: inset(-22% 0 110% 0);
		transform: translate3d(0, calc(.35 * var(--lift)), 0);
		opacity: 0;
		filter: blur(calc(4px * var(--amp)));
	}
	26% { opacity: 1; }
	42% { clip-path: inset(-22% 0 -22% 0); filter: blur(0); }
	100% {
		clip-path: inset(-22% 0 -22% 0);
		transform: none;
		opacity: 1;
		filter: blur(0);
	}
}

/* §2.6 — exits are not reversed entries. Everything in a leaving scene
   leaves together, fast, with no stagger. */
.mk .mk__scene:not([data-on="1"]) .mk__eyebrow,
.mk .mk__scene:not([data-on="1"]) .mk__clock,
.mk .mk__scene:not([data-on="1"]) .mk__h,
.mk .mk__scene:not([data-on="1"]) .mk__sub,
.mk .mk__scene:not([data-on="1"]) .mk__kicker,
.mk .mk__scene[data-step="0"] .mk__eyebrow,
.mk .mk__scene[data-step="0"] .mk__clock,
.mk .mk__scene[data-step="0"] .mk__h,
.mk .mk__scene[data-step="0"] .mk__sub,
.mk .mk__scene[data-step="0"] .mk__kicker {
	transition-duration: var(--t-2);
	transition-delay: 0ms;
	transition-timing-function: var(--e-in);
	animation: none;
}

/* Colour dramaturgy. Mint is forbidden until scene 4; it arrives on the
   switch and never leaves. Eyebrows and kickers are ash before, mint after. */
.mk__scene[data-i="3"] .mk__eyebrow,
.mk__scene[data-i="4"] .mk__eyebrow,
.mk__scene[data-i="5"] .mk__eyebrow,
.mk__scene[data-i="6"] .mk__eyebrow,
.mk__scene[data-i="3"] .mk__kicker,
.mk__scene[data-i="4"] .mk__kicker,
.mk__scene[data-i="5"] .mk__kicker,
.mk__scene[data-i="6"] .mk__kicker { color: var(--mint); }

/* Scene 5's eyebrow is two elements: MONDAY matches the dictionary, the
   digits are never touched. The clock's last digit rolls once, at 6.0s. */
.mk__eyebrow-row {
	display: flex;
	align-items: baseline;
	gap: .9em;
}

.mk .mk__clock {
	font-family: var(--display);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .12em;
	font-variant-numeric: tabular-nums;
	color: color-mix(in srgb, var(--mint) 62%, transparent);
	display: inline-flex;
	align-items: baseline;
	opacity: 0;
	transform: translate3d(0, var(--lift-s), 0);
	transition:
		opacity   var(--t-2) var(--e-out-soft),
		transform var(--t-5) var(--e-out);
}

.mk__clock-d {
	display: inline-block;
	overflow: hidden;
	block-size: 1.05em;
	inline-size: .62em;
	line-height: 1.05;
}

.mk__clock-d > i {
	display: block;
	font-style: normal;
	line-height: 1.05;
	transform: translate3d(0, 0, 0);
}

.mk__scene[data-i="4"][data-on="1"] .mk__clock-d > i {
	animation: mkf-tick 240ms var(--e-snap) 6000ms both;
}

@keyframes mkf-tick {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(0, -1.05em, 0); }
}


/* ========================================================= 5 · THE ROWS
   The recurring object, and the only actor in the film: a column of
   stacked horizontal bars. One pitch, one geometry, every scene — so the
   cross-dissolves register and scene 6's reveal can land on the frame.

   Widths are supplied per row as --w by mkScenes(). Set once, never
   animated. */

.mkf-col {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 1;
	width: var(--stack-w);
	transform: translate3d(-50%, -50%, 0);
}

/* Scenes 1-3: the column bleeds off the top and bottom — you cannot see
   the top of your own estate. */
.mkf-col--tall {
	-webkit-mask-image: linear-gradient(transparent 0%, #000 12%, #000 88%, transparent 100%);
	        mask-image: linear-gradient(transparent 0%, #000 12%, #000 88%, transparent 100%);
}

/* Scenes 4-6: the estate now fits in the frame. Only the edges are eased. */
.mkf-col--fit {
	-webkit-mask-image: linear-gradient(transparent 0%, #000 5%, #000 95%, transparent 100%);
	        mask-image: linear-gradient(transparent 0%, #000 5%, #000 95%, transparent 100%);
}

.mkf-row {
	--w: 1;
	--rc: var(--ash-row);
	display: block;
	block-size: var(--row-h);
	inline-size: calc(var(--w) * 100%);
	margin-block-end: var(--row-gap);
	border-radius: 100px;
	/* A 6% luminance ramp along the one key axis. A flat fill is not
	   minimal, it is unlit. §3.1 */
	background: linear-gradient(var(--key-deg),
		color-mix(in oklab, var(--rc) 84%, #fff 16%) 0%,
		var(--rc) 52%,
		color-mix(in oklab, var(--rc) 80%, #000 20%) 100%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, .10),
		0 1px 2px rgba(0, 0, 0, .40);
	transform-origin: 0 50%;
}

.mkf-row--mint { --rc: var(--mint-mid); }

.mkf-grp { display: block; }

/* The soft radial that gives the column weight and a shadow side.
   It is a SIBLING of the column, never a child: .mkf-col carries a
   mask-image, and a mask clips everything inside the element's box. */
.mkf-key {
	position: absolute;
	top: 50%;
	left: 50%;
	inline-size: 760px;
	block-size: 760px;
	margin: -380px 0 0 -380px;
	z-index: 0;
	pointer-events: none;
	background: radial-gradient(ellipse at 30% 45%, rgba(255, 255, 255, .06), transparent 60%);
}

/* Fixed geometry, animated intensity. Real light does not have an
   expanding edge. §3.3 */
.mkf-bloom {
	position: absolute;
	top: 50%;
	left: 50%;
	inline-size: 460px;
	block-size: 460px;
	margin: -230px 0 0 -230px;
	z-index: 0;
	pointer-events: none;
	border-radius: 50%;
	background:
		radial-gradient(circle at 50% 50%, rgba(180, 255, 232, .30) 0%, transparent 26%),
		radial-gradient(circle at 50% 50%, rgba(63, 214, 166, .24) 0%, transparent 48%),
		radial-gradient(circle at 50% 50%, rgba(21, 145, 107, .20) 0%, transparent 74%);
	mix-blend-mode: plus-lighter;
	opacity: 0;
	filter: blur(calc(16px * var(--amp)));
	transition:
		opacity var(--t-6) var(--e-glide),
		filter  var(--t-6) var(--e-glide);
}

.mk__scene[data-on="1"] .mkf-bloom { opacity: 1; filter: blur(calc(28px * var(--amp))); }


/* ================================================= SCENE 1 · THE LEAN
   Full ink field. The column stands tall, bleeding off top and bottom,
   and it leans — the way a stack leans when it has been added to for nine
   years and never rebuilt. One image, one line. */

.mkf-lean {
	transform: translate3d(-50%, -50%, 0) rotate(-3.4deg);
	opacity: 0;
}

.mk__scene[data-i="0"][data-on="1"] .mkf-lean {
	animation:
		mkf-lean-in 1400ms var(--e-out) both,
		mkf-breathe 14s var(--e-inout) 1400ms infinite alternate;
}

@keyframes mkf-lean-in {
	from { opacity: 0; transform: translate3d(-50%, calc(-50% + 18px * var(--amp)), 0) rotate(-3.4deg); }
	to   { opacity: 1; transform: translate3d(-50%, -50%, 0) rotate(-3.4deg); }
}

/* Breath, not motion you can name: 6px over 14s. */
@keyframes mkf-breathe {
	from { opacity: 1; transform: translate3d(-50%, -50%, 0) rotate(-3.4deg); }
	to   { opacity: 1; transform: translate3d(-50%, calc(-50% + 6px * var(--amp)), 0) rotate(-3.4deg); }
}


/* ========================================= SCENE 2 · THE REAL BLOCKER
   The column straightens, and grows. Rows push in from the bottom, each
   entering at scaleX(.2) and springing to full width, and the stack
   visibly outgrows the frame. The new rows carry a tighter gap: it gets
   denser, heavier, more crowded — without animating a single margin. */

.mkf-grow {
	transform: translate3d(-50%, -50%, 0) rotate(-3.4deg);
	transition: transform var(--t-6) var(--e-glide);
}

.mk__scene[data-i="1"][data-on="1"] .mkf-grow {
	transform: translate3d(-50%, -50%, 0) rotate(-1deg);
}

/* The gap the multiplying rows carry. Density is a static property of
   these rows, not an animated margin. Scene 3 inherits the same dense
   tail, so the stack the shudder happens to is the stack scene 2 grew. */
.mkf-row--tight { margin-block-end: calc(var(--row-gap) * .7); }

.mkf-row--new {
	transform: scaleX(.2);
	opacity: 0;
}

.mk__scene[data-i="1"][data-on="1"] .mkf-row--new {
	animation: mkf-push var(--t-5) var(--e-mass) calc(var(--n) * 180ms + 200ms) both;
}

@keyframes mkf-push {
	from { transform: scaleX(.2); opacity: 0; }
	18%  { opacity: 1; }
	to   { transform: scaleX(1); opacity: 1; }
}

/* The mask softens at the top as the stack multiplies, so the column
   disappears upward into darkness. Opacity only — no mask animation. */
.mkf-swallow {
	position: absolute;
	inset: -30% -40% 52% -40%;
	z-index: 2;
	pointer-events: none;
	background: linear-gradient(180deg, var(--ink) 22%, rgba(8, 35, 28, .0) 100%);
	opacity: 0;
	transition: opacity var(--t-7) var(--e-glide) 900ms;
}

.mk__scene[data-i="1"][data-on="1"] .mkf-swallow { opacity: 1; }


/* ==================================== SCENE 3 · THE FILM IN YOUR HEAD
   The loudest thing this brand has ever made, and it is still quiet.
   Three shudder bursts. One row slips out of frame and does not come
   back. The ochre appears once, and only here. Then everything stops. */

.mkf-shake { position: absolute; inset: 0; }

.mk__scene[data-i="2"][data-on="1"] .mkf-shake {
	animation: mkf-shudder 7200ms steps(1, end) both;
	will-change: transform;
}

/* 3px horizontal jitter at 40ms intervals. Three bursts of 400ms at
   2.0s / 4.2s / 6.6s, separated by unnerving stillness. steps(1,end) so
   the positions snap rather than slide. */
@keyframes mkf-shudder {
	0%, 27.778% { transform: translate3d(0, 0, 0); }
	28.333% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	28.889% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	29.444% { transform: translate3d(calc(2px * var(--amp)), 0, 0); }
	30.000% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	30.556% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	31.111% { transform: translate3d(calc(-2px * var(--amp)), 0, 0); }
	31.667% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	32.222% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	32.778% { transform: translate3d(calc(2px * var(--amp)), 0, 0); }
	33.333% { transform: translate3d(calc(-1px * var(--amp)), 0, 0); }
	33.889%, 58.333% { transform: translate3d(0, 0, 0); }
	58.889% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	59.444% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	60.000% { transform: translate3d(calc(-2px * var(--amp)), 0, 0); }
	60.556% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	61.111% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	61.667% { transform: translate3d(calc(2px * var(--amp)), 0, 0); }
	62.222% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	62.778% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	63.333% { transform: translate3d(calc(-2px * var(--amp)), 0, 0); }
	63.889% { transform: translate3d(calc(1px * var(--amp)), 0, 0); }
	64.444%, 91.667% { transform: translate3d(0, 0, 0); }
	92.222% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	92.778% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	93.333% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	93.889% { transform: translate3d(calc(-2px * var(--amp)), 0, 0); }
	94.444% { transform: translate3d(calc(3px * var(--amp)), 0, 0); }
	95.000% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	95.556% { transform: translate3d(calc(2px * var(--amp)), 0, 0); }
	96.111% { transform: translate3d(calc(-3px * var(--amp)), 0, 0); }
	96.667% { transform: translate3d(calc(2px * var(--amp)), 0, 0); }
	97.222% { transform: translate3d(calc(-1px * var(--amp)), 0, 0); }
	97.778%, 100% { transform: translate3d(0, 0, 0); }
}

/* The row that goes missing. It falls at 4.4s and it does not come back. */
.mkf-row--fall { transform-origin: 62% 50%; }

.mk__scene[data-i="2"][data-on="1"] .mkf-row--fall {
	animation: mkf-fall 900ms var(--e-in) 4400ms both;
}

@keyframes mkf-fall {
	from { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 1; }
	24%  { opacity: 1; }
	to   {
		transform: translate3d(calc(14px * var(--amp)), calc(58vh * var(--amp)), 0) rotate(calc(8deg * var(--amp)));
		opacity: 0;
	}
}

/* The rows above settle down into the gap. One pitch, one vector. */
.mk__scene[data-i="2"][data-on="1"] .mkf-grp--above {
	animation: mkf-settle var(--t-5) var(--e-out) 4600ms both;
}

@keyframes mkf-settle {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(0, var(--row-pitch), 0); }
}

/* The ochre. Once in the film, four rows, 30%, 500ms, gone.
   Carried on an overlay so only opacity moves. */
.mkf-row--flare { position: relative; }

.mkf-row--flare::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(var(--key-deg),
		color-mix(in oklab, var(--ochre) 84%, #fff 16%) 0%,
		var(--ochre) 52%,
		color-mix(in oklab, var(--ochre) 80%, #000 20%) 100%);
	opacity: 0;
	pointer-events: none;
}

.mk__scene[data-i="2"][data-on="1"] .mkf-row--flare::after {
	animation: mkf-flare 500ms var(--e-out-soft) calc(6800ms + var(--n) * 45ms) both;
}

@keyframes mkf-flare {
	0%   { opacity: 0; }
	22%  { opacity: .30; }
	54%  { opacity: .30; }
	100% { opacity: 0; }
}

/* A system in distress, without a single icon, alert or error dialogue. */
.mkf-scan {
	position: absolute;
	inset: -60% -50%;
	z-index: 2;
	pointer-events: none;
	background: repeating-linear-gradient(180deg,
		rgba(255, 255, 255, .02) 0 1px,
		transparent 1px 3px);
	opacity: 0;
	transform: translate3d(0, -100%, 0);
	mix-blend-mode: plus-lighter;
}

.mk__scene[data-i="2"][data-on="1"] .mkf-scan {
	animation: mkf-wash 1200ms var(--e-inout) 6600ms both;
}

@keyframes mkf-wash {
	0%   { opacity: 0; transform: translate3d(0, -100%, 0); }
	16%  { opacity: 1; }
	84%  { opacity: 1; }
	100% { opacity: 0; transform: translate3d(0, 100%, 0); }
}


/* ======================================== SCENE 4 · THE ACTUAL EVENT
   The mint arrives. A second, empty column materialises to the right —
   just an outline. Then the rows walk across, one at a time, bottom to
   top, turning mint at the midpoint of their travel. Two rows in flight
   at any moment. No trails, no particles, no speed lines: the visual
   equivalent of carrying a full glass across a room without looking at it.

   Explicitly forbidden here, and absent: percentages, progress bars,
   spinners, checkmarks, timers, any number implying a duration. */

.mkf-cross {
	position: absolute;
	top: 50%;
	left: 50%;
	width: var(--stack-w);
	transform: translate3d(calc(-50% - var(--cross) / 2), -50%, 0);
}

.mkf-cross__ash {
	position: absolute;
	inset: calc(-1 * var(--row-gap)) calc(-1 * var(--row-gap));
	border-radius: 14px;
	border: 1px solid rgba(107, 123, 118, .18);
	opacity: 0;
	transition: opacity var(--t-5) var(--e-out-soft);
}

.mk__scene[data-i="3"][data-on="1"] .mkf-cross__ash {
	animation: mkf-ash-out var(--t-7) var(--e-inout) 600ms both;
}

@keyframes mkf-ash-out {
	0%  { opacity: 0; }
	14% { opacity: 1; }
	62% { opacity: 1; }
	86%, 100% { opacity: 0; }
}

/* Everything that ends up mint travels together, once, at 8.0s. */
.mkf-cross__load {
	position: relative;
	transform: translate3d(0, 0, 0);
}

.mk__scene[data-i="3"][data-on="1"] .mkf-cross__load {
	animation: mkf-home 900ms var(--e-out) 8000ms both;
}

@keyframes mkf-home {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(calc(-1 * var(--cross) / 2), 0, 0); }
}

.mkf-cross__frame {
	position: absolute;
	inset: calc(-1 * var(--row-gap)) calc(-1 * var(--row-gap));
	left: calc(var(--cross) - var(--row-gap));
	width: var(--stack-w);
	border-radius: 14px;
	border: 1px solid rgba(63, 214, 166, .25);
	box-shadow: inset 0 0 40px rgba(63, 214, 166, .05);
	opacity: 0;
	transform: scaleY(.86);
	transform-origin: 50% 50%;
	transition:
		opacity   var(--t-3) var(--e-out-soft) 1000ms,
		transform var(--t-5) var(--e-out) 1000ms;
}

.mk__scene[data-i="3"][data-on="1"] .mkf-cross__frame { opacity: 1; transform: none; }

.mkf-cross__rows { position: relative; }

/* The walk. Bottom to top, 320ms apart, 700ms of travel each, and the
   ash-to-mint change lands exactly at the midpoint. */
.mkf-row--walk { position: relative; }

.mkf-row--walk::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(var(--key-deg),
		color-mix(in oklab, var(--mint-mid) 84%, #fff 16%) 0%,
		var(--mint-mid) 52%,
		color-mix(in oklab, var(--mint-mid) 80%, #000 20%) 100%);
	opacity: 0;
	pointer-events: none;
}

.mk__scene[data-i="3"][data-on="1"] .mkf-row--walk {
	animation: mkf-walk 700ms var(--e-inout) calc(1600ms + var(--n) * 320ms) both;
}

.mk__scene[data-i="3"][data-on="1"] .mkf-row--walk::after {
	animation: mkf-turn 700ms linear calc(1600ms + var(--n) * 320ms) both;
}

@keyframes mkf-walk {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(var(--cross), 0, 0); }
}

@keyframes mkf-turn {
	0%, 42%   { opacity: 0; }
	58%, 100% { opacity: 1; }
}


/* ============================================== SCENE 5 · MONDAY
   The mint column is there. Calm, level, complete. And it does nothing.
   One glow breathes behind it on a 9s cycle at 4-7%. One row — a
   different one from the row that fell, and slightly wider — sits
   perfectly in place where the gap was. Nobody points at it. */

.mkf-breathe {
	position: absolute;
	top: 50%;
	left: 50%;
	inline-size: 420px;
	block-size: 420px;
	margin: -210px 0 0 -210px;
	z-index: 0;
	pointer-events: none;
	border-radius: 50%;
	background:
		radial-gradient(circle at 50% 50%, rgba(180, 255, 232, .34) 0%, transparent 30%),
		radial-gradient(circle at 50% 50%, rgba(63, 214, 166, .26) 0%, transparent 58%),
		radial-gradient(circle at 50% 50%, rgba(21, 145, 107, .20) 0%, transparent 78%);
	mix-blend-mode: plus-lighter;
	filter: blur(calc(18px * var(--amp)));
	opacity: .04;
}

.mk__scene[data-i="4"][data-on="1"] .mkf-breathe {
	animation: mkf-glow 9s var(--e-inout) infinite alternate;
}

@keyframes mkf-glow {
	from { opacity: .04; }
	to   { opacity: .07; }
}


/* ================================== SCENE 6 · WHAT NOBODY NOTICED
   The film's one and only reveal, and the reason the whole spine exists.

   There is no bitmap here. The Talk+ interface is recreated in divs, and
   the "abstract mint bars" and the "message rows" are literally the same
   twenty elements: the bars never move, never reflow, and never change
   pitch. The app assembles around them — sidebar, channel list, header,
   composer, avatars — while the text-line rows thin from slab to type.
   Registration is exact by construction, so for the beat in the middle
   they overlay perfectly and it reads as the abstraction having been the
   app all along. */

.mkf-ui {
	--ui-side: clamp(92px, 11.5vw, 168px);
	--ui-gut:  clamp(26px, 3.2vw, 50px);
	--ui-pad:  clamp(10px, 1.4vw, 20px);
	--ui-head: clamp(38px, 5.6vh, 56px);
	--ui-rgut: clamp(16px, 2.6vw, 60px);

	position: absolute;
	top: 50%;

	/* The registration. The thread column's left edge must land exactly
	   on the column's left edge in scenes 4 and 5, which is
	   50% - stack-w/2. The thread sits ui-side + ui-pad + ui-gut inside
	   the panel, so the panel starts that much further left.

	   This lives in `left`, not in the transform: used-value arithmetic
	   is resolved once by layout and cannot be knocked out of alignment
	   by the scale that runs on top of it. */
	left: calc(50% - (var(--stack-w) / 2 + var(--ui-side) + var(--ui-pad) + var(--ui-gut)));

	inline-size: calc(var(--ui-side) + var(--ui-gut) + var(--stack-w) + var(--ui-pad) * 2 + var(--ui-rgut));
	display: grid;
	grid-template-columns: var(--ui-side) minmax(0, 1fr);
	border-radius: 18px;
	isolation: isolate;

	/* Origin is the thread column's centre, not the panel's — so the
	   1.03 to 1.00 settle cannot displace a single bar. */
	transform-origin: calc(var(--ui-side) + var(--ui-pad) + var(--ui-gut) + var(--stack-w) / 2) 50%;
	transform: translate3d(0, -50%, 0) scale(1.03);
	transition: transform 1100ms var(--e-glide);
}

.mk__scene[data-i="5"][data-on="1"] .mkf-ui {
	transform: translate3d(0, -50%, 0) scale(1);
}

/* Every piece of chrome fades up over the same 1.1s. Nothing translates:
   the app does not arrive, it resolves. */
.mkf-ui__side,
.mkf-ui__head,
.mkf-ui__comp,
.mkf-ui__av,
.mkf-ui__plate {
	opacity: 0;
	transition: opacity 1100ms var(--e-out-soft);
}

.mk__scene[data-i="5"][data-on="1"] .mkf-ui__side,
.mk__scene[data-i="5"][data-on="1"] .mkf-ui__head,
.mk__scene[data-i="5"][data-on="1"] .mkf-ui__comp,
.mk__scene[data-i="5"][data-on="1"] .mkf-ui__av,
.mk__scene[data-i="5"][data-on="1"] .mkf-ui__plate { opacity: 1; }

/* The panel body: the five-layer material, one sun, and the shadow
   ladder in full — contact, form, ambient. §3.1 */
.mkf-ui__plate {
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	background: linear-gradient(var(--key-deg),
		color-mix(in oklab, #0E2E25 90%, #fff 10%) 0%,
		#0C2A22 46%,
		color-mix(in oklab, #0C2A22 78%, #000 22%) 100%);
	box-shadow:
		inset 1px 1px 0 rgba(255, 255, 255, .10),
		inset -1px -1px 0 rgba(0, 0, 0, .45),
		0 1px 2px rgba(0, 0, 0, .55),
		0 14px 26px -10px rgba(0, 0, 0, .60),
		0 52px 90px -28px rgba(0, 0, 0, .72);
}

.mkf-ui__plate::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	background: linear-gradient(calc(var(--key-deg) - 40deg),
		transparent 28%,
		rgba(255, 255, 255, .07) 46%,
		rgba(255, 255, 255, .02) 54%,
		transparent 68%);
	mix-blend-mode: screen;
}

/* --- sidebar --- */
.mkf-ui__side {
	position: relative;
	padding: calc(var(--ui-pad) * .9);
	display: flex;
	flex-direction: column;
	gap: calc(var(--ui-pad) * .7);
	border-inline-end: 1px solid rgba(255, 255, 255, .06);
	background: linear-gradient(var(--key-deg), rgba(0, 0, 0, .16), rgba(0, 0, 0, .30));
	border-start-start-radius: 18px;
	border-end-start-radius: 18px;
	min-inline-size: 0;
}

.mkf-ui__brand {
	display: flex;
	align-items: center;
	gap: 8px;
	padding-block-end: calc(var(--ui-pad) * .5);
	min-inline-size: 0;
}

.mkf-ui__mark {
	inline-size: 18px;
	block-size: 18px;
	flex: none;
	border-radius: 6px;
	background: linear-gradient(var(--key-deg), var(--mint-hi), var(--mint) 46%, var(--mint-lo));
	box-shadow: 0 0 12px rgba(63, 214, 166, .32), inset 0 1px 0 rgba(255, 255, 255, .4);
}

.mkf-ui__wm {
	font-family: var(--display);
	font-size: 12.5px;
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--paper);
	white-space: nowrap;
	overflow: hidden;
}

.mkf-ui__srch {
	block-size: 22px;
	border-radius: 100px;
	background: rgba(255, 255, 255, .05);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), inset 0 -1px 0 rgba(0, 0, 0, .25);
	display: flex;
	align-items: center;
	padding-inline: 7px;
	gap: 6px;
	color: rgba(244, 243, 238, .28);
	flex: none;
}

.mkf-ui__srch svg { inline-size: 11px; block-size: 11px; flex: none; }
.mkf-ui__srch i { display: block; block-size: 4px; inline-size: 54%; border-radius: 100px; background: rgba(244, 243, 238, .16); }

.mkf-ui__chs { display: flex; flex-direction: column; gap: 3px; min-inline-size: 0; }

.mkf-ui__ch {
	display: grid;
	grid-template-columns: 20px minmax(0, 1fr);
	align-items: center;
	gap: 7px;
	padding: 5px 6px;
	border-radius: 8px;
	min-inline-size: 0;
}

.mkf-ui__ch--on {
	background: linear-gradient(var(--key-deg), rgba(63, 214, 166, .18), rgba(63, 214, 166, .08));
	box-shadow: inset 0 0 0 1px rgba(63, 214, 166, .22);
}

.mkf-ui__dot {
	inline-size: 20px;
	block-size: 20px;
	border-radius: 50%;
	position: relative;
	background: linear-gradient(var(--key-deg), rgba(255, 255, 255, .17), rgba(255, 255, 255, .05));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18);
}

.mkf-ui__dot--on { background: linear-gradient(var(--key-deg), var(--mint), var(--mint-lo)); }

.mkf-ui__dot::after {
	content: '';
	position: absolute;
	inset-block-end: -1px;
	inset-inline-end: -1px;
	inline-size: 7px;
	block-size: 7px;
	border-radius: 50%;
	background: var(--mint);
	box-shadow: 0 0 0 2px #0C2A22;
	opacity: 0;
}

.mkf-ui__dot--live::after { opacity: 1; }

.mkf-ui__cn { display: flex; flex-direction: column; gap: 4px; min-inline-size: 0; }
.mkf-ui__cn i { display: block; block-size: 5px; border-radius: 100px; background: rgba(244, 243, 238, .30); }
.mkf-ui__cn i + i { block-size: 4px; background: rgba(244, 243, 238, .13); }
.mkf-ui__ch--on .mkf-ui__cn i { background: rgba(180, 255, 232, .68); }

.mkf-ui__badge {
	inline-size: 16px;
	block-size: 10px;
	border-radius: 100px;
	background: var(--mint);
	box-shadow: 0 0 10px rgba(63, 214, 166, .4);
	justify-self: end;
}

/* --- main column --- */
.mkf-ui__main {
	display: grid;
	grid-template-rows: var(--ui-head) minmax(0, 1fr) var(--ui-head);
	min-inline-size: 0;
}

.mkf-ui__head {
	display: flex;
	align-items: center;
	gap: 9px;
	padding-inline: var(--ui-pad);
	border-block-end: 1px solid rgba(255, 255, 255, .06);
	min-inline-size: 0;
}

.mkf-ui__ht { display: flex; flex-direction: column; gap: 5px; flex: 1; min-inline-size: 0; }
.mkf-ui__ht i { display: block; block-size: 6px; inline-size: 34%; border-radius: 100px; background: rgba(244, 243, 238, .46); }
.mkf-ui__ht i + i { block-size: 4px; inline-size: 20%; background: rgba(63, 214, 166, .40); }

.mkf-ui__acts { display: flex; align-items: center; gap: 7px; color: rgba(244, 243, 238, .40); flex: none; }
.mkf-ui__acts svg { inline-size: 14px; block-size: 14px; }

/* --- the thread: the twenty rows, at exactly the film's pitch --- */
.mkf-ui__thread {
	position: relative;
	align-self: center;
	inline-size: var(--stack-w);
	margin-inline-start: calc(var(--ui-pad) + var(--ui-gut));
}

.mkf-ui__msg { position: relative; }

/* A message separator drawn INTO the existing gap, on a pseudo-element,
   so it groups the thread without adding a single pixel of layout and
   without disturbing the pitch. */
.mkf-ui__msg + .mkf-ui__msg::before {
	content: '';
	position: absolute;
	inset-block-start: calc(-1 * var(--row-gap) / 2 - 1px);
	inset-inline: calc(-1 * var(--ui-gut) + 6px) 0;
	block-size: 1px;
	background: rgba(255, 255, 255, .05);
	opacity: 0;
	transition: opacity 1100ms var(--e-out-soft);
	pointer-events: none;
}

.mk__scene[data-i="5"][data-on="1"] .mkf-ui__msg + .mkf-ui__msg::before,
.mk__scene[data-i="6"] .mkf-ui__msg + .mkf-ui__msg::before { opacity: 1; }

/* Avatars live in the gutter, outside the column, so they cannot move a
   single bar. */
.mkf-ui__av {
	position: absolute;
	inset-block-start: -1px;
	inset-inline-start: calc(-1 * var(--ui-gut));
	inline-size: clamp(18px, 2.2vw, 26px);
	block-size: clamp(18px, 2.2vw, 26px);
	border-radius: 50%;
	background: linear-gradient(var(--key-deg), rgba(255, 255, 255, .18), rgba(255, 255, 255, .04));
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22), 0 1px 2px rgba(0, 0, 0, .4);
}

.mkf-ui__av--mint { background: linear-gradient(var(--key-deg), var(--mint), var(--mint-lo)); }
.mkf-ui__av--ochre { background: linear-gradient(var(--key-deg), #E0BE4A, #9C7C15); }

/* The author-name rows stay mint and never change: they are the anchor
   that proves the registration. The text rows thin from slab to type. */
.mkf-row--tx { position: relative; transition: transform 1100ms var(--e-glide); }

.mkf-row--tx::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(var(--key-deg),
		rgba(244, 243, 238, .80) 0%,
		rgba(244, 243, 238, .62) 52%,
		rgba(244, 243, 238, .44) 100%);
	opacity: 0;
	pointer-events: none;
	transition: opacity 1100ms var(--e-out-soft);
}

.mk__scene[data-i="5"][data-on="1"] .mkf-row--tx { transform: scaleY(.60); }
.mk__scene[data-i="5"][data-on="1"] .mkf-row--tx::after { opacity: 1; }

/* --- composer --- */
.mkf-ui__comp {
	display: flex;
	align-items: center;
	gap: 8px;
	padding-inline: var(--ui-pad);
	border-block-start: 1px solid rgba(255, 255, 255, .06);
	min-inline-size: 0;
}

.mkf-ui__field {
	flex: 1;
	block-size: 26px;
	border-radius: 100px;
	background: rgba(255, 255, 255, .05);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), inset 0 -1px 0 rgba(0, 0, 0, .3);
	display: flex;
	align-items: center;
	padding-inline: 11px;
	min-inline-size: 0;
}

.mkf-ui__field i { display: block; block-size: 5px; inline-size: 32%; border-radius: 100px; background: rgba(244, 243, 238, .16); }

.mkf-ui__send {
	inline-size: 26px;
	block-size: 26px;
	flex: none;
	border-radius: 50%;
	display: grid;
	place-items: center;
	color: #08231C;
	background: linear-gradient(var(--key-deg), var(--mint-hi), var(--mint) 48%, var(--mint-lo));
	box-shadow: 0 0 14px rgba(63, 214, 166, .30), inset 0 1px 0 rgba(255, 255, 255, .4);
}

.mkf-ui__send svg { inline-size: 13px; block-size: 13px; }

/* Ink vignette over the panel so the words stay dominant. */
.mkf-ui__shade {
	position: absolute;
	inset: 0;
	z-index: 2;
	pointer-events: none;
	border-radius: inherit;
	background: linear-gradient(92deg, rgba(4, 19, 16, .58) 0%, transparent 34%, transparent 66%, rgba(4, 19, 16, .52) 100%);
}


/* ============================================== SCENE 7 · THE ASK
   The product screen recedes until it is texture, not content. The words
   come to the centre. One button, alone. */

.mk .mk__scene[data-i="6"] {
	grid-template-columns: minmax(0, 1fr);
	justify-items: center;
	padding-inline: clamp(24px, 8vw, 140px);
}

.mk .mk__scene[data-i="6"] .mk__art {
	position: absolute;
	inset: 0;
	margin-inline-start: 0;
	z-index: 0;
}

.mk .mk__scene[data-i="6"] .mk__words {
	align-items: center;
	text-align: center;
	max-width: min(100%, 760px);
}

.mk .mk__scene[data-i="6"] .mk__h,
.mk .mk__scene[data-i="6"] .mk__sub,
.mk .mk__scene[data-i="6"] .mk__kicker { text-align: center; }

.mk .mk__scene[data-i="6"] .mk__h { max-width: 14ch; }
.mk .mk__scene[data-i="6"] .mk__sub { max-width: 36ch; }

.mk__scene[data-i="6"] .mkf-ui {
	opacity: .34;
	filter: blur(0);
	transition:
		transform 1200ms var(--e-glide),
		opacity   1200ms var(--e-glide),
		filter    1200ms var(--e-glide);
}

.mk__scene[data-i="6"][data-on="1"] .mkf-ui {
	opacity: .13;
	filter: blur(calc(2.5px * var(--amp)));
	transform: translate3d(-17%, calc(-50% + 15%), 0) scale(.9);
}

/* Texture, not content: the words must win outright. A soft ink wash
   sits between the receded screen and the copy. */
.mk .mk__scene[data-i="6"] .mk__words::before {
	content: '';
	position: absolute;
	inset: -10% -16%;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(ellipse 60% 58% at 50% 48%,
		rgba(4, 19, 16, .90) 34%, rgba(4, 19, 16, .55) 62%, transparent 80%);
}

.mk__scene[data-i="6"] .mkf-ui__side,
.mk__scene[data-i="6"] .mkf-ui__head,
.mk__scene[data-i="6"] .mkf-ui__comp,
.mk__scene[data-i="6"] .mkf-ui__av,
.mk__scene[data-i="6"] .mkf-ui__plate { opacity: 1; }

.mk__scene[data-i="6"] .mkf-row--tx { transform: scaleY(.60); }
.mk__scene[data-i="6"] .mkf-row--tx::after { opacity: 1; }

/* A wide low mint glow along the bottom edge, so the screen feels lit
   from the direction you are walking. */
.mkf-floorlight {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: radial-gradient(ellipse at 50% 118%, rgba(63, 214, 166, .20), transparent 62%);
	opacity: 0;
	transition: opacity var(--t-7) var(--e-glide);
}

.mk__scene[data-i="6"][data-on="1"] .mkf-floorlight { opacity: 1; }

/* The button. It arrives last and it arrives alone. */
.mkf-cta {
	margin: 30px 0 0;
	opacity: 0;
	transform: translate3d(0, var(--lift), 0);
	transition:
		opacity   var(--t-3) var(--e-out-soft),
		transform var(--t-5) var(--e-out);
}

.mk__scene[data-i="6"][data-step="3"] .mkf-cta { opacity: 1; transform: none; }

.mk .mkf-go {
	position: relative;
	block-size: 56px;
	padding-inline: 32px;
	border: 0;
	border-radius: 14px;
	font-family: var(--body);
	font-size: 16px;
	font-weight: 700;
	letter-spacing: -0.005em;
	color: #08231C;
	background: linear-gradient(var(--key-deg), var(--mint-hi) 0%, var(--mint) 44%, #2BBE90 100%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, .55),
		0 1px 2px rgba(0, 0, 0, .45),
		0 14px 26px -10px rgba(0, 0, 0, .55);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transform: translate3d(0, 0, 0);
	transition: transform var(--t-2) var(--e-snap);
}

.mkf-go::after {
	content: '';
	position: absolute;
	inset: -18px -8px -26px;
	z-index: -1;
	pointer-events: none;
	border-radius: 26px;
	background: radial-gradient(ellipse at 50% 60%, rgba(63, 214, 166, .40), transparent 68%);
	filter: blur(calc(9px * var(--amp)));
	opacity: .55;
	transition: opacity var(--t-3) var(--e-out-soft);
}

.mk .mkf-go:hover { transform: translate3d(0, calc(-2px * var(--amp)), 0); }
.mk .mkf-go:hover::after { opacity: .67; }
.mk .mkf-go:focus-visible { outline: 2px solid var(--mint-hi); outline-offset: 4px; }

/* The button arrives, then the line under it, then — much later, and
   much quieter — the way back to the start. */
.mk .mk__scene[data-i="6"] .mk__kicker {
	margin-top: 22px;
	color: color-mix(in srgb, var(--mint) 74%, transparent);
}

.mk .mk__scene[data-i="6"][data-step="3"] .mk__kicker { transition-delay: 900ms; }
.mk__scene[data-i="6"][data-step="3"] .mkf-again { transition-delay: 1500ms; }


/* ========================================================== 6 · CHROME
   Never trap anyone in a film about not being trapped. */

.mk .mk__skip {
	position: absolute;
	top: 22px;
	inset-inline-end: 24px;
	z-index: 9;
	block-size: 32px;
	padding-inline: 12px;
	border: 0;
	background: transparent;
	border-radius: 100px;
	color: var(--paper);
	font-family: var(--body);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .06em;
	opacity: .4;
	display: inline-flex;
	align-items: center;
	gap: 7px;
	cursor: pointer;
	transition: opacity var(--t-2) var(--e-out-soft);
}

.mk .mk__skip:hover { opacity: 1; border-color: transparent; color: var(--paper); }

/* "Watch again" is a plain low-contrast text link, set well below the
   button and well below the kicker. It must never read as a second
   choice — no border, no fill, no chevron, 40% opacity. */
.mk .mkf-again {
	margin: 34px 0 0;
	padding: 6px 2px;
	border: 0;
	background: transparent;
	color: rgba(244, 243, 238, .9);
	font-family: var(--body);
	font-size: 12.5px;
	font-weight: 500;
	letter-spacing: .01em;
	text-decoration: underline;
	text-underline-offset: 4px;
	text-decoration-thickness: 1px;
	text-decoration-color: rgba(244, 243, 238, .3);
	opacity: 0;
	display: inline-flex;
	align-items: center;
	cursor: pointer;
	pointer-events: none;
	transition: opacity var(--t-3) var(--e-out-soft);
}

.mk__scene[data-i="6"][data-step="3"] .mkf-again {
	opacity: .4;
	pointer-events: auto;
}

.mk .mkf-again:hover { opacity: .7; }
.mk .mkf-again:focus-visible { outline: 2px solid var(--mint-hi); outline-offset: 3px; opacity: .9; }

.mk .mk__ctl {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	z-index: 8;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 14px;
	padding: 14px 24px 20px;
}

/* A 2px mint hairline pinned to the bottom edge — the existing dots,
   restyled. Segmented rather than continuous, because a continuously
   timed bar would need the engine to know each hold. */
.mk .mk__dots { display: flex; gap: 5px; align-items: center; }

.mk .mk__dot {
	inline-size: clamp(20px, 4vw, 46px);
	block-size: 2px;
	border-radius: 100px;
	border: 0;
	padding: 0;
	background: rgba(63, 214, 166, .16);
	overflow: hidden;
	position: relative;
	cursor: pointer;
	transition: background var(--t-2) var(--e-out-soft);
}

.mk .mk__dot:hover { background: rgba(63, 214, 166, .34); }
.mk .mk__dot[aria-current="true"] { background: rgba(63, 214, 166, .30); box-shadow: 0 0 10px rgba(63, 214, 166, .28); }
.mk .mk__dot i { position: absolute; inset: 0; width: 0; background: var(--mint); border-radius: 100px; }
.mk .mk__dot[data-done="1"] i { width: 100%; }

.mk .mk__ibtn {
	inline-size: 34px;
	block-size: 34px;
	border-radius: 100px;
	border: 0;
	background: transparent;
	color: rgba(244, 243, 238, .42);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: color var(--t-2) var(--e-out-soft);
}

.mk .mk__ibtn:hover { color: var(--paper); border-color: transparent; }

.mk .mk__note {
	position: absolute;
	bottom: 22px;
	inset-inline-start: 26px;
	z-index: 8;
	font-family: var(--body);
	font-size: 11px;
	letter-spacing: .02em;
	color: rgba(244, 243, 238, .26);
}


/* ====================================================== 7 · RESPONSIVE
   Under 820px the artwork moves behind the words at 22% opacity and the
   words centre. The type never shrinks to fit — it reflows. */

@media (max-width: 1080px) {
	.mk { --stack-w: clamp(160px, 24vw, 300px); }
}

@media (max-width: 820px) {
	.mk .mk__scene {
		grid-template-columns: minmax(0, 1fr);
		justify-items: center;
		padding: 64px clamp(20px, 6vw, 44px) 108px;
	}

	.mk .mk__scene .mk__art {
		position: absolute;
		inset: 0;
		margin-inline-start: 0;
		opacity: .22;
		z-index: 0;
	}

	.mk .mk__scene .mk__words {
		align-items: center;
		text-align: center;
		max-width: min(100%, 560px);
	}

	.mk .mk__scene .mk__h,
	.mk .mk__scene .mk__sub,
	.mk .mk__scene .mk__kicker { text-align: center; }

	.mk .mk__h { font-size: clamp(2.1rem, 8.4vw, 3.2rem); max-width: 14ch; }
	.mk .mk__sub { max-width: 30ch; }
	.mk .mk__eyebrow-row { justify-content: center; }
	.mk { --stack-w: clamp(180px, 52vw, 330px); }
	.mk .mk__note { display: none; }
	.mk .mkf-again { margin-top: 26px; }
}

@media (max-width: 520px) {
	.mk .mk__dot { inline-size: 16px; }
	.mk .mkf-go { block-size: 52px; padding-inline: 24px; font-size: 15px; }
}


/* ============================================ 8 · REDUCED MOTION RE-CUT
   BUG 2 — the old block applied `transform: none !important` to elements
   that are POSITIONED by transform, which deleted their poses and
   collapsed the frame. The systemic answer is the amplitude multiplier:
   every travel and blur offset in this file is written as
   calc(N * var(--amp)), so collapsing --amp to 0 removes movement while
   leaving every pose, every layout transform and every light intact.

   Reduced motion re-cuts the film. It does not cancel it. §5.5

   NOTE: the two rules that must be deleted from the old block are listed
   in film-build-notes.md — they carry !important on selectors this file
   cannot outrank for `transform`, and one of them reintroduces the
   visibility bug. Everything else is overridden below. */

@media (prefers-reduced-motion: reduce) {
	.mk {
		--amp: 0;
		--stag: 40ms;
		--stag-line: 55ms;
		--stag-word: 26ms;
		--t-5: 300ms;
		--t-6: 340ms;
		--t-7: 900ms;
	}

	/* Re-assert the cross-dissolve. The old block replaced the whole
	   shorthand with `opacity 260ms` !important, which zeroes the
	   visibility entry and brings the hard cut back. */
	.mk .mk__scene {
		transform: scale(1.018) !important;
		transition:
			opacity    var(--t-3) var(--e-in),
			transform  var(--t-6) var(--e-glide),
			filter     var(--t-4) var(--e-in),
			visibility 0s linear var(--t-6) !important;
	}

	.mk .mk__scene[data-on="1"] {
		transform: none !important;
		transition:
			opacity    var(--t-3) var(--e-out-soft),
			transform  var(--t-6) var(--e-glide),
			filter     var(--t-5) var(--e-out),
			visibility 0s linear 0s !important;
	}

	/* Keep: opacity, colour, sharpness, grain, light fields, scale <= 1.02.
	   None of these trigger a vestibular response. */
	.mk::before,
	.mk::after { animation: none !important; }
	.mk::before { opacity: .28; }

	/* Remove: loops, rotation drift, parallax, overshoot, the shudder,
	   the fall, the walk, the baton. The poses survive; the travel does not. */
	.mk .mkf-baton { animation: none !important; opacity: 0 !important; }
	.mk .mk__scene .mk__art,
	.mk .mk__scene .mk__words { transform: none !important; }

	.mk .mkf-lean { animation: none !important; opacity: 1; }
	.mk .mkf-row--new { animation: none !important; opacity: 1; transform: none; }
	.mk .mkf-shake { animation: none !important; }
	.mk .mkf-scan { animation: none !important; opacity: 0 !important; }
	.mk .mkf-breathe { animation: none !important; opacity: .06; }
	.mk .mk__clock-d > i { animation: mkf-tick 240ms var(--e-snap) 6000ms both; }

	/* The row still leaves and the rows above still close the gap — that
	   is story, not decoration — but they cross-fade instead of travelling. */
	.mk .mkf-row--fall { animation: mkf-fade-out 400ms var(--e-in) 4400ms both !important; }
	.mk .mkf-grp--above { animation: none !important; transform: none !important; }
	@keyframes mkf-fade-out { to { opacity: 0; } }

	/* The move still happens; the rows arrive rather than walking. */
	.mk .mkf-row--walk { animation: mkf-hold-place 700ms linear calc(1600ms + var(--n) * 160ms) both !important; }
	.mk .mkf-row--walk::after { animation: mkf-turn 700ms linear calc(1600ms + var(--n) * 160ms) both !important; }
	@keyframes mkf-hold-place { from { transform: none; } to { transform: none; } }
	.mk .mkf-cross { transform: translate3d(-50%, -50%, 0) !important; }
	.mk .mkf-cross__frame { display: none; }
	.mk .mkf-cross__load { animation: none !important; transform: none !important; }

	/* The one substitution: things that would have travelled now scale in
	   by 2% instead. Far below the 5% threshold where scale provokes
	   motion sensitivity. */
	.mk .mk__eyebrow,
	.mk .mk__clock,
	.mk .mk__sub,
	.mk .mk__kicker,
	.mk .mkf-cta { transform: scale(.982) !important; }

	.mk .mk__scene[data-step="1"] .mk__eyebrow,
	.mk .mk__scene[data-step="2"] .mk__eyebrow,
	.mk .mk__scene[data-step="3"] .mk__eyebrow,
	.mk .mk__scene[data-step="1"] .mk__clock,
	.mk .mk__scene[data-step="2"] .mk__clock,
	.mk .mk__scene[data-step="3"] .mk__clock,
	.mk .mk__scene[data-step="2"] .mk__sub,
	.mk .mk__scene[data-step="3"] .mk__sub,
	.mk .mk__scene[data-step="3"] .mk__kicker,
	.mk .mk__scene[data-i="6"][data-step="3"] .mkf-cta { transform: none !important; }

	.mk .mk__h {
		animation: none !important;
		transform: none !important;
		transition:
			opacity   var(--t-2) var(--e-out-soft),
			clip-path var(--t-3) var(--e-out),
			filter    var(--t-3) var(--e-out-soft) !important;
	}

	/* The old block forces `transition: opacity 260ms ease` on all four
	   type elements, which would also strip the scale substitution's
	   transition. Restore an honest one. */
	.mk .mk__eyebrow,
	.mk .mk__clock,
	.mk .mk__sub,
	.mk .mk__kicker,
	.mk .mkf-cta {
		transition:
			opacity   var(--t-3) var(--e-out-soft),
			transform var(--t-5) var(--e-out) !important;
	}

	.mk .mkf-ui { transition: opacity 1100ms var(--e-out-soft) !important; }
}

/* ================================================================
   SCENE 1 · THE MONOLITHS
   ----------------------------------------------------------------
   The column used to lean for no stated reason. Now it leans because
   something is pressing on it, and the viewer can see what.

   Anonymous by design. No name, no mark, no readable text, no vendor
   palette, and deliberately no four-colour motif. The single signifier
   is the grid of identical app tiles — the universal grammar of a
   "suite", owned by nobody. The viewer supplies the name.

   Colour embargo holds: ash and graphite only. Mint still arrives for
   the first time in scene 4.
   ================================================================ */

.mkf-mono {
	position: absolute;
	top: -12%;
	block-size: 124%;
	inline-size: clamp(104px, 16.5vw, 224px);
	z-index: 0;                 /* above .mkf-key's glow, below the column */
	pointer-events: auto;
	/* Slow by default: this is the creep back after a shove. Mass, not spring. */
	transition: transform 2600ms var(--e-out-soft);
}

/* --dir points away from centre, so one rule drives both sides.
   The right one presses harder — that asymmetry is what tips the
   column to the left, and it is why the lean now has a cause. */
.mkf-mono--l { left: 0;  --dir: -1; --press:  7px; }
.mkf-mono--r { right: 0; --dir:  1; --press: 14px; }

.mkf-mono__in {
	display: block;
	block-size: 100%;
	opacity: 0;
	will-change: transform;
}

.mkf-mono__face {
	position: absolute;
	inset: 0;
	overflow: hidden;
	border-radius: 2px;
	/* Three layers. The last is a horizontal ramp darkening toward the
	   OUTER edge, which fakes the face turning away from the viewer —
	   cheaper than a rotateY and it cannot fight the hover transform. */
	background:
		linear-gradient(100deg, rgba(255, 255, 255, .045) 0%, rgba(255, 255, 255, 0) 40%),
		linear-gradient(var(--key-deg),
			color-mix(in oklab, var(--ash) 24%, #000 76%) 0%,
			color-mix(in oklab, var(--ash) 14%, #000 86%) 48%,
			#050F0D 100%),
		linear-gradient(to var(--away, left), rgba(0, 0, 0, .55) 0%, rgba(0, 0, 0, 0) 62%);
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, .045),
		0 30px 90px rgba(0, 0, 0, .6);
}

/* Which way the face falls off. The lit edge is always the one facing
   the viewer's own work. */
.mkf-mono--l .mkf-mono__face { --away: left; }
.mkf-mono--r .mkf-mono__face { --away: right; }

/* The tile grid is its own layer so it can carry a fade without taking
   the material with it. It runs past the bottom of the slab and is eased
   at both ends, so the facade reads as continuing out of frame. */
.mkf-mono__tiles {
	position: absolute;
	inset: 0;
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	align-content: start;
	gap: clamp(5px, .62vw, 9px);
	padding: clamp(12px, 1.5vw, 22px) clamp(9px, 1.1vw, 16px);
	-webkit-mask-image: linear-gradient(transparent 0%, #000 9%, #000 82%, transparent 100%);
	        mask-image: linear-gradient(transparent 0%, #000 9%, #000 82%, transparent 100%);
}

/* The tiles. Uniform, colourless, indifferent — a facade, not an interface. */
.mkf-mono__tiles i {
	display: block;
	aspect-ratio: 1;
	border-radius: 24%;
	background: color-mix(in oklab, var(--ash) 28%, #000 72%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, .055),
		inset 0 -1px 0 rgba(0, 0, 0, .3);
}

/* Rim light on the inner edge only — the face turned toward the viewer's
   own work. It is what makes a flat slab read as a solid. */
.mkf-mono::after {
	content: '';
	position: absolute;
	top: 0;
	bottom: 0;
	inline-size: 1px;
	background: linear-gradient(to bottom,
		transparent 0%, rgba(255, 255, 255, .30) 26%,
		rgba(255, 255, 255, .13) 70%, transparent 100%);
	box-shadow: 0 0 14px rgba(255, 255, 255, .10);
	pointer-events: none;
}
.mkf-mono--l::after { right: 0; }
.mkf-mono--r::after { left: 0; }

/* Arrive, then never stop closing in. 9s each way: slower than the
   column's 14s breath, so the two never sync and the frame stays uneasy. */
.mk__scene[data-i="0"][data-on="1"] .mkf-mono__in {
	animation:
		mkf-mono-in 1600ms var(--e-out) both,
		mkf-mono-press 9s var(--e-inout) 1600ms infinite alternate;
}

@keyframes mkf-mono-in {
	from { opacity: 0; transform: translate3d(calc(var(--dir) * 54px * var(--amp)), 0, 0); }
	to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes mkf-mono-press {
	from { opacity: 1; transform: translate3d(0, 0, 0); }
	to   { opacity: 1; transform: translate3d(calc(var(--dir) * -1 * var(--press) * var(--amp)), 0, 0); }
}

/* ---- the urge ---------------------------------------------------
   Approach it and it yields, reluctantly. Push it and it goes, then
   creeps back over two and a half seconds. Immovable, but not quite —
   which is the feeling that makes a person push again.
   Hover is gated: on a touchscreen :hover latches after a tap and the
   slab would stay shoved, which reads as a bug rather than as mass. */
@media (hover: hover) {
	.mkf-mono:hover {
		transform: translate3d(calc(var(--dir) * 13px * var(--amp)), 0, 0);
		transition-duration: 420ms;
	}
	.mkf-mono:hover::after { background: linear-gradient(to bottom,
		transparent 0%, rgba(255, 255, 255, .34) 28%,
		rgba(255, 255, 255, .16) 72%, transparent 100%); }
}

/* :active works on both pointer types, so the shove is the whole
   interaction on a phone and must satisfy on its own. */
.mkf-mono:active {
	transform: translate3d(calc(var(--dir) * 54px * var(--amp)), 0, 0);
	transition-duration: 240ms;
}

/* Reduced motion: still present, still crowding, simply no longer
   creeping. Pose survives because --amp collapses travel, not layout. */
@media (prefers-reduced-motion: reduce) {
	.mk__scene[data-i="0"][data-on="1"] .mkf-mono__in {
		animation: mkf-mono-in 1600ms var(--e-out) both;
	}
}

/* On a phone the art sits behind the words. The slabs must read as
   presence, never as contrast competing with the headline. */
@media (max-width: 819.98px) {
	.mkf-mono { inline-size: clamp(86px, 26vw, 150px); }
	.mkf-mono__tiles { grid-template-columns: repeat(3, 1fr); }
	.mkf-mono::after { opacity: .5; }
}

/* ================================================================
   POSTCARDS FROM YOUR DATA · the photographic layer
   ----------------------------------------------------------------
   The previous cut was abstract shapes. This one is carried by six
   photographs, so the work here is making them read as CINEMA rather
   than as pictures behind text: one grade, one grain, one slow move,
   and type that always has a dark shoulder to sit on.

   .mkp-* only. The old .mkf-* art classes are no longer emitted by
   mkScenes(), so nothing collides and nothing needed deleting.
   ================================================================ */

.mkp { --shoulder: 54%; }

.mkp__art {
	position: absolute;
	inset: 0;
	overflow: hidden;
	z-index: 0;
}

/* The photograph. Oversized so the drift never exposes an edge. */
.mkp__img {
	position: absolute;
	inset: -6%;
	background-size: cover;
	background-position: center;
	transform: scale(1.04);
	opacity: 0;
	transition: opacity var(--t-6) var(--e-out-soft),
	            transform var(--t-7) var(--e-out-soft);
	will-change: transform, opacity;
}

.mk__scene[data-on="1"] .mkp__img { opacity: 1; }

/* Ken Burns, four directions by scene index so no two consecutive
   beats move the same way -- repetition is what makes a photo film
   feel like a screensaver. Amplitude rides --amp, so reduced motion
   keeps the framing and loses only the travel. */
.mk__scene[data-on="1"][data-drift="0"] .mkp__img { transform: scale(1.09) translate3d(calc(-1.6% * var(--amp)), calc(-1.1% * var(--amp)), 0); }
.mk__scene[data-on="1"][data-drift="1"] .mkp__img { transform: scale(1.09) translate3d(calc( 1.5% * var(--amp)), calc(-1.4% * var(--amp)), 0); }
.mk__scene[data-on="1"][data-drift="2"] .mkp__img { transform: scale(1.09) translate3d(calc( 1.3% * var(--amp)), calc( 1.5% * var(--amp)), 0); }
.mk__scene[data-on="1"][data-drift="3"] .mkp__img { transform: scale(1.09) translate3d(calc(-1.4% * var(--amp)), calc( 1.2% * var(--amp)), 0); }

/* ---- the grade -------------------------------------------------
   Three jobs in one layer, and the order matters:
     1. a mint-ink duotone wash, so six photographs from six different
        photographers read as one film rather than six stock images;
     2. a hard shoulder on the words side, so type never needs a box;
     3. a vignette, because an un-vignetted photo behind type always
        looks like a placeholder.
   ---------------------------------------------------------------- */
.mkp__grade {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background:
		linear-gradient(90deg,
			rgba(4, 19, 16, .93) 0%,
			rgba(4, 19, 16, .86) calc(var(--shoulder) - 22%),
			rgba(4, 19, 16, .38) var(--shoulder),
			rgba(4, 19, 16, .30) 100%),
		radial-gradient(120% 82% at 62% 44%,
			rgba(4, 19, 16, 0) 38%, rgba(4, 19, 16, .70) 100%),
		linear-gradient(160deg,
			rgba(63, 214, 166, .16) 0%,
			rgba(63, 214, 166, 0) 46%,
			rgba(8, 35, 28, .40) 100%);
	mix-blend-mode: normal;
}

/* Grain, as one inline SVG data URI. Without it the gradients band
   visibly on a dark ground and the whole thing reads as CSS. */
.mkp__grain {
	position: absolute;
	inset: -50%;
	pointer-events: none;
	opacity: .30;
	mix-blend-mode: overlay;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
	animation: mkp-grain 900ms steps(1, end) infinite;
}

/* Jitter, or the grain reads as a dirty lens rather than as film. */
@keyframes mkp-grain {
	0%   { transform: translate3d(0, 0, 0); }
	25%  { transform: translate3d(-2%, 1%, 0); }
	50%  { transform: translate3d(1%, -2%, 0); }
	75%  { transform: translate3d(2%, 2%, 0); }
	100% { transform: translate3d(-1%, -1%, 0); }
}

/* ---- the words ------------------------------------------------- */
.mkp__words {
	position: relative;
	z-index: 2;
	max-width: 34rem;
	padding-inline: clamp(24px, 5vw, 84px);
}

/* Scene 1 is one line and nothing else; give it the room to land.
   Ceiling pulled back from 4.6rem: at that size the English set on two
   lines but Dutch ("Je gegevens zijn op vakantie.") ran to four, which
   fits at 695px of viewport height but has no margin on a shorter
   laptop. 4rem keeps the English punchy and brings the long languages
   back to three. */
.mk__scene[data-i="0"] .mk__h { font-size: clamp(2.3rem, 5.2vw, 4rem); }

/* ---- the ask --------------------------------------------------- */
.mkp__cta { margin-block-start: 30px; }

.mkp__note {
	margin-block-start: 14px;
	opacity: .78;
}

/* A plain link, well below the button. It must never read as a second
   choice competing with the one thing we are asking for. */
.mkp__replay {
	display: block;
	margin-block-start: 30px;
	border: none;
	background: none;
	padding: 0;
	font: inherit;
	font-size: 13px;
	color: var(--paper);
	opacity: .40;
	text-decoration: underline;
	text-underline-offset: 4px;
	cursor: pointer;
	transition: opacity var(--t-2) var(--e-out);
}
.mkp__replay:hover { opacity: .78; }

/* ---- narrow ----------------------------------------------------
   Below 820px the words centre over the photograph, so the shoulder
   has to become a bottom-weighted scrim instead of a side one, or the
   type sits on the brightest part of the picture. */
@media (max-width: 819.98px) {
	.mkp__words { max-width: none; text-align: center; }
	.mkp__grade {
		background:
			linear-gradient(180deg,
				rgba(4, 19, 16, .62) 0%,
				rgba(4, 19, 16, .80) 46%,
				rgba(4, 19, 16, .94) 100%),
			radial-gradient(120% 70% at 50% 34%,
				rgba(4, 19, 16, 0) 30%, rgba(4, 19, 16, .66) 100%),
			linear-gradient(160deg,
				rgba(63, 214, 166, .14) 0%,
				rgba(63, 214, 166, 0) 50%,
				rgba(8, 35, 28, .40) 100%);
	}
	.mkp__cta { display: flex; flex-direction: column; align-items: center; }
}

/* Grain is a full-screen overlay repainting five times a second; on a
   reduced-motion setting it is exactly the kind of thing to stop. */
@media (prefers-reduced-motion: reduce) {
	.mkp__grain { animation: none; }
}

/* ---- chrome legibility over photography -------------------------
   The controls, the Skip affordance and the caption were designed
   against a flat ink ground at 40% opacity. With a photograph behind
   them they vanish -- measured on scene 1, where the road runs dark
   right through the control strip. Two scrims and a little more
   contrast; the controls must never become a puzzle. */
.mk::after {
	content: '';
	position: absolute;
	inset: auto 0 0 0;
	block-size: 190px;
	pointer-events: none;
	z-index: 6;
	background: linear-gradient(to top,
		rgba(4, 19, 16, .82) 0%,
		rgba(4, 19, 16, .46) 42%,
		rgba(4, 19, 16, 0) 100%);
}

/* Skip sits top-right, where a bright sky is just as likely as a dark
   one, so it gets its own small pill rather than a full-width scrim. */
.mk__skip {
	opacity: .72;
	padding: 5px 11px;
	border-radius: 999px;
	background: rgba(4, 19, 16, .46);
	-webkit-backdrop-filter: saturate(140%) blur(8px);
	        backdrop-filter: saturate(140%) blur(8px);
}
.mk__skip:hover { opacity: 1; background: rgba(4, 19, 16, .66); }

.mk__note { opacity: .62; }

/* ---- integration corrections (not part of the delivered film.css) ---- */
/* Defensive only. The scene art deliberately bleeds past the left edge
   (.mk__scene measures 1464px at a 1400px viewport) and .mk already clips
   it. Investigated a reported 1px of page scroll and it was NOT the film:
   scrollLeft never leaves 0, and scrollWidth reads the same with the film
   closed -- it is sub-pixel rounding from a fractional devicePixelRatio.
   These two declarations cost nothing and keep the bleed contained if the
   film is ever mounted somewhere without a clipping ancestor. */
.mk { max-width: 100%; overflow-x: hidden; }

/* ===== Space Home overview + channel templates ===== */
.sph-nav__ic { flex-shrink: 0; opacity: .75; display: flex; }
.sphome { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; padding: 18px 20px 28px; }
.sph-card { background: var(--bg-raised); border: 1px solid var(--border); border-radius: 14px; padding: 14px 16px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.sph-card__h { display: flex; align-items: center; gap: 8px; font: 600 14px var(--display); }
.sph-card__act { margin-inline-start: auto; background: none; border: none; color: var(--brand); font: inherit; font-size: 12.5px; cursor: pointer; padding: 0; }
.sph-card__act:hover { text-decoration: underline; }
.sph-group { font-size: 12px; color: var(--text-muted); font-weight: 600; padding: 8px 8px 2px; }
.sph-row { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 9px; width: 100%; text-align: start; border: none; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.sph-row:hover { background: var(--bg-hover); }
.sph-row__t { min-width: 0; display: flex; flex-direction: column; flex-grow: 1; }
.sph-row__n { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sph-row__s { font-size: 12.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sph-when { width: 64px; flex-shrink: 0; font-size: 12.5px; color: var(--text-muted); text-align: end; }
.sph-empty { color: var(--text-muted); font-size: 13.5px; padding: 6px 8px; }
.sph-dot { width: 12px; height: 12px; border-radius: 100px; flex-shrink: 0; }
.tpl-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-block-end: 12px; }
.tpl { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg-subtle); color: inherit; text-align: start; font: inherit; cursor: pointer; }
.tpl[aria-pressed="true"] { border-color: var(--brand); background: var(--brand-soft); }
.tpl__n { font-weight: 600; }
.tpl__d { font-size: 12.5px; color: var(--text-muted); }
/* ---- per-conversation notifications + person hover card ---- */
.notif { align-items: flex-start; text-align: start; width: 100%; border: none; background: transparent; cursor: pointer; }
.notif > svg { margin-block-start: 2px; flex-shrink: 0; }
.notif[aria-pressed="true"] { background: var(--brand-soft); }
.notif .mem__n { font-weight: 600; }
.notif .mem__r { white-space: normal; overflow: visible; }
.chan__mute { color: var(--text-muted); flex-shrink: 0; display: inline-flex; align-items: center; }
.pcard[hidden] { display: none !important; }
.pcard { position: fixed; z-index: 250; width: 300px; background: var(--bg-raised); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 16px 48px rgba(0,0,0,.22); padding: 14px; display: flex; flex-direction: column; gap: 8px; }
.pcard__head { display: flex; gap: 12px; align-items: center; }
.pcard__n { font: 600 15px var(--display); }
.pcard__l { font-size: 12.5px; color: var(--text-muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pcard__acts { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.pcard__acts .btn { flex-direction: column; gap: 3px; font-size: 11.5px; padding: 8px 4px; min-height: 0; }
[data-person] { cursor: pointer; }
.pcav { display: inline-flex; flex-shrink: 0; }

/* ---- command palette (Ctrl+K / Cmd+K): one #cpal overlay outside render(), like #pcard ---- */
.cpal { position: fixed; inset: 0; z-index: 260; display: flex; align-items: flex-start; justify-content: center; padding: 12vh 16px 0; }
.cpal[hidden] { display: none !important; }
.cpal__bd { position: absolute; inset: 0; background: rgba(0,0,0,.35); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.cpal__panel { position: relative; width: 100%; max-width: 640px; max-height: 76vh; display: flex; flex-direction: column; background: var(--bg-raised); color: var(--text); border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 24px 80px rgba(0,0,0,.35), 0 2px 8px rgba(0,0,0,.12); overflow: hidden; animation: cpal-in 120ms ease-out; }
@keyframes cpal-in { from { opacity: 0; transform: translateY(-6px) scale(.985); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .cpal__panel { animation: none; } }
.cpal__in { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--border); color: var(--text-muted); }
.cpal__in > svg { flex-shrink: 0; }
.cpal__q { flex: 1; min-width: 0; border: none; outline: none; background: transparent; color: var(--text); font: 400 17px var(--display); padding: 0; }
.cpal__q::placeholder { color: var(--text-muted); }
.cpal__kbd, .cpal__h kbd { font: 500 10.5px/1 var(--display); color: var(--text-muted); border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px; background: color-mix(in srgb, var(--text) 4%, transparent); white-space: nowrap; }
.cpal__res { overflow-y: auto; max-height: 60vh; padding: 6px 8px 10px; overscroll-behavior: contain; }
.cpal__g { font: 600 11px var(--display); letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); padding: 12px 12px 6px; display: flex; align-items: center; gap: 8px; }
.cpal__g .tf-spin { width: 11px; height: 11px; border-width: 2px; }
.cpal__row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 12px; border-radius: 10px; color: var(--text); text-align: left; cursor: pointer; position: relative; }
.cpal__row[aria-selected="true"] { background: color-mix(in srgb, var(--brand) 12%, transparent); }
.cpal__row[aria-selected="true"]::before { content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 2px; border-radius: 2px; background: var(--brand); }
.cpal__ic { width: 28px; height: 28px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text-muted); }
.cpal__row[aria-selected="true"] .cpal__ic { color: var(--brand); }
.cpal__row .av { flex-shrink: 0; }
.cpal__b { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cpal__t { font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cpal__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cpal__t mark, .cpal__s mark { background: none; color: var(--brand); font-weight: 600; padding: 0; border-radius: 0; }
.cpal__h { font-size: 11.5px; color: var(--text-muted); flex-shrink: 0; white-space: nowrap; }
.cpal__empty { padding: 28px 12px 24px; text-align: center; color: var(--text-muted); font-size: 13.5px; }
/* the header entry point */
.cpal-btn { position: relative; color: var(--chrome-muted); }
.cpal-btn kbd { position: absolute; right: calc(100% + 2px); top: 50%; transform: translateY(-50%) translateX(6px); font: 500 10.5px/1 var(--display); letter-spacing: .03em; color: var(--chrome-muted); opacity: 0; white-space: nowrap; pointer-events: none; transition: opacity .18s ease, transform .18s ease; }
.cpal-btn:hover kbd, .cpal-btn:focus-visible kbd { opacity: .75; transform: translateY(-50%); }
@media (max-width: 1023.98px), (hover: none) { .cpal-btn kbd { display: none; } }
@media (prefers-reduced-motion: reduce) { .cpal-btn kbd { transition: none; } }

/* ============================================ notification settings
   The Notifications page is the only settings page long enough to need
   headings inside it: five blocks, four of them one app each. The
   subheader carries a line of explanation because "Talk+ calls" on its
   own does not tell you why that block has no counter row. */
.set__sub { display: flex; flex-direction: column; gap: 3px; padding-block: 20px 8px; }
.set__sub:first-child { padding-block-start: 4px; }
.set__subt { font-size: 11px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-muted); }
.set__subd { font-size: 12.5px; color: var(--text-muted); max-width: 64ch; }

.nv-tone { display: flex; align-items: center; gap: 6px; }
.set__c .nv-tone .select { min-width: 152px; }
.nv-tone__p { flex-shrink: 0; color: var(--brand); }
.nv-tone__p[disabled] { color: var(--text-muted); opacity: 0.5; cursor: default; }

.nv-vol { display: flex; align-items: center; gap: 10px; }
.nv-vol__i { width: 152px; accent-color: var(--brand); }
.nv-vol__n { font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums; min-width: 4ch; text-align: end; }


/* ======================================================= Talk+ left bar
   Two zones (2026-09-28). The top zone is the person's own conversations;
   the bottom zone is the open space, tinted with that space's colour (--sp,
   the same colour as its tile in the rail) so chats and channels can never
   be mistaken for each other. */
.list__head--talk { padding-block-end: 6px; }
.list__scroll--zones { padding-inline: 0; padding-block-end: 0; gap: 0; }
.zone { display: flex; flex-direction: column; gap: 2px; padding: 4px 8px 14px; }
.zone--space {
	flex-grow: 1;
	margin-block-start: 8px;
	padding-block-start: 12px;
	border-block-start: 1px solid color-mix(in oklab, var(--sp) 38%, var(--border));
	background: color-mix(in oklab, var(--sp) 9%, var(--bg-subtle));
}
.zone__eyebrow {
	padding: 0 6px 6px;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.9px;
	text-transform: uppercase;
	color: color-mix(in oklab, var(--sp) 72%, var(--text));
}
.zone__space { display: flex; align-items: center; gap: 10px; padding: 0 6px 8px; min-width: 0; }
.zone__tile {
	width: 34px; height: 34px; flex-shrink: 0;
	border-radius: var(--r);
	color: #fff;
	font: 600 13px var(--display);
	display: flex; align-items: center; justify-content: center;
	box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
}
.zone__text { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; gap: 1px; }
.zone__name { font: 600 16px/1.2 var(--display); letter-spacing: -0.2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zone__meta { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zone__hint { margin: 0; padding: 4px 10px 6px; font-size: 13px; color: var(--text-muted); }
.zone--space .sect { color: color-mix(in oklab, var(--sp) 55%, var(--text-muted)); }
.zone--space .sect__toggle:hover { color: var(--text); }
.zone--me .sect:first-child { padding-block-start: 6px; }
.chan--home { font-weight: 500; }
/* a row and its star: the star is a sibling, never inside the row button */
.chan__wrap { display: flex; align-items: center; gap: 2px; min-width: 0; }
.chan__wrap > .chan { flex-grow: 1; min-width: 0; }
.chan__fav {
	flex-shrink: 0;
	width: 30px; height: 30px;
	border: none; border-radius: var(--r-sm);
	background: transparent;
	color: var(--text-muted);
	display: flex; align-items: center; justify-content: center;
	opacity: 0;
	transition: opacity 120ms ease, transform 120ms ease;
}
.chan__wrap:hover .chan__fav, .chan__fav:focus-visible, .chan__fav[aria-pressed="true"] { opacity: 1; }
.chan__fav:hover { background: var(--bg-hover); color: var(--text); transform: scale(1.08); }
.chan__fav[aria-pressed="true"] { color: #ff8a3d; }
.chan__fav[aria-pressed="true"] svg { fill: currentColor; }
.chan__where { display: block; font-size: 11px; font-weight: 400; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; }
.chan[aria-current="true"] .chan__where { color: var(--brand-text); opacity: .8; }
.chan--saved .sph-nav__ic { color: #ff8a3d; opacity: 1; }
@media (hover: none) { .chan__fav { opacity: .45; } }

/* ================================================ Talk+ polish (2026-09-28)
   The content column wears the open space's colour: a shade darker than the
   page, the top bar and tab strip a touch more, the # badge in the colour
   itself. --sp is set on #app by renderMain; a chat (no space) clears it. */
#app[data-inspace="1"] .main { background: color-mix(in oklab, var(--sp) 7%, var(--bg)); }
#app[data-inspace="1"] .main > .topbar,
#app[data-inspace="1"] .main .tabstrip {
	background: color-mix(in oklab, var(--sp) 12%, var(--bg));
	border-color: color-mix(in oklab, var(--sp) 28%, var(--border));
}
#app[data-inspace="1"] .topbar__icon { background: color-mix(in oklab, var(--sp) 22%, var(--bg)); color: color-mix(in oklab, var(--sp) 78%, var(--text)); }
#app[data-inspace="1"] .side { background: color-mix(in oklab, var(--sp) 5%, var(--bg)); border-color: color-mix(in oklab, var(--sp) 28%, var(--border)); }

/* The rail: a space's tile keeps its own colour when selected; the selection
   is the orange -- a ring around the tile and the marker beside it. A tap
   lights the launcher's travelling arc on the tile for a moment. */
/* No marker bar: the selected tile speaks for itself with a soft orange halo,
   a thin translucent line hugging the tile and a faint glow around it. */
.rail__marker { display: none; }
.rail__tile { position: relative; transition: transform 120ms ease, box-shadow 200ms ease; }
.rail__tile[aria-current="true"] {
	box-shadow:
		0 0 0 2px var(--chrome-2),
		0 0 0 3.5px rgba(255, 138, 61, .62),
		0 0 14px 3px rgba(255, 138, 61, .28);
}
/* Inside Favourites the star is a quiet mark, not a call for attention; it
   comes back to full orange under the pointer. Elsewhere it stays as it is. */
.favlist .chan__fav[aria-pressed="true"] { color: color-mix(in oklab, #FF8A3D 45%, var(--text-muted)); opacity: .55; }
.favlist .chan__wrap:hover .chan__fav[aria-pressed="true"], .favlist .chan__fav:focus-visible { color: #FF8A3D; opacity: 1; }
.rail__tile[data-act="space"]::after {
	content: '';
	position: absolute;
	inset: -7px;
	border-radius: calc(var(--r-lg) + 7px);
	padding: 2.5px;
	background: conic-gradient(from var(--launch-a, 0deg), #FF8A3D 0 26%, rgba(255, 138, 61, .18) 26% 100%);
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	opacity: 0;
	transition: opacity .15s ease;
	pointer-events: none;
}
.rail__tile.is-launching { transform: scale(1.06); }
.rail__tile.is-launching::after { opacity: 1; animation: rail-ring .9s linear infinite; }
@keyframes rail-ring { to { --launch-a: 360deg; } }
@media (prefers-reduced-motion: reduce) { .rail__tile.is-launching::after { animation: none; background: rgba(255, 138, 61, .9); } }

/* The About panel: calls as one row, notifications as one quiet line. */
.side__calls { display: flex; gap: 8px; padding: 12px 8px 0; }
.side__calls .btn { flex: 1 1 0; justify-content: center; }
.nrow { display: flex; align-items: center; gap: 6px; padding: 14px 8px 2px; }
.nrow__t { display: flex; align-items: center; gap: 6px; flex-grow: 1; min-width: 0; font-size: 12px; font-weight: 600; color: var(--text-muted); }
.nseg { display: inline-flex; gap: 2px; padding: 2px; border-radius: 100px; background: var(--bg-hover); }
.nseg__b {
	width: 28px; height: 26px;
	border: none; border-radius: 100px;
	background: transparent;
	color: var(--text-muted);
	display: flex; align-items: center; justify-content: center;
	transition: background 120ms ease, color 120ms ease;
}
.nseg__b:hover { color: var(--text); }
.nseg__b[aria-pressed="true"] { background: var(--bg); color: var(--text); box-shadow: 0 1px 2px rgba(0, 0, 0, .14); }
.nseg__b--calls { margin-inline-start: 2px; background: var(--bg-hover); }
.nseg__b--calls[aria-pressed="true"] { color: var(--brand); background: var(--brand-soft); }
.nrow__hint { margin: 0; padding: 0 8px 4px 31px; font-size: 11.5px; color: var(--text-muted); }
.side__head .dd { min-width: 262px; }

/* ---- Space Home cards in the space colour (2026-09-28): a card is a tile of
   the space, not of the brand -- its ground, edge, glyph, count and link all
   take --sp, the same colour as the tile in the rail and the zone in the bar. */
#app[data-inspace="1"] .sph-card {
	background: color-mix(in oklab, var(--sp) 11%, var(--bg));
	border-color: color-mix(in oklab, var(--sp) 34%, var(--border));
}
#app[data-inspace="1"] .sph-card__h > svg { color: color-mix(in oklab, var(--sp) 82%, var(--text)); }
#app[data-inspace="1"] .sph-card__h .pill-count { background: color-mix(in oklab, var(--sp) 82%, var(--text)); color: #fff; }
#app[data-inspace="1"] .sph-card__act { color: color-mix(in oklab, var(--sp) 80%, var(--text)); }
#app[data-inspace="1"] .sph-card .tf-spin { border-color: color-mix(in oklab, var(--sp) 30%, transparent); border-top-color: color-mix(in oklab, var(--sp) 85%, var(--text)); }
#app[data-inspace="1"] .sph-row:hover { background: color-mix(in oklab, var(--sp) 16%, var(--bg)); }
#app[data-inspace="1"] .chan--home[aria-current="true"] { background: color-mix(in oklab, var(--sp) 88%, var(--text)); color: #fff; }
/* ======================================================= Help & demos
   Settings > Help: one card per app, each with a scripted demo -- a moving
   sketch of the app in its own design, with captions and the film's score
   underneath. The player is a full-screen overlay; the "app" inside it is a
   1180 x 720 stage scaled to fit, so a demo's cursor lands where it should
   on every screen. */
.hp { display: flex; flex-direction: column; gap: 16px; }
.hp__hero { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 16px 18px; border: 1px solid var(--brand-line); background: var(--brand-soft); border-radius: var(--r-xl); }
.hp__hero b { font: 600 16px var(--display); }
.hp__hero .muted { font-size: 13px; }
.hp__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.hp__card { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--bg-raised); --hc: var(--brand); position: relative; overflow: hidden; }
.hp__card--wide { grid-column: 1 / -1; background: linear-gradient(135deg, color-mix(in oklab, var(--hc) 12%, var(--bg-raised)), var(--bg-raised) 60%); }
.hp__card--wide .hp__t { font-size: 16px; }
.hp__coming { display: flex; flex-direction: column; gap: 2px; margin: 22px 0 10px; padding-top: 16px; border-top: 1px solid var(--border); }
.hp__coming b { font: 600 15px var(--display); }
.hp__card--wip { --hc: #8a9490; filter: saturate(0); }
/* A work-in-progress demo plays in grey: the stage and the phone frame lose
   their colour, and only the NuvoCloud logo and wordmark keep
   it, so a preview can never be mistaken for the finished app. */
.dm--wip .dm-hdr, .dm--wip .dmp-hdr, .dm--wip .dmp-status, .dm--wip .dmp-tabs { background: #2a2f2d; }
.dm--wip .dm-hdr > *:not(:first-child):not(.wordmark), .dm--wip .dmp-hdr > *:not(:first-child):not(.wordmark), .dm--wip .dm-body, .dm--wip .dmp-status, .dm--wip .dmp-body, .dm--wip .dmp-tabs, .dm--wip .dmp-home, .dm--wip .dm-toast { filter: grayscale(1); }
.dm--wip .dm__app { background: #1c201f; }
.dm__wipmark { position: absolute; top: 14px; right: 14px; z-index: 25; display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 100px; background: rgba(20, 22, 21, .72); border: 1.5px solid #FF8A3D; color: #FF8A3D; box-shadow: 0 6px 18px -8px rgba(0,0,0,.6); font: 500 12.5px var(--display); letter-spacing: .02em; pointer-events: none; }
.dm__wipmark b { font-weight: 700; font-size: 11px; letter-spacing: .08em; padding: 1px 6px; border-radius: 6px; border: 1.5px solid #FF8A3D; color: #FF8A3D; }
.dm--phone .dm__wipmark { top: 60px; right: 12px; }
/* The player chrome follows: no orange while a preview plays. */
.dm--wip .dm__pp, .dm--wip .dm__bar, .dm--wip .dm__chap, .dm--wip .dm__cap span, .dm--wip .dm__end .btn--primary, .dm--wip .dm__chip, .dm--wip .dm__tick { filter: grayscale(1); }
.hp__card::before { content: ''; position: absolute; inset-inline-start: 0; inset-block: 0; width: 4px; background: var(--hc); }
.hp__top { display: flex; align-items: center; gap: 10px; }
.hp__ic { width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; color: var(--hc); background: color-mix(in oklab, var(--hc) 14%, var(--bg)); flex-shrink: 0; }
.hp__t { font: 600 15px var(--display); }
.hp__len { margin-inline-start: auto; font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
.hp__tag { font-size: 13px; color: var(--text-muted); margin: 0; }
.hp__hl { display: flex; flex-wrap: wrap; gap: 5px; margin: 0; padding: 0; list-style: none; }
.hp__hl li { font-size: 11.5px; font-weight: 600; padding: 2px 8px; border-radius: 100px; background: var(--bg-subtle); color: var(--text-muted); border: 1px solid var(--border); }
.hp__play { margin-block-start: 2px; align-self: flex-start; display: inline-flex; align-items: center; gap: 6px; }
.hp__hint { font-size: 12px; color: var(--text-muted); }
.hp__hint kbd { font: 600 11px var(--display); padding: 1px 6px; border: 1px solid var(--border); border-radius: 5px; background: var(--bg-subtle); }

/* ---- the player ---- */
.dm { position: fixed; inset: 0; z-index: 300; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 14px clamp(12px, 3vw, 40px); background: rgba(6, 17, 14, .9); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); color: #e8f0ec; font-family: var(--font, inherit); animation: dm-in .32s ease both; }
@keyframes dm-in { from { opacity: 0; } to { opacity: 1; } }
.dm__head { width: min(100%, 1240px); display: flex; align-items: center; gap: 12px; min-height: 40px; }
.dm__logo { width: 30px; height: 30px; flex-shrink: 0; }
.dm__title { font: 600 17px var(--display); letter-spacing: -.2px; color: #fff; display: flex; align-items: center; gap: 10px; min-width: 0; }
.dm__chap { font: 500 13px var(--display); color: #ff8a3d; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dm__chap::before { content: '\00b7'; margin-inline-end: 8px; color: rgba(255,255,255,.4); }
.dm__hbtns { margin-inline-start: auto; display: flex; gap: 4px; }
.dm__ibtn { width: 36px; height: 36px; border: none; border-radius: 10px; background: rgba(255,255,255,.08); color: #e8f0ec; display: grid; place-items: center; cursor: pointer; transition: background .15s ease, transform .12s ease; }
.dm__ibtn:hover { background: rgba(255,255,255,.16); }
.dm__ibtn:active { transform: scale(.94); }
.dm__ibtn[aria-pressed="false"] { color: rgba(232,240,236,.45); }
.dm__stage { position: relative; width: min(100%, 1240px); flex: 0 1 auto; max-height: calc(100dvh - 190px); aspect-ratio: 1180 / 720; }
.dm__scale { position: absolute; inset-block-start: 0; inset-inline-start: 0; width: 1180px; height: 720px; transform-origin: 0 0; }
.dm__app { position: absolute; inset: 0; border-radius: 16px; overflow: hidden; background: var(--bg); color: var(--text); border: 1px solid rgba(255,255,255,.12); box-shadow: 0 40px 100px -40px rgba(0,0,0,.8); display: flex; flex-direction: column; font-size: 14px; line-height: 1.45; }
.dm__app * { min-width: 0; }
/* the pointer + the click ring */
.dm__cur { position: absolute; z-index: 20; inset-block-start: 0; inset-inline-start: 0; width: 24px; height: 24px; pointer-events: none; opacity: 0; filter: drop-shadow(0 2px 3px rgba(0,0,0,.4)); transition: transform .72s cubic-bezier(.3,.7,.2,1), opacity .3s ease; }
.dm__cur[data-on] { opacity: 1; }
.dm__ring { position: absolute; z-index: 19; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%; border: 2.5px solid #FF8A3D; pointer-events: none; animation: dm-ring .55s ease-out forwards; }
@keyframes dm-ring { from { transform: scale(.35); opacity: .95; } to { transform: scale(1.35); opacity: 0; } }
[data-press] { transform: scale(.94) !important; transition: transform .1s ease; }
/* generic "not yet" state a demo toggles with data-off */
.dm__app [data-off] { opacity: 0 !important; pointer-events: none; }
.dm__app .dm-fade { transition: opacity .38s ease, transform .38s ease; }
.dm__app .dm-rise { transition: opacity .38s ease, transform .38s ease; }
.dm__app .dm-rise[data-off] { transform: translateY(8px); }
.dm__app .dm-slide { transition: transform .42s cubic-bezier(.2,.7,.2,1), opacity .3s ease; }
.dm__app .dm-slide[data-off] { transform: translateX(28px); }
.dm__app .dm-pop { transition: transform .28s cubic-bezier(.2,1.4,.3,1), opacity .2s ease; }
.dm__app .dm-pop[data-off] { transform: scale(.85); }
/* typing caret */
.dm-caret { display: inline-block; width: 1.5px; height: 1.05em; background: currentColor; vertical-align: -.15em; margin-inline-start: 1px; animation: dm-blink 1s steps(1) infinite; }
@keyframes dm-blink { 50% { opacity: 0; } }
/* captions */
.dm__cap { width: min(100%, 1240px); min-height: 44px; display: flex; align-items: center; justify-content: center; text-align: center; }
.dm__cap span { display: inline-block; font: 500 clamp(15px, 1.7vw, 19px)/1.35 var(--display); letter-spacing: -.2px; color: #fff; background: rgba(8, 35, 28, .72); border: 1px solid rgba(255,255,255,.1); padding: 8px 18px; border-radius: 100px; max-width: 100%; text-wrap: balance; opacity: 0; transform: translateY(6px); transition: opacity .3s ease, transform .3s ease; }
.dm__cap span[data-on] { opacity: 1; transform: none; }
/* progress + transport */
.dm__foot { width: min(100%, 1240px); display: flex; align-items: center; gap: 12px; }
.dm__bar { position: relative; flex: 1; height: 26px; display: flex; align-items: center; cursor: pointer; }
.dm__bar::before { content: ''; position: absolute; inset-inline: 0; height: 4px; border-radius: 4px; background: rgba(255,255,255,.14); }
.dm__bar i { position: absolute; inset-inline-start: 0; height: 4px; border-radius: 4px; background: #FF8A3D; width: 0; transition: width .12s linear; }
.dm__tick { position: absolute; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: #0b1512; border: 2px solid rgba(255,255,255,.55); cursor: pointer; z-index: 1; }
.dm__tick:hover { border-color: #FF8A3D; }
.dm__tick[data-done] { border-color: #FF8A3D; background: #FF8A3D; }
.dm__time { font: 600 12px var(--display); font-variant-numeric: tabular-nums; color: rgba(232,240,236,.7); white-space: nowrap; }
.dm__btns { display: flex; gap: 6px; }
.dm__pp { width: 44px; height: 44px; border-radius: 12px; background: #FF8A3D; color: #08231c; border: none; display: grid; place-items: center; cursor: pointer; transition: transform .12s ease; }
.dm__pp:active { transform: scale(.94); }
/* end card */
.dm__end { position: absolute; inset: 0; z-index: 30; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; text-align: center; background: rgba(8, 35, 28, .78); backdrop-filter: blur(6px); color: #fff; padding: 24px; opacity: 0; pointer-events: none; transition: opacity .4s ease; }
.dm__end[data-on] { opacity: 1; pointer-events: auto; }
.dm__end b { font: 600 clamp(20px, 3vw, 30px) var(--display); letter-spacing: -.4px; text-wrap: balance; max-width: 22ch; }
.dm__end p { margin: 0; color: rgba(232,240,236,.8); max-width: 44ch; }
.dm__end .btn { min-height: 44px; font-size: 15px; }
.dm__end .btn--primary { background: #FF8A3D; color: #08231c; }
.dm__endbtns { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-block-start: 6px; }

/* ---- the mock app kit (used by every demo) ---- */
.dm-hdr { height: 52px; flex-shrink: 0; display: flex; align-items: center; gap: 6px; padding-inline: 14px; background: var(--chrome); color: #fff; }
.dm-hdr .wordmark { font-size: 18px; margin-inline: 8px 22px; color: #fff; }
.dm-hdr .nuvo { font-weight: 700; } .dm-hdr .cloud { font-weight: 500; color: #3fd6a6; } .dm-hdr .eu { font-weight: 600; font-size: .52em; color: #ff8a3d; vertical-align: .15em; }
.dm-app { height: 34px; padding-inline: 12px; border-radius: 9px; color: rgba(255,255,255,.66); font-size: 13.5px; font-weight: 500; display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.dm-app[aria-current="true"] { background: rgba(63,214,166,.22); color: #b5eedb; font-weight: 600; }
.dm-app .nav-ic { width: 17px; height: 17px; }
.dm-hdr__me { margin-inline-start: auto; display: flex; align-items: center; gap: 12px; }
.dm-body { flex: 1; min-height: 0; display: flex; }
.dm-rail { width: 56px; flex-shrink: 0; background: var(--chrome-2); display: flex; flex-direction: column; align-items: center; gap: 8px; padding-block: 10px; }
.dm-list { width: 272px; flex-shrink: 0; background: var(--bg-subtle); border-inline-end: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
.dm-list__t { font: 600 17px var(--display); padding: 14px 14px 8px; }
.dm-list__scroll { flex: 1; min-height: 0; overflow: hidden; padding: 0 8px 12px; display: flex; flex-direction: column; gap: 2px; }
.dm-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; background: var(--bg); }
.dm-side { width: 280px; flex-shrink: 0; border-inline-start: 1px solid var(--border); background: var(--bg); display: flex; flex-direction: column; padding: 12px 10px; gap: 8px; }
.dm-av { width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center; font: 700 11px var(--display); color: #fff; }
.dm-av--lg { width: 40px; height: 40px; font-size: 14px; }
.dm-av--sm { width: 24px; height: 24px; font-size: 9px; }
.dm-scroll { flex: 1; min-height: 0; overflow: hidden; padding: 16px 20px 8px; display: flex; flex-direction: column; justify-content: flex-end; gap: 12px; }
.dm-comp { flex-shrink: 0; padding: 6px 18px 16px; }
.dm-comp__box { min-height: 46px; border: 1px solid var(--border-2, var(--border)); border-radius: 12px; display: flex; align-items: center; gap: 8px; padding: 5px 7px 5px 14px; background: var(--bg); transition: border-color .2s ease, box-shadow .2s ease; }
.dm-comp__box[data-focus] { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.dm-comp__in { flex: 1; font-size: 14.5px; white-space: nowrap; overflow: hidden; }
.dm-comp__in:empty::before { content: attr(data-ph); color: var(--text-muted); }
.dm-send { width: 34px; height: 34px; border-radius: 9px; background: var(--brand); color: var(--brand-text); display: grid; place-items: center; flex-shrink: 0; }
.dm-typing { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-muted); padding-inline-start: 42px; height: 18px; }
.dm-dots { display: inline-flex; gap: 3px; }
.dm-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--brand); animation: dm-dot 1s infinite ease-in-out; }
.dm-dots i:nth-child(2) { animation-delay: .15s; } .dm-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes dm-dot { 0%, 80%, 100% { opacity: .25; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-3px); } }
.dm-toast { position: absolute; inset-block-end: 18px; inset-inline-start: 50%; transform: translate(-50%, 0); z-index: 12; background: var(--chrome); color: #fff; font-size: 13.5px; font-weight: 600; padding: 9px 16px; border-radius: 100px; box-shadow: 0 10px 30px rgba(0,0,0,.25); display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.dm-toast[data-off] { transform: translate(-50%, 10px); }
.dm-pal { position: absolute; inset-block-start: 60px; inset-inline-start: 50%; transform: translateX(-50%); width: min(560px, 90%); z-index: 14; background: var(--bg-raised, var(--bg)); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 30px 70px -30px rgba(0,0,0,.6); overflow: hidden; }
.dm-pal__in { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-block-end: 1px solid var(--border); font-size: 15px; }
.dm-pal__row { display: flex; align-items: center; gap: 10px; padding: 9px 14px; font-size: 13.5px; }
.dm-pal__row[aria-selected="true"] { background: var(--brand-soft); }
.dm-pal__k { font-size: 11px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--text-muted); padding: 8px 14px 2px; }
.dm-pal__row .muted { margin-inline-start: auto; font-size: 12px; }
.dm-panel { position: absolute; inset-block: 0; inset-inline-end: 0; width: 300px; z-index: 11; background: var(--bg); border-inline-start: 1px solid var(--border); padding: 14px; display: flex; flex-direction: column; gap: 10px; box-shadow: -18px 0 40px -28px rgba(0,0,0,.4); }
.dm-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.dm-kpi { border: 1px solid var(--border); border-radius: 14px; padding: 10px 13px; display: flex; flex-direction: column; background: var(--bg-raised, var(--bg)); transition: background .3s ease, border-color .3s ease; }
.dm-kpi__l { font-size: 11.5px; font-weight: 600; color: var(--text-muted); }
.dm-kpi__v { font: 600 24px var(--display); letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.dm-kpi[data-warn] { background: var(--warn-bg, #fdf1e8); border-color: var(--warn-border, #f0c9a8); }
.dm-hi { outline: 2px solid #FF8A3D; outline-offset: 3px; border-radius: 8px; transition: outline-color .2s ease; }
.dm-callbar { display: flex; align-items: center; gap: 12px; padding: 10px 18px; background: color-mix(in oklab, var(--brand) 14%, var(--bg)); border-block-end: 1px solid var(--brand-line); font-size: 13.5px; }
.dm__app .dm-callbar[data-off] { display: none; }
.dm-callbar .rec-dot { width: 9px; height: 9px; border-radius: 50%; background: #e8792b; animation: dm-blink 1.2s steps(1) infinite; }
.dm-callgrid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; padding: 16px 20px; background: #06110e; }
.dm-tile { position: relative; border-radius: 14px; background: #0f1b18; display: grid; place-items: center; color: #fff; overflow: hidden; border: 1px solid rgba(255,255,255,.08); }
.dm-tile span { position: absolute; inset-block-end: 10px; inset-inline-start: 12px; font-size: 12.5px; font-weight: 600; background: rgba(0,0,0,.45); padding: 3px 9px; border-radius: 100px; }
.dm-tile[data-speaking] { box-shadow: inset 0 0 0 2px #3fd6a6; }

@media (max-width: 767.98px) {
	.dm { padding: 8px 8px; gap: 6px; }
	.dm__title { font-size: 15px; }
	.dm__chap { display: none; }
	.dm__cap span { font-size: 13.5px; padding: 6px 12px; border-radius: 14px; }
	.dm__stage { max-height: calc(100dvh - 150px); }
}
@media (prefers-reduced-motion: reduce) {
	.dm { animation: none; }
	.dm__cur { transition: opacity .2s ease; }
	.dm__app .dm-fade, .dm__app .dm-rise, .dm__app .dm-slide, .dm__app .dm-pop, .dm__cap span { transition: none; }
	.dm-dots i, .dm-caret, .dm-callbar .rec-dot { animation: none; }
}

/* ---- the phone edition (2026-09-28) ---- */
.hp__btns { display: flex; gap: 8px; flex-wrap: wrap; margin-block-start: 2px; }
.hp__btns .hp__play { margin-block-start: 0; }
.dm--phone .dm__stage { width: auto; height: min(calc(100dvh - 190px), 760px); max-height: none; }
.dm--phone .dm__app { border-radius: 46px; border: 10px solid #0e1613; box-shadow: 0 0 0 2px rgba(255,255,255,.08), 0 50px 120px -40px rgba(0,0,0,.85); }
.dm--phone.dm--onphone .dm__stage { height: calc(100dvh - 150px); }
.dm--phone.dm--onphone .dm__app { border-radius: 18px; border-width: 1px; }
.dm--phone .dm__cur { display: none; }
.dm--phone .dm__ring { width: 52px; height: 52px; margin: -26px 0 0 -26px; border-width: 3px; background: rgba(255, 138, 61, .18); }
.dm--phone .dm__end b { font-size: 24px; }
.dm--phone .dm__end .btn { min-height: 48px; }
/* status bar, header, tab bar, home indicator */
.dmp-status { height: 46px; flex-shrink: 0; background: var(--chrome); color: #fff; display: flex; align-items: center; justify-content: space-between; padding: 6px 26px 0; font: 600 15px var(--display); position: relative; }
.dmp-island { position: absolute; inset-inline-start: 50%; inset-block-start: 8px; width: 118px; height: 32px; margin-inline-start: -59px; border-radius: 20px; background: #000; }
.dm--onphone .dmp-island { display: none; }
.dmp-status__r { display: flex; align-items: center; gap: 5px; }
.dmp-sig { width: 17px; height: 11px; background: linear-gradient(to right, #fff 0 20%, transparent 20% 27%, #fff 27% 47%, transparent 47% 54%, #fff 54% 74%, transparent 74% 81%, #fff 81%); clip-path: polygon(0 60%, 20% 60%, 20% 40%, 47% 40%, 47% 20%, 74% 20%, 74% 0, 100% 0, 100% 100%, 0 100%); }
.dmp-wifi { width: 15px; height: 11px; border-radius: 50% 50% 0 0; background: radial-gradient(circle at 50% 100%, #fff 0 2px, transparent 2.5px 4.5px, #fff 5px 6.5px, transparent 7px 9px, #fff 9.5px 11px, transparent 11.5px); }
.dmp-bat { width: 25px; height: 12px; border: 1.5px solid rgba(255,255,255,.55); border-radius: 4px; position: relative; }
.dmp-bat::before { content: ''; position: absolute; inset: 2px; inset-inline-end: 5px; background: #fff; border-radius: 1.5px; }
.dmp-hdr { height: 52px; flex-shrink: 0; background: var(--chrome); display: flex; align-items: center; gap: 8px; padding-inline: 14px; color: #fff; }
.dmp-hdr .wordmark { font-size: 17px; margin-inline-start: 2px; color: #fff; }
.dmp-hdr .nuvo { font-weight: 700; } .dmp-hdr .cloud { font-weight: 500; color: #3fd6a6; } .dmp-hdr .eu { font-weight: 600; font-size: .52em; color: #ff8a3d; vertical-align: .15em; }
.dmp-hdr__r { margin-inline-start: auto; display: flex; align-items: center; gap: 14px; }
.dmp-body { flex: 1; min-height: 0; position: relative; overflow: hidden; background: var(--bg); }
.dmp-tabs { height: 56px; flex-shrink: 0; background: var(--chrome); border-block-start: 1px solid rgba(255,255,255,.08); display: flex; align-items: stretch; justify-content: space-around; padding-inline: 2px; }
.dmp-tab { position: relative; flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; font-size: 10px; font-weight: 600; color: rgba(255,255,255,.62); isolation: isolate; }
.dmp-tab .nav-ic, .dmp-tab > svg { width: 22px; height: 22px; }
.dmp-tab[aria-current="true"] { color: var(--chrome-active-text); }
.dmp-tab[aria-current="true"]::after { content: ''; position: absolute; inset: 5px 3px; border-radius: 12px; background: var(--chrome-active); z-index: -1; }
.dmp-tab[aria-current="true"]::before { content: ''; position: absolute; inset-block-start: 0; inset-inline: 22%; height: 2px; border-radius: 100px; background: var(--brand-dark); }
.dmp-tab .pill-count { position: absolute; inset-block-start: 4px; inset-inline-start: 50%; margin-inline-start: 3px; min-width: 17px; height: 17px; font-size: 10px; background: #FF8A3D; color: #08231C; }
.dmp-home { height: 22px; flex-shrink: 0; background: var(--chrome); display: grid; place-items: center; }
.dmp-home i { width: 134px; height: 5px; border-radius: 100px; background: rgba(255,255,255,.85); }
/* pages stack in the body; a page slides in from the right */
/* each page is its own stacking context: an inner z-index (the real .mlist has one) can never lift a page under a later one */
.dmp-page { position: absolute; inset: 0; z-index: 1; isolation: isolate; display: flex; flex-direction: column; background: var(--bg); transition: transform .38s cubic-bezier(.2,.7,.2,1), opacity .3s ease; }
.dmp-page[data-off] { transform: translateX(100%); opacity: 1 !important; pointer-events: none; }
.dmp-page--under[data-off] { transform: translateX(-24%); opacity: .0 !important; }
.dmp-top { height: 52px; flex-shrink: 0; display: flex; align-items: center; gap: 8px; padding-inline: 8px 10px; border-block-end: 1px solid var(--border); }
.dmp-top .nav-back { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.dmp-top__t { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.dmp-top__n { font: 600 15px var(--display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dmp-top__s { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dmp-top .btn { min-height: 34px; padding-inline: 10px; font-size: 13px; }
.dmp-rail { height: 62px; flex-shrink: 0; display: flex; align-items: center; gap: 8px; padding-inline: 10px; background: var(--chrome-2); overflow: hidden; }
.dmp-rail .rail__tile { width: 40px; height: 40px; flex-shrink: 0; }
.dmp-list { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; background: var(--bg-subtle); }
.dmp-scroll { flex: 1; min-height: 0; overflow: hidden; padding: 14px 16px 6px; display: flex; flex-direction: column; justify-content: flex-end; gap: 12px; }
.dmp-comp { flex-shrink: 0; padding: 6px 12px 12px; border-block-start: 1px solid var(--border); }
.dmp-sheet { position: absolute; inset-inline: 0; inset-block-end: 0; z-index: 12; background: var(--bg-raised, var(--bg)); border-radius: 18px 18px 0 0; box-shadow: 0 -20px 50px -20px rgba(0,0,0,.5); padding: 10px 16px 18px; display: flex; flex-direction: column; gap: 8px; transition: transform .38s cubic-bezier(.2,.7,.2,1); }
.dmp-sheet[data-off] { transform: translateY(105%); opacity: 1 !important; }
.dmp-sheet::before { content: ''; width: 40px; height: 5px; border-radius: 100px; background: var(--border); margin: 0 auto 4px; }
.dmp-veil { position: absolute; inset: 0; z-index: 11; background: rgba(6,17,14,.45); transition: opacity .3s ease; }
.dmp-rowbtn { display: flex; align-items: center; gap: 12px; min-height: 48px; padding-inline: 4px; font-size: 15px; }
.dm--phone .dm-toast { font-size: 13px; padding: 8px 14px; inset-block-end: 96px; max-width: 86%; white-space: normal; text-align: center; }
.dm--phone .dm__app .msg__text { font-size: 15px; }

/* ---- the end card's link to the other demos ---- */
.dm__more { margin-block-start: 18px; display: flex; flex-direction: column; align-items: center; gap: 8px; max-width: 100%; }
.dm__more-t { font-size: 11.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: rgba(232,240,236,.6); }
.dm__chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; max-width: 560px; }
.dm__chip { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; border-radius: 100px; border: 1px solid rgba(255,255,255,.14); background: rgba(255,255,255,.08); color: #fff; font: 600 12.5px var(--display); cursor: pointer; transition: background .15s ease, transform .12s ease; }
.dm__chip .nav-ic { width: 16px; height: 16px; color: var(--hc); }
.dm__chip:hover { background: rgba(255,255,255,.16); }
.dm__chip:active { transform: scale(.95); }
.dm--phone .dm__chips { max-width: 100%; }
.dm--phone .dm__chip { padding: 6px 10px; font-size: 12px; }

/* the honest line under the end card */
.dm__note { margin-block-start: 14px; font-size: 12px; color: rgba(232,240,236,.55); max-width: 46ch; }
/* ================================================================
   Industry-pack widgets on the Today sheet: one vocabulary for every
   widget (fields, result rows, buttons, a footer), tinted in the pack
   colour (the "Get work done" material at the end of this file). Everything else comes from the .nvw card and the shell's
   controls, so a widget looks like NuvoCloud without trying.
   ================================================================ */
.nvw--widget { --wc: var(--brand); gap: 8px; position: relative; }
.nvw--widget::before { content: ''; position: absolute; top: 0; left: 22px; right: 22px; height: 2px; border-radius: 0 0 2px 2px; background: color-mix(in srgb, var(--wc) 70%, transparent); }
.nvw--w4 { grid-column: span 4; }
.nvw--w8 { grid-column: span 8; }
.nvw--widget .nvw__t .w__head { margin-inline-start: auto; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.w__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; }
.w__grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.w__f { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.w__f--wide { grid-column: 1 / -1; }
.w__l { font-size: 11.5px; font-weight: 600; color: var(--text-muted); letter-spacing: .01em; }
.w__in { display: flex; align-items: center; gap: 0; }
.w__in .input { flex: 1 1 auto; min-width: 0; height: 34px; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.w__aff { padding: 0 8px; font-size: 12.5px; color: var(--text-muted); white-space: nowrap; }
.w__f .select { height: 34px; font-size: 13.5px; }
.w__tabs { display: inline-flex; gap: 2px; padding: 2px; border-radius: 100px; background: color-mix(in srgb, var(--text) 8%, transparent); }
.w__tab { border: none; background: transparent; color: var(--text-muted); font: 600 12px var(--display); padding: 5px 11px; border-radius: 100px; cursor: pointer; }
.w__tab[aria-current="true"] { background: var(--brand); color: var(--brand-text); }
.w__out { display: flex; flex-direction: column; gap: 2px; }
.w__row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 5px 0; border-bottom: 1px solid color-mix(in srgb, var(--text) 7%, transparent); font-size: 13px; }
.w__row:last-child { border-bottom: none; }
.w__rl { color: var(--text-muted); min-width: 0; }
.w__rv { font-variant-numeric: tabular-nums; text-align: end; white-space: nowrap; color: var(--text); }
.w__row--strong { padding-top: 8px; }
.w__row--strong .w__rl { color: var(--text); font-weight: 600; }
.w__row--strong .w__rv { font: 600 17px var(--display); color: var(--brand); }
.w__row--muted .w__rv { color: var(--text-muted); }
.w__btns { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.w__btns .btn { min-height: 32px; font-size: 12.5px; padding-inline: 12px; }
.w__link { text-decoration: none; }
.w__ext { opacity: .7; font-size: 11px; }
.w__foot { font-size: 11.5px; color: var(--text-muted); margin-top: 4px; }
.w__empty { font-size: 13px; color: var(--text-muted); padding: 6px 0; }
.w__err { font-size: 12.5px; color: var(--danger); }
.w__list { display: flex; flex-direction: column; gap: 2px; }
.w__item { display: flex; align-items: center; gap: 10px; width: 100%; border: none; background: transparent; color: var(--text); font: inherit; text-align: start; padding: 6px 8px; border-radius: 10px; cursor: pointer; }
.w__item:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.w__item .nav-ic, .w__item > svg { flex-shrink: 0; color: var(--text-muted); }
.w__item__t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.w__item__n { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.w__item__s { font-size: 11.5px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.w__item__r { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.w__pin { border: none; background: transparent; color: var(--text-muted); cursor: pointer; padding: 2px; border-radius: 6px; }
.w__pin[aria-pressed="true"] { color: #ff8a3d; }
.w__plate { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 700; letter-spacing: .06em; background: #ffe873; color: #08231c; border-radius: 6px; padding: 2px 8px; }
.w__calc { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 5px; }
.w__calc .btn { min-height: 32px; padding: 0; font-size: 13px; }
.w__calc .btn--op { background: color-mix(in srgb, var(--text) 10%, transparent); }
.w__calc .btn--wide { grid-column: span 2; }
.w__calc--simple { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.w__calc--simple .btn { min-height: 36px; font-size: 14px; }
.w__disp { border-radius: 12px; background: color-mix(in srgb, var(--text) 6%, transparent); padding: 8px 12px; text-align: end; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.w__disp__x { font-size: 12px; color: var(--text-muted); min-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.w__disp__r { font-size: 22px; font-weight: 700; color: var(--brand); min-height: 28px; }
.w__disp__na { color: var(--text-muted); font-size: 16px; font-weight: 500; }
.w__tape { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; color: var(--text-muted); display: flex; flex-direction: column; gap: 1px; }
.w__lines { display: flex; flex-direction: column; gap: 4px; }
.w__line { display: grid; grid-template-columns: minmax(0, 2fr) 60px 70px 80px 28px; gap: 6px; align-items: center; }
.w__line .input { height: 30px; font-size: 12.5px; padding-inline: 8px; }
.w__line__t { font-size: 12.5px; text-align: end; font-variant-numeric: tabular-nums; }
.w__hits { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
@media (max-width: 640px) {
	.nvw--w4, .nvw--w8 { grid-column: span 12; }
	.w__grid, .w__grid--3 { grid-template-columns: 1fr; }
	.w__calc { grid-template-columns: repeat(4, minmax(0, 1fr)); }
	.w__line { grid-template-columns: minmax(0, 1fr) 50px 60px 70px 28px; }
}

/* ================================================================
   Today, two sections (047): the standard cards, then "Get work done"
   with the industry widgets in a grid of their own. Add widget opens the
   picker; Edit puts a minus badge on every card. A card a person removed
   is hidden by a class on the sheet (nvh-<key>), so a feed that repaints
   itself cannot bring it back.
   ================================================================ */
.nv-today.nvh-snake [data-card="snake"], .nv-today.nvh-talk [data-card="talk"], .nv-today.nvh-mail [data-card="mail"],
.nv-today.nvh-cal [data-card="cal"], .nv-today.nvh-log [data-card="log"] { display: none !important; }
/* The sheet head: Focus, Add widget, Edit and Esc sit together on the right. */
.nv-today__head > .nv-today__focus { margin-inline-start: auto; }
.nv-today__head > .nv-today__arr { align-self: flex-start; }
/* On a phone the head follows the iOS large-title pattern: the three
   buttons on their own at the top right, like a navigation bar (four
   since Focus came: icons only, about 230px at 360px wide); the greeting
   across the full width under them; then the date and the pill, each on
   a line of their own (the weather is in the Now band). A grid, so
   nothing in it can push the sheet wider than the screen. Esc keeps a little air
   from the edge of the glass. */
@media (max-width: 640px) {
	.nv-today__head { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto auto; column-gap: 6px; row-gap: 0; align-items: start; margin-bottom: 22px; }
	.nv-today__head > :first-child { display: contents; }
	.nv-today__head > .nv-today__focus { grid-column: 2; grid-row: 1; margin: 0; }
	.nv-today__head > .nv-today__addw { grid-column: 3; grid-row: 1; margin: 0; }
	.nv-today__head > .nv-today__arr[data-act="today-arrange"] { grid-column: 4; grid-row: 1; margin: 0; }
	.nv-today__head > .nv-today__close { grid-column: 5; grid-row: 1; margin: 0 6px 0 0; }
	.nv-today__hello { grid-column: 1 / -1; grid-row: 2; margin-top: 14px; overflow-wrap: anywhere; }
	.nv-today__date { grid-column: 1 / -1; grid-row: 3; align-self: start; }
	.nv-today__needs { grid-column: 1 / -1; grid-row: 4; justify-self: start; }
	.nv-today__head .nv-today__arr, .nv-today__head .nv-today__close { min-height: 36px; padding-inline: 10px; }
	.nv-today__sheet { overflow-x: hidden; }
}
.nv-work { margin: 8px 0 16px; }
.nv-work__h { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 0 2px 14px; padding-top: 18px; border-top: 1px solid color-mix(in srgb, var(--text) 10%, transparent); }
.nv-work__hb { min-width: 0; }
.nv-work__t { margin: 0; font-family: var(--display); font-size: clamp(20px, 2.2vw, 26px); font-weight: 500; letter-spacing: -.4px; line-height: 1.1; text-wrap: balance; }
.nv-work__s { font-size: 13.5px; color: var(--text-muted); margin-top: 4px; }
.nv-work__h .nv-today__arr { margin-inline-end: 0; }
.nv-today__cards--work { margin-bottom: 0; }
.nv-work__empty { grid-column: 1 / -1; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 18px 22px; border-radius: 24px; border: 1.5px dashed color-mix(in srgb, var(--text) 18%, transparent); color: var(--text-muted); }
.nv-work__empty > div { flex: 1 1 240px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nv-work__empty b { color: var(--text); font-weight: 600; }
.nv-work__empty span { font-size: 13px; }
/* The remove badge: top-left, like a phone's home screen in edit mode. */
.nv-rm { position: absolute; top: -9px; left: -9px; z-index: 5; width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--bg); background: #d7263d; color: #fff; display: grid; place-items: center; cursor: pointer; padding: 0; box-shadow: 0 4px 12px rgba(0, 0, 0, .25); }
.nv-rm i { width: 11px; height: 2px; border-radius: 2px; background: currentColor; }
.nv-rm:hover, .nv-rm:focus-visible { transform: scale(1.1); outline: none; }
.nv-today.is-arrange .nvw > .nv-rm { pointer-events: auto; }
.nv-today.is-arrange .nvw > .nv-rm i { pointer-events: none; }
/* A card that has just been added says so once. */
.nvw.is-new { animation: nv-card-new 1.6s ease-out; }
@keyframes nv-card-new { 0%, 30% { box-shadow: 0 0 0 3px var(--brand), 0 10px 32px rgba(0, 0, 0, .1); } 100% { box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 9%, transparent), 0 10px 32px rgba(0, 0, 0, .1); } }
/* The picker. */
.nv-pick { position: fixed; inset: 0; z-index: 160; display: grid; place-items: center; padding: 16px; background: color-mix(in srgb, #000 28%, transparent); }
.nv-pick__card { width: min(560px, 100%); max-height: min(720px, calc(100% - 16px)); display: flex; flex-direction: column; border-radius: 24px; background: var(--bg); color: var(--text); border: 1px solid color-mix(in srgb, var(--text) 10%, transparent); box-shadow: 0 30px 80px -20px rgba(0, 0, 0, .5); overflow: hidden; }
.nv-pick__h { display: flex; align-items: flex-start; gap: 12px; padding: 20px 20px 12px 22px; }
.nv-pick__h > div { flex: 1; min-width: 0; }
.nv-pick__t { font-family: var(--display); font-size: 21px; font-weight: 500; letter-spacing: -.3px; }
.nv-pick__s { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
.nv-pick__list { overflow-y: auto; padding: 0 14px 8px; display: flex; flex-direction: column; gap: 14px; }
.nv-pick__sec { display: flex; flex-direction: column; gap: 4px; }
.nv-pick__st { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); padding: 8px 8px 2px; }
.nv-pick__pk { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; padding: 8px 8px 2px; }
.nv-pick__pk i { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.nv-pick__mine { font-size: 11px; font-weight: 600; color: var(--brand); border: 1px solid color-mix(in srgb, var(--brand) 45%, transparent); border-radius: 100px; padding: 1px 8px; }
.nv-pick__i { --wc: var(--brand); display: flex; align-items: center; gap: 12px; padding: 10px 8px; border-radius: 14px; }
.nv-pick__i:hover { background: var(--bg-hover); }
.nv-pick__g { width: 38px; height: 38px; border-radius: 12px; flex-shrink: 0; display: grid; place-items: center; color: var(--wc); background: color-mix(in srgb, var(--wc) 12%, transparent); }
.nv-pick__b { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.nv-pick__b b { font-weight: 600; font-size: 14px; }
.nv-pick__b small { font-size: 12.5px; color: var(--text-muted); }
.nv-pick__none { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); padding: 6px 8px; }
.nv-pick__f { padding: 10px 20px 16px; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); display: flex; justify-content: flex-end; }
@media (max-width: 640px) {
	.nv-pick { place-items: end stretch; padding: 0; }
	.nv-pick__card { width: 100%; max-height: 88%; border-radius: 24px 24px 0 0; padding-bottom: env(safe-area-inset-bottom, 0px); }
	.nv-pick__i .btn { padding-inline: 10px; }
}
@media (prefers-reduced-motion: reduce) { .nvw.is-new { animation: none; outline: 3px solid var(--brand); } }

/* ================================================================
   "Get work done" material (2026-09-29). The standard cards are frosted
   glass; a work widget is tinted in its trade's colour, the way every
   iOS app's widget wears the app's own colour. One tint recipe for all
   (--wc is the pack colour, set on the card by the kit), mixed with the
   theme's own ground so light and dark mode each get their version:
   pastel on light, deep and saturated on dark. On that tint the
   widget's working surfaces (fields, results, lists) sit on a lighter
   inset panel, like an inset-grouped list, so text stays as readable as
   on a plain card.
   ================================================================ */
.nvw--widget {
	--wc-ink: color-mix(in srgb, var(--wc) 72%, var(--text));
	--wc-fill: color-mix(in srgb, var(--wc) 16%, transparent);
	--wc-panel: color-mix(in srgb, var(--bg) 72%, transparent);
	gap: 12px; padding: 16px 18px 18px;
	background:
		radial-gradient(130% 90% at 0% 0%, color-mix(in srgb, var(--wc) 26%, transparent) 0%, transparent 58%),
		linear-gradient(160deg, color-mix(in srgb, var(--wc) 24%, var(--bg)) 0%, color-mix(in srgb, var(--wc) 11%, var(--bg)) 100%);
	border: 1px solid color-mix(in srgb, var(--wc) 30%, transparent);
	box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent), 0 14px 34px -14px color-mix(in srgb, var(--wc) 55%, transparent);
	transition: transform .22s cubic-bezier(.2, .8, .2, 1), box-shadow .22s;
}
.nvw--widget::before { content: none; }
/* Dark mode keeps the colour but lets it glow less and sit deeper. */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) .nvw--widget { --wc-panel: color-mix(in srgb, #000 22%, transparent); --wc-ink: color-mix(in srgb, var(--wc) 62%, #fff); }
}
:root[data-theme="dark"] .nvw--widget { --wc-panel: color-mix(in srgb, #000 22%, transparent); --wc-ink: color-mix(in srgb, var(--wc) 62%, #fff); }

/* Header: icon tile, title with the trade under it, live figure right. */
.nvw--widget .w__hd { gap: 10px; min-height: 30px; color: var(--text); }
.w__ic { width: 28px; height: 28px; flex-shrink: 0; display: grid; place-items: center; border-radius: 8px; color: #fff;
	background: linear-gradient(160deg, color-mix(in srgb, var(--wc) 78%, #fff), var(--wc) 55%, color-mix(in srgb, var(--wc) 80%, #000));
	box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 35%, transparent), 0 2px 6px -2px color-mix(in srgb, var(--wc) 70%, transparent); }
.w__ic svg { width: 15px; height: 15px; }
.w__ttl { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.w__ttl b { font: 600 14.5px var(--display); letter-spacing: -.01em; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.w__ttl small { font-size: 11px; font-weight: 600; color: var(--wc-ink); letter-spacing: .02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nvw--widget .w__hd .w__head { margin-inline-start: auto; padding: 3px 10px; border-radius: 100px; background: var(--wc-panel); color: var(--text); font: 600 12.5px var(--display); font-variant-numeric: tabular-nums; white-space: nowrap; }
.nvw--widget .w__hd .w__head:empty { display: none; }

/* Fields: filled, no border, as iOS text fields are. */
.nvw--widget .input, .nvw--widget .select { background: var(--wc-panel); border-color: transparent; border-radius: 10px; }
.nvw--widget .input:focus, .nvw--widget .select:focus { border-color: var(--wc); box-shadow: 0 0 0 3px color-mix(in srgb, var(--wc) 28%, transparent); }
.nvw--widget .w__l { color: var(--wc-ink); }
.nvw--widget .w__in { background: var(--wc-panel); border-radius: 10px; }
.nvw--widget .w__in .input { background: transparent; }

/* Results and lists on an inset panel. */
.nvw--widget .w__out:not(:empty) { background: var(--wc-panel); border-radius: 14px; padding: 6px 14px; }
.nvw--widget .w__out:has(> .w__empty:only-child), .nvw--widget .w__out:has(> .w__err:only-child) { background: transparent; padding: 0 2px; }
.nvw--widget .w__row { border-bottom-color: color-mix(in srgb, var(--text) 8%, transparent); }
.nvw--widget .w__row--strong .w__rv { color: var(--wc-ink); font-size: 19px; }
.nvw--widget .w__disp { background: var(--wc-panel); }
.nvw--widget .w__disp__r { color: var(--wc-ink); }
.nvw--widget .w__item:hover { background: var(--wc-fill); }

/* The segmented control: a track and a raised thumb, never a coloured pill. */
.nvw--widget .w__tabs { background: color-mix(in srgb, var(--text) 9%, transparent); padding: 2px; border-radius: 10px; }
.nvw--widget .w__tab { border-radius: 8px; color: var(--text); font-weight: 500; }
.nvw--widget .w__tab[aria-current="true"] { background: var(--bg); color: var(--text); font-weight: 600; box-shadow: 0 1px 3px rgba(0, 0, 0, .14), 0 0 0 .5px rgba(0, 0, 0, .05); }

/* Buttons: the main action filled in the trade colour, the rest tinted. */
.nvw--widget .btn { border-color: transparent; background: var(--wc-fill); color: var(--wc-ink); border-radius: 10px; font-weight: 600; }
.nvw--widget .btn:hover:not(:disabled) { background: color-mix(in srgb, var(--wc) 24%, transparent); }
.nvw--widget .btn--primary { background: color-mix(in srgb, var(--wc) 76%, #000); color: #fff; }
.nvw--widget .btn--primary:hover:not(:disabled) { background: color-mix(in srgb, var(--wc) 68%, #000); filter: none; }
.nvw--widget .btn:focus-visible { outline: 2px solid var(--wc); outline-offset: 2px; }
.nvw--widget .w__calc .btn { background: var(--wc-panel); color: var(--text); }
.nvw--widget .w__calc .btn--op { background: var(--wc-fill); color: var(--wc-ink); }
.nvw--widget .w__calc .btn--primary { background: color-mix(in srgb, var(--wc) 76%, #000); color: #fff; }
.nvw--widget .w__foot { color: var(--text-muted); opacity: .9; }

/* Pointer lift, as on iPadOS: only with a real pointer, never in Edit mode. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
	.nv-today:not(.is-arrange) .nvw--widget:hover { transform: translateY(-2px); box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent), 0 22px 44px -16px color-mix(in srgb, var(--wc) 65%, transparent); }
}
/* The section itself: a quiet band so the two materials read as two places. */
.nv-today__cards--work { padding: 4px 0 2px; }

/* ================================================================
   The app tiles (047): Talk+, Mail, Calendar and Photos, four across,
   each with a title that opens the item that matters and a size control.
   ================================================================ */
.nv-today.nvh-photos [data-card="photos"] { display: none !important; }
.nvw--feed .nvw__t { gap: 6px; }
.nvw--feed .nvw__count, .nvw--feed .nvw__t .nvw__link { margin-inline-start: 0; }
/* The title is a doorway: it looks like a heading until the pointer is on
   it, then it shows where it goes. */
.nvw__go { display: inline-flex; align-items: center; gap: 8px; min-width: 0; margin: -4px auto -4px -6px; padding: 4px 6px; border: 0; border-radius: 8px; background: none; color: inherit; font: inherit; cursor: pointer; }
.nvw__go span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nvw__go > svg:last-child { opacity: 0; transform: translateX(-3px); transition: opacity .15s, transform .15s; flex-shrink: 0; }
.nvw__go:hover, .nvw__go:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 7%, transparent); outline: none; }
.nvw__go:hover > svg:last-child, .nvw__go:focus-visible > svg:last-child { opacity: .8; transform: none; }
.nvw__go:focus-visible { box-shadow: 0 0 0 2px var(--brand); }
/* Expand and shrink: a quiet round control, the way a widget offers more. */
.nvw__xp { flex-shrink: 0; width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: 50%; background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text-muted); cursor: pointer; transition: background .15s, color .15s, transform .15s; }
.nvw__xp:hover { background: color-mix(in srgb, var(--text) 13%, transparent); color: var(--text); }
.nvw__xp:active { transform: scale(.92); }
.nvw__xp:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.nvw__xp[aria-pressed="true"] { background: color-mix(in srgb, var(--brand) 16%, transparent); color: var(--brand); }
/* "3 more": what a compact tile left out, and the way to see it. */
.nvw__more { align-self: flex-start; display: inline-flex; align-items: center; gap: 4px; margin-top: auto; padding: 4px 8px; border: 0; border-radius: 8px; background: none; color: var(--brand); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
.nvw__more:hover, .nvw__more:focus-visible { background: color-mix(in srgb, var(--brand) 12%, transparent); outline: none; }
/* Compact tiles keep their rows to one line each. */
.nvw--feed:not(.is-big) .nv-feed__b b, .nvw--feed:not(.is-big) .nv-feed__b small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nvw--feed .nv-feed__b { min-width: 0; }
/* Photos: a small contact sheet of the newest pictures and videos. */
.nv-ph { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; border-radius: 14px; overflow: hidden; }
.nvw--photos.is-big .nv-ph { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.nv-ph__t { position: relative; aspect-ratio: 1; max-width: 100%; padding: 0; border: 0; border-radius: 4px; overflow: hidden; background: color-mix(in srgb, var(--text) 8%, transparent); cursor: pointer; }
.nvw--photos.is-big .nv-ph__t { border-radius: 8px; }
.nv-ph__t img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .35s cubic-bezier(.2, .8, .2, 1), filter .2s; }
.nv-ph__t:hover img, .nv-ph__t:focus-visible img { transform: scale(1.05); filter: brightness(1.05); }
.nv-ph__t:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.nv-ph__v { position: absolute; left: 5px; bottom: 5px; display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px 2px 4px; border-radius: 100px; background: rgba(0, 0, 0, .55); color: #fff; font-size: 10.5px; font-weight: 600; font-variant-numeric: tabular-nums; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.nv-ph__v svg { fill: currentColor; }
.nv-ph--wait .nv-ph__t { cursor: default; animation: nv-ph-wait 1.4s ease-in-out infinite alternate; }
@keyframes nv-ph-wait { from { opacity: .45; } to { opacity: .9; } }
/* The slide when a tile changes size: neighbours glide to their new place. */
.nvw.is-flip { transition: transform .34s cubic-bezier(.2, .8, .2, 1); }
@media (prefers-reduced-motion: reduce) {
	.nvw.is-flip, .nv-ph__t img, .nvw__go > svg:last-child { transition: none; }
	.nv-ph--wait .nv-ph__t { animation: none; }
}
@media (max-width: 640px) {
	/* Half a phone wide, a tile keeps its name whole: the glyph and the hover
	   arrow give way (a touch screen has no hover), the controls tighten. */
	.nvw--feed .nvw__go > svg { display: none; }
	.nvw--feed .nvw__go { margin-inline-start: -4px; padding-inline: 4px; }
	.nvw--feed .nvw__t { gap: 4px; }
	.nvw--feed .nvw__count { padding: 1px 7px; }
	.nvw--feed .nvw__xp { width: 26px; height: 26px; }
	.nvw--feed { padding: 14px 12px 16px 14px; }
	.nvw--feed .nv-feed__i { padding-inline: 4px; }
}

/* An expanded tile has the whole row: its list runs in two columns, the
   photos in a strip of six, so the extra width shows more, not emptier. */
@media (min-width: 641px) {
	.nvw--feed.is-big .nv-feed { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px 18px; }
	.nvw--feed.is-big .nvw__dem { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 18px; }
	.nvw--photos.is-big .nv-ph { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
.nvw--feed.is-big { min-height: 0; }
/* ================================================================
   Today, five blocks (047-today-now / -needs / -shelf): the head with one
   pill, the Now band with the day ribbon, Needs you, the app tiles, and
   the shelf. Tokens only, so light and dark follow the app; the brand
   atmosphere (the drifting lights, the orange sun, the green "now" hour)
   is the sheet's own and stays. 8pt rhythm: 8, 12, 16, 24.
   ================================================================ */

/* ---- the head: one pill, and the Focus toggle ---- */
.nv-today__needs { display: flex; margin-top: 12px; padding: 0; background: none; border-radius: 0; }
.nv-today__pill { display: inline-flex; align-items: center; gap: 8px; min-height: 30px; padding: 4px 12px 4px 10px; border: 0; border-radius: 100px; background: color-mix(in srgb, var(--warn) 15%, transparent); color: var(--warn); font: inherit; font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; cursor: pointer; transition: background .18s ease; }
.nv-today__pill i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.nv-today__pill:hover { background: color-mix(in srgb, var(--warn) 22%, transparent); }
.nv-today__pill.is-clear { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
.nv-today__pill.is-clear:hover { background: color-mix(in srgb, var(--brand) 20%, transparent); }
.nv-today__pill:focus-visible, .nv-today__arr:focus-visible, .nv-today__close:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.nv-today__focus svg { flex-shrink: 0; }

/* ---- Now ----
   Three columns on a wide screen (time, next meeting, sky) over the
   ribbon; two on a tablet, with the meeting on a row of its own; on a
   phone the time and the sky share the first row and everything else
   stacks under them. Placement is by `order`, never by explicit rows, so
   a column that grows (the place picker) simply takes a row of its own. */
.nvw--now { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.35fr) minmax(0, 1.1fr); gap: 16px 24px; padding: 20px 24px; align-items: start; }
.nv-now__time, .nv-now__next, .nv-now__wx { min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.nv-now__next, .nv-now__wx { padding-inline-start: 24px; border-inline-start: 1px solid color-mix(in srgb, var(--text) 8%, transparent); }
.nvw--now.is-wxpick .nv-now__wx { grid-column: 1 / -1; padding-inline-start: 0; border-inline-start: 0; }
.nv-now__k { font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted); }
.nv-now__k .nv-next__cd { text-transform: none; letter-spacing: 0; font-size: 12.5px; color: var(--text); }
.nv-now__k .nv-next__cd.is-soon { color: var(--warn); }
.nv-now__clock { font-size: clamp(44px, 5vw, 64px); }
.nv-now__sub { display: flex; flex-direction: column; gap: 2px; font-size: 13px; color: var(--text-muted); }
.nv-now__sub > span:empty { display: none; }
.nv-now__pres { display: inline-flex; align-items: center; gap: 6px; color: var(--text); }
.nv-now__pres i { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
/* Next up, told short. */
.nv-now__title { display: flex; align-items: stretch; gap: 10px; min-width: 0; margin: 0; padding: 0; border: 0; background: none; color: var(--text); font: inherit; font-family: var(--display); font-size: 20px; font-weight: 600; line-height: 1.2; letter-spacing: -.015em; text-align: start; cursor: pointer; }
.nv-now__title > span:last-child { min-width: 0; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.nv-now__title:hover > span:last-child { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.nv-now__title:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 6px; }
.nv-now__bar { width: 4px; border-radius: 4px; flex-shrink: 0; }
.nv-now__meta { font-size: 13px; color: var(--text-muted); overflow-wrap: anywhere; }
.nv-now__calm { font-size: 14px; color: var(--text-muted); }
.nv-now__row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; margin-top: 4px; }
.nv-now__row .nv-next__who { min-width: 0; }
.nv-now__acts { display: flex; flex-wrap: wrap; gap: 8px; margin-inline-start: auto; }
.nv-now__acts .btn { white-space: nowrap; }
/* The sky: the orange sun of the weather card, the temperature, the place
   (the way to change it), then six hours and the days ahead. */
.nv-now__wxtop { display: flex; align-items: center; gap: 12px; min-width: 0; }
.nv-now__wxb { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nv-now__temp { font-family: var(--display); font-size: 30px; font-weight: 600; line-height: 1; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.nv-now__place { display: inline-flex; align-items: center; gap: 2px; align-self: flex-start; max-width: 100%; margin-inline-start: -6px; padding: 2px 6px; border: 0; border-radius: 8px; background: none; color: var(--text); font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.nv-now__place svg { flex-shrink: 0; color: var(--text-muted); }
.nv-now__place:hover { background: color-mix(in srgb, var(--text) 8%, transparent); }
.nv-now__place:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--brand); }
.nv-now__cond { font-size: 13px; color: var(--text-muted); }
.nv-now__hours { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; overflow: visible; padding-bottom: 0; }
.nv-now__hours .nv-wx__h { min-width: 0; padding: 6px 0; border-radius: 10px; }
.nv-now__hours .nv-wx__h--now small, .nv-now__hours .nv-wx__h--now b { color: var(--brand); }
.nv-now__wxfoot { display: flex; justify-content: flex-end; }
.nv-now__wx .nv-wx__fold { margin-top: -8px; }
.nv-now__wx.is-days .nv-wx__fold { grid-template-rows: 1fr; margin-top: 0; }
.nv-now__wx.is-days .nv-wx__fold > div { visibility: visible; opacity: 1; transition: opacity .3s ease .08s, visibility 0s; }
.nv-now__wx.is-days .nv-wx__more svg { transform: rotate(-90deg); }
.nv-now__wx .nv-wx__more:focus-visible { box-shadow: 0 0 0 2px var(--brand); }

/* ---- the day ribbon ---- */
.nv-rib { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 6px; min-width: 0; padding-top: 4px; }
.nv-rib__bar { position: relative; height: 28px; border-radius: 8px; background: color-mix(in srgb, var(--text) 6%, transparent); overflow: hidden; }
.nv-rib__work { position: absolute; top: 0; bottom: 0; background: color-mix(in srgb, var(--brand) 13%, transparent); }
.nv-rib__ev { position: absolute; top: 5px; bottom: 5px; min-width: 10px; margin: 0; padding: 0 6px; border: 1px solid color-mix(in srgb, var(--text) 14%, transparent); border-inline-start: 3px solid var(--ec, var(--brand)); border-radius: 5px; background: color-mix(in srgb, var(--bg) 82%, transparent); color: var(--text-muted); font: inherit; font-size: 10.5px; font-weight: 600; line-height: 16px; text-align: start; overflow: hidden; cursor: pointer; }
.nv-rib__ev span { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.nv-rib__ev:hover { color: var(--text); }
.nv-rib__ev.is-past { opacity: .45; }
.nv-rib__ev.is-next { background: var(--brand); border-color: var(--brand); color: var(--brand-text); }
/* Shorter than an hour: a marker, its name in the tooltip. */
.nv-rib__ev.is-dot { padding: 0; }
.nv-rib__ev.is-dot span { display: none; }
.nv-rib__ev:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--text); z-index: 2; }
.nv-rib__now { position: absolute; top: 0; bottom: 0; width: 2px; margin-inline-start: -1px; background: var(--brand); box-shadow: 0 0 0 1px color-mix(in srgb, var(--bg) 70%, transparent); pointer-events: none; z-index: 1; transition: left .35s ease; }
.nv-rib__now::before { content: ""; position: absolute; top: 0; left: -3px; width: 8px; height: 8px; border-radius: 50%; background: var(--brand); }
.nv-rib__ticks { position: relative; height: 14px; font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.nv-rib__ticks span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.nv-rib__ticks span:first-child { transform: none; }
.nv-rib__ticks span:last-child { transform: translateX(-100%); }

/* ---- Needs you ---- */
.nvw--needs { grid-column: 1 / -1; padding: 10px 10px 8px; gap: 4px; }
.nvw--needs.is-menu { z-index: 10; }
.nv-nd__h { flex-wrap: wrap; gap: 4px 10px; padding: 8px 12px 4px; border-radius: 12px; outline: none; }
.nv-nd__h:focus-visible { box-shadow: 0 0 0 2px var(--brand); }
.nv-nd__t { font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -.01em; color: var(--text); }
.nv-nd__since { font-size: 12px; font-weight: 500; color: var(--text-muted); }
.nv-nd__links { display: flex; flex-wrap: wrap; gap: 4px; margin-inline-start: auto; }
.nv-nd__links .nvw__link { margin-inline-start: 0; color: var(--brand); }
.nv-nd__links .nvw__link:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--brand); }
.nvw--needs .nvib__r { padding: 10px 12px; border-radius: 16px; }
/* The row's actions are the point of this list: always there. */
.nvw--needs .nvib__acts { opacity: 1; }
.nv-nd__aw { width: 100%; margin: 0; border: 0; background: none; color: var(--text); font: inherit; text-align: start; cursor: pointer; }
.nv-nd__aw:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--brand); }
.nv-nd__n { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); }
.nv-nd__aw .nvib__ts { display: flex; color: var(--text-muted); }
.nv-nd__more { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; margin-top: 4px; padding: 10px 12px; border: 0; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); border-radius: 0 0 14px 14px; background: none; color: var(--text-muted); font: inherit; font-size: 13px; text-align: start; cursor: pointer; }
.nv-nd__more:hover { color: var(--text); background: color-mix(in srgb, var(--text) 4%, transparent); }
.nv-nd__more:focus-visible { outline: none; color: var(--text); box-shadow: inset 0 0 0 2px var(--brand); }
.nv-nd__sh { flex-shrink: 0; font-weight: 600; color: var(--brand); }
.nv-nd__fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .36s cubic-bezier(.2, .9, .25, 1); }
.nv-nd__fold > div { min-height: 0; overflow: hidden; visibility: hidden; opacity: 0; transition: opacity .24s ease, visibility 0s linear .36s; }
.nvw--needs.is-open .nv-nd__fold { grid-template-rows: 1fr; }
.nvw--needs.is-open .nv-nd__fold > div { visibility: visible; opacity: 1; transition: opacity .3s ease .08s, visibility 0s; }
.nvw--needs.is-settled .nv-nd__fold > div { overflow: visible; }
.nv-nd__fold .nvib__r { opacity: .85; }
.nv-nd__calm { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 4px 12px 10px; font-size: 13px; color: var(--text-muted); }
.nv-nd__calm svg { color: var(--brand); flex-shrink: 0; }
.nv-nd__calm b { font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--text); }

/* ---- the shelf ----
   Not a card: a row of chips on the glass, with the two panels opening
   under it. It is not a stacking context either, so a post-it's share
   popover still hangs over what follows. */
.nvw--shelf { grid-column: 1 / -1; gap: 12px; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
.nv-shelf__row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; min-width: 0; }
.nv-shelf__chip { display: inline-flex; align-items: center; gap: 10px; max-width: 100%; min-height: 44px; padding: 6px 16px 6px 8px; border: 1px solid color-mix(in srgb, var(--text) 9%, transparent); border-radius: 100px; background: color-mix(in srgb, var(--bg) 50%, transparent); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); color: var(--text); font: inherit; font-size: 13.5px; font-weight: 600; text-align: start; cursor: pointer; transition: background .18s ease, border-color .18s ease; }
.nv-shelf__chip:hover, .nv-shelf__chip[aria-expanded="true"] { background: color-mix(in srgb, var(--bg) 80%, transparent); }
.nv-shelf__chip[aria-expanded="true"] { border-color: color-mix(in srgb, var(--brand) 40%, transparent); }
.nv-shelf__chip:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.nv-shelf__g { width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%; display: grid; place-items: center; background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
.nv-shelf__chip--work .nv-shelf__g { background: color-mix(in srgb, var(--wc, var(--brand)) 16%, transparent); color: var(--wc, var(--brand)); }
.nv-shelf__chip--work[aria-expanded="true"] { border-color: color-mix(in srgb, var(--wc, var(--brand)) 45%, transparent); }
.nv-shelf__chip small { font-size: 12.5px; font-weight: 500; color: var(--text-muted); }
.nv-shelf__chip small:empty { display: none; }
.nv-shelf__chip--add { gap: 6px; padding-inline: 16px; border-style: dashed; background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; color: var(--text-muted); font-weight: 500; }
.nv-shelf__chip--add:hover { color: var(--text); }
.nv-shelf__fold { display: grid; grid-template-rows: 0fr; margin-top: -12px; transition: grid-template-rows .36s cubic-bezier(.2, .9, .25, 1), margin-top .36s cubic-bezier(.2, .9, .25, 1); }
.nv-shelf__fold > div { min-width: 0; min-height: 0; overflow: hidden; visibility: hidden; opacity: 0; transition: opacity .24s ease, visibility 0s linear .36s; }
.nvw--shelf.is-pits .nv-shelf__fold--pits, .nvw--shelf.is-work .nv-shelf__fold--work, .nv-today.is-arrange .nv-shelf__fold { grid-template-rows: 1fr; margin-top: 0; }
.nvw--shelf.is-pits .nv-shelf__fold--pits > div, .nvw--shelf.is-work .nv-shelf__fold--work > div, .nv-today.is-arrange .nv-shelf__fold > div { visibility: visible; opacity: 1; transition: opacity .3s ease .08s, visibility 0s; }
.nv-shelf__fold.is-settled > div { overflow: visible; }
.nvw--shelf .nv-work { margin: 0; padding: 16px; border-radius: 24px; border: 1px solid color-mix(in srgb, var(--text) 7%, transparent); background: color-mix(in srgb, var(--bg) 40%, transparent); }
.nvw--shelf .nv-work__h { padding-top: 0; border-top: 0; }
/* Edit: the shelf moves as one; the widgets inside it still move among
   themselves, and the board inside it is not a card of its own. */
.nv-today.is-arrange .nvw--shelf .nvw[data-card] { pointer-events: auto; }
.nv-today.is-arrange .nvw--shelf .nvw--pits { animation: none; outline: none; cursor: inherit; }
/* Now and Needs you do not move. */
.nv-today.is-arrange .nvw--now, .nv-today.is-arrange .nvw--needs { animation: none; outline: none; cursor: default; opacity: .72; }

/* ---- Focus ---- */
/* Pinned tools stay: a pin is the person's own essential (047-today-pins.js). */
.nv-today.is-focus:not(.is-arrange) .nv-today__cards .nvw[data-card]:not(.nvw--now):not(.nvw--needs):not(.is-pinned) { display: none; }
.nv-today.is-focus:not(.is-arrange) .nv-nd__list > :nth-child(n+2), .nv-today.is-focus:not(.is-arrange) .nv-nd__more, .nv-today.is-focus:not(.is-arrange) .nv-nd__fold { display: none; }
.nv-today.is-focus .nv-today__bg i { opacity: .28; }

/* ---- tablet ---- */
@media (max-width: 1023.98px) {
	.nvw--now { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
	.nv-now__time { order: 1; }
	.nv-now__wx { order: 2; }
	.nv-now__next { order: 3; grid-column: 1 / -1; padding: 16px 0 0; border-inline-start: 0; border-top: 1px solid color-mix(in srgb, var(--text) 8%, transparent); }
	.nv-rib { order: 4; }
}
/* ---- phone ----
   The time and the sky side by side, the sky's details under the meeting.
   With the forecast in, the sky's box steps aside (display: contents) so
   its parts take their own rows in the band's grid. */
@media (max-width: 640px) {
	.nvw--now { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px 16px; padding: 16px; }
	.nv-now__clock { font-size: 44px; }
	.nv-now__time { order: 0; }
	.nv-now__next { order: 2; padding-top: 12px; }
	.nv-now__title { font-size: 18px; }
	.nv-now__wx { order: 3; grid-column: 1 / -1; padding-inline-start: 0; border-inline-start: 0; }
	.nv-now__wx.is-ok { display: contents; }
	.nv-now__wx.is-ok .nv-now__wxtop { order: 1; grid-column: 2; flex-direction: column; align-items: flex-end; gap: 4px; text-align: end; }
	.nv-now__wx.is-ok .nv-now__wxb { align-items: flex-end; }
	.nv-now__wx.is-ok .nv-now__place { align-self: flex-end; margin-inline: 0 -6px; }
	.nv-now__wx.is-ok .nv-now__hours { order: 3; grid-column: 1 / -1; }
	.nv-now__wx.is-ok .nv-now__wxfoot { order: 4; grid-column: 1 / -1; }
	.nv-now__wx.is-ok .nv-wx__fold { order: 5; grid-column: 1 / -1; margin-top: -12px; }
	.nv-now__wx.is-ok.is-days .nv-wx__fold { margin-top: 0; }
	.nv-rib { order: 6; }
	.nv-rib__ev { padding: 0; }
	.nv-rib__ev span { display: none; }
	.nvw--needs { padding: 6px 4px 4px; }
	.nv-nd__h { padding: 8px 10px 4px; }
	.nvw--needs .nvib__r { flex-wrap: wrap; row-gap: 6px; gap: 10px; padding: 10px 8px; }
	.nvw--needs .nvib__b { flex: 1 1 0; }
	/* A row with actions gives its text a line of its own; the buttons sit
	   under it, on the right. */
	.nvw--needs .nvib__r:has(.nvib__acts) .nvib__b { flex-basis: calc(100% - 44px); }
	.nvw--needs .nvib__acts { margin-inline-start: auto; }
	.nvw--needs .nvib__r:not(.nv-nd__aw) .nvib__ts { display: none; }
	.nv-shelf__row { gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
	.nv-nd__fold, .nv-nd__fold > div, .nv-shelf__fold, .nv-shelf__fold > div, .nv-rib__now, .nv-shelf__chip, .nv-today__pill { transition: none; }
}

/* ---- tile states (047-today-feeds.js nvTileState) ----
   Loading keeps the tile's shape with two quiet bars; an error keeps the
   last rows, dimmed, with when they were fresh and a Retry. */
.nv-tile__wait { display: flex; flex-direction: column; gap: 10px; padding: 8px 4px 4px; }
.nv-tile__wait i { display: block; height: 12px; border-radius: 6px; background: color-mix(in srgb, var(--text) 9%, transparent); animation: nv-tile-wait 1.3s ease-in-out infinite alternate; }
.nv-tile__wait i:nth-child(2) { width: 62%; animation-delay: -.65s; }
@keyframes nv-tile-wait { from { opacity: .55; } to { opacity: 1; } }
.nv-feed.is-stale { opacity: .55; filter: saturate(.6); }
.nv-tile__err { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-top: auto; padding: 6px 4px 0; font-size: 12.5px; color: var(--text-muted); }
.nv-tile__err .nvw__link { margin-inline-start: 0; color: var(--brand); }
/* Needs you at rest: nothing urgent, the rest waits for work to start. */
.nv-nd__calm--rest b { font-weight: 600; }
.nv-nd__more.is-rest span:first-child { color: var(--text-muted); }
@media (prefers-reduced-motion: reduce) { .nv-tile__wait i { animation: none; } }

/* ---- pinned to the top (047-today-pins.js) ----
   A row of its own under Needs you, in the main grid's twelve columns. One
   pin takes the full width; two sit side by side, each at its own span when
   the two fit (8 + 4), otherwise half and half. The cards keep the tinted
   widget material (037); the kit's order style is overruled here because
   inside this row the pin order is the DOM order. */
.nv-pins { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 16px; min-width: 0; }
.nv-pins[hidden] { display: none; }
.nv-pins > .nvw { order: 0 !important; grid-column: span 6; }
.nv-pins--n1 > .nvw { grid-column: 1 / -1; }
.nv-pins--n2:has(> .nvw--w8):has(> .nvw--w4) > .nvw--w8 { grid-column: span 8; }
.nv-pins--n2:has(> .nvw--w8):has(> .nvw--w4) > .nvw--w4 { grid-column: span 4; }
/* The pin in a widget's header: quiet until pressed, then in the trade colour. */
.w__pin { flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px; margin-inline-start: 4px; padding: 0; border: 0; border-radius: 100px; background: transparent; color: var(--text-muted); cursor: pointer; transition: background .15s ease, color .15s ease; }
.w__head:empty + .w__pin { margin-inline-start: auto; }
.w__pin:hover { background: var(--wc-panel, var(--bg-hover)); color: var(--text); }
.w__pin[aria-pressed="true"] { background: var(--wc-fill, var(--bg-hover)); color: var(--wc-ink, var(--brand)); }
.w__pin:focus-visible { outline: 2px solid var(--wc, var(--brand)); outline-offset: 2px; }
/* Edit: the row does not move (like Now and Needs you); only the minus badge works. */
.nv-today.is-arrange .nv-pins > .nvw { animation: none; cursor: default; outline-style: solid; outline-color: color-mix(in srgb, var(--text) 12%, transparent); }
@media (max-width: 1023.98px) {
	.nv-pins--n2:has(> .nvw--w8):has(> .nvw--w4) > .nvw { grid-column: span 6; }
}
@media (max-width: 640px) {
	/* Phones: one column, full width, no sideways scroll. */
	.nv-pins { display: flex; flex-direction: column; gap: 12px; }
	.nv-pins[hidden] { display: none; }
}
@media (prefers-reduced-motion: reduce) { .w__pin { transition: none; } }
/* =================================================== Talk+ Home (2026-09-30)
   004-talk-home.js. The Home tile at the top of the rail, the Home list,
   the pull-down inside a space and the Home overview. The three series
   colours (chats, group chats, channels) are tokens, restated for dark in
   both places the theme is set, like every other colour in this file. */
:root {
	--th-c1: #15916B;
	--th-c2: #3B6FD0;
	--th-c3: #E0782E;
	--th-home: linear-gradient(145deg, #3FD6A6 0%, #15916B 46%, #0F5D6E 100%);
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) { --th-c1: #3FD6A6; --th-c2: #7FA8F5; --th-c3: #FF9D5C; }
}
:root[data-theme="dark"] { --th-c1: #3FD6A6; --th-c2: #7FA8F5; --th-c3: #FF9D5C; }

/* ---- the mark */
.thome-glyph { display: block; flex-shrink: 0; }
.thome-glyph__d { transform-box: fill-box; transform-origin: center; }

/* ---- the Home tile: brand glass, a soft sheen on hover and on a tap */
.rail__home {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	color: #fff;
	background: var(--th-home);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .24), inset 0 1px 0 rgba(255, 255, 255, .35), 0 6px 16px -8px rgba(21, 145, 107, .9);
}
.rail__home::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		radial-gradient(120% 80% at 20% 0%, rgba(255, 255, 255, .38), rgba(255, 255, 255, 0) 58%),
		linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, .42) 48%, transparent 66%) no-repeat;
	background-size: 100% 100%, 260% 100%;
	background-position: 0 0, 160% 0;
	transition: background-position .7s cubic-bezier(.2, .8, .2, 1);
}
.rail__home:hover::before, .rail__home.is-launching::before { background-position: 0 0, -60% 0; }
.rail__home[aria-current="true"] {
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, .24),
		inset 0 1px 0 rgba(255, 255, 255, .35),
		0 0 0 2px var(--chrome-2),
		0 0 0 3.5px rgba(255, 138, 61, .62),
		0 0 14px 3px rgba(255, 138, 61, .28);
}
.rail__home.is-launching .thome-glyph__d { animation: th-dot .6s ease both; }
.rail__home.is-launching .thome-glyph__d--2 { animation-delay: .08s; }
.rail__home.is-launching .thome-glyph__d--3 { animation-delay: .16s; }
@keyframes th-dot { 40% { transform: translateY(-2px) scale(1.25); } }
:root:not([data-theme="dark"]) .rail .rail__home { color: #fff; }
.rail__sep--home { margin-block: 2px 4px; }

/* ---- the Home list */
.zone--home { padding-block-start: 8px; }
.zone__space--home { padding-block-start: 2px; }
.zone__tile--home, .topbar__home {
	color: #fff;
	background: var(--th-home);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2), inset 0 1px 0 rgba(255, 255, 255, .3);
}
.topbar__home {
	width: 30px; height: 30px; flex-shrink: 0;
	border-radius: 9px;
	display: flex; align-items: center; justify-content: center;
}
.zone--home > .chan--home { margin-block-end: 2px; }

/* ---- "Your chats" inside a space: a heading until you reach for it */
.mepull__wrap { padding: 0 8px 4px; }
.mepull {
	width: 100%;
	min-height: 32px;
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 10px 4px 8px;
	border: none;
	border-radius: 8px;
	background: transparent;
	color: var(--text-muted);
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	text-align: start;
	cursor: pointer;
	transition: background-color .15s ease, color .15s ease;
}
.mepull:hover { background: color-mix(in oklab, var(--text) 5%, transparent); color: var(--text); }
.mepull[aria-expanded="true"] { color: var(--text); }
.mepull:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.mepull__t { flex-grow: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mepull__n {
	flex-shrink: 0;
	min-width: 20px; height: 18px; padding-inline: 6px;
	border-radius: 100px;
	display: inline-flex; align-items: center; justify-content: center;
	font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
	color: var(--text);
	background: color-mix(in oklab, var(--text) 10%, transparent);
}
.mepull__n--at { background: #FF8A3D; color: #08231c; }
.mepull__chev { display: inline-flex; flex-shrink: 0; opacity: .7; transition: transform .25s cubic-bezier(.2, .8, .2, 1); }
.mepull[aria-expanded="true"] .mepull__chev { transform: rotate(90deg); }

/* the drawer's content: faces, a few chats, the way to all of them */
.mechats { display: flex; flex-direction: column; gap: 1px; padding: 2px 8px 8px; }
.mefavs { display: flex; gap: 8px; padding: 4px 6px 8px; overflow-x: auto; scrollbar-width: none; }
.mefavs::-webkit-scrollbar { display: none; }
.mefav {
	position: relative; flex-shrink: 0;
	display: flex; padding: 2px;
	border: none; border-radius: 100px;
	background: transparent; cursor: pointer;
	transition: transform .15s ease;
}
.mefav:hover { transform: translateY(-1px); }
.mefav[aria-current="true"] { box-shadow: 0 0 0 2px var(--brand); }
.mefav:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.mefav__ch { width: 30px; height: 30px; border-radius: 9px; font-size: 14px; }
.mefav__dot { position: absolute; inset-block-end: 1px; inset-inline-end: 1px; width: 9px; height: 9px; border-radius: 100px; box-shadow: 0 0 0 2px var(--bg-subtle); }
.mefav__n { position: absolute; inset-block-start: 0; inset-inline-end: 0; width: 9px; height: 9px; border-radius: 100px; background: #FF8A3D; box-shadow: 0 0 0 2px var(--bg-subtle); }
.mechats__foot { display: flex; align-items: center; gap: 2px; margin-block-start: 4px; padding-block-start: 6px; border-block-start: 1px solid color-mix(in oklab, var(--border) 70%, transparent); }
.mechats__all {
	flex-grow: 1; min-width: 0;
	display: flex; align-items: center; gap: 8px;
	padding: 6px 8px;
	border: none; border-radius: 8px;
	background: transparent; color: var(--text-muted);
	font: inherit; font-size: 12.5px; text-align: start; cursor: pointer;
}
.mechats__all span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mechats__all:hover { background: var(--bg-hover); color: var(--text); }
.mechats__all .thome-glyph { color: var(--brand); }
.mechats__b { width: 30px; height: 30px; }

/* The drawer: its height animates from nothing to its content (grid rows),
   so the space below is pushed down by exactly what it shows. */
.medrawer {
	display: grid;
	grid-template-rows: 0fr;
	opacity: 0;
	transition: grid-template-rows .34s cubic-bezier(.2, .8, .2, 1), opacity .22s ease;
}
.medrawer[data-open="1"] { grid-template-rows: 1fr; opacity: 1; }
.medrawer__in { min-height: 0; overflow: hidden; }
.medrawer[data-open="0"] + .zone--space { margin-block-start: 0; }

/* ---- the overview */
.thome-wrap { container-type: inline-size; }
.thome {
	display: grid;
	grid-template-columns: repeat(12, minmax(0, 1fr));
	gap: 16px;
	padding: 20px 22px 32px;
	max-width: 1240px;
	margin-inline: auto;
}
.th-card {
	grid-column: span 6;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 16px 18px;
	border-radius: 16px;
	border: 1px solid var(--border);
	background: var(--bg-raised);
	animation: th-in .42s cubic-bezier(.2, .8, .2, 1) both;
}
.th-card:nth-child(2) { animation-delay: .04s; }
.th-card:nth-child(3) { animation-delay: .08s; }
.th-card:nth-child(4) { animation-delay: .12s; }
.th-card:nth-child(5) { animation-delay: .16s; }
.th-card:nth-child(6) { animation-delay: .2s; }
@keyframes th-in { from { opacity: 0; transform: translateY(6px); } }
.th-card__h { display: flex; align-items: center; gap: 8px; font: 600 14px var(--display); }
.th-card__h > svg { color: var(--brand); flex-shrink: 0; }
.th-card__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.th-card__sub { margin-inline-start: auto; font-size: 12.5px; font-weight: 500; color: var(--text-muted); white-space: nowrap; }
.th-card__h .pill-count { margin-inline-start: auto; }

.th-wait { grid-column: span 5; }
.th-act { grid-column: span 7; }
.th-favs { grid-column: span 7; }
.th-recent { grid-column: span 5; }
.th-allspaces { grid-column: 1 / -1; }

/* hero */
.th-hero {
	grid-column: 1 / -1;
	flex-direction: row;
	align-items: center;
	gap: 28px;
	padding: 22px 26px;
	position: relative;
	overflow: hidden;
	background:
		radial-gradient(60% 120% at 100% 0%, color-mix(in oklab, #FF8A3D 14%, transparent), transparent 70%),
		linear-gradient(135deg, color-mix(in oklab, var(--brand) 13%, var(--bg-raised)) 0%, var(--bg-raised) 62%);
	border-color: color-mix(in oklab, var(--brand) 26%, var(--border));
}
.th-hero__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.th-hero__hi { font: 600 26px/1.15 var(--display); letter-spacing: -.4px; }
.th-hero__line { margin: 0; font-size: 14.5px; color: var(--text-muted); }
.th-hero__ring { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.th-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin-block-start: 10px; }
.th-stat {
	display: grid;
	grid-template-columns: auto 1fr;
	grid-template-rows: auto auto;
	column-gap: 10px;
	align-items: center;
	padding: 10px 12px;
	border-radius: 12px;
	background: color-mix(in oklab, var(--bg-raised) 70%, transparent);
	border: 1px solid color-mix(in oklab, var(--border) 80%, transparent);
	min-width: 0;
}
.th-stat__ic {
	grid-row: 1 / 3;
	width: 30px; height: 30px;
	border-radius: 9px;
	display: flex; align-items: center; justify-content: center;
	color: var(--brand);
	background: color-mix(in oklab, var(--brand) 13%, transparent);
}
.th-stat__n { font: 600 20px/1.1 var(--display); font-variant-numeric: tabular-nums; }
.th-stat__l { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ring */
.th-ring { width: 132px; height: 132px; display: block; }
.th-ring__track { fill: none; stroke: color-mix(in oklab, var(--border) 85%, transparent); stroke-width: 12; }
.th-ring__arc { fill: none; stroke-width: 12; stroke-linecap: round; animation: th-ring .7s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes th-ring { from { opacity: 0; } }
.th-ring__n { text-anchor: middle; font: 600 28px var(--display); fill: var(--text); font-variant-numeric: tabular-nums; }
.th-ring__l { text-anchor: middle; font-size: 11px; fill: var(--text-muted); letter-spacing: .4px; }
.th-key { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 12px; font-size: 11.5px; color: var(--text-muted); }
.th-key span { display: inline-flex; align-items: center; gap: 5px; }
.th-key i { width: 8px; height: 8px; border-radius: 3px; display: inline-block; }

/* bars */
.th-bars { display: flex; align-items: stretch; height: 150px; margin-block-start: 6px; }
.th-bar {
	position: relative;
	height: 100%;
	padding-block-end: 20px;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	align-items: center;
}
.th-bar::before {
	content: '';
	position: absolute;
	inset-block: 0 20px;
	width: min(62%, 22px);
	border-radius: 7px;
	background: color-mix(in oklab, var(--text) 4%, transparent);
}
.th-bar__col {
	position: relative;
	width: min(62%, 22px);
	display: flex;
	flex-direction: column;
	border-radius: 7px 7px 4px 4px;
	overflow: hidden;
	transform-origin: bottom;
	animation: th-grow .6s cubic-bezier(.2, .8, .2, 1) both;
}
.th-bar__col i { display: block; min-height: 3px; }
.th-bar:nth-child(n+8) .th-bar__col { animation-delay: .06s; }
@keyframes th-grow { from { transform: scaleY(0); } }
.th-bar__d { position: absolute; inset-block-end: 0; font-size: 10.5px; color: var(--text-muted); }
.th-bar--today .th-bar__d { color: var(--brand); font-weight: 700; }
.th-bar--today::before { background: color-mix(in oklab, var(--brand) 9%, transparent); }

/* rows, chips, empty states */
.th-row { padding-block: 6px; }
.th-row .sph-when { width: auto; white-space: nowrap; }
.th-chan {
	width: 32px; height: 32px; flex-shrink: 0;
	border-radius: 9px;
	display: flex; align-items: center; justify-content: center;
	font: 600 15px var(--display);
	color: color-mix(in oklab, var(--sp) 80%, var(--text));
	background: color-mix(in oklab, var(--sp) 17%, var(--bg-raised));
	box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--sp) 28%, transparent);
}
.th-chan--lg { width: 44px; height: 44px; border-radius: 13px; font-size: 19px; }
.th-at {
	width: 20px; height: 20px; flex-shrink: 0;
	border-radius: 100px;
	display: inline-flex; align-items: center; justify-content: center;
	font-size: 11.5px; font-weight: 700;
	background: #FF8A3D; color: #08231c;
}
.th-empty {
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
	min-height: 96px; padding: 14px;
	color: var(--text-muted); font-size: 13.5px; text-align: center;
}
.th-empty > svg { color: var(--brand); opacity: .8; }
.th-more, .th-note { margin: 0; padding: 2px 8px; font-size: 12px; color: var(--text-muted); }

/* favourites */
.th-favgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(86px, 1fr)); gap: 4px; }
.th-fav {
	display: flex; flex-direction: column; align-items: center; gap: 7px;
	min-width: 0;
	padding: 10px 4px 8px;
	border: none; border-radius: 12px;
	background: transparent; color: inherit;
	font: inherit; cursor: pointer;
	transition: background-color .15s ease, transform .15s ease;
}
.th-fav:hover { background: var(--bg-hover); transform: translateY(-1px); }
.th-fav__av { position: relative; display: flex; }
.th-fav__dot { position: absolute; inset-block-end: 0; inset-inline-end: 0; box-shadow: 0 0 0 2.5px var(--bg-raised); }
.th-fav__n {
	position: absolute; inset-block-start: -4px; inset-inline-end: -6px;
	min-width: 18px; height: 18px; padding-inline: 5px;
	border-radius: 100px;
	display: flex; align-items: center; justify-content: center;
	font-size: 10.5px; font-weight: 700;
	background: #FF8A3D; color: #08231c;
	box-shadow: 0 0 0 2px var(--bg-raised);
}
.th-fav__name { max-width: 100%; font-size: 12.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* spaces, grouped */
.th-group {
	display: flex; align-items: center; gap: 8px;
	margin: 8px 2px 2px;
	font-size: 11px; font-weight: 700; letter-spacing: .9px; text-transform: uppercase;
	color: var(--text-muted);
}
.th-group span { font-size: 11px; letter-spacing: 0; padding: 1px 7px; border-radius: 100px; background: var(--bg-hover); }
.th-spaces { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.th-space {
	display: flex; flex-direction: column; gap: 2px;
	min-width: 0;
	padding: 10px;
	border-radius: 14px;
	border: 1px solid color-mix(in oklab, var(--sp) 30%, var(--border));
	background:
		linear-gradient(var(--sp), var(--sp)) top / 100% 3px no-repeat,
		color-mix(in oklab, var(--sp) 6%, var(--bg-raised));
	transition: transform .18s ease, box-shadow .18s ease;
}
.th-space:hover { transform: translateY(-1px); box-shadow: 0 10px 24px -16px color-mix(in oklab, var(--sp) 70%, transparent); }
.th-space__h {
	display: flex; align-items: center; gap: 10px;
	width: 100%; min-width: 0;
	padding: 4px 4px 8px;
	border: none; background: transparent; color: inherit;
	font: inherit; text-align: start; cursor: pointer;
}
.th-space__name { font: 600 15px/1.2 var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.th-space__h .zone__text { gap: 2px; }
.th-space__ok {
	width: 22px; height: 22px; flex-shrink: 0;
	border-radius: 100px;
	display: flex; align-items: center; justify-content: center;
	color: var(--ok, #15916B);
	background: color-mix(in oklab, var(--ok, #15916B) 14%, transparent);
}
.th-sprow {
	display: flex; align-items: center; gap: 8px;
	width: 100%; min-width: 0;
	padding: 6px 8px;
	border: none; border-radius: 8px;
	background: transparent; color: inherit;
	font: inherit; font-size: 13.5px; text-align: start; cursor: pointer;
}
.th-sprow:hover { background: color-mix(in oklab, var(--sp) 11%, transparent); }
.th-sprow__h { font-weight: 600; color: color-mix(in oklab, var(--sp) 70%, var(--text-muted)); flex-shrink: 0; }
.th-sprow__n { flex-grow: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.th-sprow__bar { width: 44px; height: 4px; flex-shrink: 0; border-radius: 100px; overflow: hidden; background: color-mix(in oklab, var(--sp) 16%, transparent); }
.th-sprow__bar i { display: block; height: 100%; border-radius: 100px; background: var(--sp); }
.th-sprow .sph-when { width: auto; }
.th-sprow--more { color: var(--text-muted); font-size: 12.5px; }

/* the side panel on Home */
.th-mem { width: 100%; border: none; background: transparent; color: inherit; font: inherit; text-align: start; cursor: pointer; border-radius: 10px; }
.th-mem:hover { background: var(--bg-hover); }

.thome :focus-visible, .th-mem:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* narrow content column: one card per row, the ring under the greeting */
@container (max-width: 780px) {
	.thome { gap: 12px; padding: 14px 14px 24px; }
	.th-card, .th-wait, .th-act, .th-favs, .th-recent { grid-column: 1 / -1; }
	.th-hero { flex-direction: column; align-items: stretch; gap: 16px; padding: 18px; }
	.th-hero__hi { font-size: 22px; }
	.th-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (max-width: 380px) {
	.th-stat { padding: 8px; column-gap: 8px; }
	.th-stat__ic { width: 26px; height: 26px; }
}

.thome--quiet .th-card, .thome--quiet .th-bar__col, .thome--quiet .th-ring__arc { animation: none; }

@media (prefers-reduced-motion: reduce) {
	.medrawer, .mepull__chev, .rail__home::before, .th-fav, .th-space { transition: none; }
	.th-card, .th-bar__col, .th-ring__arc, .rail__home.is-launching .thome-glyph__d { animation: none; }
}
/* =================================================== Talk+ calls: speed and experience (2026-09-30)
   054-talk-calls-plus.js. The held (pre-booted) frame, the stuck and calling
   veil, the in-call Chat / People panel, the draggable mini player, the
   pre-join sheet, the full-screen ring on a phone, and Live now + the call
   button on Talk+ Home. The call window stays dark in both themes (it frames
   video); its colours are tokens here, restated in both dark places like
   every other colour. The sheets use the theme's own tokens. */
:root {
	--nc-answer: #22B98A;
	--nc-answer-ink: #08231C;
	--nc-decline: #D9463E;
	--nc-call-bg: #0f1b18;
	--nc-call-panel: #13231f;
	--nc-call-line: rgba(255, 255, 255, .10);
	--nc-call-fg: #ffffff;
	--nc-call-muted: rgba(255, 255, 255, .64);
	--nc-call-chip: rgba(255, 255, 255, .10);
	--nc-call-chip-hover: rgba(255, 255, 255, .20);
	--nc-ring-glow: rgba(34, 185, 138, .20);
	--nc-scrim: rgba(6, 16, 13, .55);
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) { --nc-answer: #2ccf9c; --nc-decline: #e5544b; --nc-call-bg: #0c1714; --nc-call-panel: #111f1b; --nc-ring-glow: rgba(44, 207, 156, .16); --nc-scrim: rgba(0, 0, 0, .62); }
}
:root[data-theme="dark"] { --nc-answer: #2ccf9c; --nc-decline: #e5544b; --nc-call-bg: #0c1714; --nc-call-panel: #111f1b; --nc-ring-glow: rgba(44, 207, 156, .16); --nc-scrim: rgba(0, 0, 0, .62); }

.ncall-vh { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---- the held frame: laid out (so Talk loads normally) but off screen,
   out of the accessibility tree and out of the tab order (inert) */
.nuvo-call.nuvo-call--pre {
	position: fixed !important; inset: auto !important; top: 0 !important; left: -20000px !important;
	width: 940px !important; height: 600px !important; transform: none !important;
	visibility: hidden; pointer-events: none; animation: none !important; opacity: 0;
}

/* ---- header buttons that belong to one state only */
.nuvo-call__btn[data-act="call-corner"] { display: none; }
.nuvo-call--pip .nuvo-call__btn[data-act="call-corner"] { display: flex; }
.nuvo-call--pip .nuvo-call__btn[data-act="call-panel"] { display: none; }
.nuvo-call__btn[aria-expanded="true"] { background: var(--nc-call-fg); color: var(--nc-call-bg); }
.nuvo-call__btn:focus-visible, .nuvo-call__vbtn:focus-visible, .ncp__tab:focus-visible, .ncp__sendbtn:focus-visible, .ncp__add:focus-visible { outline: 2px solid var(--nc-answer); outline-offset: 2px; }

/* ---- the veil: calling, ringing time, cancel; stuck with a way forward */
.nuvo-call__callee { display: flex; }
.nuvo-call__callee .av { box-shadow: 0 0 0 6px var(--nc-ring-glow); }
.nuvo-call__ringt { font-size: 12px; color: var(--nc-call-muted); font-variant-numeric: tabular-nums; margin-block-start: -8px; }
.nuvo-call__veilacts { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
.nuvo-call__vbtn {
	display: inline-flex; align-items: center; gap: 6px; height: 38px; padding-inline: 16px;
	border: 0; border-radius: 100px; cursor: pointer; font: inherit; font-size: 13px; font-weight: 600;
	background: var(--nc-answer); color: var(--nc-answer-ink);
}
.nuvo-call__vbtn--ghost { background: var(--nc-call-chip); color: var(--nc-call-fg); }
.nuvo-call__vbtn--ghost:hover { background: var(--nc-call-chip-hover); }
.nuvo-call__vbtn--end { background: var(--nc-decline); color: #fff; }
.nuvo-call__stuck { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; max-width: 360px; padding-inline: 16px; color: var(--nc-call-fg); }
.nuvo-call__stuck b { font-size: 16px; font-weight: 600; }
.nuvo-call__stuck span { font-size: 13px; color: var(--nc-call-muted); }

/* ---- in-call panel: right side on a desktop, bottom sheet on a phone */
.nuvo-call__grab { display: none; }
.nuvo-call__panel[hidden] { display: none !important; }
.nuvo-call__panel {
	position: absolute; z-index: 4; inset-block-start: 56px; inset-block-end: 0; inset-inline-end: 0; width: 340px;
	display: flex; flex-direction: column; min-height: 0;
	background: var(--nc-call-panel); color: var(--nc-call-fg); border-inline-start: 1px solid var(--nc-call-line);
}
.nuvo-call--panel:not(.nuvo-call--full):not(.nuvo-call--pip) { width: min(1240px, 96vw); }
.nuvo-call--panel.nuvo-call--audio:not(.nuvo-call--full):not(.nuvo-call--pip) { width: min(900px, 96vw); }
.nuvo-call--panel .nuvo-call__stage { margin-inline-end: 340px; }
.ncp__head { display: flex; align-items: center; gap: 8px; padding: 10px 10px 8px 12px; border-block-end: 1px solid var(--nc-call-line); }
.ncp__tabs { display: flex; gap: 4px; flex: 1; }
.ncp__tab { border: 0; background: transparent; color: var(--nc-call-muted); font: inherit; font-size: 13px; font-weight: 600; padding: 7px 12px; border-radius: 100px; cursor: pointer; }
.ncp__tab[aria-selected="true"] { background: var(--nc-call-chip); color: var(--nc-call-fg); }
.ncp__x { width: 32px; height: 32px; }
.ncp__body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.ncp__msgs { list-style: none; margin: 0; padding: 10px 12px; flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.ncp__m { display: flex; flex-direction: column; gap: 2px; max-width: 92%; }
.ncp__m--mine { align-self: flex-end; text-align: end; }
.ncp__meta { font-size: 11.5px; color: var(--nc-call-muted); }
.ncp__meta b { color: var(--nc-call-fg); font-weight: 600; }
.ncp__txt { font-size: 13.5px; line-height: 1.4; white-space: pre-wrap; overflow-wrap: anywhere; background: var(--nc-call-chip); padding: 7px 10px; border-radius: 12px; }
.ncp__m--mine .ncp__txt { background: var(--nc-answer); color: var(--nc-answer-ink); }
.ncp__sys, .ncp__day { font-size: 12px; color: var(--nc-call-muted); text-align: center; }
.ncp__send { display: flex; gap: 6px; padding: 10px; border-block-start: 1px solid var(--nc-call-line); }
.ncp__input { flex: 1; min-width: 0; height: 38px; border-radius: 100px; border: 1px solid var(--nc-call-line); background: var(--nc-call-bg); color: var(--nc-call-fg); font: inherit; font-size: 16px; padding-inline: 14px; }
.ncp__input:focus { outline: none; border-color: var(--nc-answer); }
.ncp__input::placeholder { color: var(--nc-call-muted); }
.ncp__sendbtn { width: 38px; height: 38px; border: 0; border-radius: 100px; background: var(--nc-answer); color: var(--nc-answer-ink); display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; }
.ncp__people { list-style: none; margin: 0; padding: 8px; overflow-y: auto; }
.ncp__person { display: flex; align-items: center; gap: 10px; padding: 7px 6px; border-radius: 10px; }
.ncp__pt { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.ncp__pn { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ncp__you { font-weight: 400; color: var(--nc-call-muted); }
.ncp__ps { font-size: 12px; color: var(--nc-call-muted); }
.ncp__note { margin: 0; padding: 4px 14px 10px; font-size: 12px; color: var(--nc-call-muted); }
.ncp__add { display: inline-flex; align-items: center; gap: 8px; margin: 4px 12px 14px; align-self: flex-start; border: 0; border-radius: 100px; padding: 8px 14px; background: var(--nc-call-chip); color: var(--nc-call-fg); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.ncp__add:hover { background: var(--nc-call-chip-hover); }

/* ---- mini player: a floating tile that snaps to a corner */
.nuvo-call--pip .nuvo-call__grab { display: block; position: absolute; inset: 0; z-index: 1; cursor: grab; touch-action: none; }
.nuvo-call--drag .nuvo-call__grab { cursor: grabbing; }
.nuvo-call--drag { transition: none !important; box-shadow: 0 36px 90px rgba(0, 0, 0, .6); }
.nuvo-call.nuvo-call--pip[class*="nuvo-call--c-"] { inset: auto; }
.nuvo-call.nuvo-call--pip.nuvo-call--c-tl { top: calc(var(--header-h, 56px) + 12px); left: 20px; }
.nuvo-call.nuvo-call--pip.nuvo-call--c-tr { top: calc(var(--header-h, 56px) + 12px); right: 20px; }
.nuvo-call.nuvo-call--pip.nuvo-call--c-br { bottom: calc(var(--tabbar-h, 0px) + var(--sab, 0px) + 20px); right: 20px; }
.nuvo-call.nuvo-call--pip.nuvo-call--c-bl { bottom: calc(var(--tabbar-h, 0px) + var(--sab, 0px) + 20px); left: 20px; }
.nuvo-call--pip .nuvo-call__bar { z-index: 3; }
.nuvo-call--pip:focus-within .nuvo-call__bar, .nuvo-call--peek .nuvo-call__bar,
.nuvo-call--pip:focus-within .nuvo-call__piphint, .nuvo-call--peek .nuvo-call__piphint { opacity: 1; }
@media (hover: none) {
	.nuvo-call--pip .nuvo-call__bar, .nuvo-call--pip .nuvo-call__piphint { opacity: 0; }
	.nuvo-call--pip.nuvo-call--peek .nuvo-call__bar, .nuvo-call--pip.nuvo-call--peek .nuvo-call__piphint { opacity: 1; }
}

/* ---- phone: the panel is a bottom sheet over the call */
@media (max-width: 767.98px) {
	.nuvo-call--panel .nuvo-call__stage { margin-inline-end: 0; }
	.nuvo-call__panel {
		inset-block-start: auto; inset-inline: 0; width: auto; height: min(64dvh, 520px);
		border-inline-start: 0; border-radius: 18px 18px 0 0; padding-block-end: var(--sab, 0px);
		box-shadow: 0 -20px 60px rgba(0, 0, 0, .5);
	}
	.nuvo-call.nuvo-call--pip.nuvo-call--c-tl, .nuvo-call.nuvo-call--pip.nuvo-call--c-tr { top: calc(var(--header-h, 56px) + var(--sat, 0px) + 8px); }
	.nuvo-call.nuvo-call--pip.nuvo-call--c-br, .nuvo-call.nuvo-call--pip.nuvo-call--c-bl { bottom: calc(var(--tabbar-h, 56px) + var(--sab, 0px) + 20px); }
	.nuvo-call.nuvo-call--pip.nuvo-call--c-tl, .nuvo-call.nuvo-call--pip.nuvo-call--c-bl { left: 12px; }
	.nuvo-call.nuvo-call--pip.nuvo-call--c-tr, .nuvo-call.nuvo-call--pip.nuvo-call--c-br { right: 12px; }
}

/* ---- the pre-join sheet */
.npj {
	position: fixed; inset: 0; z-index: 101; display: flex; align-items: center; justify-content: center;
	padding: 16px; background: var(--nc-scrim); animation: npj-fade .18s ease-out both;
}
.npj__card {
	width: min(520px, 100%); max-height: calc(100dvh - 32px); overflow-y: auto;
	display: flex; flex-direction: column; gap: 12px; padding: 18px 20px 16px;
	background: var(--bg-raised); color: var(--text); border: 1px solid var(--border); border-radius: 20px;
	box-shadow: 0 30px 90px rgba(0, 0, 0, .35); animation: npj-in .24s cubic-bezier(.2, .8, .2, 1) both;
}
@keyframes npj-fade { from { opacity: 0; } }
@keyframes npj-in { from { opacity: 0; transform: translateY(10px) scale(.985); } }
.npj__head { display: flex; align-items: flex-start; gap: 10px; }
.npj__head > div { flex: 1; min-width: 0; }
.npj__t { margin: 0; font: 600 18px var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.npj__d { margin: 2px 0 0; font-size: 13px; color: var(--text-muted); }
.npj__stage { position: relative; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden; background: var(--nc-call-bg); }
.npj__video { width: 100%; height: 100%; object-fit: cover; display: block; transform: scaleX(-1); }
.npj__off { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; color: var(--nc-call-muted); font-size: 13px; background: var(--nc-call-bg); }
.npj__off[hidden] { display: none; }
/* The mic level: a small glass capsule on the preview, bright when you speak, so "is my mic working?" is answered at a glance. */
.npj__meter { position: absolute; inset-inline-start: 14px; inset-block-end: 14px; width: min(160px, 40%); height: 8px; border-radius: 100px; background: rgba(255, 255, 255, .22); box-shadow: 0 0 0 5px rgba(8, 20, 16, .42); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); overflow: hidden; }
.npj__meter i { display: block; height: 100%; border-radius: 100px; background: linear-gradient(90deg, #3FD6A6, #9BF0D2); transform: scaleX(0); transform-origin: left center; transition: transform .08s linear; }
[dir="rtl"] .npj__meter i { transform-origin: right center; }
.npj__msg { margin: 0; font-size: 13px; color: var(--text); min-height: 0; }
.npj__msg:empty { display: none; }
.npj__toggles { display: flex; gap: 8px; }
.npj__tg {
	flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 42px;
	border: 1px solid var(--border-strong); border-radius: 100px; background: var(--bg); color: var(--text);
	font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer;
}
.npj__tg[aria-pressed="false"] { background: var(--bg-hover); color: var(--text-muted); text-decoration: line-through; text-decoration-thickness: 1px; }
.npj__tg:disabled { opacity: .55; cursor: not-allowed; }
.npj__devs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.npj__dev { display: flex; flex-direction: column; gap: 4px; min-width: 0; font-size: 12px; font-weight: 600; color: var(--text-muted); }
.npj__dev .select { width: 100%; min-width: 0; }
.npj__hint { margin: 0; font-size: 12px; color: var(--text-muted); }
.npj__skip { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; align-self: flex-start; }
.npj__foot { display: flex; justify-content: flex-end; gap: 8px; padding-block-start: 4px; }
.npj :focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (max-width: 767.98px) {
	.npj { align-items: flex-end; padding: 0; }
	.npj__card { width: 100%; max-height: 96dvh; border-radius: 20px 20px 0 0; padding-block-end: calc(16px + var(--sab, 0px)); }
	.npj__devs { grid-template-columns: 1fr; }
	.npj__foot .btn { flex: 1; justify-content: center; }
}

/* ---- the full-screen ring on a phone */
.nuvo-ring.nuvo-ring--sheet { inset: 0; padding: 0; pointer-events: auto; background: var(--bg); }
.nrs__card {
	width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: space-between;
	padding: calc(28px + var(--sat, 0px)) 24px calc(28px + var(--sab, 0px));
	background: radial-gradient(120% 60% at 50% 30%, var(--nc-ring-glow), transparent 70%);
	animation: npj-fade .22s ease-out both;
}
.nrs__where { margin: 0; font-size: 14px; color: var(--text-muted); text-align: center; }
.nrs__who { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; min-width: 0; max-width: 100%; }
.nrs__av { position: relative; display: inline-flex; border-radius: 50%; margin-block-end: 8px; }
.nrs__av::after { content: ''; position: absolute; inset: -8px; border-radius: 50%; border: 2px solid var(--nc-answer); animation: nuvo-ring-pulse 1.8s ease-out infinite; }
.nrs__name { margin: 0; font: 600 28px var(--display); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nrs__sub { margin: 0; font-size: 15px; color: var(--text-muted); }
.nrs__acts { display: flex; justify-content: space-around; align-items: flex-start; width: 100%; max-width: 360px; }
.nrs__act { display: flex; flex-direction: column; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; }
.nrs__btn { width: 72px; height: 72px; border: 0; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #fff; box-shadow: 0 12px 30px -10px rgba(0, 0, 0, .45); }
.nrs__btn--decline { background: var(--nc-decline); }
.nrs__btn--decline svg { transform: rotate(135deg); }
.nrs__btn--answer, .nrs__btn--video { background: var(--nc-answer); color: var(--nc-answer-ink); }
.nrs__btn:active { transform: scale(.95); }
.nrs__btn:focus-visible, .nrs__mute:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; }
.nrs__mute { display: inline-flex; align-items: center; gap: 8px; border: 0; background: transparent; color: var(--text-muted); font: inherit; font-size: 13px; padding: 8px 12px; border-radius: 100px; cursor: pointer; }

/* ---- Talk+ Home: Live now, and the call button on a favourite chat */
.th-live { grid-column: 1 / -1; }
.th-live__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--nc-answer); margin-inline-start: auto; animation: nuvo-livepill 1.4s ease-in-out infinite; }
.th-live .th-card__h .pill-count { margin-inline-start: 0; }
.th-live__row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.th-live__row > .th-row { flex: 1; min-width: 0; }
.th-live__acts { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.th-live__btn { white-space: nowrap; }
.th-fav__wrap { position: relative; min-width: 0; display: flex; }
.th-fav__wrap > .th-fav { flex: 1; }
.th-fav__call {
	position: absolute; inset-block-start: 6px; inset-inline-end: 6px;
	width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--border);
	display: flex; align-items: center; justify-content: center; cursor: pointer;
	background: var(--bg-raised); color: var(--brand); opacity: 0; transition: opacity .15s ease;
}
.th-fav__wrap:hover .th-fav__call, .th-fav__call:focus-visible { opacity: 1; }
.th-fav__call:hover { background: var(--brand); color: #fff; border-color: var(--brand); }
@media (hover: none) { .th-fav__call { opacity: 1; } }
@container (max-width: 380px) {
	.th-live__btn { padding-inline: 10px; }
	.th-live__row .sph-when { display: none; }
}

@media (prefers-reduced-motion: reduce) {
	.npj, .npj__card, .nrs__card { animation: none; }
	.nrs__av::after, .th-live__dot { animation: none; }
	.npj__meter i, .th-fav__call { transition: none; }
}

/* Phones: full screen means nothing on a phone, and the name needs the room. */
@media (max-width: 767.98px) {
	.nuvo-call__btn[data-act="call-full"] { display: none; }
}
/* ===== private channels */
/* The lock that stands where a channel's # stands (nvChGlyph in
   app/101-private-channels-ui.js), the Open / Private choice and its member
   picker in New channel, and the Private channel card with its honest lines.
   Existing tokens only -- nothing here has a colour of its own, so light,
   dark and the OS setting all follow the palette. */

/* The glyph slot: the # and the lock share one fixed box, so a name sits in
   the same place whether its channel is open or private. */
.ch-lock { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
.ch-lock svg { display: block; }
.chan__hash,
.th-sprow__h { display: inline-flex; align-items: center; justify-content: center; width: 13px; flex-shrink: 0; }
/* A 12px stroke icon reads lighter than a semibold #: one pixel more. */
.chan__hash .ch-lock svg { width: 13px; height: 13px; }
.ch-mark { display: inline-flex; align-items: center; justify-content: center; width: 12px; margin-inline-end: 2px; vertical-align: -1px; }
.ch-mark .ch-lock svg { width: 12px; height: 12px; }

/* New channel: Open / Private, full width, the same segmented control as
   Calendar and Queues. */
.priv-seg { width: 100%; }
.priv-seg button { flex: 1 1 0; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px; }
.priv-seg button > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.priv-seg__h { font-weight: 700; opacity: .7; }
.priv-seg button > svg { flex-shrink: 0; }
.priv-note[hidden],
.priv-pick[hidden],
#ch-adopt[hidden] { display: none; }
.priv-pick { display: flex; flex-direction: column; gap: 8px; margin-block-start: 4px; }
.priv-list {
	display: flex; flex-direction: column; gap: 2px;
	max-height: 248px; overflow-y: auto; overscroll-behavior: contain;
	padding: 4px; border: 1px solid var(--border); border-radius: var(--r);
}
.priv-row { width: 100%; text-align: start; border: none; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.priv-row:hover { background: var(--bg-hover); }
.priv-row[aria-pressed="true"] { background: var(--brand-soft); }
.priv-row.is-fixed { cursor: default; }
.priv-row.is-fixed:hover { background: transparent; }
/* Checked, but not yours to change: the box steps back. */
.priv-row.is-fixed .fsel { opacity: .5; }
.priv-row .mem__r { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.priv-foot { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.priv-count { flex-shrink: 0; font-size: 12px; font-weight: 600; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.priv-none { font-size: 13px; padding: 10px; margin: 0; }

/* The Private channel card: the About panel and Settings > Spaces & channels. */
.priv-card { display: flex; flex-direction: column; gap: 6px; margin: 0 8px 14px; }
.setsp__sub .priv-card { margin: 0; }
.priv-card__row { padding: 10px 12px; }
.priv-card__ic { display: inline-flex; flex-shrink: 0; color: var(--text-muted); }
.priv-card__ic.is-on { color: var(--text); }
.priv-line { display: flex; align-items: flex-start; gap: 8px; padding: 2px 4px 0 12px; font-size: 12.5px; line-height: 1.45; color: var(--text-muted); }
.priv-line > svg { flex-shrink: 0; margin-block-start: 1px; }
.priv-line__t { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.priv-line__fix { color: var(--text); }
/* ============================================ feedback / help corner
   The fixed "?" button (body.html, app/103-feedback-help.js): bottom-right,
   on every app. Sits under the modal backdrop's z-index (100) so an open
   form covers it, same as every other floating control in the shell. */
.fbhelp {
	position: fixed;
	inset-block-end: max(20px, calc(env(safe-area-inset-bottom, 0px) + 12px));
	inset-inline-end: 20px;
	z-index: 80;
}
.fbhelp__btn {
	width: 46px;
	height: 46px;
	border-radius: 50%;
	border: 1px solid var(--border);
	background: var(--bg);
	color: var(--brand);
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 10px 28px rgba(6, 17, 14, .22);
	transition: transform .15s ease, box-shadow .15s ease;
}
.fbhelp__btn:hover { background: var(--bg-hover); transform: translateY(-1px); box-shadow: 0 14px 34px rgba(6, 17, 14, .28); }
.fbhelp__btn[aria-expanded="true"] { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 40%, transparent); }

.fbhelp__pop {
	position: absolute;
	inset-block-end: calc(100% + 10px);
	inset-inline-end: 0;
	z-index: 90;
	width: 230px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: 0 18px 48px rgba(6, 17, 14, .3);
	padding: 6px;
	transform-origin: bottom right;
	animation: launch-panel 180ms cubic-bezier(.2, 1.1, .3, 1);
}
.fbhelp__item {
	width: 100%;
	min-height: 42px;
	border: none;
	background: transparent;
	border-radius: var(--r);
	display: flex;
	align-items: center;
	gap: 11px;
	padding-inline: 10px;
	font-size: 13.5px;
	font-weight: 500;
	color: var(--text);
	text-align: start;
}
.fbhelp__item:hover { background: var(--bg-hover); }
.fbhelp__item svg { color: var(--brand); flex-shrink: 0; }

@media (max-width: 767.98px) {
	.fbhelp { inset-inline-end: 14px; inset-block-end: max(14px, calc(env(safe-area-inset-bottom, 0px) + 10px)); }
}