/* Shared components (SU1-01): buttons, fields, disclosure, tables, filters, facts, findings,
	the panel. Linked by base.html after app.css; colours are the tokens of app.css only. No
	shadow or stripe; the only gradients are the table scroll fades and the select chevron
	(SU2-11) and the current tab's signal underline (AI1-07). Controls are 40px at radius 10,
	the panel radius 14 (the Signal look). */

/* Page header (SU1-07, spec 6.8): crumbs, the h1 and its meta line on the left, the page's
	actions on the right; tabs sit under it in the same .page-top. Full-width actions on a phone. */
.page-top { display: grid; gap: var(--space-4); }
.page-header { display: flex; flex-wrap: wrap; align-items: flex-end;
	justify-content: space-between; gap: var(--space-4); }
.page-header-main { display: grid; gap: var(--space-2); min-width: 0; }
/* Document ids are 32 unbreakable hex characters: crumbs wrap them (S4-09c). */
.crumbs { font-size: var(--text-sm); color: var(--muted); overflow-wrap: anywhere; }
.crumbs a, .crumbs a:visited { color: var(--muted); text-decoration: none; }
/* A touch target at least 44px high that moves nothing and keeps the focus ring on the text. */
.crumbs a { position: relative; }
.crumbs a::after { content: ""; position: absolute; inset: calc(-1 * (var(--space-3) + 2px)) 0; }
.crumbs a:hover { color: var(--fg); text-decoration: underline; }
.page-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
	font-size: var(--text-sm); color: var(--muted); }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); width: 100%; }

/* Tabs (spec 6.9; AI1-07): the current tab is in the ink over a 2px signal underline, drawn on
	its ::after over the transparent border; a hovered tab shows the border in the strong line. */
.tabs { display: flex; align-items: flex-end; gap: var(--space-6);
	border-bottom: 1px solid var(--border); overflow-x: auto; }
.tab, .tab:visited { position: relative; padding: var(--space-2) 0; margin-bottom: -1px;
	border-bottom: 2px solid transparent; font-size: var(--text-md); font-weight: 500;
	color: var(--muted); text-decoration: none; white-space: nowrap;
	transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.tab:hover { color: var(--fg); border-bottom-color: var(--border-strong); }
.tab[aria-current="page"] { color: var(--fg); border-bottom-color: transparent; }
.tab[aria-current="page"]::after { content: ""; position: absolute; left: 0; right: 0;
	bottom: -2px; height: 2px; border-radius: 1px; background: var(--grad-signal); }

/* Data tables (spec 6.10) scroll inside a labelled, focusable region instead of widening the
	page on a phone (S4-09c). The edge fades (S4-11) show only while there is more table in
	that direction: the cover layers scroll with the content (background-attachment: local)
	and hide the fixed shadow layers at either end. Not sortable, no sticky header. */
.table-wrap {
	position: relative;
	overflow-x: auto;
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	background:
		linear-gradient(to right, var(--surface) 40%, var(--bg-clear)) left / 2.5rem 100%
			no-repeat local,
		linear-gradient(to left, var(--surface) 40%, var(--bg-clear)) right / 2.5rem 100%
			no-repeat local,
		linear-gradient(to right, var(--edge-shade), var(--edge-clear)) left / 1rem 100%
			no-repeat scroll,
		linear-gradient(to left, var(--edge-shade), var(--edge-clear)) right / 1rem 100%
			no-repeat scroll,
		var(--surface);
}

/* Outside a .stack a table keeps its own space below; inside one the gap spaces it. */
:where(:not(.stack)) > :is(.table-wrap, .data) { margin-bottom: var(--space-8); }
.data { width: 100%; border-collapse: collapse; font-size: var(--text-md); }
.data caption { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border);
	font-size: var(--text-sm); font-weight: 600; text-align: left; }

/* A caption is as wide as its table: cap it at the screen and pin it so it wraps and stays
	readable while the table scrolls under it (S4-11). */
.table-wrap > .data { margin-bottom: 0; }
.table-wrap > .data > caption { position: sticky; left: 0; max-width: calc(100vw - 2rem); }
/* A caption the page's own heading already names is for screen readers only: it takes no band,
	and the region (position: relative above) contains it so it never widens a phone page. */
.table-wrap > .data > caption.visually-hidden { position: absolute; padding: 0; border: 0; }
.data th, .data td { padding: 0.625rem 0.75rem; text-align: left; vertical-align: middle;
	border-bottom: 1px solid var(--border); }
.data thead th { padding: 0.5rem 0.75rem; font-size: var(--text-xs); font-weight: 600;
	color: var(--muted); background: var(--tint); white-space: nowrap; }
.data tbody tr:last-child > * { border-bottom: 0; }
.data tbody tr:hover td { background: var(--tint); }
.data tr.is-current td { background: var(--accent-bg); }

/* S6-07: counts and rates read down the column, right-aligned and tabular. SC2-02: a long
	numeric header wraps so the calibration table fits at 1280px; its values do not. */
.data th.num, .data td.num { text-align: right; font-variant-numeric: tabular-nums; }
.data th.num { white-space: normal; vertical-align: bottom; }
.data td.num { white-space: nowrap; }
.data td.stamp { font-size: var(--text-sm); color: var(--muted);
	font-variant-numeric: tabular-nums; }
.data td.hash, .data td.hash code, .data td.stamp { white-space: nowrap; word-break: normal; }

/* Phone columns (queue, intake list): under 48rem a .col-secondary cell is visually hidden
	(still read by a screen reader) and the primary cell's .row-meta repeats its values. */
.data .col-secondary { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
	overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.row-meta { display: block; font-size: var(--text-xs); color: var(--muted); }

@media (min-width: 48rem) {
	.page-actions { width: auto; }
	.data .col-secondary { position: static; width: auto; height: auto; margin: 0;
		padding: 0.625rem 0.75rem; overflow: visible; clip-path: none; white-space: normal;
		border-bottom: 1px solid var(--border); }
	.data thead th.col-secondary { padding: 0.5rem 0.75rem; white-space: nowrap; }
	.data tbody tr:last-child > .col-secondary { border-bottom: 0; }
	.row-meta { display: none; }
}

/* Buttons (SU1-06, spec 6.4). The accent fill marks the one main action of a view; .secondary
	is every other action, .quiet sits inline (Sign out, Clear), .danger is Disable / Revoke.
	a.button and a.quiet are links drawn as buttons. */
button,
a.button,
a.button:visited,
a.quiet,
a.quiet:visited {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	height: var(--control-h);
	padding: 0 0.875rem;
	font: inherit;
	font-size: var(--text-md);
	font-weight: 600;
	line-height: var(--leading-tight);
	color: var(--on-accent);
	background: var(--accent);
	border: 1px solid transparent;
	border-radius: var(--radius-md);
	cursor: pointer;
	white-space: nowrap;
	text-decoration: none;
	transition:
		background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease),
		transform var(--dur-instant) var(--ease);
}

/* A press sinks the button a little (AI1-07); with reduced motion it stays still. */
@media (prefers-reduced-motion: no-preference) {
	button:active:not(:disabled),
	a.button:active,
	a.quiet:active {
		transform: scale(0.98);
	}
}

button:hover:not(:disabled),
a.button:hover {
	color: var(--on-accent);
	background: var(--accent-dark);
	text-decoration: none;
}

button.secondary,
a.button.secondary,
a.button.secondary:visited {
	color: var(--fg);
	background: var(--surface);
	border-color: var(--border-strong);
}

button.secondary:hover:not(:disabled),
a.button.secondary:hover {
	color: var(--fg);
	background: var(--tint);
}

button.quiet,
a.quiet,
a.quiet:visited {
	color: var(--muted);
	background: transparent;
	border-color: transparent;
}

button.quiet:hover:not(:disabled),
a.quiet:hover {
	color: var(--fg);
	background: var(--tint);
	text-decoration: none;
}

/* A destructive action (Disable, Revoke): an outline in the error colour, no confirm step. */
button.danger,
a.button.danger,
a.button.danger:visited {
	color: var(--error);
	background: var(--surface);
	border-color: var(--error);
}

button.danger:hover:not(:disabled),
a.button.danger:hover {
	color: var(--error);
	background: var(--error-bg);
}

button.is-small,
a.button.is-small,
a.quiet.is-small {
	height: 1.875rem;
	padding: 0 0.625rem;
	font-size: var(--text-sm);
	border-radius: var(--radius);
}

button.is-block,
a.button.is-block {
	width: 100%;
}

/* A disabled button keeps its look on hover: the hover rules above skip :disabled. */
button:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* On a phone the main actions of a view are full width at the large touch height. */
.page-actions a.button,
.page-actions button,
.composer-actions button,
.decision-buttons button {
	width: 100%;
	height: var(--control-h-lg);
}

@media (min-width: 48rem) {
	.page-actions a.button,
	.page-actions button,
	.composer-actions button,
	.decision-buttons button {
		width: auto;
	}

	.page-actions a.button,
	.page-actions button,
	.composer-actions button,
	.decision-buttons button {
		height: var(--control-h);
	}

	.page-actions a.button.is-small,
	.page-actions button.is-small {
		height: 1.875rem;
	}
}

/* Fields (SU1-06, spec 6.5): a label, the control, then help or an error, in one column.
	Controls sit on --surface with a --border-strong edge (3:1). */
form.inline {
	display: inline;
}

/* A form is a .stack (app.css, spec 6.15): its gap spaces the fields and the submit row. */
form.stack {
	max-width: 28rem;
}

form.stack > button {
	align-self: flex-start;
}

.field {
	display: grid;
	gap: var(--space-1);
}

/* Inside a .stack the gap spaces the fields; anywhere else consecutive fields keep it too. */
:where(:not(.stack)) > .field + .field {
	margin-top: var(--space-4);
}
/* One shape for a refused field on every form (R08-13): a line between label and field, and the
	summary of a form of several fields links to it. */
.field-error { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--error); }
.error-summary ul { margin: var(--space-2) 0 0; padding-left: 1.25rem; }
.error-summary a, .error-summary a:visited { color: var(--error); }

label {
	display: block;
	font-size: var(--text-sm);
	font-weight: 600;
}

label.inline,
.check label {
	font-size: var(--text-md);
	font-weight: 500;
}

input[type="text"],
input[type="password"],
input[type="date"],
input[type="search"],
select,
textarea {
	width: 100%;
	max-width: 100%;
	height: var(--control-h);
	padding: 0 0.75rem;
	font: inherit;
	font-size: var(--text-md);
	color: var(--fg);
	background: var(--surface);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-md);
	transition: border-color var(--dur-fast) var(--ease);
}

textarea {
	display: block;
	height: auto;
	padding: 0.5rem 0.75rem;
}

:is(input[type="text"], input[type="password"], input[type="date"], input[type="search"],
	select, textarea):hover {
	border-color: var(--muted);
}

:is(input[type="text"], input[type="password"], input[type="date"], input[type="search"],
	select, textarea):focus {
	border-color: var(--accent);
}

/* The chevron is two small gradient triangles in the muted ink at the right. */
select {
	appearance: none;
	padding-right: 2rem;
	background-image:
		linear-gradient(45deg, transparent 50%, var(--muted) 50%),
		linear-gradient(135deg, var(--muted) 50%, transparent 50%);
	background-position:
		right 1rem center,
		right 0.6875rem center;
	background-size: 0.3125rem 0.3125rem;
	background-repeat: no-repeat;
}

input[type="file"] {
	max-width: 100%;
	font-size: var(--text-sm);
	color: var(--muted);
}

input[type="file"]::file-selector-button {
	height: 2rem;
	margin-right: var(--space-3);
	padding: 0 0.75rem;
	font: inherit;
	font-weight: 600;
	color: var(--fg);
	background: var(--surface);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius);
	cursor: pointer;
	transition: background-color var(--dur-fast) var(--ease);
}

input[type="file"]::file-selector-button:hover {
	background: var(--tint);
}

input[type="checkbox"] {
	flex: none;
	width: 1rem;
	height: 1rem;
	margin: 0;
	accent-color: var(--accent);
}

/* A control in error: the error edge wins over hover and focus borders. */
[aria-invalid="true"],
:is(input, select, textarea)[aria-invalid="true"],
:is(input, select, textarea)[aria-invalid="true"]:is(:hover, :focus) {
	border-color: var(--error);
	box-shadow: 0 0 0 1px var(--error);
}

/* The chosen file's name and size under a file picker (home, intake). */
.file-facts { font-size: var(--text-sm); overflow-wrap: anywhere; }

/* Checkbox chips (queue filters): the chip turns accent when its box is ticked. */
.check {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: 0.25rem 0.75rem 0.25rem 0.5rem;
	border: 1px solid var(--border);
	border-radius: var(--radius-full);
	background: var(--surface);
}

.check:has(input:checked) {
	background: var(--accent-bg);
	border-color: var(--accent);
}

fieldset {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

legend {
	margin-bottom: var(--space-2);
	padding: 0;
	font-size: var(--text-sm);
	font-weight: 600;
}

/* A filter form (queue, analytics, calibration; SC1-05): chips and labelled fields wrap side by
	side; each field takes its own line below 64rem, so a long class or rule id never widens
	the page. */
.filters fieldset {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-bottom: var(--space-4);
}

.filters .field {
	flex: 1 1 100%;
	max-width: 100%;
	margin: 0.25rem 0 0.5rem;
}

@media (min-width: 64rem) {
	.filters .field {
		flex-basis: 14rem;
	}
}

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

.keys {
	color: var(--muted);
}

.keys > p {
	margin: var(--space-2) 0 0;
}

/* Disclosure (SU1-06, spec 6.6). Each summary drops the browser marker and carries one chevron,
	a rotated corner in currentColor that turns down over --dur when open. */
details.secondary-action > summary,
details.tech > summary,
details.filters > summary,
details.keys > summary {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	list-style: none;
	cursor: pointer;
}

details.secondary-action > summary::-webkit-details-marker,
details.tech > summary::-webkit-details-marker,
details.filters > summary::-webkit-details-marker,
details.keys > summary::-webkit-details-marker {
	display: none;
}

details.secondary-action > summary::before,
details.tech > summary::before,
details.filters > summary::before,
details.keys > summary::before {
	content: "";
	flex: none;
	width: 0.4rem;
	height: 0.4rem;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: rotate(-45deg);
	transition: transform var(--dur) var(--ease);
}

details.secondary-action[open] > summary::before,
details.tech[open] > summary::before,
details.filters[open] > summary::before,
details.keys[open] > summary::before {
	transform: rotate(45deg);
}

/* Opening a disclosure fades its content in with a 4px drop over --dur-base (AI1-10; the
	chevron turns with it); closing is instant. The content is never hidden while it plays, so a
	control focused as the disclosure opens ("/" on the queue) takes the focus at once. */
@media (prefers-reduced-motion: no-preference) {
	details.secondary-action[open]::details-content, details.tech[open]::details-content,
	details.filters[open]::details-content, details.keys[open]::details-content {
		animation: details-in var(--dur-base) var(--ease-out); }
}
@keyframes details-in { from { opacity: 0; transform: translateY(-4px); } }

details.secondary-action > summary {
	font-size: var(--text-md);
	font-weight: 500;
	color: var(--fg);
}

details.secondary-action[open] > :not(summary) {
	margin-top: var(--space-3);
	padding: var(--space-4);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	background: var(--surface);
}

/* Technical details (S4-05a2, one closed block since SC1-03): hashes, versions, pins, the
	rules-fired and per-validator tables, the reasons. Closed until the audit reader opens it;
	nothing in it is needed to decide. */
details.tech {
	padding: 0 var(--space-5);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
}

details.tech[open] {
	padding-bottom: var(--space-5);
}

details.tech > summary {
	display: flex;
	margin: 0 calc(-1 * var(--space-5));
	padding: var(--space-4) var(--space-5);
	font-size: var(--text-md);
	font-weight: 600;
	color: var(--muted);
}

details.tech > summary > h2,
.compare-column > summary > h3 {
	display: inline;
	margin: 0;
	font-size: inherit;
	color: inherit;
}

td.tech > details.tech {
	padding: 0;
	background: none;
	border: 0;
}

td.tech > details.tech > summary {
	margin: 0;
	padding: 0;
	font-size: var(--text-sm);
}

/* The filters toggle is a small secondary button with the chevron and an optional count. */
details.filters > summary {
	height: 1.875rem;
	padding: 0 0.625rem;
	font-size: var(--text-sm);
	font-weight: 600;
	color: var(--fg);
	background: var(--surface);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius);
	transition: background-color var(--dur-fast) var(--ease);
}

details.filters > summary:hover {
	background: var(--tint);
}

details.keys > summary {
	font-size: var(--text-sm);
	font-weight: 500;
	color: var(--muted);
}

dl.keys-list {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: var(--space-1) var(--space-4);
	margin: var(--space-3) 0 0;
}

dl.keys-list dt,
dl.keys-list dd {
	margin: 0;
}

dl.keys-list dd {
	font-size: var(--text-sm);
}

.compare-column > summary {
	cursor: pointer;
	font-weight: 600;
	color: var(--accent);
}

/* Detail view (S4-05a1; plain-language order SC1-03) */

.findings,
.redactions { padding-left: 0; list-style: none; margin: 0 0 1rem; }

.findings li,
.redactions li {
	padding: 0.5rem 0.75rem;
	margin-bottom: 0.5rem;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}

.findings li.is-current { background: var(--accent-bg); }

.finding-meta {
	color: var(--muted);
	font-size: 0.9rem;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 var(--space-3);
}

/* Small classes the templates carry (SC1-02): pins and reason codes are muted mono. */
.pin,
.code { color: var(--muted); font-size: 0.9em; }

.pin,
.code { font-family: var(--mono); }

/* A rule cell (SC1-05): the description with the id muted after it. The cell keeps a
	readable width and the id stays whole, so a narrow table scrolls in its region instead of
	breaking the id mid-word. */
.data .rule { display: inline-block; min-width: 16rem; }

.data .rule .code { white-space: nowrap; }

/* Panel (SU2-11, spec 2.1): the one bordered surface, for a form you submit; no shadow.
	Allowed only in the templates spec 2.1 names, at most one per page. Radius 14 (AI1-07). */
.panel { background: var(--surface); border: 1px solid var(--border);
	border-radius: var(--radius-lg); padding: var(--space-4); }

/* Facts (spec 6.12): a term beside its value.
	.facts (not dl.facts) so an area sheet's own dl class (.header-facts) still wins. */
.facts { display: grid; grid-template-columns: max-content 1fr;
	gap: var(--space-2) var(--space-6); margin: 0; }
/* A dl groups each pair in a div: in the grid the div steps aside, so dt and dd align. */
.facts > div { display: contents; }
.facts dt { font-size: var(--text-sm); font-weight: 500; color: var(--muted); }
.facts dd { margin: 0; font-size: var(--text-md); overflow-wrap: anywhere; }

