/* task-manager's styles over gl/ui. Tokens live in gl's theme layer (they
   override gl defaults, accents and presets); rules live in the app layer
   (they override gl components; gl utilities still override them). */
@layer theme {
	:root {
		--container-max: 720px;
		/* Task-page section widths: forms, checklist-style panels, the
		   activity feed. */
		--tm-measure-form: 34rem;
		--tm-measure-panel: 40rem;
		--tm-measure-feed: 48rem;
		/* Card and section move animations (view transitions). */
		--tm-move-duration: 240ms;
		--tm-enter-duration: 220ms;
		--tm-leave-duration: 160ms;
		--tm-ease-leave: cubic-bezier(0.4, 0, 0.6, 1);
		/* Moving cards and tabs paint above the other view-transition groups. */
		--tm-z-vt-front: 10;
		/* Chart colours. Plotly traces resolve var() tokens, not data-colour,
		   so each palette key gets a token mirroring gl's swatch; charts then
		   match badges, columns and meters. */
		--tm-colour-grey: light-dark(oklch(0.552 0.016 285.938), oklch(0.705 0.015 286.067));
		--tm-colour-red: light-dark(oklch(0.637 0.237 25.331), oklch(0.704 0.191 22.216));
		--tm-colour-orange: light-dark(oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934));
		--tm-colour-amber: light-dark(oklch(0.769 0.188 70.08), oklch(0.828 0.189 84.429));
		--tm-colour-green: light-dark(oklch(0.723 0.219 149.579), oklch(0.792 0.209 151.711));
		--tm-colour-blue: light-dark(oklch(0.623 0.214 259.815), oklch(0.707 0.165 254.624));
		--tm-colour-violet: light-dark(oklch(0.606 0.25 292.717), oklch(0.702 0.183 293.541));
		/* "No priority" and other unranked remainders. */
		--tm-chart-none: light-dark(oklch(0.87 0.005 286), oklch(0.4 0.005 286));
		/* Ahead / behind schedule: the theme's diverging poles. */
		--tm-chart-ahead: var(--chart-div-1);
		--tm-chart-behind: var(--chart-div-5);
		--tm-dashboard-max: 80rem;
		--tm-chart-label: 10rem;
	}

	/* An app palette key: a meter remainder that reads as the empty track. */
	[data-colour="muted"] {
		--swatch: var(--muted);
		--swatch-text: var(--muted-foreground);
	}
}

@layer app {
	.container-full {
		width: 100%;
		max-width: none;
		margin-inline: 0;
		padding-inline: var(--container-pad);
	}

	.app-nav {
		border-block-end: var(--border-width) solid var(--border);
		background: var(--background);
	}

	.app-nav-inner {
		display: grid;
		grid-template-columns: 1fr auto 1fr;
		align-items: center;
		gap: var(--space-4);
		padding: var(--space-3) var(--container-pad);
		width: 100%;
		max-width: none;
	}

	.app-title {
		font-weight: var(--font-semibold);
		color: var(--foreground);
		text-decoration: none;
	}

	.app-nav-center {
		justify-self: center;
		display: flex;
		width: 100%;
		min-width: 12rem;
	}

	.app-nav-right {
		justify-self: end;
	}

	.app-nav-search {
		justify-content: space-between;
	}

	.app-nav-search-label {
		display: inline-flex;
		align-items: center;
		gap: var(--space-2);
	}

	.command-palette > input {
		margin-block-end: var(--space-3);
	}

	.command-palette > menu {
		padding-inline: var(--space-2);
		padding-block-start: var(--space-2);
		border-block-start: var(--border-width) solid var(--border);
	}

	.board-center-actions {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--space-3);
	}

	/* Counter form.css's full-width and top-margin rules so the field fits the
	   centered row. */
	.board-filter {
		width: 14rem;
		min-width: 10rem;
		max-width: 100%;
		flex: 1 1 auto;
		margin-block-start: 0;
	}

	@media (width <= 48rem) {
		.board-center-actions {
			justify-content: center;
		}

		.board-filter {
			width: 100%;
			flex: 1 1 100%;
		}
	}

	.board-center-actions lw-dropdown {
		display: inline-flex;
	}

	/* The board's filter bar takes the row's free space; on phones it wraps
	   to a full-width line of its own. */
	.board-center-actions > lw-filter-bar {
		flex: 1 1 auto;
	}

	@media (width <= 48rem) {
		.board-center-actions > lw-filter-bar {
			flex-basis: 100%;
			/* The facets center under the full-width search, like the row. */
			justify-content: center;
		}
	}

	/* Light mode tints the bottom with a little accent so the gradient doesn't
	   fade completely to grey. */
	.lw-board-column {
		background: linear-gradient(
			to bottom,
			color-mix(
				in oklab,
				var(--lw-board-accent, var(--primary)) 10%,
				var(--secondary)
			),
			light-dark(
				color-mix(
					in oklab,
					var(--lw-board-accent, var(--primary)) 4%,
					var(--secondary)
				),
				var(--secondary)
			)
		);
		/* Add-task pending chip: absolutely positioned so the column never
		   reserves space for a task that hasn't landed yet. */
		position: relative;
		z-index: 0;
		view-transition-class: board-column;
	}

	/* Cards should stack above their own column so they never visually sink
	   behind a column while dragging or during view transitions. The view
	   transition class lets board patches glide each card to its new spot. */
	.lw-board-card {
		position: relative;
		z-index: var(--z-raised);
		view-transition-class: board-card;
	}

	.board-column-edit,
	.board-column-edit:hover {
		color: var(--muted-foreground);
	}

	/* A collapsed column (lw-board hides its cards, so cards landing in it get
	   no new VT snapshot and the board-card-leave fade plays) stays a narrow
	   strip: the time totals would widen it. */
	.lw-board-column[data-collapsed] .lw-board-column-stats .time-badge {
		display: none;
	}

	.board-add-pending {
		position: absolute;
		inset-block-start: var(--space-2);
		inset-inline-end: var(--space-2);
		width: 0.5rem;
		height: 0.5rem;
		border-radius: var(--radius-full);
		background: var(--lw-board-accent, var(--primary));
		/* csslint-disable-next-line token-values -- the pending chip's own pulse */
		animation: board-add-pulse 0.9s var(--tm-ease-leave) infinite;
		pointer-events: none;
		z-index: var(--z-raised);
	}

	@keyframes board-add-pulse {
		50% {
			opacity: 0.25;
			transform: scale(0.75);
		}
	}

	/* The task edit panel shares the clicked card's view-transition-name, so the
	   board → task navigation flies the card into the panel and back. Browsers
	   without cross-document view transitions get the panel's own entrance. */
	@view-transition {
		navigation: auto;
	}

	/* Board patches run inside a view transition and each card has a unique
	   view-transition-name, so moves glide. The root crossfade is disabled so
	   non-card chrome updates instantly. */
	::view-transition-old(root),
	::view-transition-new(root) {
		animation: none;
	}

	/* Card view-transition groups must always paint above column groups so cards
	   never slide behind a column on their way to a new destination. */
	::view-transition-group(.board-card) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
		z-index: var(--tm-z-vt-front);
	}

	::view-transition-group(.board-column) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
		z-index: 0;
	}

	/* Cards/columns with no counterpart snapshot (added/removed) fade and drift. */
	::view-transition-new(.board-card):only-child {
		animation: board-card-enter var(--tm-enter-duration) var(--ease-emphasized) both;
	}

	::view-transition-old(.board-card):only-child {
		animation: board-card-leave var(--tm-leave-duration) var(--tm-ease-leave) both;
	}

	::view-transition-new(.board-column):only-child {
		animation: board-column-enter var(--tm-enter-duration) var(--ease-emphasized) both;
	}

	::view-transition-old(.board-column):only-child {
		animation: board-column-leave var(--tm-leave-duration) var(--tm-ease-leave) both;
	}

	@keyframes board-card-enter {
		from {
			opacity: 0;
			transform: translateY(-6px) scale(0.98);
		}
	}

	@keyframes board-card-leave {
		to {
			opacity: 0;
			transform: scale(0.98);
		}
	}

	@keyframes board-column-enter {
		from {
			opacity: 0;
			transform: translateX(-6px) scale(0.98);
		}
	}

	@keyframes board-column-leave {
		to {
			opacity: 0;
			transform: scale(0.98);
		}
	}

	/* Column collapse/expand: cards get their own view-transition group so they
	   fade out early / in late, keeping the focus on the column width change. */
	.lw-board-card.board-card-collapse {
		view-transition-class: board-card-collapse;
	}

	::view-transition-group(board-card-collapse) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
		z-index: var(--tm-z-vt-front);
	}

	::view-transition-new(board-card-collapse):only-child {
		animation: board-card-collapse-enter var(--tm-move-duration) var(--ease-emphasized)
			both;
	}

	::view-transition-old(board-card-collapse):only-child {
		animation: board-card-collapse-leave var(--tm-move-duration) var(--tm-ease-leave) both;
	}

	@keyframes board-card-collapse-enter {
		0%,
		70% {
			opacity: 0;
			transform: translateY(-6px) scale(0.98);
		}
		100% {
			opacity: 1;
			transform: none;
		}
	}

	@keyframes board-card-collapse-leave {
		0% {
			opacity: 1;
			transform: none;
		}
		30%,
		100% {
			opacity: 0;
			transform: scale(0.98);
		}
	}

	@media (prefers-reduced-motion: reduce) {
		::view-transition-group(.board-card),
		::view-transition-old(.board-card),
		::view-transition-new(.board-card),
		::view-transition-group(.board-column),
		::view-transition-old(.board-column),
		::view-transition-new(.board-column),
		::view-transition-group(board-card-collapse),
		::view-transition-old(board-card-collapse),
		::view-transition-new(board-card-collapse) {
			/* csslint-disable-next-line no-important -- reduced motion: stops the view-transition animations whatever else sets them */
			animation: none !important;
		}
	}

	/* Column pending state (data-pending until the SSE patch confirms). */
	.lw-board-column[data-pending] {
		pointer-events: none;
		cursor: wait;

		& > * {
			opacity: 0.3;
		}

		&::after {
			content: "";
			position: absolute;
			inset: 0;
			margin: auto;
			width: 1.5rem;
			height: 1.5rem;
			background-color: currentColor;
			mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 1 1-6.219-8.56'/%3E%3C/svg%3E");
			mask-position: center;
			mask-repeat: no-repeat;
			mask-size: contain;
			animation: board-column-spin var(--duration-loop) linear infinite;
			z-index: var(--z-raised);
		}
	}

	@keyframes board-column-spin {
		to {
			transform: rotate(360deg);
		}
	}

	.board-card-meta {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
		gap: var(--space-2);
		align-items: center;
		width: 100%;
		min-width: 0;
	}

	.board-card-actions {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	/* The card menu wraps the whole board without taking a box. */
	.board-card-menu {
		display: contents;
	}

	/* The Send-to-board entry is an anchor among ghost buttons; lw's menuitem
	   rule leaves font metrics to the element, and only buttons get the small
	   size (and the transparent border box) from the button base — match them. */
	.board-card-menu a[role="menuitem"] {
		font-size: var(--text-7);
		font-weight: var(--font-medium);
		line-height: var(--leading-normal);
		border: var(--border-width) solid transparent;
	}

	.board-card-priority-slot,
	.board-card-type-slot {
		min-width: 0;
		overflow: hidden;

		.badge {
			max-width: 100%;
			text-overflow: ellipsis;
		}
	}

	.board-card-title {
		display: flex;
		align-items: baseline;
		gap: var(--space-2);
		min-width: 0;
		width: 100%;

		& a {
			min-width: 0;
			overflow-wrap: anywhere;
			font-size: var(--text-7);
		}
	}

	.board-card-number {
		flex-shrink: 0;
		text-decoration: underline;
		color: var(--muted-foreground);
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		line-height: var(--leading-none);
	}

	.board-card-checklist {
		display: inline-flex;
		align-items: center;
		gap: var(--space-1);
		color: var(--muted-foreground);
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		font-variant-numeric: tabular-nums;
		line-height: var(--leading-none);
	}

	.board-card-due {
		margin-inline-start: auto;
		flex-shrink: 0;
		color: var(--muted-foreground);
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		line-height: var(--leading-none);
		white-space: nowrap;
	}

	.star-button {
		padding: 0;
		color: var(--muted-foreground);

		&:hover {
			color: var(--foreground);
		}

		& svg {
			inline-size: var(--icon-size-sm);
			block-size: var(--icon-size-sm);
		}
	}

	/* The label is hidden because the ring is too small to read; aria-valuenow
	   still exposes the value. */
	.board-card-radial.radial {
		--radial-bg: var(--popover);
		vertical-align: middle;

		&::after {
			content: none;
		}
	}

	.board-card-times {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		min-width: 0;
		width: 100%;
		min-height: 1.5rem;
	}

	/* Projects card meters: rows use subgrid so every track (a segmented
	   lw.Meter) starts at the same x regardless of caption width. */
	.project-meters {
		display: grid;
		grid-template-columns: max-content minmax(0, 1fr);
		column-gap: var(--space-2);
		row-gap: var(--space-2);
		width: 100%;
		margin-block-start: var(--space-1);
	}

	.project-meter-row {
		grid-column: 1 / -1;
		display: grid;
		grid-template-columns: subgrid;
		align-items: center;
	}

	.project-meter-caption {
		font-size: var(--text-8);
		color: var(--muted-foreground);
		white-space: nowrap;
	}

	/* Estimate and remaining share neutral styling so they read as a pair rather
	   than accented status. */
	.time-badge {
		display: inline-flex;
		align-items: center;
		gap: var(--space-1);
		flex-shrink: 0;
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		line-height: var(--leading-none);
		padding: var(--space-0_5) var(--space-2);
		border-radius: var(--radius-full);
		background-color: var(--muted);
		color: var(--muted-foreground);
	}

	.time-badge-separator {
		opacity: 0.6;
		padding-inline: var(--space-1);
	}

	/* Hours and minutes, each an input group whose suffix names the unit. */
	.time-input-pair {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--space-2);
	}

	.star-button[data-pending] {
		pointer-events: none;
		opacity: 0.6;
	}

	/* Colour swatch: tinted with the active theme's primary. Square under
	   zero-radius styles (lyra, sera), a circle under any rounded style. */
	.theme-swatch {
		display: inline-block;
		width: 0.875rem;
		height: 0.875rem;
		background: var(--primary);
		border-radius: clamp(0px, calc(var(--radius) * 100), 50%);
		box-shadow: inset 0 0 0 var(--border-width)
			color-mix(in oklab, var(--foreground) 15%, transparent);
	}

	.board-card-assignees {
		margin-inline-start: auto;
	}

	.form-field-pair {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--space-3);
	}


	nav[aria-label="Breadcrumb"] li:last-child a {
		display: inline-block;
		max-width: 48ch;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		vertical-align: bottom;
	}

	dialog.new-task-dialog > form > footer,
	.task-edit-panel > form > footer {
		padding-block-start: var(--space-4);
		padding-block-end: var(--space-8);
	}

	/* The new-task dialog is double the default width, laid out as two parallel
	   form columns (core fields left, people/time/recurrence right). */
	dialog.new-task-dialog {
		width: min(100% - 2rem, 56rem);
	}

	.task-form-columns {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--space-6);
		align-items: start;
	}

	.task-form-col {
		display: flex;
		flex-direction: column;
		gap: var(--space-6);
		min-width: 0;
	}

	/* The task form's labelled groups (About, Classification, Schedule,
	   People): the legend is a group heading, not a field label. */
	.task-form-group {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
		min-inline-size: 0;
		margin: 0;
		padding: 0;
		border: 0;
	}

	.task-edit-panel > form > .vstack {
		gap: var(--space-6);
	}

	@media (width <= 48rem) {
		.task-form-columns {
			grid-template-columns: 1fr;
		}
	}

	/* Standalone edit panel, styled like the dialog surface. The entrance is a
	   plain CSS animation (once per navigation); lightweight-ui's global
	   reduced-motion guard neutralises it. */
	/* Relative: "Saved" shows in its top corner (TaskEditManager.saved). */
	.task-edit-panel {
		position: relative;
		view-transition-class: board-card;
		width: 100%;
		margin-inline: 0;
		margin-block-start: 0;
		padding: var(--space-4);
		background-color: var(--popover);
		color: var(--popover-foreground);
		border-radius: var(--radius-xlarge);
		box-shadow: var(--surface-ring);
		font-size: var(--text-7);
		overflow: hidden;
		animation: task-panel-enter var(--duration) var(--ease-emphasized);
	}

	.task-edit-panel > form {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
	}

	.task-edit-panel-heading {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		margin: 0;
		font-size: var(--text-6);
		font-weight: var(--font-medium);
		color: var(--foreground);
	}

	.task-edit-panel > form > footer {
		display: flex;
		flex-direction: column-reverse;
		gap: var(--space-2);

		@media (width >= 40rem) {
			flex-direction: row;
			justify-content: flex-end;
		}

		/* The actions exist only while the form is dirty (app.js's TaskEditManager
		   toggles data-dirty). Same display-transition idiom as lightweight-ui's
		   dialogs: quick exit, decelerated entry from a slight rise. */
		transition:
			opacity var(--duration-fast) var(--ease-in),
			transform var(--duration-fast) var(--ease-in),
			display var(--duration-fast) var(--ease-in) allow-discrete;
	}

	.task-edit-panel > form:not([data-dirty]) > footer {
		display: none;
		opacity: 0;
		transform: translateY(4px);
	}

	/* The send-to-board form has no dirty tracking: its actions are always shown. */
	.task-edit-panel > form[id="send-tasks-form"] > footer {
		display: flex;
		opacity: 1;
		transform: none;
	}

	.task-edit-panel > form[data-dirty] > footer {
		transition-duration: var(--duration);
		transition-timing-function: var(--ease-emphasized);
	}

	@starting-style {
		.task-edit-panel > form[data-dirty] > footer {
			opacity: 0;
			transform: translateY(4px);
		}
	}

	/* Inline save confirmation: the panel is data-ignore-morph'd, so it survives
	   the confirming SSE patch. */
	.task-save-status {
		position: absolute;
		inset-block-start: var(--space-3);
		inset-inline-end: var(--space-4);
		font-size: var(--text-8);
		color: var(--muted-foreground);
		opacity: 0;
		transition: opacity var(--duration-fast) var(--ease-in);

		&.visible {
			opacity: 1;
			transition-duration: var(--duration);
			transition-timing-function: var(--ease-emphasized);
		}
	}

	.task-edit-panel > form[data-pending] {
		pointer-events: none;
		opacity: 0.6;
	}

	@keyframes task-panel-enter {
		from {
			opacity: 0;
			transform: scale(0.95);
		}
	}

	/* On desktop the body is fixed to the viewport and main may shrink, so the
	   body → main → task-layout → task-page flex chain has a definite height and
	   each panel scrolls independently instead of growing the page. */
	@media (width >= 80rem) {
		body:has(.task-layout) {
			height: 100vh;
			overflow: hidden;
		}

		body:has(.task-layout) main {
			min-height: 0;
		}
	}

	main.container,
	main.container-full {
		padding-inline: 0;
	}

	/* The breadcrumb and toolbar rows above a page's content: main has no
	   gutter (boards and panes run edge to edge), so these keep their own. */
	.page-bar {
		padding-inline: var(--container-pad);
	}

	/* Kanban frames (task board + projects) get a small gutter of their own. No
	   bottom padding: the board is height-anchored to the viewport bottom. */
	[id="tasks"][data-board-id],
	[id="projects"] {
		padding: var(--space-4) var(--space-4) 0;
	}

	.task-layout {
		display: block;
	}

	@media (width >= 80rem) {
		.task-layout {
			display: flex;
			flex-direction: column;
			flex: 1;
			min-height: 0;
		}
	}

	.task-page {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
		padding: 0;
		margin-block-start: 0;
	}

	@media (width >= 80rem) {
		.task-page {
			flex: 1;
			min-height: 0;
			overflow: hidden;
		}
	}

	/* The panes (lw-panes) stack below 80rem with every section shown; the
	   element reflects that as data-stacked, this query covers the first paint. */
	.task-page lw-panes {
		block-size: auto;
	}

	@media (width >= 80rem) {
		.task-page lw-panes {
			flex: 1;
			min-block-size: 0;
		}
	}

	@media (width < 80rem) {
		.task-page lw-resizable[data-stack-below="79.99rem"] {
			flex-direction: column;
			block-size: auto;

			> [data-panel] {
				flex: none;
				overflow: visible;
			}

			> [data-handle] {
				display: none;
			}
		}
	}

	/* A pane is one resizable column: a tab strip over its sections, the active
	   one filling the pane (its body scrolls). */
	.task-page [data-pane] {
		gap: var(--space-4);
		padding: 0;
	}

	.task-edit-panel-wrap,
	.task-checklists,
	.task-related,
	.task-files,
	.task-members,
	.task-emails,
	.task-recurring,
	.task-chat {
		display: flex;
		flex-direction: column;
		min-height: 0;
		padding-block-end: var(--space-4);
		width: min(100% - 2rem, 28rem);
		margin-inline: auto;
	}

	/* Per-section content cap: content stays at --section-max and centres, so
	   as the pane grows the inset (not the content) absorbs the width; the max()
	   floor keeps a 1rem inset on narrow panes. The tab strip starts at the same
	   edge (its --section-max follows the pane's visible section). */
	.task-edit-panel-wrap {
		--section-max: var(--tm-measure-form);
	}

	.task-chat {
		--section-max: var(--tm-measure-feed);
	}

	.task-page [data-pane] > [role="tabpanel"] {
		box-sizing: border-box;
		inline-size: 100%;
		margin-inline: 0;
		padding-inline: max(var(--space-4), calc((100% - var(--section-max, var(--tm-measure-panel))) / 2));
	}

	.task-page [data-pane] > [role="tablist"] {
		--section-inset: max(var(--space-4), calc((100% - var(--section-max, var(--tm-measure-panel))) / 2));
		margin-inline-start: var(--section-inset);
		max-inline-size: calc(100% - 2 * var(--section-inset));
	}

	.task-page [data-pane]:has(> .task-edit-panel-wrap:where(:not([hidden]))) > [role="tablist"] {
		--section-max: var(--tm-measure-form);
	}

	.task-page [data-pane]:has(> .task-chat:where(:not([hidden]))) > [role="tablist"] {
		--section-max: var(--tm-measure-feed);
	}

	.send-page {
		display: flex;
		justify-content: center;
		padding: 0 var(--container-pad);
	}

	.send-page .task-edit-panel-wrap {
		width: min(100% - 2rem, 34rem);
		margin-inline: 0;
	}

	.send-tasks-list {
		list-style: none;
		margin: 0;
		padding: 0 var(--space-2);
		display: flex;
		flex-direction: column;
		gap: var(--space-1);
		font-size: var(--text-7);
	}

	.send-tasks-list .send-task-number {
		font-variant-numeric: tabular-nums;
	}

	@media (width >= 80rem) {
		.task-page [data-pane] > [role="tabpanel"] {
			max-height: 100%;
		}

		.task-page [data-pane] {
			overflow: hidden;
		}

		/* Each panel body scrolls independently below its heading; scrollbar-gutter
		   keeps content from shifting when overflow appears. */
		.task-edit-panel,
		.task-checklists-body,
		.task-related-body,
		.task-files-body,
		.task-members-body,
		.task-emails-body {
			flex: 1;
			overflow-y: auto;
			min-height: 0;
			padding-block-end: var(--space-6);
			scrollbar-width: thin;
			scrollbar-color: var(--border) var(--background);
			scrollbar-gutter: stable;

			&::-webkit-scrollbar {
				inline-size: 4px;
				block-size: 4px;
			}

			&::-webkit-scrollbar-thumb {
				background: var(--border);
				border-radius: var(--radius-full);
			}

			&::-webkit-scrollbar-track {
				background: var(--background);
			}
		}

		/* The card fits its fields and scrolls only when they outgrow the
		   pane. */
		.task-edit-panel {
			flex: 0 1 auto;
			width: 100%;
			margin-inline: 0;
		}

		/* These bodies hold cards flush with their scroll box, which clips
		   what a card draws outside itself: leave room for its --surface-ring
		   (2px under the neobrutalism style). The edit panel is itself the
		   card and keeps its own padding. */
		.task-checklists-body,
		.task-related-body,
		.task-files-body,
		.task-members-body,
		.task-emails-body {
			padding-block-start: var(--space-0_5);
			padding-inline: var(--space-0_5);
		}

	}

	/* The record pages' header (task, board, person): breadcrumb, the
	   record's name, and its actions at the end edge. */
	.record-header {
		margin-block-end: var(--space-4);
		padding-inline: var(--space-3);
	}

	.page-actions {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	/* A pane holding one section shows its name as a label rather than a
	   one-tab strip. It stays a tab list: the drop target for moving
	   sections between panes. */
	.task-page :where([data-pane] > [role="tablist"]:not(:has(> [role="tab"] ~ [role="tab"]))) {
		min-block-size: 0;
		padding: 0;
		background: none;
		box-shadow: none;

		&::before {
			display: none;
		}

		> [role="tab"] {
			padding-inline: 0;
			background: none;
			border-color: transparent;
			box-shadow: none;
			color: var(--foreground);
			font-size: var(--text-6);
			font-weight: var(--font-semibold);
		}
	}

	/* Type roles on the record pages, one per kind of text: group and list
	   headings, help, row titles, meta. */
	.subsection-heading,
	.task-form-group > legend {
		margin: 0;
		padding: 0;
		font-size: var(--text-8);
		font-weight: var(--font-semibold);
		letter-spacing: 0.04em;
		text-transform: uppercase;
		color: var(--muted-foreground);
	}

	/* A legend is not a flex item, so its group's gap stops short of it. */
	.task-form-group > legend {
		margin-block-end: var(--space-3);
	}

	.panel-help {
		margin: 0 0 var(--space-3);
		font-size: var(--text-7);
		color: var(--muted-foreground);
	}

	/* An empty list or section: the gl Empty, sized for a panel. */
	.panel-empty {
		padding: var(--space-5) var(--space-4);
		gap: var(--space-1);
		font-size: var(--text-7);

		> :is(h1, h2, h3, h4, h5, h6) {
			font-size: var(--text-7);
			font-weight: var(--font-semibold);
		}

		> p {
			font-size: var(--text-7);
		}
	}

	/* Adds that open a dialog sit under their list. */
	.panel-add {
		margin-block-start: var(--space-3);
	}

	/* Delete and Remove on rows: full-strength text (muted means disabled),
	   tinted destructive on hover. */
	.row-delete:not(:disabled) {
		color: var(--foreground);

		&:hover {
			color: var(--destructive-text);
			background-color: color-mix(in srgb, var(--destructive) 10%, transparent);
		}
	}

	/* Sections and tab chips animate between panes (match-element names each
	   by identity; the morph keeps their ids), the chips above the panels. */
	.task-page [data-pane] > [role="tabpanel"]:not([hidden]) {
		view-transition-name: match-element;
		view-transition-class: task-section;
	}

	.task-page lw-resizable:where(:not([data-stacked])) > [data-pane] > [role="tablist"] > [role="tab"] {
		view-transition-name: match-element;
		view-transition-class: section-tab;
	}

	::view-transition-group(.task-section) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
		z-index: 0;
	}

	::view-transition-group(.section-tab) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
		z-index: var(--tm-z-vt-front);
	}

	::view-transition-new(.task-section):only-child {
		animation: task-section-enter var(--tm-enter-duration) var(--ease-emphasized) both;
	}

	::view-transition-old(.task-section):only-child {
		animation: task-section-leave var(--tm-leave-duration) var(--tm-ease-leave) both;
	}

	@keyframes task-section-enter {
		from {
			opacity: 0;
			transform: translateY(-6px) scale(0.98);
		}
	}

	@keyframes task-section-leave {
		to {
			opacity: 0;
			transform: scale(0.98);
		}
	}

	@media (prefers-reduced-motion: reduce) {
		::view-transition-group(.task-section),
		::view-transition-old(.task-section),
		::view-transition-new(.task-section),
		::view-transition-group(.section-tab) {
			/* csslint-disable-next-line no-important -- reduced motion: stops the view-transition animations whatever else sets them */
			animation: none !important;
		}
	}

	.task-checklists-body,
	.task-files-body {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
		min-height: 0;
	}

	.task-related-body {
		display: flex;
		flex-direction: column;
		gap: var(--space-3);
		min-height: 0;
	}


	.task-related-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	/* One row style for every list on the record pages (fields, members,
	   addresses, related tasks, recurring series, a person's boards, agents
	   and keys): a bordered row, title first, actions at the end. */
	:is(.vocab-row, .recurring-row, .task-member-row, .board-email-item, .task-related-row, .person-board-row, .people-agent, .people-token) {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		min-block-size: calc(var(--control-height) + var(--space-2));
		padding: var(--space-1) var(--space-3);
		border: var(--border-width) solid var(--border);
		border-radius: var(--radius);
		background: var(--card);
		font-size: var(--text-7);
	}

	.task-related-link {
		flex: 1;
		min-inline-size: 0;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		color: var(--foreground);
		text-decoration: none;
		font-size: var(--text-7);
	}

	.task-related-link:hover {
		text-decoration: underline;
	}

	.task-related-edit {
		margin: 0;
	}

	.task-related-edit select {
		height: 1.75rem;
		font-size: var(--text-8);
	}

	/* The fixed type track keeps the select from squeezing the combobox to
	   nothing in a narrow pane. */
	.task-related-add {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 10rem auto;
		align-items: center;
		gap: var(--space-2);
		margin-block-start: var(--space-2);
	}

	.task-related-add lw-combobox {
		min-inline-size: 0;
	}

	.task-related-add select {
		inline-size: 100%;
		max-inline-size: 100%;
	}

	/* Chat panel: the feed scrolls (lw-chat-scroll pins to the bottom) while the
	   composer stays put at the panel's foot. On mobile the feed is height-capped
	   so the composer stays reachable in the stacked flow. */
	.task-chat-body {
		display: flex;
		flex-direction: column;
		gap: var(--space-3);
		min-height: 0;
	}

	.task-chat-feed {
		min-height: 0;
	}

	.task-chat-feed lw-chat-scroll {
		max-height: 22rem;
		border: var(--border-width) solid var(--border);
		border-radius: var(--radius-large);
		padding: var(--space-4);
		background-color: var(--card);
		scrollbar-gutter: stable;
	}

	@media (width >= 80rem) {
		/* The chat panel fills the grid row height (other panels keep their
		   natural height), and the scroller is sized by the flex chain panel →
		   body → feed — no percentages, so the feed caps at the remaining space
		   and the composer stays pinned at the panel's foot. */
		.task-chat {
			height: 100%;
			padding-block-end: var(--space-4);
			box-sizing: border-box;
		}

		.task-chat-body {
			flex: 1;
		}

		.task-chat-feed {
			flex: 1;
			display: flex;
			flex-direction: column;
		}

		.task-chat-feed lw-chat-scroll {
			flex: 1;
			min-height: 0;
			max-height: none;
			box-sizing: border-box;
		}
	}

	.task-chat-form {
		flex-shrink: 0;
	}

	.activity-card {
		border: var(--border-width) solid var(--border);
		border-radius: var(--radius-large);
		padding: var(--space-3);
		background-color: var(--card);
		cursor: pointer;
	}

	.activity-card-header {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		margin-block-end: var(--space-2);
	}

	.activity-card-subject {
		font-weight: var(--font-semibold);
	}

	.activity-card-excerpt {
		margin: 0;
		color: var(--muted-foreground);
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}

	.activity-message-header {
		display: flex;
		align-items: flex-start;
		gap: var(--space-3);
		margin-block-end: var(--space-4);
	}

	.activity-message-header h3 {
		margin: 0;
	}

	.activity-message-meta {
		margin: 0;
		color: var(--muted-foreground);
		font-size: var(--text-7);
	}

	.activity-message-body {
		white-space: pre-wrap;
		word-break: break-word;
		font-family: inherit;
		font-size: var(--text-regular);
		margin: 0;
		max-height: 50vh;
		overflow: auto;
	}

	.task-emails {
		gap: 0;
	}

	.task-emails-body {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
		min-height: 0;
	}

	.board-email-list {
		list-style: none;
		margin: 0 0 var(--space-3);
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.board-email-item form {
		margin: 0;
		margin-inline-start: auto;
	}

	.board-email-address {
		font-family: var(--font-mono);
	}

	.board-email-empty {
		list-style: none;
	}

	.board-email-add {
		margin-block-start: var(--space-3);
	}

	/* View-transition names come from data-vt-name (boot.js applies them
	   around each transition; no inline style); classes are static. */
	.checklist-card {
		view-transition-class: checklist-card;
		background-color: var(--popover);
		color: var(--popover-foreground);
		border-radius: var(--radius-xlarge);
		box-shadow: var(--surface-ring);
		padding: var(--space-4);
		font-size: var(--text-7);
	}

	.checklist-header {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		margin-block-end: var(--space-3);
		padding-inline: var(--space-2);
	}

	/* Titles and labels are lw-inline-edits: the element takes the row's
	   free space and its display button truncates. */
	.checklist-title,
	.checklist-label {
		flex: 1;
		min-width: 0;

		> [data-inline-edit-display] {
			flex: 1;
			min-width: 0;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
			text-align: start;
		}

		> [data-inline-edit-input] {
			flex: 1;
		}
	}

	.checklist-title {
		font-weight: var(--font-medium);
	}

	.checklist-card[data-collapsed] .checklist-header {
		margin-block-end: 0;
	}

	.checklist-progress {
		flex-shrink: 0;
		display: inline-flex;
		align-items: center;
		gap: var(--space-2);
		font-size: var(--text-8);
		color: var(--muted-foreground);
		font-variant-numeric: tabular-nums;
	}

	.checklist-progress-bar {
		width: 4rem;
		height: 0.5rem;
	}

	.checklist-delete,
	.task-file-delete {
		flex-shrink: 0;
	}

	.checklist-collapse {
		flex-shrink: 0;
		color: var(--muted-foreground);
		background: transparent;
		transition: color var(--duration-fast) var(--ease-standard);

		&:hover {
			color: var(--secondary-foreground);
		}
	}

	.checklist-card:not([data-collapsed]) .checklist-collapse .icon-chevron-up,
	.checklist-card[data-collapsed] .checklist-collapse .icon-chevron-down {
		display: none;
	}

	/* Collapsed checklist: the card height change is animated by the existing
	   checklist-card view transition. */
	.checklist-card[data-collapsed] .checklist-items,
	.checklist-card[data-collapsed] .checklist-add-item-form {
		display: none;
	}

	/* Exclude the checklist panel and its delete dialog from cross-document view
	   transitions so they don't cause the browser to skip the board→task transition. */
	.task-checklists,
	[id="delete-checklist"],
	.task-file-delete-dialog {
		view-transition-name: none;
	}

	/* Excluded from cross-document view transitions like the checklist panel;
	   rows animate individually during SSE morphs. */
	.task-files {
		gap: 0;
		view-transition-name: none;
	}

	/* The confirmation dialog is a popover (top layer); the wrapper just groups it
	   with its lw-item for clean morphing. */
	.task-file-row {
		display: block;
	}

	.task-file-upload {
		display: flex;
		flex-direction: column;
		min-height: 10rem;
	}

	.task-file-upload lw-upload {
		flex: 1;
		justify-content: center;
	}

	.task-file-list {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.task-file-list .item .icon svg {
		display: block;
	}

	.task-file-upload-progress,
	.task-file-progress {
		width: 100%;
		height: 0.5rem;
	}

	.task-file-progress {
		margin-block-start: var(--space-2);
	}

	.task-file-failed p {
		color: var(--destructive);
	}

	.task-members {
		gap: 0;
		view-transition-name: none;
	}

	.task-members-body {
		display: flex;
		flex-direction: column;
		gap: var(--space-4);
		min-height: 0;
	}

	.task-member-add {
		display: flex;
		gap: var(--space-2);
		align-items: center;
		flex-wrap: wrap;
		margin-block-start: var(--space-3);
	}

	.task-member-add select {
		flex: 1;
		min-width: 8rem;
	}

	.task-member-list {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.task-member-row {
		justify-content: space-between;
	}

	.task-member-person strong {
		font-weight: var(--font-medium);
	}

	.task-member-actions {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	.task-member-actions select {
		width: auto;
	}

	.task-member-tier-label {
		color: var(--muted-foreground);
		font-size: var(--text-7);
	}

	::view-transition-group(.checklist-card),
	::view-transition-group(.checklist-item) {
		animation-duration: var(--tm-move-duration);
		animation-timing-function: var(--tm-ease-leave);
	}

	/* Cards and items are lw-sortables (lw-sortable-item rows, gl's handle). */
	.checklist-cards > .lw-sortable-list {
		gap: var(--space-4);
	}

	.checklist-cards:not(:has([data-sortable-item])) {
		display: none;
	}

	.checklist-items {
		min-height: 1.5rem;

		> .lw-sortable-list {
			gap: var(--space-1);
		}

		/* An item dragged over another checklist: only that list's line shows. */
		&[data-cross-drop] > .lw-sortable-indicator {
			display: none;
		}
	}

	/* One compact row (at most 40px) per item. */
	.checklist-item {
		view-transition-class: checklist-item;
		padding: var(--space-1) var(--space-2);
		border-radius: var(--radius);
		background-color: color-mix(in oklab, var(--background) 60%, transparent);
		cursor: default;

		> .lw-sortable-content {
			display: flex;
			align-items: center;
			gap: var(--space-2);
		}

		&:hover {
			background-color: color-mix(
				in oklab,
				var(--background) 100%,
				transparent
			);
		}

		&[data-pending] {
			pointer-events: none;
			opacity: 0.5;
		}
	}

	.checklist-checkbox {
		flex-shrink: 0;
		width: 1rem;
		height: 1rem;
		margin: 0;
		cursor: pointer;
	}

	.checklist-label.completed > [data-inline-edit-display] {
		text-decoration: line-through;
		color: var(--muted-foreground);
	}

	.checklist-item .checklist-delete {
		flex-shrink: 0;
		color: var(--muted-foreground);
		opacity: 0;
		transition: opacity var(--transition-fast);

		&:hover {
			color: var(--destructive);
		}
	}

	.checklist-item:hover .checklist-delete,
	.checklist-item:focus-within .checklist-delete {
		opacity: 1;
	}

	.checklist-drop-indicator {
		height: var(--border-width-thick);
		border-radius: var(--radius-full);
		background-color: var(--ring);
		pointer-events: none;
	}

	.checklist-add-item,
	.checklist-add-checklist {
		margin-block-start: var(--space-3);
	}

	.checklist-add-error {
		margin-block-start: var(--space-2);
		font-size: var(--text-8);
		color: var(--destructive);
	}

	.checklist-add-item-form,
	.checklist-add-checklist-form {
		margin: 0;
	}

	/* Pending checklist card (ChecklistManager's data-pending). */
	.checklist-card[data-pending] {
		pointer-events: none;
		opacity: 0.6;
	}

	.task-file-meta {
		margin: 0;
		font-size: var(--text-8);
		color: var(--muted-foreground);
	}

	/* Login page: layout only; all chrome comes from the design system. */
	.login-body {
	  min-height: 100vh;
	  display: flex;
	  align-items: center;
	  justify-content: center;
	  background: var(--muted);
	}

	.login-main {
	  width: 100%;
	  display: flex;
	  justify-content: center;
	  padding: var(--space-4);
	}

	.login-stack {
	  width: 100%;
	  max-width: 24rem;
	  display: flex;
	  flex-direction: column;
	  gap: var(--space-4);
	}

	.login-brand {
	  text-align: center;
	  font-weight: var(--font-semibold);
	  font-size: var(--text-4);
	  color: var(--foreground);
	}

	.login-error {
	  margin: var(--space-3) 0 0;
	  color: var(--destructive);
	  font-size: var(--text-7);
	  text-align: center;
	}

	/* Visible only while focused: the first stop for keyboard users. */
	.skip-link {
		position: absolute;
		inset-inline-start: var(--space-2);
		inset-block-start: var(--space-2);
		z-index: var(--z-modal);
		padding: var(--space-2) var(--space-3);
		border-radius: var(--radius-medium);
		background: var(--background);
		color: var(--foreground);
		box-shadow: var(--shadow-medium);
		translate: 0 calc(-100% - var(--space-4));

		&:focus-visible {
			translate: none;
		}
	}

	.app-nav-menu {
		display: none;
	}

	.app-nav-sheet-links {
		display: flex;
		flex-direction: column;
		gap: var(--space-1);
		padding-block-start: var(--space-8);

		.button {
			justify-content: flex-start;
		}
	}

	/* Nav links are lw link buttons (a.button + variant classes); layout only. */
	.app-nav-left {
		justify-self: start;
		display: flex;
		align-items: center;
		gap: var(--space-3);
	}

	.app-nav-links {
		display: flex;
		align-items: center;
		gap: var(--space-1);
	}

	/* Phones: links in the sheet, search as an icon button, three columns
	   that fit 360px. */
	@media (width <= 48rem) {
		.app-nav-inner {
			grid-template-columns: auto 1fr auto;
			gap: var(--space-2);
		}

		.app-nav-links {
			display: none;
		}

		.app-nav-menu {
			display: inline-flex;
		}

		.app-nav-center {
			justify-self: end;
			width: auto;
			min-width: 0;
		}

		.app-nav-search {
			min-inline-size: var(--control-height);
			padding-inline: var(--space-2);

			:is(.app-nav-search-text, kbd) {
				display: none;
			}
		}
	}

	/* Directory pages (People, Queues). */
	.boards-page {
		display: flex;
		flex-direction: column;
		gap: var(--space-6);
		padding-block-start: var(--space-4);
	}

	.board-list-name {
		color: var(--foreground);
		text-decoration: none;
	}

	.board-list-name:hover {
		text-decoration: underline;
	}

	.queues-page {
		display: flex;
		flex-direction: column;
		gap: var(--space-6);
		padding-block-start: var(--space-4);
	}

	.queue-section {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	/* Closed queues show only while the action bar's Show closed switch is on
	   (its checked state is client-owned; a morph leaves it alone). */
	main:has([data-show-closed]:not(:checked)) .queue-section[data-queue-status="closed"] {
		display: none;
	}

	.queue-grid {
		display: grid;
		grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
		gap: var(--space-3);
	}

	/* The card chrome (background, radius, ring/shadow, padding, rhythm) comes from
	   gl's .card component; only the directory-specific child layout lives here. */
	.queue-card-head {
		display: flex;
		align-items: flex-start;
		justify-content: space-between;
		gap: var(--space-2);
	}

	.queue-card-title {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		flex-wrap: wrap;
		min-width: 0;
	}

	.queue-card-title .board-list-name {
		font-weight: var(--font-medium);
	}

	.queue-card-foot {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--space-2);
		margin-block-start: auto;
	}

	.queues-empty {
		margin: 0;
		padding: var(--space-2) var(--space-3);
	}

	.template-vocab-label {
		color: var(--muted-foreground);
		white-space: nowrap;
	}

	.template-vocab-value {
		color: var(--foreground);
	}

	.template-vocab-pills {
		display: flex;
		flex-wrap: wrap;
		gap: var(--space-1);
	}

	.templates-empty {
		margin: 0;
		padding: var(--space-2) var(--space-3);
	}


	/* Task list page: lw-table and lw-filter-bar style the table, its sort,
	   selection and column drag, and the facet bar; only the page layout
	   lives here. */
	.task-list-page {
		padding-block-start: var(--space-4);
		padding-inline: var(--container-pad);
	}

	.task-list-toolbar {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: var(--space-3);
		flex-wrap: wrap;
	}

	/* The inline size too: the centered toolbar sizes to its content, and a
	   flex basis alone doesn't count there, so the last facet wrapped. */
	.task-list-filter > input[type="search"] {
		flex: 0 1 16rem;
		inline-size: 16rem;
	}

	.task-list-view-actions {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		flex-wrap: wrap;
	}

	.task-list-view-picker {
		width: 12rem;
	}

	/* Indented past the 2.5rem checkbox column (and its cell padding) to start at
	   the first data column. */
	.task-list-status {
		display: flex;
		align-items: center;
		gap: var(--space-3);
		margin-block-start: var(--space-2);
		padding-block-end: var(--space-1);
		padding-inline-start: calc(var(--space-10) + var(--space-2));
	}

	.task-list-table th:first-child,
	.task-list-table td:first-child {
		width: 2.5rem;
		min-width: 2.5rem;
		text-align: center;
		white-space: nowrap;
	}

	.task-list-table input[data-table-select-row]:disabled {
		cursor: not-allowed;
	}

	/* Editable cells on the list page show an affordance for the double-click
	   bulk-edit dialog. */
	.task-list-table td[data-field] {
		cursor: pointer;
	}

	.task-list-table td[data-field]:hover {
		background-color: light-dark(
			rgb(from var(--primary) r g b / 0.03),
			rgb(from var(--primary) r g b / 0.06)
		);
	}

	.task-list-link {
		color: var(--foreground);
		text-decoration: none;
	}

	.task-list-link:hover {
		text-decoration: underline;
	}

	.task-list-number {
		font-size: var(--text-7);
	}

	.delete-confirm-desc {
		margin: 0 0 var(--space-3);
	}

	.delete-board-modes {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
		margin-block: var(--space-2);
	}

	.delete-board-modes label {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	.vocab-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: var(--space-1);
	}

	.vocab-row.dragging {
		opacity: 0.5;
	}

	.vocab-drag-handle {
		cursor: grab;
		touch-action: none;
	}

	.vocab-swatch {
		inline-size: var(--icon-size-sm);
		block-size: var(--icon-size-sm);
	}

	/* Name, default badge and count wrap as a group on a narrow pane, so
	   the name keeps its width and the actions stay on the first line. */
	.vocab-main {
		flex: 1 1 auto;
		min-inline-size: 0;
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		column-gap: var(--space-2);
		row-gap: var(--space-0_5);
	}

	.vocab-name {
		flex: 0 1 auto;
		min-inline-size: 0;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		font-size: var(--text-7);
		font-weight: var(--font-medium);
	}

	.vocab-default {
		flex: 0 0 auto;
	}

	.vocab-count {
		flex: 0 0 auto;
		margin-inline-start: var(--space-1);
		white-space: nowrap;
		font-size: var(--text-8);
	}

	.board-fields {
		display: flex;
		flex-direction: column;
		gap: var(--space-6);
	}

	.vocab-panel {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.vocab-actions {
		flex: 0 0 auto;
		margin-inline-start: auto;
		display: flex;
		align-items: center;
		gap: var(--space-1);
	}

	.vocab-add {
		margin-block-start: var(--space-1);
	}

	.vocab-empty {
		list-style: none;
	}

	.vocab-drop-indicator {
		height: 2px;
		background: var(--primary);
		border-radius: var(--radius-full);
		margin: var(--space-1) 0;
	}

	.app-nav-avatar {
		display: inline-flex;
		align-items: center;
		border-radius: var(--radius-full);
		text-decoration: none;
	}

	/* Person record page: read-only details for plain directory viewers. */
	.person-detail-list {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.person-detail-row {
		display: flex;
		align-items: baseline;
		gap: var(--space-2);
	}

	.person-board-list {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.person-board-row {
		justify-content: space-between;
	}

	.people-agent-list,
	.people-token-list {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.people-agent,
	.people-token {
		justify-content: space-between;
	}

	.recurring-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}



	.recurring-main {
		display: flex;
		flex-direction: column;
		gap: var(--space-0_5);
		min-width: 0;
	}

	.recurring-name {
		font-weight: var(--font-medium);
	}

	.recurring-meta {
		display: block;
	}

	.recurring-actions {
		margin-inline-start: auto;
		display: flex;
		align-items: center;
		gap: var(--space-1);
	}

	.recurring-empty {
		list-style: none;
	}

	.recurring-frequency {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	.recurring-frequency input {
		width: 5rem;
	}

	.recurring-toggle {
		margin-block: var(--space-2);
	}

	/* Checklist templates reuse the task page's checklist markup/styles. The
	   wrapper is task-checklist-templates (not task-checklists) so the task page's
	   ChecklistManager never attaches to the template panel. */
	.task-checklist-templates {
		gap: 0;
	}

	.checklist-template-picker {
		display: flex;
		flex-direction: column;
		gap: var(--space-2);
	}

	.checklist-template-toggle {
		display: flex;
		align-items: center;
		gap: var(--space-2);
	}

	/* --- Charts (charts.go) ------------------------------------------ */

	.dashboard {
		display: grid;
		grid-template-columns: repeat(12, minmax(0, 1fr));
		gap: var(--space-4);
		inline-size: 100%;
		max-inline-size: var(--tm-dashboard-max);
		margin-inline: auto;
		padding-inline: var(--space-4);
		padding-block-end: var(--space-8);

		> * {
			grid-column: span 12;
			min-inline-size: 0;
		}

		> [data-span="4"] {
			grid-column: span 4;
		}

		> [data-span="5"] {
			grid-column: span 5;
		}

		> [data-span="6"] {
			grid-column: span 6;
		}

		> [data-span="7"] {
			grid-column: span 7;
		}

		> [data-span="8"] {
			grid-column: span 8;
		}

		@media (width < 64rem) {
			> [data-span] {
				grid-column: span 12;
			}
		}
	}

	.chart-card {
		min-inline-size: 0;

		> footer.chart-note {
			font-size: var(--text-8);
			color: var(--muted-foreground);
		}
	}

	.chart-empty {
		padding-block: var(--space-6);
		text-align: center;
		font-size: var(--text-7);
		color: var(--muted-foreground);
	}

	.stat-row {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
		gap: var(--space-4);
	}

	.stat-tile {
		display: grid;
		align-content: start;
		gap: var(--space-1);
		padding: var(--space-4);
		border: var(--border-width) solid var(--border);
		border-radius: var(--radius-large);
		background: var(--card);
		color: var(--card-foreground);
		text-decoration: none;
		min-inline-size: 0;
	}

	a.stat-tile:hover {
		border-color: var(--ring);
	}

	.stat-tile-label {
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		color: var(--muted-foreground);
	}

	.stat-tile-value {
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: var(--space-2);
		font-size: var(--text-3);
		font-weight: var(--font-semibold);
		line-height: var(--leading-none);
	}

	.stat-tile-detail {
		font-size: var(--text-8);
		font-weight: var(--font-normal);
		color: var(--muted-foreground);
	}

	.stat-tile[data-tone="bad"] .stat-tile-detail {
		color: var(--destructive);
	}

	.sparkline {
		display: block;
		inline-size: 100%;
		block-size: 1.75rem;
		margin-block-start: var(--space-1);
		overflow: visible;
	}

	.sparkline-line {
		fill: none;
		stroke: var(--tm-colour-blue);
		stroke-width: 1.5;
		stroke-linejoin: round;
	}

	.sparkline-area {
		fill: color-mix(in oklab, var(--tm-colour-blue) 14%, transparent);
	}

	.chart-rows {
		display: grid;
		grid-template-columns: minmax(6rem, var(--tm-chart-label)) minmax(0, 1fr) max-content;
		align-items: center;
		column-gap: var(--space-3);
		row-gap: var(--space-3);
		font-size: var(--text-7);
	}

	.chart-row {
		display: contents;
	}

	.chart-row-label {
		min-inline-size: 0;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;

		> a {
			color: inherit;
		}

		> small {
			display: block;
			font-size: var(--text-8);
			color: var(--muted-foreground);
			white-space: normal;
		}
	}

	.chart-row-value {
		font-size: var(--text-8);
		color: var(--muted-foreground);
		font-variant-numeric: tabular-nums;
		text-align: end;
	}

	.bullet,
	.diverging {
		display: block;
		inline-size: 100%;
		block-size: 0.875rem;
		overflow: visible;
	}

	.bullet-track {
		fill: var(--muted);
	}

	.bullet-done {
		fill: var(--tm-colour-blue);
	}

	.bullet-tick {
		stroke: var(--foreground);
		stroke-width: 2;
	}

	.diverging-neg {
		fill: var(--tm-chart-behind);
	}

	.diverging-pos {
		fill: var(--tm-chart-ahead);
	}

	.diverging-axis {
		stroke: var(--muted-foreground);
		stroke-width: 1;
	}

	.chart-legend {
		display: flex;
		flex-wrap: wrap;
		gap: var(--space-1) var(--space-4);
		margin-block-start: var(--space-3);
		font-size: var(--text-8);
		color: var(--muted-foreground);

		> li {
			display: inline-flex;
			align-items: center;
			gap: var(--space-1_5);
		}
	}

	.chart-legend-key {
		inline-size: 0.625rem;
		block-size: 0.625rem;
		border-radius: var(--radius-small);
		background: var(--swatch, var(--foreground));
	}

	.chart-pill {
		display: inline-flex;
		align-items: center;
		padding: var(--space-0_5) var(--space-2);
		border-radius: var(--radius-full);
		font-size: var(--text-8);
		font-weight: var(--font-medium);
		white-space: nowrap;
		color: var(--swatch-text, var(--muted-foreground));
		background: color-mix(in oklab, var(--swatch, var(--muted-foreground)) 15%, transparent);
	}

	.insights-summary {
		font-size: var(--text-7);
		color: var(--muted-foreground);
	}

	.stat-stack {
		display: grid;
		gap: var(--space-3);

		> .stat-tile {
			padding: var(--space-3);
		}
	}

	.diverging-key-neg {
		background: var(--tm-chart-behind);
	}

	.diverging-key-pos {
		background: var(--tm-chart-ahead);
	}

	.project-card-stats {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--space-1) var(--space-3);
		margin-block-start: var(--space-2);
		font-size: var(--text-8);
		color: var(--muted-foreground);

		b {
			font-weight: var(--font-semibold);
			color: var(--foreground);
		}
	}

	.queue-card-stats {
		display: flex;
		flex-wrap: wrap;
		gap: var(--space-1) var(--space-3);
		font-size: var(--text-8);
		color: var(--muted-foreground);
		margin-block-start: var(--space-2);

		b {
			font-weight: var(--font-semibold);
			color: var(--foreground);
		}
	}
}
