/*
 * ui-lib.css
 * Stylesheet for the widgets added to ui-lib.pl: page header, grids,
 * cards, stat tiles, description lists, badges, chips, lists, activity
 * feeds, empty states, progress bars, toggles, search boxes and the
 * boxed choice, radio list and select switch widgets.
 *
 * Widgets use their own classes, with shared spacing and margin resets
 * inside .ui_page. Existing tabs, forms, tables and buttons retain their
 * theme styling. Widgets use the theme's --font-family and
 * --font-family-mono when defined, otherwise text inherits the page font
 * and code uses the monospace fallback below.
 *
 * The .ui_page wrapper emitted by ui_page_start supplies the widget tokens.
 * The palette and shared spacing come from --ui-* custom properties,
 * which a theme may redefine on .ui_page to restyle every
 * widget at once. Setting data-ui-scheme="dark" (or "auto") on any
 * ancestor switches to the built-in dark palette.
 */

.ui_page {
	/* Palette tokens read the theme's own custom properties first - the
	 * names Authentic defines for its palettes and night mode - and
	 * fall back to the colors of the gray theme, which defines only the
	 * four --text-color-* state colors itself. */

	/* Core palette */
	--ui-canvas: var(--bg-color, #f2f3f5);
	--ui-surface: var(--main-content, #ffffff);
	--ui-surface-2: var(--bg-table-header, #f5f5f5);
	--ui-border: var(--border-color, #d7dbe0);
	--ui-border-soft: var(--border-color-light, #e8eaee);
	--ui-border-strong: var(--border-color-darker, #b3bac2);
	--ui-fg: var(--text-color, #212121);
	--ui-fg-muted: var(--text-color-muted, #4b5563);

	/* Accent */
	--ui-accent: var(--link-color, #0b46ab);
	--ui-accent-soft: var(--element-highlight-bg-color, #e8f1fb);
	--ui-ring: var(--border-color-focused, rgba(11, 70, 171, 0.25));

	/* States. The base color is used for icons, dots and bars; the
	 * -text variant is a darker shade for text sitting on the -soft
	 * background, as in badges. */
	--ui-success: var(--text-color-success, #3c763d);
	--ui-success-text: var(--text-color-success-stressed, #1e4f18);
	--ui-success-soft: var(--bg-color-success, #edf7e7);
	--ui-success-line: var(--border-color-success, #b9e0a4);
	--ui-warning: var(--text-color-warning, #b58900);
	--ui-warning-text: var(--text-color-warning-stressed, #795600);
	--ui-warning-soft: var(--bg-color-warning, #fdf4d8);
	--ui-warning-line: var(--border-color-warning, #eed483);
	--ui-danger: var(--text-color-danger, #bc0303);
	--ui-danger-text: var(--text-color-danger-stressed, #7d1007);
	--ui-danger-soft: var(--bg-color-danger, #fbeae8);
	--ui-danger-line: var(--border-color-danger, #f2bcb6);
	--ui-info: var(--text-color-info, #108eda);
	--ui-info-text: var(--text-color-info-stressed, #00477e);
	--ui-info-soft: var(--bg-color-info, #e8f1fb);
	--ui-info-line: var(--border-color-info, #b8d6f2);
	--ui-neutral: var(--text-color-muted, #4b5563);
	--ui-neutral-text: var(--text-color-neutral-stressed, #40474f);
	--ui-neutral-soft: var(--bg-color-neutral, #eff1f3);
	--ui-neutral-line: var(--border-color-neutral, #d7dbe0);

	/* Controls */
	--ui-toggle-bg: var(--toggle-bg-color, var(--ui-border-strong));
	--ui-toggle-bg-checked: var(--toggle-bg-color-checked, var(--ui-accent));
	--ui-toggle-thumb: var(--toggle-thumb-color, #ffffff);

	/* Shape and rhythm. Boxed widgets have square corners; dots,
	 * activity markers, ring gauges and toggles use circles or rounded tracks. */
	--ui-gap: 7px;
	/* Shared inset for boxed choice widgets: padding, option spacing,
	 * vertical field gaps and gaps between labels and inputs */
	--ui-inset: 5px;
	/* Where the label text starts after a theme radio, so descriptions
	 * and fields line up under it */
	--ui-radio-indent: 1.6em;

	/* Fonts. A theme that defines --font-family and --font-family-mono
	 * (Authentic does) sets the widgets' text and code fonts with them;
	 * otherwise text inherits the page font and code uses the system
	 * monospace stack. */
	--ui-font: var(--font-family, inherit);
	--ui-font-mono: var(--font-family-mono, ui-monospace, SFMono-Regular,
		"SF Mono", Menlo, Consolas, "Liberation Mono", monospace);

	color-scheme: light;
	color: var(--ui-fg);
	font-family: var(--ui-font);
	text-align: left;
}

/* Built-in dark palette, enabled with data-ui-scheme="dark" on any
 * ancestor element (or on the .ui_page wrapper itself, via the scheme
 * option of ui_page_start). With data-ui-scheme="auto" the dark
 * palette follows the browser's prefers-color-scheme setting instead.
 * The two blocks below must be kept identical. */
[data-ui-scheme="dark"] .ui_page,
.ui_page[data-ui-scheme="dark"] {
	--ui-canvas: #15171b;
	--ui-surface: #1e2126;
	--ui-surface-2: #23262c;
	--ui-border: #363b43;
	--ui-border-soft: #2a2f36;
	--ui-border-strong: #4d545e;
	--ui-fg: #e6e8ea;
	--ui-fg-muted: #99a3ae;
	--ui-accent: #5aa2ec;
	--ui-accent-soft: rgba(90, 162, 236, 0.14);
	--ui-ring: rgba(90, 162, 236, 0.35);
	--ui-success: #7ec563;
	--ui-success-text: #8fd376;
	--ui-success-soft: rgba(126, 197, 99, 0.13);
	--ui-success-line: rgba(126, 197, 99, 0.4);
	--ui-warning: #e0a63c;
	--ui-warning-text: #eab54f;
	--ui-warning-soft: rgba(224, 166, 60, 0.13);
	--ui-warning-line: rgba(224, 166, 60, 0.4);
	--ui-danger: #ef7b6f;
	--ui-danger-text: #f28c82;
	--ui-danger-soft: rgba(239, 123, 111, 0.13);
	--ui-danger-line: rgba(239, 123, 111, 0.4);
	--ui-info: #5aa2ec;
	--ui-info-text: #78b3ef;
	--ui-info-soft: rgba(90, 162, 236, 0.13);
	--ui-info-line: rgba(90, 162, 236, 0.4);
	--ui-neutral: #aeb6bf;
	--ui-neutral-text: #b6bec7;
	--ui-neutral-soft: #272b31;
	--ui-neutral-line: #3c424b;
	color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
	[data-ui-scheme="auto"] .ui_page,
	.ui_page[data-ui-scheme="auto"] {
		--ui-canvas: #15171b;
		--ui-surface: #1e2126;
		--ui-surface-2: #23262c;
		--ui-border: #363b43;
		--ui-border-soft: #2a2f36;
		--ui-border-strong: #4d545e;
		--ui-fg: #e6e8ea;
		--ui-fg-muted: #99a3ae;
		--ui-accent: #5aa2ec;
		--ui-accent-soft: rgba(90, 162, 236, 0.14);
		--ui-ring: rgba(90, 162, 236, 0.35);
		--ui-success: #7ec563;
		--ui-success-text: #8fd376;
		--ui-success-soft: rgba(126, 197, 99, 0.13);
		--ui-success-line: rgba(126, 197, 99, 0.4);
		--ui-warning: #e0a63c;
		--ui-warning-text: #eab54f;
		--ui-warning-soft: rgba(224, 166, 60, 0.13);
		--ui-warning-line: rgba(224, 166, 60, 0.4);
		--ui-danger: #ef7b6f;
		--ui-danger-text: #f28c82;
		--ui-danger-soft: rgba(239, 123, 111, 0.13);
		--ui-danger-line: rgba(239, 123, 111, 0.4);
		--ui-info: #5aa2ec;
		--ui-info-text: #78b3ef;
		--ui-info-soft: rgba(90, 162, 236, 0.13);
		--ui-info-line: rgba(90, 162, 236, 0.4);
		--ui-neutral: #aeb6bf;
		--ui-neutral-text: #b6bec7;
		--ui-neutral-soft: #272b31;
		--ui-neutral-line: #3c424b;
		color-scheme: dark;
	}
	body[data-ui-scheme="auto"]:has(.ui_page),
	[data-ui-scheme="auto"] body:has(.ui_page),
	body:has(.ui_page[data-ui-scheme="auto"]) {
		background: var(--ui-canvas, #15171b);
	}
}

/* Paint the page canvas behind widget pages. Themes can override the
 * color by defining --ui-canvas on :root or body. */
body:has(.ui_page) {
	background: var(--ui-canvas, var(--bg-color, #f2f3f5));
}
body[data-ui-scheme="dark"]:has(.ui_page),
[data-ui-scheme="dark"] body:has(.ui_page),
body:has(.ui_page[data-ui-scheme="dark"]) {
	background: var(--ui-canvas, #15171b);
}

/* ---- Spacing between blocks ----
 * Top-level blocks are spaced by the page area. Inside any other wrapper
 * (a tab panel, a table cell) a widget that follows a sibling, and
 * whatever follows a widget, get the same gap, so rows of cards and the
 * forms between them line up whatever the theme wraps them in.
 * Children of grids, stacks, clusters and stat rows use their own gaps. */

.ui_page > * + * { margin-top: var(--ui-gap); }
.ui_page :not(.ui_grid, .ui_stack, .ui_cluster, .ui_stats) >
	* + :is(.ui_grid, .ui_stack, .ui_card, .ui_empty),
.ui_page :not(.ui_grid, .ui_stack, .ui_cluster, .ui_stats) >
	:is(.ui_grid, .ui_stack, .ui_card, .ui_empty) + * {
	margin-top: var(--ui-gap);
}
.ui_page [hidden] { display: none !important; }

/* Widgets size their boxes including padding and borders */
.ui_page_head, .ui_grid, .ui_stack, .ui_cluster,
.ui_card, .ui_card *, .ui_stats, .ui_stat, .ui_stat *,
.ui_dl, .ui_dl *, .ui_badge, .ui_chip, .ui_list, .ui_list *,
.ui_feed, .ui_feed *, .ui_empty, .ui_empty *, .ui_progress,
.ui_progress *, .ui_toggle, .ui_toggle *,
.ui_search, .ui_search * {
	box-sizing: border-box;
}
.ui_page h1, .ui_page h2, .ui_page p, .ui_page dl, .ui_page dd { margin: 0; }
.ui_page svg.ui_svg_icon { flex-shrink: 0; vertical-align: -0.18em; }

/* Plain links inside widget text are underlined so they still read as
 * links next to chips and badges. Theme buttons made of ui_link are not. */
.ui_dl_row dd a:not(.ui_link), .ui_feed_text a:not(.ui_link),
.ui_list_desc a:not(.ui_link), .ui_empty_desc a:not(.ui_link),
.ui_card_desc a:not(.ui_link) {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

/* ---- Utilities ---- */

.ui_push { margin-left: auto; }
.ui_code {
	font-family: var(--ui-font-mono);
	font-size: 0.92em;
	background: var(--ui-neutral-soft);
	border: 1px solid var(--ui-border-soft);
	padding: 1px 5px;
}
.ui_code_block {
	font-family: var(--ui-font-mono);
	font-size: 0.92em;
	line-height: 1.5;
	background: var(--ui-surface-2);
	border: 1px solid var(--ui-border-soft);
	padding: 10px 12px;
	margin: 0;
	overflow: auto;
	white-space: pre;
	color: var(--ui-fg);
}
.ui_fg_success { color: var(--ui-success); }
.ui_fg_warning { color: var(--ui-warning); }
.ui_fg_danger { color: var(--ui-danger); }
.ui_fg_info { color: var(--ui-info); }
.ui_fg_neutral { color: var(--ui-neutral); }
.ui_bg_success { background: var(--ui-success); }
.ui_bg_warning { background: var(--ui-warning); }
.ui_bg_danger { background: var(--ui-danger); }
.ui_bg_info { background: var(--ui-info); }
.ui_bg_neutral { background: var(--ui-neutral); }

/* ---- Page header ---- */

.ui_page_head {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 10px 24px;
	flex-wrap: wrap;
	margin: 4px 0 2px;
}
.ui_page_title {
	font-size: 1.85em;
	font-weight: 650;
	letter-spacing: -0.015em;
	line-height: 1.2;
}
.ui_page_titles {
	flex: 1 1 auto;
	min-width: 0;
}
.ui_page_desc {
	color: var(--ui-fg-muted);
	margin-top: 4px;
}
.ui_page_actions {
	display: flex;
	align-items: center;
	gap: 12px;
	padding-top: 7px;
}
.ui_page_help {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-weight: 500;
}

/* ---- Layout primitives ---- */

.ui_grid {
	display: grid;
	gap: var(--ui-gap);
	grid-template-columns: repeat(auto-fit,
		minmax(min(var(--ui-grid-min, 340px), 100%), 1fr));
	align-items: stretch;
}
.ui_grid_fixed {
	grid-template-columns: var(--ui-grid-template,
		repeat(var(--ui-grid-cols, 2), minmax(0, 1fr)));
}
.ui_stack {
	display: flex;
	flex-direction: column;
	gap: var(--ui-gap);
}
.ui_cluster {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: calc(var(--ui-gap) / 2) var(--ui-gap);
}
.ui_cluster { --ui-gap: 10px; }

/* Themes that regroup adjacent submit buttons into one box, as Authentic
 * does with its btn-group, wrap them inside that box with no vertical
 * space. Give those rows a gap while keeping the buttons joined. */
.ui_cluster > .btn-group {
	display: inline-flex;
	flex-wrap: wrap;
	row-gap: 7px;
}
.ui_cluster_center { justify-content: center; }
.ui_cluster_end { justify-content: flex-end; }
.ui_cluster_between { justify-content: space-between; }

@media (max-width: 760px) {
	.ui_grid_fixed { grid-template-columns: 1fr; }
}

/* ---- Cards ---- */

.ui_card {
	background: var(--ui-surface);
	border: 1px solid var(--ui-border);
	display: flex;
	flex-direction: column;
	min-width: 0;
}
.ui_card_success { border-left: 3px solid var(--ui-success); }
.ui_card_warning { border-left: 3px solid var(--ui-warning); }
.ui_card_danger { border-left: 3px solid var(--ui-danger); }
.ui_card_info { border-left: 3px solid var(--ui-info); }
.ui_card_head {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 4px 12px;
	padding: 5px 6px 0 7px;
	flex-wrap: wrap;
}
.ui_card_title {
	font-size: 1.07697em;
	font-weight: 650;
	line-height: 1.3;
}
.ui_card_desc {
	color: var(--ui-fg-muted);
	font-size: 0.93em;
	margin-top: 3px;
}
.ui_card_actions {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
}
.ui_card_body {
	padding: 3px 7px 7px;
	flex: 1;
	min-width: 0;
}
.ui_card_body.ui_card_flush { padding: 1px 0 0; }
.ui_card_head + .ui_card_body.ui_card_flush { padding-top: 3px; }
.ui_card_foot {
	border-top: 1px solid var(--ui-border-soft);
	padding: 5px;
	color: var(--ui-fg-muted);
	font-size: 0.93em;
}

/* ---- Stat tiles ---- */

.ui_stats {
	display: grid;
	gap: 12px 24px;
	grid-template-columns: repeat(auto-fit,
		minmax(min(var(--ui-grid-min, 150px), 100%), 1fr));
}
.ui_stat {
	display: flex;
	flex-direction: column;
	gap: 1px;
	min-width: 0;
	color: inherit;
	text-decoration: none;
}
.ui_stat_value {
	font-size: 1.85em;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: -0.01em;
	display: flex;
	align-items: center;
	gap: 8px;
}
.ui_stat_label { font-weight: 600; }
.ui_stat_desc { color: var(--ui-fg-muted); font-size: 0.9em; }
a.ui_stat, a.ui_stat:hover {
	color: inherit !important;
	text-decoration: none !important;
}
a.ui_stat:hover .ui_stat_value { color: var(--ui-accent); }

/* ---- Description lists ---- */

/* The list is one grid and every row contributes its dt and dd to it, so
 * all labels share a single column sized to the longest label, up to the
 * fraction given by --ui-dl-label. Labels only wrap past that limit. */
.ui_dl {
	display: grid;
	grid-template-columns: var(--ui-dl-label, fit-content(45%)) 1fr;
	gap: 10px 20px;
	align-items: baseline;
}
.ui_dl_cols {
	grid-template-columns:
		repeat(2, var(--ui-dl-label, fit-content(45%)) 1fr);
	column-gap: 24px;
}
.ui_dl_row { display: contents; }
.ui_dl_row dt { font-weight: 600; }
.ui_dl_row dd {
	min-width: 0;
	overflow-wrap: anywhere;
}
@media (max-width: 560px) {
	.ui_dl, .ui_dl_cols { grid-template-columns: 1fr; }
	.ui_dl { row-gap: 2px; }
	.ui_dl_row dd { margin-bottom: 8px; }
}

/* ---- Badges and chips ---- */

.ui_badge {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 2px 10px;
	border: 1px solid transparent;
	font-size: 0.9em;
	font-weight: 600;
	line-height: 1.5;
	vertical-align: middle;
	white-space: nowrap;
}
.ui_badge_success {
	background: var(--ui-success-soft);
	border-color: var(--ui-success-line);
	color: var(--ui-success-text);
}
.ui_badge_warning {
	background: var(--ui-warning-soft);
	border-color: var(--ui-warning-line);
	color: var(--ui-warning-text);
}
.ui_badge_danger {
	background: var(--ui-danger-soft);
	border-color: var(--ui-danger-line);
	color: var(--ui-danger-text);
}
.ui_badge_info {
	background: var(--ui-info-soft);
	border-color: var(--ui-info-line);
	color: var(--ui-info-text);
}
.ui_badge_neutral {
	background: var(--ui-neutral-soft);
	border-color: var(--ui-neutral-line);
	color: var(--ui-neutral-text);
}
.ui_chip {
	display: inline-flex;
	align-items: center;
	padding: 1px 8px;
	background: var(--ui-neutral-soft);
	border: 1px solid var(--ui-border);
	color: var(--ui-neutral-text);
	font-size: 0.86em;
	line-height: 1.5;
	vertical-align: middle;
	white-space: nowrap;
}

/* ---- Lists ---- */

.ui_list { display: flex; flex-direction: column; }
.ui_list_item {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	padding: 5px 0;
	border-bottom: 1px solid var(--ui-border-soft);
}
.ui_list_item:last-child { border-bottom: 0; }
.ui_list_flush .ui_list_item { padding: 5px 6px 5px 7px; }
.ui_list_main { flex: 1; min-width: 0; }
.ui_list_title {
	font-weight: 600;
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	overflow-wrap: anywhere;
}
.ui_list_desc {
	color: var(--ui-fg-muted);
	font-size: 0.93em;
	margin-top: 2px;
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
}
.ui_list_side {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-shrink: 0;
	padding-top: 1px;
}
.ui_list_meta { color: var(--ui-fg-muted); font-size: 0.9em; }
/* Badges in list rows are chip-sized, so they do not outweigh the text */
.ui_list_item .ui_badge {
	padding: 1px 8px;
	gap: 4px;
	font-size: 0.86em;
}
.ui_list_item .ui_badge .ui_svg_icon { width: 1em; height: 1em; }
/* Description text is 0.93em, so badges and chips inside it are scaled
 * back by that much to match the ones next to the title */
.ui_list_desc :is(.ui_badge, .ui_chip) { font-size: calc(0.86em / 0.93); }
.ui_list_icon { padding-top: 2px; color: var(--ui-fg-muted); }
a.ui_list_link, a.ui_list_link:hover {
	color: inherit !important;
	text-decoration: none !important;
}
a.ui_list_link:hover { color: var(--ui-accent) !important; }

/* ---- Activity feed ---- */

.ui_feed { display: flex; flex-direction: column; }
.ui_feed_item {
	position: relative;
	padding: 0 0 16px 20px;
	border-left: 2px solid var(--ui-border-soft);
	margin-left: 5px;
}
.ui_feed_item:last-child { padding-bottom: 2px; }
.ui_feed_item::before {
	content: "";
	position: absolute;
	left: -6px;
	top: 4px;
	width: 10px;
	height: 10px;
	border-radius: 999px;
	background: var(--ui-border-strong);
	border: 2px solid var(--ui-surface);
}
.ui_feed_success::before { background: var(--ui-success); }
.ui_feed_warning::before { background: var(--ui-warning); }
.ui_feed_danger::before { background: var(--ui-danger); }
.ui_feed_info::before { background: var(--ui-info); }
.ui_feed_when { font-weight: 600; font-size: 1em; }
.ui_feed_text { color: var(--ui-fg-muted); font-size: 0.93em; margin-top: 1px; }
.ui_feed_flush { padding: 3px 19px 7px; }

/* ---- Empty states ---- */

.ui_empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	padding: 1px 7px 7px;
	text-align: center;
}
.ui_empty_icon { color: var(--ui-border-strong); margin-bottom: 2px; }
.ui_empty_title { font-weight: 600; font-size: 1.04em; }
.ui_empty_desc {
	color: var(--ui-fg-muted);
	font-size: 0.93em;
	max-width: 46ch;
}
.ui_empty_actions { margin-top: 6px; }

/* ---- Progress ---- */

.ui_progress_head {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	font-size: 0.93em;
	font-weight: 600;
	margin-bottom: 6px;
}
.ui_progress_value { color: var(--ui-fg-muted); font-weight: 400; }
.ui_progress_track {
	display: flex;
	height: 4px;
	background: var(--ui-neutral-soft);
	overflow: hidden;
}
.ui_progress_bar {
	height: 100%;
	flex-shrink: 0;
	transition: width 0.4s ease;
}

/* Inline layout : label, bar and value on one line */
.ui_progress_inline {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 0.93em;
}
.ui_progress_inline .ui_progress_label {
	font-weight: 600;
	white-space: nowrap;
}
.ui_progress_inline .ui_progress_track { flex: 1 1 auto; }
.ui_progress_inline .ui_progress_value {
	min-width: 3em;
	text-align: right;
	white-space: nowrap;
}

/* Value shown as a small marker riding on the end of the bar, which
 * keeps the same height as every other bar */
.ui_progress_inside .ui_progress_track { overflow: visible; }
.ui_progress_inside .ui_progress_bar { position: relative; }
.ui_progress_inside_value {
	position: absolute;
	top: 50%;
	left: 100%;
	transform: translate(-50%, -50%);
	padding: 1px 4px;
	/* The bar's own color, lightened by a white veil, with dark text */
	background: inherit;
	background-image: linear-gradient(rgba(255, 255, 255, 0.6),
					  rgba(255, 255, 255, 0.6));
	color: #1c1c1c;
	font-size: 0.75em;
	font-weight: 600;
	line-height: 1.2;
	white-space: nowrap;
}
.ui_progress_inside_start .ui_progress_inside_value {
	transform: translate(0, -50%);
}
.ui_progress_inside_end .ui_progress_inside_value {
	transform: translate(-100%, -50%);
}

/* Legend under a segmented bar */
.ui_progress_legend {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 16px;
	margin-top: 6px;
	font-size: 0.9em;
}
.ui_progress_key {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.ui_progress_dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
}

/* Unknown progress : a bar sliding along the track */
.ui_progress_indeterminate .ui_progress_bar {
	width: 35%;
	animation: ui_progress_slide 1.4s ease-in-out infinite;
}
@keyframes ui_progress_slide {
	from { transform: translateX(-100%); }
	to { transform: translateX(300%); }
}
@media (prefers-reduced-motion: reduce) {
	.ui_progress_indeterminate .ui_progress_bar {
		width: 100%;
		animation: none;
		opacity: 0.6;
		background-image: repeating-linear-gradient(45deg,
			transparent 0 6px, rgba(255, 255, 255, 0.45) 6px 12px);
	}
}

/* Ring gauge : the bar is a circle of circumference 100 whose dash
 * length is the percentage */
.ui_progress_ring {
	display: inline-flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
}
.ui_progress_ring_box {
	position: relative;
	display: inline-block;
	line-height: 0;
}
.ui_progress_ring_svg { transform: rotate(-90deg); }
/* The stroke width is set on the circles by ui_progress, scaled to the
 * ring size so it is always 3 pixels */
.ui_progress_ring_track {
	fill: none;
	stroke: var(--ui-neutral-soft);
}
.ui_progress_ring_bar {
	fill: none;
	stroke: currentColor;
	stroke-linecap: round;
	transition: stroke-dasharray 0.4s ease;
}
.ui_progress_ring.ui_progress_indeterminate .ui_progress_ring_svg {
	animation: ui_progress_spin 1s linear infinite;
}
@keyframes ui_progress_spin {
	from { transform: rotate(-90deg); }
	to { transform: rotate(270deg); }
}
.ui_progress_ring_box .ui_progress_value {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 0.8em;
	font-weight: 600;
	line-height: 1;
	color: var(--ui-fg);
}
.ui_progress_ring .ui_progress_label {
	font-size: 0.85em;
	color: var(--ui-fg-muted);
}

/* ---- Choice lists ----
 * One solid box holding a row per option : the theme's own radio button
 * with its label, the inline inputs beside it, and further fields under
 * them in as many columns as fit, indented under the label. Everything
 * stays visible. */
.ui_choice {
	display: grid;
	gap: var(--ui-inset);
	min-width: 0;
	/* Half the inset above and below, the full inset at the sides */
	padding: calc(var(--ui-inset) / 2) var(--ui-inset);
	border: 1px solid var(--ui-border);
	background: var(--ui-surface);
}
.ui_choice_item { min-width: 0; }
.ui_choice_head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
/* Only the option's own label is bold, not labels of inputs in its content */
.ui_choice_head label:not(.ui_choice_content label) { font-weight: 600; }
.ui_choice_content {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_choice_desc {
	margin-left: var(--ui-radio-indent);
	color: var(--ui-fg-muted);
	font-size: 0.93em;
}
.ui_choice_fields {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
	gap: var(--ui-inset) 20px;
	margin: var(--ui-inset) 0 0 var(--ui-radio-indent);
}
.ui_choice_field {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_choice_field_label { color: var(--ui-fg-muted); }
.ui_choice_field_input { min-width: 0; }
.ui_choice_disabled { opacity: 0.6; }

/* ---- Radio lists ----
 * The compact form : the theme's radio buttons at the left edge of a
 * box, one option per line, an optional input after the label */
.ui_radio_list {
	display: grid;
	gap: var(--ui-inset);
	min-width: 0;
	padding: var(--ui-inset);
	border: 1px solid var(--ui-border);
	background: var(--ui-surface);
}
.ui_radio_list_item {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_radio_list_item label:not(.ui_radio_list_content label) {
	font-weight: 600;
}
.ui_radio_list_content {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_radio_list_disabled { opacity: 0.6; }

/* ---- Select switches ----
 * A select, and under it the block of the chosen option only */
.ui_select_switch {
	display: grid;
	justify-items: start;
	gap: var(--ui-inset);
	min-width: 0;
}
.ui_select_switch_panel {
	display: grid;
	gap: var(--ui-inset);
	width: 100%;
	min-width: 0;
	padding: var(--ui-inset);
	border: 1px solid var(--ui-border);
	background: var(--ui-surface);
}
.ui_select_switch_desc {
	color: var(--ui-fg-muted);
	font-size: 0.93em;
}
.ui_select_switch_content {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_select_switch_fields {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
	gap: var(--ui-inset) 20px;
}
.ui_select_switch_field {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px var(--ui-inset);
	min-width: 0;
}
.ui_select_switch_field_label { color: var(--ui-fg-muted); }
.ui_select_switch_field_input { min-width: 0; }

/* ---- Toggle switch ----
 * Some themes wrap checkbox inputs in their own markup with JavaScript,
 * so the real input - or whatever wrapper it ends up inside - is parked
 * invisibly over the track, where clicks and keyboard focus still reach
 * it, and the checked state is read with :has() which does not depend on
 * the input being the track's sibling. */

.ui_toggle {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	cursor: pointer;
	position: relative;
	font-weight: normal;
}
.ui_toggle > :not(.ui_toggle_track):not(.ui_toggle_label),
.ui_toggle input {
	position: absolute !important;
	left: 0 !important;
	top: 0 !important;
	width: 28px !important;
	height: 14px !important;
	margin: 0 !important;
	padding: 0 !important;
	opacity: 0 !important;
	overflow: hidden;
	z-index: 1;
	cursor: pointer;
}
.ui_toggle_track {
	display: inline-flex;
	align-items: center;
	width: 28px;
	height: 14px;
	padding: 2px;
	border-radius: 999px;
	background: var(--ui-toggle-bg);
	transition: background 0.15s ease;
	flex-shrink: 0;
}
.ui_toggle_thumb {
	width: 10px;
	height: 10px;
	border-radius: 999px;
	background: var(--ui-toggle-thumb);
	box-shadow: 0 1px 2px rgba(16, 24, 40, 0.25);
	transition: transform 0.15s ease;
}
.ui_toggle input:checked ~ .ui_toggle_track,
.ui_toggle:has(input:checked) .ui_toggle_track {
	background: var(--ui-toggle-bg-checked);
}
.ui_toggle input:checked ~ .ui_toggle_track .ui_toggle_thumb,
.ui_toggle:has(input:checked) .ui_toggle_thumb {
	transform: translateX(14px);
}
.ui_toggle input:focus-visible ~ .ui_toggle_track,
.ui_toggle:has(input:focus-visible) .ui_toggle_track {
	box-shadow: 0 0 0 3px var(--ui-ring);
}
.ui_toggle input:disabled ~ .ui_toggle_track,
.ui_toggle:has(input:disabled) .ui_toggle_track { opacity: 0.5; }

/* ---- Search box ---- */

.ui_search {
	position: relative;
	display: inline-flex;
	max-width: 100%;
}
.ui_search .ui_search_icon {
	position: absolute;
	left: 10px;
	top: 50%;
	transform: translateY(-50%);
	color: var(--ui-fg-muted);
	pointer-events: none;
}
.ui_search .ui_search_input {
	padding-left: 30px;
	width: 100%;
	min-width: 0;
	font: inherit;
	color: inherit;
	background: var(--ui-surface);
	border: 1px solid var(--ui-border-strong);
	padding-top: 5px;
	padding-bottom: 5px;
	padding-right: 10px;
}
.ui_search .ui_search_input:focus {
	outline: none;
	border-color: var(--ui-accent);
	box-shadow: 0 0 0 3px var(--ui-ring);
}

/* ---- Reduced motion ---- */

@media (prefers-reduced-motion: reduce) {
	.ui_progress_ring.ui_progress_indeterminate .ui_progress_ring_svg {
		animation: none;
	}
	.ui_page *, .ui_page *::before, .ui_page *::after {
		transition: none !important;
	}
}
