/*
	Component styles. Tokens are declared globally but only consumed by .ui- rules, so adding
	this sheet to a page cannot change anything that is already on it.

	:root carries the light palette because that is what the site is today. Dark is opt in via
	data-theme="dark" on the html element. There is deliberately no prefers-color-scheme query
	yet, a dark OS should not repaint components on a page that is still light everywhere else.
	When the redesign flips the site to dark by default, swap these two blocks and add the query.
*/

:root {
	--ui-sunk: #E7E2DC;
	--ui-raised: #FFFFFF;
	--ui-inset: #F2EEEA;
	--ui-line: #DCD4CB;
	--ui-line-hi: #BFB4A9;
	--ui-tx: #211A16;
	--ui-t2: #5F554C;
	--ui-t3: #8C8076;

	--ui-brand: #BD2221;
	--ui-brand-ink: #BD2221;
	--ui-on-brand: #FFFFFF;

	--ui-good: #1E7F4F;
	--ui-warn: #8A6A12;
	--ui-bad: #BD2221;
	/* separate from --ui-t3, which is too pale to carry white text at pill sizes */
	--ui-neutral: #5F554C;

	/* the two sides of a team game. the site has no opinion about these anywhere else,
	   but anything drawing a side has to agree with everything else drawing one */
	--ui-team-red: #BD2221;
	--ui-team-blue: #2A78D6;

	/* the categorical series colors, handed out in fixed order rather than picked for what
	   a series means, so two charts of the same shape agree with each other. four is the
	   whole set: a fifth series folds into neutral rather than being given a generated hue
	   nothing else has an opinion about */
	--ui-c1: #2A78D6;
	--ui-c2: #EB6834;
	--ui-c3: #1BAF7A;
	--ui-c4: #6D3F8F;

	--ui-radius: 3px;
	--ui-gap: 12px;
}

:root[data-theme="dark"] {
	--ui-sunk: #15110F;
	--ui-raised: #231D19;
	--ui-inset: #1B1613;
	--ui-line: #372E28;
	--ui-line-hi: #4B3F37;
	--ui-tx: #F0E9E3;
	--ui-t2: #AC9F95;
	--ui-t3: #7C6F65;

	--ui-brand: #D43E30;
	--ui-brand-ink: #E2483A;

	--ui-good: #5FBE8B;
	--ui-warn: #D9A93F;
	--ui-bad: #E2483A;
	--ui-neutral: #7C6F65;

	--ui-team-red: #D43E30;
	--ui-team-blue: #3987E5;

	--ui-c1: #3987E5;
	--ui-c2: #D95926;
	--ui-c3: #199E70;
	--ui-c4: #A875E0;
}

/* Pill */

.ui-pill {
	display: inline-block;
	padding: 1px 8px;
	border: 1px solid transparent;
	border-radius: 999px;
	font-size: 11px;
	font-weight: 600;
	line-height: 17px;
	letter-spacing: 0.02em;
	white-space: nowrap;
	vertical-align: middle;
	color: var(--ui-on-brand);
}

.ui-pill-neutral { background: var(--ui-neutral); }
.ui-pill-good    { background: var(--ui-good); }
.ui-pill-warn    { background: var(--ui-warn); }
.ui-pill-bad     { background: var(--ui-bad); }
.ui-pill-brand   { background: var(--ui-brand); }

/* the light palette's good and warn are dark enough to carry white text, the dark palette's
   are not, so those fills take dark ink instead */
:root[data-theme="dark"] .ui-pill-good:not(.ui-pill-outline),
:root[data-theme="dark"] .ui-pill-warn:not(.ui-pill-outline) {
	color: #15110F;
}

.ui-pill-outline {
	background: transparent;
	border-color: currentColor;
}

.ui-pill-outline.ui-pill-neutral { color: var(--ui-t2); }
.ui-pill-outline.ui-pill-good    { color: var(--ui-good); }
.ui-pill-outline.ui-pill-warn    { color: var(--ui-warn); }
.ui-pill-outline.ui-pill-bad     { color: var(--ui-bad); }
.ui-pill-outline.ui-pill-brand   { color: var(--ui-brand-ink); }

/* Stat tile */

.ui-stat-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
	gap: var(--ui-gap);
}

.ui-stat-tile {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 10px 12px;
	background: var(--ui-raised);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
	color: var(--ui-tx);
	text-decoration: none;
}

a.ui-stat-tile:link,
a.ui-stat-tile:visited,
a.ui-stat-tile:active {
	color: var(--ui-tx);
	text-decoration: none;
}

a.ui-stat-tile:hover {
	border-color: var(--ui-line-hi);
}

.ui-stat-label {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ui-t3);
}

.ui-stat-value {
	font-size: 26px;
	font-weight: 600;
	line-height: 1.15;
	font-variant-numeric: tabular-nums;
}

.ui-stat-unit {
	margin-left: 3px;
	font-size: 13px;
	font-weight: 500;
	color: var(--ui-t2);
}

.ui-stat-delta {
	font-size: 12px;
	font-variant-numeric: tabular-nums;
}

.ui-stat-up   { color: var(--ui-good); }
.ui-stat-down { color: var(--ui-bad); }
.ui-stat-flat { color: var(--ui-t3); }

.ui-stat-hint {
	font-size: 12px;
	color: var(--ui-t2);
}

/* Data table */

.ui-table {
	border-collapse: collapse;
	color: var(--ui-tx);
}

/* headings sit on the bottom of the row rather than in the middle of it, so a heading that
   wraps to two lines and one that does not still read off the same line */
.ui-table .ui-table-head {
	padding: 6px 8px;
	vertical-align: bottom;
	text-align: left;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ui-t3);
	border-bottom: 1px solid var(--ui-line);
}

/* deliberately not list_cell_formatting, that class paints text white for the red heading bar */
.ui-table .ui-table-cell {
	padding: 6px 8px;
	color: var(--ui-tx);
	font-size: 10pt;
	font-variant-numeric: tabular-nums;
	border-bottom: 1px solid var(--ui-line);
}

.ui-table tr:last-child .ui-table-cell {
	border-bottom: 0;
}

/* a set of breakdowns hanging off one table has to agree with the others and not only with
   itself, so the widths become the whole of the layout rather than a hint weighed against
   the content */
.ui-table-fixed {
	table-layout: fixed;
}

.ui-table-empty {
	padding: 18px 8px;
	text-align: center;
	color: var(--ui-t3);
}

/* a column group, so a wide table can say which figures belong together without being
   split into a table of its own. the edge classes go on the columns, which puts them on
   the heading and every cell beneath it in one place */

.ui-table .ui-table-group {
	padding: 3px 8px 2px;
	text-align: center;
	font-size: 10px;
	font-weight: bold;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ui-t3);
}

.ui-table-group-on { background: var(--ui-inset); }

.ui-table .ui-group-first { border-left: 1px solid var(--ui-line-hi); }
.ui-table .ui-group-last  { border-right: 1px solid var(--ui-line-hi); }

/* a table wider than the panel scrolls inside its own box rather than making the page
   scroll sideways */
.ui-table-scroll { overflow-x: auto; }

/* the legacy sheet gives every table a 2px margin, so one at full width is 4px wider than
   the box holding it. outside a scroller that is just a margin; inside one it is a
   scrollbar on a table that already fits, so it comes off here and nowhere else. */
.ui-table-scroll > .ui-table {
	margin-left: 0;
	margin-right: 0;
}

.ui-align-left   { text-align: left; }
.ui-align-center { text-align: center; }
.ui-align-right  { text-align: right; }

.ui-table-head.ui-align-center { text-align: center; }
.ui-table-head.ui-align-right  { text-align: right; }

/* for a cell whose value is one thing written with separators in it, which a wrap turns
   into two things */
.ui-table .ui-nowrap { white-space: nowrap; }

/* the other way round, for a cell in a fixed layout holding text of somebody else's
   choosing. a name with no space in it is one long word, and a column laid out on its
   width alone has no more room to give it, so it breaks rather than running into the
   figures next to it */
.ui-table .ui-cell-wrap {
	overflow-wrap: break-word;
	word-break: break-word;
}

/* sortable columns. the heading is a plain heading until the script adds ui-table-sorted,
   so a reader with no javascript is never offered a control that cannot answer */

.ui-table .ui-table-sorthead {
	padding: 0;
}

/* the label and the arrow are two flex items rather than one run of inline content. as
   inline content the arrow is an atomic box the line can break before, so a column only
   just too narrow for both put the arrow on a line of its own - which cost the heading a
   whole line and left its text sitting below every heading beside it. the label still
   wraps on its own spaces, since it is a flex item of its own. */
.ui-table-sort {
	display: flex;
	align-items: flex-end;
	gap: 5px;
	width: 100%;
	margin: 0;
	padding: 6px 8px;
	background: none;
	border: 0;
	font: inherit;
	letter-spacing: inherit;
	text-transform: inherit;
	text-align: inherit;
	color: inherit;
	cursor: default;
}

.ui-table-head.ui-align-center .ui-table-sort { justify-content: center; }
.ui-table-head.ui-align-right .ui-table-sort  { justify-content: flex-end; }

/* a heading carrying a note beside its control. the note sits outside the control rather
   than inside it, because inside it is part of the click target: opening the note would
   reorder the column, and on touch, where there is no hover to open it with, tapping the
   mark would be the only thing that happened.

   the pair is laid out by a span inside the heading rather than by the heading itself. a
   th that is not a table cell is wrapped in an anonymous one, and consecutive siblings
   share a single anonymous cell - so two noted headings beside each other became one cell
   with both stacked in it, the header row came up a column short, and every heading past
   them sat over the figures of the column before. */
.ui-table-noteline {
	display: flex;
	align-items: flex-end;
}

.ui-table-head.ui-align-center .ui-table-noteline { justify-content: center; }
.ui-table-head.ui-align-right .ui-table-noteline  { justify-content: flex-end; }

/* the control sizes to its label rather than filling the heading, or there is no room
   beside it and the note is pushed onto a line of its own */
.ui-table-noted .ui-table-sort { width: auto; }

/* the padding the control carries, so a note on a sortable heading sits inside the cell
   edge rather than against it */
.ui-table-sorthead .ui-table-noteline > .ui-tip { margin-right: 8px; }

.ui-table-sorted .ui-table-sort {
	cursor: pointer;
}

.ui-table-sorted .ui-table-sort:hover {
	color: var(--ui-tx);
}

.ui-table-sort:focus-visible {
	outline: 2px solid var(--ui-brand);
	outline-offset: -2px;
}

.ui-sort-arrow {
	flex: none;
	width: 0;
	height: 0;
	margin-bottom: 4px;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	opacity: 0;
}

.ui-table-sorted .ui-table-sort:hover .ui-sort-arrow {
	opacity: 0.4;
}

.ui-table-sorted .ui-table-sorthead[aria-sort="descending"] .ui-sort-arrow,
.ui-table-sorted .ui-table-sorthead[aria-sort="ascending"] .ui-sort-arrow {
	opacity: 1;
}

.ui-table-sorted .ui-table-sorthead[aria-sort="ascending"] .ui-sort-arrow {
	border-top: 0;
	border-bottom: 5px solid currentColor;
}

.ui-table-sorted .ui-table-sorthead[aria-sort="ascending"],
.ui-table-sorted .ui-table-sorthead[aria-sort="descending"] {
	color: var(--ui-tx);
	border-bottom-color: var(--ui-line-hi);
}

/* expandable rows. the detail is open in the markup, so hiding it is the script's job */

.ui-table-caret {
	width: 24px;
	padding-right: 0;
}

.ui-table-summary {
	cursor: pointer;
}

.ui-table-summary:hover .ui-table-cell {
	background: var(--ui-inset);
}

.ui-table-toggle {
	display: block;
	margin: 0;
	padding: 2px 4px;
	background: none;
	border: 0;
	color: var(--ui-t2);
	cursor: pointer;
	line-height: 0;
}

.ui-table-toggle:hover {
	color: var(--ui-tx);
}

.ui-table-toggle:focus-visible {
	outline: 2px solid var(--ui-brand);
	outline-offset: 1px;
}

.ui-caret {
	display: inline-block;
	width: 0;
	height: 0;
	border-left: 5px solid currentColor;
	border-top: 4px solid transparent;
	border-bottom: 4px solid transparent;
	transition: transform 150ms ease;
}

.ui-table-toggle[aria-expanded="true"] .ui-caret {
	transform: rotate(90deg);
}

/* an open row keeps its own ground and only loses the rule under it, so it reads as joined
   to the detail below rather than as a second selected state. the hover shading still
   applies, since being open is not being pointed at */
.ui-table-open .ui-table-cell {
	border-bottom: 0;
}

.ui-table-detailrow[hidden] {
	display: none;
}

.ui-table-detail {
	padding: 4px 8px 12px 32px;
	background: var(--ui-inset);
	border-bottom: 1px solid var(--ui-line);
}

/* the detail's own box, and the reason opening a row does not move the columns above it.

   the cell it sits in spans every column, and an auto laid out table widens the columns a
   spanning cell reaches until they hold its content - so a breakdown wider than the summary
   row would re-lay the whole table under the reader the moment they opened it. a width of
   zero is what the cell measures, and the minimum is what the box is actually laid out at,
   so the detail still fills the row it hangs off.

   deliberately not a scroll container. a breakdown wider than the row would now overflow the
   box rather than stretch the table, and overflow-x would answer that - but it makes the box
   clip on the other axis too, and the headings inside carry info tips that would be cut off
   by it. every breakdown drawn in one is full width and fits. */
.ui-table-detailbox {
	width: 0;
	min-width: 100%;
}

/* a table nested in a detail is a breakdown of the row above it, not a table in its own right */
.ui-table-detail .ui-table {
	background: var(--ui-raised);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
}

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

/* Notice */

.ui-notice {
	margin: 0;
	padding: 10px 12px;
	background: var(--ui-inset);
	border: 1px solid var(--ui-line);
	border-left: 3px solid var(--ui-neutral);
	border-radius: var(--ui-radius);
	color: var(--ui-t2);
	font-size: 12px;
	line-height: 1.55;
}

.ui-notice p {
	margin: 0;
}

.ui-notice p + p {
	margin-top: 4px;
}

.ui-notice-title {
	color: var(--ui-tx);
	font-weight: bold;
}

.ui-notice-good { border-left-color: var(--ui-good); }
.ui-notice-warn { border-left-color: var(--ui-warn); }
.ui-notice-bad  { border-left-color: var(--ui-bad); }

/* Key and value list */

.ui-kv {
	display: grid;
	gap: 1px;
	background: var(--ui-line);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
	overflow: hidden;
}

.ui-kv-item {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 8px 10px;
	background: var(--ui-raised);
}

.ui-kv-label {
	color: var(--ui-t3);
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.ui-kv-value {
	color: var(--ui-tx);
	font-size: 13px;
}

.ui-kv-hint {
	color: var(--ui-t3);
	font-size: 11px;
}

/* Level shot */

/* 4:3, the shape files_images already produces at 200x150. sized in css rather than on the
   element so one rule moves every shot on the site */
.ui-shot {
	flex: none;
	display: block;
	width: 80px;
	height: 60px;
	border: 1px solid var(--ui-line);
	border-radius: 2px;
	background: var(--ui-inset);
	overflow: hidden;
}

.ui-shot-sm { width: 48px; height: 36px; }
.ui-shot-lg { width: 112px; height: 84px; }

/* 200x150 is what files_images produces, so the largest shot is the shot itself rather
   than one upscaled past it */
.ui-shot-xl { width: 200px; height: 150px; }

.ui-shot img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* the site's link hover paints a red ground, which would sit behind the picture */
a.ui-shot:hover {
	background: var(--ui-inset);
	border-color: var(--ui-line-hi);
	opacity: 1;
}

/* no file carries this level name, so the tile holds the row's shape instead */
.ui-shot-none {
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--ui-t3);
}

/* Avatar */

/* a person's picture beside their name, square because the site's own avatars are. the
   handler always answers, serving the default image where an account has none, so there is
   no empty state here the way there is for a level shot */
.ui-avatar {
	flex: none;
	display: block;
	width: 64px;
	height: 64px;
	border: 1px solid var(--ui-line);
	border-radius: 2px;
	background: var(--ui-inset);
	overflow: hidden;
}

.ui-avatar-sm { width: 32px; height: 32px; }

/* the size a hero wants, which is what the site stores them at */
.ui-avatar-lg { width: 100px; height: 100px; }

.ui-avatar img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* the site's link hover paints a red ground, which would sit behind the picture */
a.ui-avatar:hover {
	background: var(--ui-inset);
	border-color: var(--ui-line-hi);
	opacity: 1;
}

/* Game row */

.ui-gamerow {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}

.ui-gamerow-text {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 3px;
	padding-top: 1px;
}

.ui-gamerow-title {
	font-size: 10pt;
	line-height: 1.3;
}

.ui-gamerow-facts {
	font-size: 8pt;
	color: var(--ui-t2);
	line-height: 1.4;
}

.ui-gamerow-links {
	font-size: 8pt;
	color: var(--ui-t3);
	line-height: 1.4;
}

.ui-gamerow-links a { font-size: 8pt; }

/* said as an id, so it reads as one rather than as a hash somebody left in */
.ui-id {
	font: 8pt/1.4 ui-monospace, "DejaVu Sans Mono", Consolas, monospace;
	letter-spacing: 0.03em;
}

/* a game the processor has not addressed yet */
.ui-id-none {
	color: var(--ui-t3);
	font-style: italic;
}

.ui-on { color: var(--ui-t3); }

/* launches the client through the af:// handler. carries the game id, never a signed link */
.ui-demo {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 0 6px;
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
	background: var(--ui-raised);
	font-size: 8pt;
	font-weight: bold;
	line-height: 16px;
	vertical-align: -1px;
}

a.ui-demo:link,
a.ui-demo:visited,
a.ui-demo:active {
	color: var(--ui-brand-ink);
	text-decoration: none;
}

a.ui-demo:hover {
	color: var(--ui-brand-ink);
	background: var(--ui-inset);
	border-color: var(--ui-brand);
	opacity: 1;
}

.ui-demo svg { display: block; }

/* how long ago, and the clock time to cross reference by */
.ui-when {
	font-size: 10pt;
	line-height: 1.3;
	white-space: nowrap;
}

.ui-when span {
	display: block;
	font-size: 8pt;
	color: var(--ui-t3);
}

/* the quiet second line inside a table cell */
.ui-cell-sub {
	display: block;
	font-size: 8pt;
	color: var(--ui-t3);
}

.ui-cell-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
}

/* Row link */

/* a listing row is one subject, and the row is a link to that subject. the tint and the
   caret are css, so the affordance is there before the script that wires the row click is */
.ui-rowlink { cursor: pointer; }

.ui-rowlink:hover .ui-table-cell { background: var(--ui-inset); }

.ui-table .ui-table-go {
	width: 1px;
	padding-left: 0;
	padding-right: 8px;
}

.ui-row-go { opacity: 0; }

.ui-rowlink:hover .ui-row-go { opacity: 1; }

.ui-row-go svg { display: block; }

a.ui-row-go:link,
a.ui-row-go:visited,
a.ui-row-go:active {
	color: var(--ui-t3);
	background: transparent;
}

a.ui-row-go:hover {
	color: var(--ui-brand-ink);
	background: transparent;
	opacity: 1;
}

/* Server card */

.ui-card-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
	gap: var(--ui-gap);
}

.ui-server-card {
	display: block;
	padding: 10px 12px;
	background: var(--ui-raised);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
}

.ui-server-card-live { border-color: var(--ui-line-hi); }

.ui-server-body {
	display: flex;
	align-items: center;
	gap: 10px;
}

/* the card carries a taller shot than a row does, so the picture fills the height the text
   beside it takes rather than leaving a gap under itself. the pair is sized here rather than
   stretched, since a stretched item keeps the width it was given and the shape would go with it */
.ui-server-body > .ui-shot {
	width: 112px;
	height: 84px;
}

.ui-server-text {
	min-width: 0;
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.ui-server-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
}

.ui-server-name {
	font-size: 10pt;
	font-weight: bold;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ui-server-now { font-size: 10pt; line-height: 1.35; }

.ui-server-meta { font-size: 8pt; color: var(--ui-t3); }

/* Panel row */

/* two panels sharing a row, wrapping on their own rather than at a breakpoint. the basis is
   what decides when they stack, so nothing here has to be kept in step with a media query.

   the bottom margin is a longhand on purpose. a caller centers this the way it centers a panel,
   with margin_center and a width, and this sheet loads after ff.css - so the margin shorthand
   would set left and right to zero, beat that auto, and shove the row to one side */
.ui-panel-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ui-gap);
	margin-bottom: 10px;
}

.ui-panel-col {
	flex: 1 1 420px;
	min-width: 0;
	display: flex;
}

/* the panel already carries the margins the row is now providing */
.ui-panel-col > .box_container {
	flex: 1;
	margin: 0;
}

/* Component cell */

/* the site sizes content-box and .full_width is width:100%, so a cell carrying a padding
   comes out wider than the panel around it and the panel clips whatever sits at its right
   edge - the end of a mix strip's bar, the end of its note, the figure at the end of a pie
   chart's key. a cell holding a component is sized the way the library sizes everything
   else. the :has() is what keeps the promise at the top of this sheet: a page with no
   components on it has no cell this can match */
.list_cell.full_width:has(> [class^="ui-"]),
.list_cell.full_width:has(> [class*=" ui-"]) {
	box-sizing: border-box;
}

/* Team tick */

/* the little colored bar that says which side a thing belongs to. shared, because a
   subhead, a versus band and a comparison row all have to agree about it */
.ui-tick {
	display: inline-block;
	flex: none;
	width: 3px;
	height: 13px;
	margin-right: 6px;
	border-radius: 1px;
	vertical-align: -2px;
	background: var(--ui-t3);
}

.ui-tick-red  { background: var(--ui-team-red); }
.ui-tick-blue { background: var(--ui-team-blue); }
.ui-tick-none { background: var(--ui-t3); }

/* Subhead */

.ui-subhead {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	padding: 6px 10px;
	background: var(--ui-inset);
	border-top: 1px solid var(--ui-line);
	border-bottom: 1px solid var(--ui-line);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ui-t2);
}

.ui-subhead .ui-tick { margin-right: 0; }

.ui-subhead-sp { flex: 1; }

.ui-subhead-note {
	font-weight: normal;
	letter-spacing: 0;
	text-transform: none;
	color: var(--ui-t3);
}

.ui-subhead-fig {
	font-size: 13px;
	font-weight: bold;
	letter-spacing: 0;
	color: var(--ui-tx);
	font-variant-numeric: tabular-nums;
}

/* Chip band */

.ui-chipband {
	display: flex;
	gap: 8px;
	align-items: baseline;
	padding: 8px 10px;
	background: var(--ui-raised);
	border: 1px solid var(--ui-line);
	border-top: 0;
}

.ui-chipband-label {
	flex: none;
	color: var(--ui-t3);
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.ui-chipband-set {
	display: flex;
	flex-wrap: wrap;
	gap: 5px;
}

.ui-chipband-empty {
	font-size: 12px;
	color: var(--ui-t3);
}

/* Info tip */

/* an i that explains a heading without spending a row on it. no script, and the same
   text is in the title attribute for anything that cannot hover */
.ui-tip {
	position: relative;
	display: inline-block;
	margin-left: 4px;
	vertical-align: middle;
}

.ui-tip-mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 13px;
	height: 13px;
	border: 1px solid var(--ui-line-hi);
	border-radius: 999px;
	color: var(--ui-t3);
	font: italic bold 9px/1 Georgia, "Times New Roman", serif;
	letter-spacing: 0;
	text-transform: none;
	cursor: help;
}

.ui-tip:hover .ui-tip-mark {
	color: var(--ui-tx);
	border-color: var(--ui-t3);
}

.ui-tip-body {
	display: none;
	position: absolute;
	z-index: 20;
	top: 20px;
	right: 0;
	width: 268px;
	padding: 8px 10px;
	background: var(--ui-raised);
	border: 1px solid var(--ui-line-hi);
	border-radius: var(--ui-radius);
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
	font: normal 12px/1.5 Verdana, Arial, Helvetica, sans-serif;
	letter-spacing: 0;
	text-transform: none;
	text-align: left;
	white-space: normal;
	color: var(--ui-t2);
}

.ui-tip:hover .ui-tip-body {
	display: block;
}

/* Team versus */

.ui-versus {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 14px;
	background: var(--ui-raised);
	border-bottom: 1px solid var(--ui-line);
}

.ui-versus-side {
	flex: 1 1 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.ui-versus-right {
	align-items: flex-end;
	text-align: right;
}

.ui-versus-name {
	display: flex;
	align-items: center;
	gap: 7px;
	font-size: 15px;
	font-weight: bold;
	letter-spacing: 0.02em;
}

.ui-versus-name .ui-tick { height: 17px; width: 4px; border-radius: 2px; }

.ui-versus-meta {
	font-size: 11px;
	color: var(--ui-t3);
}

.ui-versus-score {
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
}

.ui-versus-figs {
	display: flex;
	align-items: baseline;
	gap: 10px;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}

.ui-versus-fig {
	font-size: 30px;
	font-weight: bold;
}

.ui-versus-dash {
	font-size: 18px;
	color: var(--ui-t3);
}

.ui-versus-verdict {
	max-width: 320px;
	font-size: 11px;
	line-height: 1.45;
	text-align: center;
	color: var(--ui-t3);
}

/* the side's ink, which the name, the figure and its half of every bar all take */
.ui-versus-red  { color: var(--ui-team-red); }
.ui-versus-blue { color: var(--ui-team-blue); }
.ui-versus-none { color: var(--ui-t2); }

/* one figure, both sides of it, and how far apart they were. its own component, so a
   rivalry list and a versus band agree about what a comparison looks like */

.ui-compare {
	padding: 8px 14px 12px;
	background: var(--ui-raised);
}

.ui-compare-row {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 4px 0;
}

.ui-compare-v {
	flex: 0 0 76px;
	font-size: 13px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.ui-compare-left  { text-align: right; }
.ui-compare-right { text-align: left; }

.ui-compare-mid {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 3px;
}

.ui-compare-label {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--ui-t3);
}

.ui-compare-bar {
	display: flex;
	gap: 3px;
	width: 100%;
	height: 6px;
}

.ui-compare-half {
	flex: 1;
	display: flex;
	overflow: hidden;
	background: var(--ui-inset);
	border-radius: 3px;
}

/* the left half fills towards the middle, so the two bars meet at the label */
.ui-compare-halfleft { justify-content: flex-end; }

.ui-compare-fill {
	height: 100%;
	background: currentColor;
}

/* a side taking one of the ink tones rather than a team's color. the ink names say what a
   fill is and not what the figure beside it reads as, so this is what turns one into both */
.ui-compare-ink { color: var(--ui-ink, var(--ui-neutral)); }

/* Control */

/* a small control, and the band a row of them sits in. shared rather than one page's own,
   since any panel with something to switch between wants the same row of them */

.ui-ctl {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--ui-t2);
	background: var(--ui-raised);
	border: 1px solid var(--ui-line-hi);
	border-radius: var(--ui-radius);
	padding: 3px 9px;
	cursor: pointer;
	line-height: 17px;
}

.ui-ctl:hover { color: var(--ui-tx); border-color: var(--ui-t3); }
.ui-ctl[aria-pressed="true"] { background: var(--ui-tx); border-color: var(--ui-tx); color: var(--ui-raised); }
.ui-ctl:focus-visible { outline: 2px solid var(--ui-brand); outline-offset: 2px; }

/* a set of controls that are one choice between them, so they read as one control */
.ui-ctl-seg {
	display: inline-flex;
	border: 1px solid var(--ui-line-hi);
	border-radius: var(--ui-radius);
	overflow: hidden;
}

.ui-ctl-seg .ui-ctl { border: 0; border-right: 1px solid var(--ui-line-hi); border-radius: 0; }
.ui-ctl-seg .ui-ctl:last-child { border-right: 0; }

.ui-ctl-div {
	width: 1px;
	min-height: 20px;
	align-self: stretch;
	margin: 0 2px;
	background: var(--ui-line-hi);
}

.ui-ctl-label {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ui-t2);
}

/* pushes everything after it to the far end of the band */
.ui-ctl-sp { flex: 1; }

/* the one link that belongs beside a switch rather than in it, at the far end of the band.
   the site's own a rules paint a link red and invert it on hover, which is written for body
   copy on a white panel rather than for a control band, so this needs its own reset the same
   way the tab links do */
.ui-ctl-trail { font-size: 12px; }

.ui-ctl-trail a:link,
.ui-ctl-trail a:visited,
.ui-ctl-trail a:active {
	color: var(--ui-t2);
	text-decoration: none;
}

.ui-ctl-trail a:hover {
	color: var(--ui-tx);
	background: transparent;
	text-decoration: underline;
	opacity: 1;
}

.ui-ctlbar {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	padding: 7px 10px;
	background: var(--ui-inset);
	border-bottom: 1px solid var(--ui-line);
}

/* a band that is the whole of the block it sits in rather than the top of one, which is
   what a control narrowing a page rather than a panel is */
.ui-ctlbar-solo { border-bottom: 0; }

/* Tabs */

/* the control band as a set of links rather than buttons, for a switch that navigates. the
   .ui-ctl rules are written for a button, so an anchor needs its own reset here: the site's
   own a rules are as specific as a class and would otherwise paint the link red and invert
   it on hover */

.ui-tabs a.ui-ctl {
	display: inline-block;
	text-decoration: none;
}

.ui-tabs a.ui-ctl:link,
.ui-tabs a.ui-ctl:visited,
.ui-tabs a.ui-ctl:active {
	color: var(--ui-t2);
	background: var(--ui-raised);
	text-decoration: none;
}

.ui-tabs a.ui-ctl:hover {
	color: var(--ui-tx);
	background: var(--ui-raised);
	border-color: var(--ui-t3);
	text-decoration: none;
	opacity: 1;
}

/* the choice the page is on, which is to a link what aria-pressed is to a button */
.ui-tabs a.ui-ctl[aria-current="page"],
.ui-tabs a.ui-ctl[aria-current="page"]:link,
.ui-tabs a.ui-ctl[aria-current="page"]:visited,
.ui-tabs a.ui-ctl[aria-current="page"]:active,
.ui-tabs a.ui-ctl[aria-current="page"]:hover {
	background: var(--ui-tx);
	border-color: var(--ui-tx);
	color: var(--ui-raised);
	opacity: 1;
}

/* Checks */

/* the control band as a set of checkboxes, for narrowing what a listing shows. every one is
   an anchor, so it needs the same reset the tab links do - and unlike a tab, both settings
   are ordinary rather than one of them being the choice the page is on, so the set state is
   the box being filled rather than the whole control being inverted */

.ui-checks a.ui-check {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	line-height: 17px;
	padding: 3px 9px 3px 5px;
	border: 1px solid transparent;
	border-radius: var(--ui-radius);
	text-decoration: none;
}

.ui-checks a.ui-check:link,
.ui-checks a.ui-check:visited,
.ui-checks a.ui-check:active {
	color: var(--ui-t2);
	text-decoration: none;
}

.ui-checks a.ui-check:hover {
	color: var(--ui-tx);
	border-color: var(--ui-line-hi);
	text-decoration: none;
	opacity: 1;
}

.ui-checks a.ui-check-on:link,
.ui-checks a.ui-check-on:visited,
.ui-checks a.ui-check-on:active,
.ui-checks a.ui-check-on:hover { color: var(--ui-tx); }

.ui-checks a.ui-check:focus-visible { outline: 2px solid var(--ui-brand); outline-offset: 2px; }

.ui-check-box {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 14px;
	height: 14px;
	border: 1px solid var(--ui-line-hi);
	border-radius: 3px;
	background: var(--ui-raised);
}

/* the tick is in the markup either way, so the box does not resize as it is set */
.ui-check-box svg { visibility: hidden; }

.ui-check-on .ui-check-box {
	background: var(--ui-tx);
	border-color: var(--ui-tx);
	color: var(--ui-raised);
}

.ui-check-on .ui-check-box svg { visibility: visible; }

/* Pager */

/* the control band at the foot of a panel rather than the head of one, for the way to the
   pages either side of the one being shown. the steps are anchors, so they need the same
   reset the tab links do, and a step with nowhere to go is drawn inert rather than left out
   so the bar does not move as the reader pages through it */

.ui-pager {
	border-bottom: 0;
	border-top: 1px solid var(--ui-line);
}

.ui-pager a.ui-ctl {
	display: inline-block;
	text-decoration: none;
}

.ui-pager a.ui-ctl:link,
.ui-pager a.ui-ctl:visited,
.ui-pager a.ui-ctl:active {
	color: var(--ui-t2);
	background: var(--ui-raised);
	text-decoration: none;
}

.ui-pager a.ui-ctl:hover {
	color: var(--ui-tx);
	background: var(--ui-raised);
	border-color: var(--ui-t3);
	text-decoration: none;
	opacity: 1;
}

.ui-ctl-off {
	display: inline-block;
	color: var(--ui-t3);
	cursor: default;
	opacity: 0.6;
}

/* the block a server sorted table and its pager are swapped as one of. the script marks it
   while a fetch is in the air, which is a moment on a fast network and worth saying on a
   slow one */
.ui-tableblock {
	display: block;
}

.ui-tableblock.ui-table-loading,
.ui-pagebody.ui-table-loading {
	opacity: 0.55;
}

/* a server sorted heading, which is a link rather than a button. the table carries
   ui-table-sorted in the markup, since the ordering is the query's and works with no
   javascript at all.

   the ground is reset along with the color. the legacy sheet paints every link on the site
   red on hover, and the control does not fill the heading it sits in - a heading beside one
   whose label wrapped is taller than its own control - so the block landed part way up the
   row and read as a column out of line rather than as a hover. the button headings on the
   servers listing were never affected, which is the whole difference between the two. */

.ui-table a.ui-table-sort:link,
.ui-table a.ui-table-sort:visited,
.ui-table a.ui-table-sort:active,
.ui-table a.ui-table-sort:hover {
	color: inherit;
	background: none;
	text-decoration: none;
	opacity: 1;
}

.ui-table a.ui-table-sort:hover { color: var(--ui-tx); }

/* Filter views */

/* one listing per state of the filter checks, with the state the request asked for the one
   that is not hidden. the script swaps which that is, so nothing here says which is showing
   - only that a view it hid stays hidden however the listing inside is laid out */

[data-filter-view][hidden] { display: none; }

/* View switch */

/* one figure read two ways, with the group that picks between them above the panes. every
   pane is in the markup and the script hides the rest, so nothing here says which one is
   showing - only that a pane the script hid stays hidden even where it carries a display
   of its own */

.ui-views-body > [data-view][hidden] { display: none; }

/* Cockpit */

/* a panel body of a definite height, with a stage and a rail beside it. what drives the
   stage cannot scroll away from it and the panel never grows.

   deliberately one line and never wrapped: the height here is definite, so a single line
   takes it exactly and the two panes are stretched to it whatever they hold. let the line
   wrap and it sizes to its content instead, which a drawing's own aspect ratio then drives
   past the height the panel was drawn at - and the panel clips what will not fit. the
   stacked layout is the media query's job rather than the wrap's. */

.ui-cockpit {
	display: flex;
	height: 372px;
}

.ui-cockpit-stage {
	flex: 1 1 460px;
	min-width: 0;
	display: flex;
	flex-direction: column;
	border-right: 1px solid var(--ui-line);
}

.ui-cockpit-rail {
	flex: 0 0 296px;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

/* a stage nothing is driving, which is a drawing rather than something with a playhead to
   keep beside it. there is no control that can scroll away from it, so the panel is as tall
   as what it holds instead of the height the timeline needs. the rail still stretches to the
   stage, so the two panes stay level */
.ui-cockpit-fit { height: auto; }

/* the rail is a fixed width, so the stage is whatever is left of the panel. below this the
   two no longer both fit and the rail goes underneath, which is why the breakpoint is where
   the stage would start eating into the width it asks for rather than at a device size. */
@media (max-width: 1100px) {
	.ui-cockpit { display: block; height: auto; }
	.ui-cockpit-stage { border-right: 0; border-bottom: 1px solid var(--ui-line); height: 340px; }
	.ui-cockpit-rail { height: 340px; }
	.ui-cockpit-fit .ui-cockpit-stage,
	.ui-cockpit-fit .ui-cockpit-rail { height: auto; }
}

/* a heading band inside either pane, which is the control band at the size of a label */
.ui-cockpit-head {
	flex: none;
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	padding: 6px 10px;
	background: var(--ui-inset);
	border-bottom: 1px solid var(--ui-line);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ui-t2);
}

/* the quiet half of the heading, which is a reading rather than a name */
.ui-cockpit-head .ui-cockpit-sub {
	font-weight: normal;
	letter-spacing: 0;
	text-transform: none;
	color: var(--ui-t3);
}

/* Tone ink */

/* what a tone means as a color, written once because more than one component fills with it.
   the class sets the ink and the component's own rule is what spends it */

.ui-ink-neutral { --ui-ink: var(--ui-neutral); }
.ui-ink-brand   { --ui-ink: var(--ui-brand); }
.ui-ink-good    { --ui-ink: var(--ui-good); }
.ui-ink-warn    { --ui-ink: var(--ui-warn); }
.ui-ink-bad     { --ui-ink: var(--ui-bad); }
.ui-ink-c1      { --ui-ink: var(--ui-c1); }
.ui-ink-c2      { --ui-ink: var(--ui-c2); }
.ui-ink-c3      { --ui-ink: var(--ui-c3); }
.ui-ink-c4      { --ui-ink: var(--ui-c4); }

/* Meter bar */

/* sized to sit in a table cell beside the figure it is a bar for, so the track takes what
   is left after the label rather than a width of its own */

.ui-meter {
	display: flex;
	align-items: center;
	gap: 6px;
}

.ui-meter-track {
	flex: 1;
	min-width: 30px;
	height: 6px;
	border-radius: 3px;
	background: var(--ui-line);
	overflow: hidden;
}

.ui-meter-fill {
	display: block;
	height: 100%;
	border-radius: 3px;
	background: var(--ui-ink, var(--ui-neutral));
}

.ui-meter-label {
	flex: none;
	font-size: 11px;
	font-variant-numeric: tabular-nums;
	text-align: right;
	color: var(--ui-t2);
}

/* Mix strip */

.ui-mix {
	display: flex;
	flex-direction: column;
	gap: 5px;
}

.ui-mix-bar {
	display: flex;
	height: 10px;
	border-radius: var(--ui-radius);
	background: var(--ui-line);
	overflow: hidden;
}

.ui-mix-seg {
	height: 100%;
	min-width: 0;
	background: var(--ui-ink, var(--ui-neutral));
}

/* a hairline between neighbors, so two segments of a similar hue still read as two */
.ui-mix-seg + .ui-mix-seg {
	box-shadow: inset 1px 0 0 var(--ui-raised);
}

.ui-mix-key {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 3px 12px;
	font-size: 11px;
	color: var(--ui-t2);
}

.ui-mix-item {
	display: inline-flex;
	align-items: center;
	gap: 5px;
}

.ui-mix-swatch {
	flex: none;
	width: 9px;
	height: 9px;
	border-radius: 2px;
	background: var(--ui-ink, var(--ui-neutral));
}

.ui-mix-value {
	color: var(--ui-tx);
	font-variant-numeric: tabular-nums;
}

/* the note is the far end of the key row rather than a line of its own */
.ui-mix-note {
	margin-left: auto;
	color: var(--ui-t3);
}

.ui-mix-empty {
	font-size: 12px;
	color: var(--ui-t3);
}

/* Pie chart */

/* the mix strip's segments drawn as a ring, with the key beside it rather than under it.
   an arc takes its color the way every other tone does, through the ink variable, so one
   class both fills the swatch in the key and strokes the arc it names */

.ui-pie {
	display: flex;
	align-items: center;
	gap: 14px;
}

.ui-pie-ring {
	flex: none;
}

/* the rest of the whole, showing wherever the segments do not add up to it */
.ui-pie-track {
	stroke: var(--ui-line);
	stroke-width: 6;
}

.ui-pie-seg {
	color: var(--ui-ink, var(--ui-neutral));
	stroke: currentColor;
	stroke-width: 6;
}

/* the key is as wide as it needs to be rather than as wide as the panel: stretched, the
   figure ends up an inch from the label it belongs to and the eye cannot carry one to the
   other. capped, a long label ellipses rather than dragging the column back out */
.ui-pie-key {
	flex: 0 1 auto;
	min-width: 0;
	max-width: 300px;
	display: flex;
	flex-direction: column;
	gap: 4px;
	font-size: 11px;
	color: var(--ui-t2);
}

.ui-pie-item {
	display: flex;
	align-items: center;
	gap: 6px;
}

.ui-pie-swatch {
	flex: none;
	width: 9px;
	height: 9px;
	border-radius: 2px;
	background: var(--ui-ink, var(--ui-neutral));
}

.ui-pie-label {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* the figure is the far end of its row, so the numbers line up down the key */
.ui-pie-value {
	margin-left: auto;
	padding-left: 8px;
	color: var(--ui-tx);
	font-variant-numeric: tabular-nums;
}

.ui-pie-note {
	padding-top: 2px;
	color: var(--ui-t3);
}

.ui-pie-empty {
	font-size: 12px;
	color: var(--ui-t3);
}

/* under this the ring and its key no longer both fit on a line, so the key goes underneath */
@media (max-width: 420px) {
	.ui-pie { flex-direction: column; align-items: flex-start; }
	.ui-pie-key { width: 100%; max-width: none; }
}

/* Hero */

/* the block that names the subject of a detail page, at a size that says it. one column
   of text, with a picture beside it where the subject has one - a game has a level and a
   server does not, so the shot belongs to whatever it happens to be running */

.ui-hero {
	display: flex;
	gap: 14px;
	align-items: flex-start;
}

.ui-hero-main {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.ui-hero-head {
	display: flex;
	align-items: baseline;
	gap: 10px;
	flex-wrap: wrap;
}

.ui-hero-title {
	font-size: 24px;
	font-weight: bold;
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: var(--ui-tx);
}

/* the second identifier, said as the filename it is rather than as more of the name */
.ui-hero-sub {
	font: 11px/1.4 ui-monospace, "DejaVu Sans Mono", Consolas, monospace;
	color: var(--ui-t3);
}

.ui-hero-pills {
	display: inline-flex;
	gap: 5px;
	flex-wrap: wrap;
}

.ui-hero-where {
	font-size: 15px;
	color: var(--ui-t2);
}

.ui-hero-where strong { color: var(--ui-tx); }

.ui-hero-when {
	font-size: 12px;
	color: var(--ui-t2);
}

.ui-hero-when span { color: var(--ui-t3); }

.ui-hero-tiles { margin-top: 10px; }

/* beside a picture the text column is narrower, so the head and the figures sit a little
   tighter and the pills take a line of their own rather than the end of the title's */
.ui-hero-media .ui-hero-head { gap: 9px; }
.ui-hero-media .ui-hero-pills { display: flex; margin-top: 4px; }
.ui-hero-media .ui-hero-tiles { margin-top: 8px; }

/* Heat grid */

/* a magnitude over a grid, one cell per bucket. a week of hours, a year of days */

.ui-heat { padding: 12px 12px 4px; }

.ui-heat-row {
	display: flex;
	align-items: center;
	gap: 2px;
}

.ui-heat-row + .ui-heat-row { margin-top: 2px; }

.ui-heat-cap {
	flex: none;
	width: 32px;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ui-t3);
}

.ui-heat-colcap {
	flex: 1 1 0;
	min-width: 0;
	font-size: 9px;
	color: var(--ui-t3);
	text-align: center;
	font-variant-numeric: tabular-nums;
}

/* a year of days puts a month above a column narrower than the word, so the caption is set
   from the left edge of the week the month starts in and overhangs the blank ones after it.
   the columns after a caption are blank by construction, which is what makes that readable
   rather than two words on top of each other */
.ui-heat-months .ui-heat-colcap {
	text-align: left;
	white-space: nowrap;
	overflow: visible;
}

/* the cell height is what the grid is a grid of rather than what a heat grid is, so the
   component sets it on the container and this is only the week's */
.ui-heat-cell {
	flex: 1 1 0;
	min-width: 0;
	height: var(--ui-heat-h, 22px);
	border-radius: 2px;
	cursor: crosshair;
}

/*
	Five steps of one hue, which is what a magnitude ramp is. The empty step keeps its
	outline instead of a fill, so a bucket nothing landed in reads as empty rather than
	as the palest thing on the ramp - those are the two states a reader is choosing
	between, and a ramp that runs into the ground cannot tell them apart.
*/
.ui-heat-0 {
	background: var(--ui-raised);
	box-shadow: inset 0 0 0 1px var(--ui-line);
}

.ui-heat-1 { background: #DFD6DD; }
.ui-heat-2 { background: #C5B2CB; }
.ui-heat-3 { background: #A588B5; }
.ui-heat-4 { background: #8862A1; }
.ui-heat-5 { background: #6D3F8F; }

/* the same ramp mixed into the dark ground instead, since a ramp is only a magnitude if
   its steps run one way in lightness and these would run backwards on a dark panel. the
   empty step is already tokens, so it follows on its own */
:root[data-theme="dark"] .ui-heat-1 { background: #2F2330; }
:root[data-theme="dark"] .ui-heat-2 { background: #4B3659; }
:root[data-theme="dark"] .ui-heat-3 { background: #6D4D8A; }
:root[data-theme="dark"] .ui-heat-4 { background: #8C62B7; }
:root[data-theme="dark"] .ui-heat-5 { background: #A875E0; }

.ui-heat-foot {
	padding: 6px 12px 12px;
	font-size: 11px;
	line-height: 1.55;
	color: var(--ui-t3);
}

/* the ramp, named at both ends so the cells mean something without being pointed at */

.ui-scale {
	display: inline-flex;
	align-items: center;
	gap: 3px;
}

.ui-scale i {
	display: block;
	width: 16px;
	height: 10px;
	border-radius: 1px;
}

.ui-scale-cap {
	font-size: 10px;
	color: var(--ui-t3);
	font-variant-numeric: tabular-nums;
}

/* Reading */

/* one headline figure and what it is of, at the size a rail is worth opening for. one
   line, so the rail beside a stage does not grow past the stage */

.ui-read {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 12px;
}

.ui-read-fig {
	font-size: 30px;
	font-weight: 600;
	line-height: 1.05;
	font-variant-numeric: tabular-nums;
	color: var(--ui-tx);
}

.ui-read-unit {
	font-size: 12px;
	color: var(--ui-t2);
}

/* Histogram */

/* a distribution. one series, so no legend: the heading names it and the axis says what
   it is of */

.ui-hist {
	display: flex;
	align-items: flex-end;
	gap: 3px;
	height: 126px;
	padding: 12px 12px 0;
}

.ui-hist-col {
	flex: 1 1 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	height: 100%;
}

.ui-hist-fill {
	display: block;
	width: 100%;
	background: var(--ui-c1);
	border-radius: 3px 3px 0 0;
}

.ui-hist-cap {
	display: block;
	margin-top: 4px;
	font-size: 9px;
	color: var(--ui-t3);
	text-align: center;
	font-variant-numeric: tabular-nums;
}

.ui-hist-axis {
	display: flex;
	justify-content: space-between;
	padding: 4px 12px 8px;
	font-size: 10px;
	color: var(--ui-t3);
}

.ui-hist-mark {
	color: var(--ui-c1);
	font-weight: 600;
}

/* Level cell */

/* a level in a listing row, its shot beside its two names */

.ui-lvl {
	display: flex;
	align-items: center;
	gap: 8px;
}

.ui-lvl-text {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

/* Trophy case */

/* what a subject earned, as a grid of what was granted rather than a table of mostly
   noughts. only what is listed was earned, so an absent award means not earned */

.ui-trophies {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
	gap: 8px;
	padding: 12px;
}

.ui-trophy {
	display: flex;
	align-items: center;
	gap: 9px;
	padding: 8px 10px;
	background: var(--ui-raised);
	border: 1px solid var(--ui-line);
	border-radius: 4px;
}

.ui-trophy-mark {
	flex: none;
	display: flex;
	color: var(--ui-c3);
}

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

.ui-trophy-name {
	font-size: 12px;
	font-weight: 600;
	color: var(--ui-tx);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ui-trophy-when {
	font-size: 10px;
	color: var(--ui-t3);
}

.ui-trophy-count {
	flex: none;
	font-size: 17px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--ui-t2);
}

/* the tail of a long case, said as a count rather than as more tiles */
.ui-trophy-rest {
	justify-content: center;
	font-size: 11px;
	color: var(--ui-t3);
	border-style: dashed;
	background: none;
}

.ui-trophies-empty {
	grid-column: 1 / -1;
	font-size: 12px;
	color: var(--ui-t3);
}

/* Secret field */

/* a credential shown in a listing, masked until a reader asks for it. the width comes off
   the size attribute rather than off the value, so revealing one cannot widen the column
   and shift every row under it - which is the whole reason this is a field and not a span
   of text. the legacy sheet styles every input, so the border and the ground are restated
   here on the class rather than left to it */

.ui-secret { display: block; }

.ui-secret-value {
	padding: 2px 4px;
	font-family: ui-monospace, "DejaVu Sans Mono", Consolas, monospace;
	font-size: 8pt;
	letter-spacing: 0.03em;
	color: var(--ui-tx);
	background: var(--ui-inset);
	border: 1px solid var(--ui-line-hi);
	border-radius: var(--ui-radius);
}

.ui-secret-masked { color: var(--ui-t3); }

/* the controls are built by the script, so this is empty until it runs */
.ui-secret-ctls {
	display: block;
	white-space: nowrap;
}

/* UI kit gallery, this section is only used by ?action=uikit */

.uikit-body {
	padding: 10px 12px;
	background: var(--ui-raised);
	color: var(--ui-tx);
}

.uikit-body p {
	margin: 0 0 8px 0;
}

.uikit-item {
	margin: 0 0 22px 0;
	padding: 0 0 18px 0;
	border-bottom: 1px solid var(--ui-line);
}

.uikit-item:last-child {
	border-bottom: 0;
}

.uikit-name {
	margin: 0 0 2px 0;
	font-size: 15px;
	font-weight: 600;
	color: var(--ui-tx);
}

.uikit-note {
	margin: 0 0 10px 0;
	font-size: 12px;
	color: var(--ui-t2);
}

.uikit-stage {
	padding: 14px;
	background: var(--ui-sunk);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
}

.uikit-call {
	overflow-x: auto;
	margin: 8px 0 0 0;
	padding: 10px 12px;
	background: var(--ui-inset);
	border: 1px solid var(--ui-line);
	border-radius: var(--ui-radius);
	font: 12px/1.5 ui-monospace, "DejaVu Sans Mono", Consolas, monospace;
	color: var(--ui-t2);
	white-space: pre;
}

.uikit-row {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: center;
}
