.visualizationToggle
{
	order: 10;
	margin-left: auto;
	flex: 0 0 3em;
	font-size: 1.5em;
	padding: .2em;
	border: none;
}
.visualizationToggle[aria-pressed="true"] { color: var(--accent); background: var(--surface-alt); }
.radialView { padding-bottom: 7em; }
.treemapView { padding-bottom: 7em; }
.treemapChart { display: block; width: 100%; height: clamp(260px, 45vh, 480px); touch-action: pan-y; }
.treemapArea { cursor: pointer; outline: none; }
.treemapArea rect { stroke: var(--bg); stroke-width: 2; }
.treemapArea text { fill: #101318; pointer-events: none; font-weight: 600; font-variant-numeric: tabular-nums; }
.treemapRoot text { fill: var(--text); }
.treemapHighlighted rect, .treemapArea:focus-visible rect { stroke: var(--text); stroke-width: 3; }
.radialChart { display: block; width: 100%; overflow: visible; }
.radialChunk { cursor: pointer; outline: none; }
.radialChunk > path, .radialChunk > circle
{
	stroke: var(--bg);
	stroke-width: 2;
	transition: filter .2s, stroke .2s;
}
.radialChunk:not(.radialHighlighted) > path { filter: saturate(.65) brightness(.7); }
.radialChunk.radialHighlighted > path, .radialChunk.radialHighlighted > circle { stroke: var(--text); stroke-width: 2.5; }
.radialChunk:focus-visible > path, .radialChunk:focus-visible > circle { stroke: var(--accent); stroke-width: 4; }
.radialChunk text { fill: #101318; pointer-events: none; font-weight: 600; }
.radialChunk:has(circle) text { fill: var(--text); }
.radialIcon { font-size: 27px; }
.radialAmount { font-size: 18px; font-variant-numeric: tabular-nums; }
#radialLegend:not(.hidden)
{
	position: fixed;
	bottom: calc(var(--action-bar-height) + env(safe-area-inset-bottom));
	left: 0;
	right: 0;
	z-index: 99;
	max-height: min(35vh, 18em);
	overflow-y: auto;
	background: var(--bg);
	border-top: 1px solid var(--border);
	padding: .3em max(.7em, calc((100vw - 620px) / 2));
}
.radialLegendRow
{
	display: flex;
	align-items: center;
	gap: .6em;
	width: 100%;
	padding: .45em .5em;
	border: none;
	font-size: .85em;
	text-align: left;
}
.radialLegendRow.radialHighlighted { background: var(--surface-alt); }
.radialSwatch { width: .8em; height: .8em; border-radius: 50%; flex: none; }
.radialLegendName { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.radialLegendAmount { flex: none; font-variant-numeric: tabular-nums; }
.radialLeafBody { overflow: hidden; display: flex; flex-direction: column; gap: .6em; }
.radialLegendContent.radialOutgoing
{
	position: absolute;
	top: .3em;
	inset-inline: max(.7em, calc((100vw - 620px) / 2));
	pointer-events: none;
}
.hidden
{
	display: none;
}
.transactionSummary
{
	display: flex;
	flex-direction: row;
	justify-content: space-between;
	align-items: center;
	padding: 1em;
}
input, button, body
{
	background-color: #222;
	color: white;
	font-family: monospace;
	font-size: large;
}
:root
{
	--bg: #0b0d10;
	--surface: #16191e;
	--surface-alt: #1e232a;
	--surface-hover: #262c34;
	--border: #2a3038;
	--text: #e9ecf1;
	--text-dim: #9aa3af;
	--accent: #6c8cff;
	--accent-dim: #3d4d99;
	/* Much lower saturation than --accent - used only for "this option/row is selected"
	   highlights inside the view editor (filters/grouping/sort/fields tabs), which are
	   everywhere and shouldn't compete visually with real actions/accents elsewhere. */
	--select-pale: hsl(227, 25%, 68%);
	--select-pale-dim: hsl(227, 15%, 42%);
	--positive: #4ade80;
	--negative: #f87171;
	--info: #38bdf8;
	--radius: 12px;
	--radius-sm: 8px;
	--nav-height: 3.5em;
	/* The icon-over-label layout (1-4 buttons) is the tallest content the bar ever holds;
	   fixing the bar itself to that height, rather than letting it size to content, is what
	   keeps .singleAction's shorter icon-beside-label row from shrinking the bar - see
	   the #...ActionBar rule below. */
	--action-bar-height: 4.35em;
	/* The nesting ladder every group panel and every grouped transaction row is painted
	   from: step 0 matches --surface exactly, and each level deeper takes one small step
	   up in lightness (and one down in saturation). The steps are deliberately tiny -
	   depth only needs to be readable as "one level in", not as a different color - and
	   they are strictly monotonic, so a row nested under a panel is always lighter than
	   that panel, never darker again. */
	--nest-hue: 216;
	--nest-sat: 16%;
	--nest-sat-step: 1.5%;
	--nest-light: 10%;
	--nest-light-step: 3.5%;
	color-scheme: dark;
}

*
{
	box-sizing: border-box;
}

/* html's own background matters as much as body's: on overscroll/rubber-band (iOS bounce,
   Android's overscroll glow) the area revealed past body's edge is html's background, not
   body's - left at its default (transparent, falling through to white) it flashes a wrong
   color right at the edge that's supposed to read as one continuous surface with the OS
   chrome around it. */
html { background: var(--bg); }

body
{
	background: var(--bg);
	color: var(--text);
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	font-size: 16px;
	margin: 0;
	padding: calc(var(--nav-height) + env(safe-area-inset-top) + 1em) 1em 2em;
	max-width: 640px;
	margin-inline: auto;
	min-height: 100vh;
}

/* This app is driven by tap/long-press/drag gestures throughout (long-press-to-select,
   paint-grouper drag, divisor drag, swipe calendar nav) - text selection and the mobile
   tap-highlight overlay just get in the way of those and serve no purpose here. Actual
   text inputs opt back in below since typing still needs normal selection/cursor behavior. */
*
{
	-webkit-user-select: none;
	user-select: none;
	-webkit-tap-highlight-color: transparent;
}

input, textarea
{
	-webkit-user-select: text;
	user-select: text;
}

::selection
{
	background: var(--accent-dim);
	color: var(--text);
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--surface-alt); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: var(--surface-hover); }

/* Persistent top navigation bar. height/padding-top both add env(safe-area-inset-top) - with
   viewport-fit=cover (see index.html) the page draws under any display cutout/status bar
   instead of the browser reserving that strip itself, so without this the bar's own
   background would stop above the inset and the OS's own (non-matching) fill would show
   through right where the two are supposed to read as one continuous surface. The inset is
   0 wherever there's nothing to avoid (no cutout, not installed as a standalone PWA), so
   this is a no-op there. */
#topNav
{
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: calc(var(--nav-height) + env(safe-area-inset-top));
	padding-top: env(safe-area-inset-top);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: .5em;
	padding-left: .5em;
	padding-right: .5em;
	background: var(--bg);
	border-bottom: 1px solid var(--border);
	z-index: 100;
}

#navTitle
{
	margin: 0;
	font-size: 1.05em;
	font-weight: 600;
	letter-spacing: .2px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	flex: 1;
	min-width: 0;
	text-align: center;
	cursor: pointer;
}

#navTitleInput
{
	flex: 1;
	min-width: 0;
	width: auto;
	margin: 0;
	padding: .3em .6em;
	font-size: 1.05em;
	font-weight: 600;
	text-align: center;
}

#navHome, #navSettings
{
	background: transparent;
	border: none;
	color: var(--text);
	font-size: 1.3em;
	line-height: 1;
	width: 2.4em;
	height: 2.4em;
	border-radius: 50%;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	transition: background-color .15s ease, transform .1s ease;
}

#navSettings:hover { background: var(--surface-alt); }
#navHome:active, #navSettings:active { transform: scale(.9); }

/* Screen transitions. Opacity only, no transform: a section's action bar is
   position:fixed but still its DOM child, and a non-"none" transform on an ancestor makes
   it the containing block for fixed-position descendants - so a translateY here would
   pin the bar to the animating section instead of the viewport for the animation's
   duration, and it'd visibly jump to the true bottom edge once the transform settled
   to "none" at the end. */
section { animation: screenIn .2s ease; }

@keyframes screenIn
{
	from { opacity: 0; }
	to { opacity: 1; }
}

/* Generic controls */
input
{
	appearance: none;
	-webkit-appearance: none;
	font-family: inherit;
	font-size: 1em;
	width: 100%;
	margin-bottom: .6em;
	background: var(--surface);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: .6em .8em;
}

input::placeholder { color: var(--text-dim); }
input:focus, button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

button
{
	appearance: none;
	-webkit-appearance: none;
	font-family: inherit;
	font-size: 1em;
	cursor: pointer;
	background: transparent;
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: .6em .8em;
	transition: background-color .15s ease, transform .1s ease, border-color .15s ease;
}

button:hover { background: var(--surface-hover); border-color: var(--accent-dim); }
button:active { transform: scale(.97); }

/* Reserves room below the content for whichever fixed bottom bar the current screen has
   (action bar or .primaryAction), so the list doesn't scroll under it. Sized off
   --action-bar-height (what the bar itself now uses - see the #...ActionBar rule) plus the
   same safe-area-inset-bottom the bar adds to its own height, not --nav-height (the *top*
   bar's height, a coincidental near-match this used to borrow). */
body:has(#transactionsScreen:not(.hidden)),
body:has(#importerScreen:not(.hidden)),
body:has(#viewEditorScreen:not(.hidden)),
body:has(#settingsScreen:not(.hidden)),
body:has(#renameScreen:not(.hidden)),
body:has(#ruleScopeScreen:not(.hidden))
{
	padding-bottom: calc(var(--action-bar-height) + env(safe-area-inset-bottom) + 1em);
}

.primaryAction
{
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	width: 100%;
	margin: 0;
	font-size: 1.05em;
	font-weight: 600;
	padding: .8em .8em calc(.8em + env(safe-area-inset-bottom));
	color: var(--accent);
	background: var(--bg);
	border: none;
	border-top: 1px solid var(--border);
	border-radius: 0;
	z-index: 100;
}

.primaryAction:hover { background: var(--accent-dim); }

/* Transaction list: single-screen, account name gets the space */
/* :not(.hidden) beats the protected .hidden{display:none} class selector on specificity;
   a plain #transactionList rule would win on specificity regardless of source order and
   make setVisibility()'s .hidden toggling a no-op (bit us with body:has() rules before). */
#transactionList:not(.hidden) { display: flex; flex-direction: column; gap: .6em; padding-bottom: 1em; }

.transactionSummary
{
	display: block;
	background: var(--surface);
	border: 1px solid var(--border);
	border-left: 3px solid var(--border);
	border-radius: var(--radius);
	padding: .5em .7em;
	transition: border-color .15s ease;
	animation: rowIn .15s cubic-bezier(.16, 1, .3, 1) both;
}

@keyframes rowIn
{
	from { opacity: 0; transform: translateY(4px); }
	to { opacity: 1; transform: none; }
}

.txMain { display: flex; align-items: center; gap: .4em; }

/* Space starts another equally sized column; fields with the same alignment stay
   together within it. Empty columns intentionally retain their share of the row. */
.fieldColumn
{
	flex: 1 1 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: .25em;
}
.fieldRun
{
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .25em .4em;
	min-width: 0;
	overflow-wrap: anywhere;
	justify-content: flex-start;
	text-align: left;
}
.fieldRun[data-align="center"] { justify-content: center; text-align: center; }
.fieldRun[data-align="right"] { justify-content: flex-end; text-align: right; }
.fieldRun > * { min-width: 0; max-width: 100%; }

/* Every text dimension in the current view uses the same readable treatment as name/amount. */
.txField
{
	flex: none;
	font-size: 1em;
	color: var(--text);
	font-variant-numeric: tabular-nums;
	padding: 0 .2em;
}

.txDetails
{
	overflow: hidden;
}

.txDetailsContent
{
	display: flex;
	flex-direction: column;
	padding-top: .6em;
	font-size: .7em;
	line-height: 1.5;
	border-top: 2px solid var(--border);
}

.txDetailRow
{
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	align-items: center;
	gap: .6em;
	padding: .55em 0;
	border-top: 1px solid var(--border);
	font-size: 1em;
	font-weight: 400;
	font-variant-numeric: tabular-nums;
	color: var(--text);
}

.txDetailHeader
{
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	border-top: none;
	border-bottom: 2px solid var(--border);
	font-size: 1em;
	font-weight: 400;
}

.txDetailRow > span
{
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.txDetailAccount
{
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: .5em;
	text-align: left;
}

.txDetailProviderIcon
{
	width: 1em;
	height: 1em;
	object-fit: contain;
	flex: none;
}

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

.txDetailDateTime
{
	display: flex;
	flex-direction: row;
	justify-content: flex-end;
	align-items: flex-end;
	gap: .5em;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

.txDetailAmount { text-align: right; }
.txDetailParty { text-align: left; }
.txDetailTransfer
{
	grid-template-columns: repeat(4, minmax(0, 1fr));
	border-top: none;
	font-size: 1em;
}
.txDetailTransfer + .txDetailTransfer { border-top: 1px solid var(--border); }

.txIcon
{
	flex: none;
	width: 1.8em;
	height: 1.8em;
	font-size: 1.15em;
	line-height: 1;
	border: none;
	background: none;
	padding: 0;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
}

.txIcon:hover:not(:disabled) { background: var(--surface-hover); }
.txIcon:disabled { cursor: default; opacity: .8; }

/* Keep long names inside their column while preserving the full saved value. */
.txAccount
{
	flex: none;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	padding: .2em .3em;
	border-radius: var(--radius-sm);
	transition: background-color .15s ease;
}

.txAccount:hover { background: var(--surface-alt); }

.txAccountEdit { width: auto; flex: 1; min-width: 0; padding: .2em .3em; margin: 0; font-size: 1em; }

.txAmount { flex: none; font-variant-numeric: tabular-nums; }

/* Detail-style screens */
#transactionScreen label:not(.hidden), #hintScreen label:not(.hidden), #merchantScreen label:not(.hidden)
{
	display: block;
	color: var(--text-dim);
	font-size: .85em;
	text-transform: uppercase;
	letter-spacing: .05em;
	margin-top: 1.4em;
	margin-bottom: .7em;
}

#transactionScreen br, #hintScreen br, #merchantScreen br { display: none; }

#detailHeader
{
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	align-items: center;
	gap: .8em;
	margin-bottom: 1.2em;
}

#detailAccount
{
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: .5em;
	min-width: 0;
}

#detailProviderIcon
{
	width: 1.5em;
	height: 1.5em;
	object-fit: contain;
	flex: none;
}

#detailAccountName
{
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

#detailDateTime
{
	display: flex;
	flex-direction: row;
	align-items: flex-end;
	gap: .5em;
	text-align: right;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

#detailDate, #detailTime, #kindName, #kindCategory, #merchantCategory { display: block; }

#detailHint:not(.hidden) { display: block; width: auto; text-align: left; }

/* Transfer rows: read like plain text, no button chrome, no horizontal scroll.
   A 3-column grid: account names left/right (wrap, smaller), amount+asset
   stacked in the middle so they take less horizontal space. */
#detailTransferList { margin-top: 1.2em; }

#detailTransferList > div
{
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	column-gap: .5em;
	padding: .7em 0;
}

#detailTransferList > div + div { border-top: 1px solid var(--border); }

#detailTransferList > div > button
{
	background: none;
	border: none;
	border-radius: 0;
	padding: 0;
	font: inherit;
	color: var(--text-dim);
	min-width: 0;
}

#detailTransferList > div > button:hover { background: none; color: var(--accent); text-decoration: underline; }

/* from / to accounts: smaller, wrap instead of scrolling */
#detailTransferList > div > button:nth-of-type(1),
#detailTransferList > div > button:nth-of-type(3)
{
	font-size: .8em;
	line-height: 1.3;
	white-space: normal;
	overflow-wrap: break-word;
}

#detailTransferList > div > button:nth-of-type(1) { grid-column: 1; grid-row: 1 / 3; text-align: left; }
#detailTransferList > div > button:nth-of-type(3) { grid-column: 3; grid-row: 1 / 3; text-align: right; }

/* amount + asset: stacked two lines, centered between the accounts */
#detailTransferList > div > span,
#detailTransferList > div > button:nth-of-type(2)
{
	grid-column: 2;
	text-align: center;
	white-space: nowrap;
}

#detailTransferList > div > span
{
	grid-row: 1;
	font-variant-numeric: tabular-nums;
	font-weight: 700;
	color: var(--text);
}

#detailTransferList > div > button:nth-of-type(2) { grid-row: 2; font-weight: 600; }

#detailTransferList > div > button:nth-of-type(1)::after
{
	content: "···";
	margin-left: .4em;
	color: var(--border);
	letter-spacing: 1px;
}

#detailTransferList > div > button:nth-of-type(3)::before
{
	content: "···";
	margin-right: .4em;
	color: var(--border);
	letter-spacing: 1px;
}

/* Settings */
#settingsScreen p { color: var(--text-dim); margin: 1em 0 .3em; font-weight: 600; }

/* Accounts/views/rename/icon/ignore lists - each one a .groupPanel (via
   settingsSectionToggle), so a settings section reads as the same bordered, shaded panel a
   transaction group is: a .groupHeader toggle on top, its rows (already .transactionSummary)
   merged flush into a .groupBody underneath, exactly like grouped transactions. This rule
   only adds the gap between one section's panel and the next - .groupPanel supplies the
   border/radius/background/layout itself - since these are plain sibling divs on the
   settings screen rather than children of a flex list with a shared gap. */
#accountsList, #viewsSettingsList, #renameRulesList, #iconRulesList, #ignoreRulesList, #logsList { margin-bottom: .6em; }

#accountKindsList:not(.hidden) { display: flex; flex-direction: column; gap: .4em; padding-bottom: 1em; }
#accountEditor:not(.hidden) { display: flex; flex-direction: column; gap: .8em; padding-bottom: 1em; }

.accountRow { display: flex; align-items: center; justify-content: space-between; gap: .5em; }
.accountName { font-weight: 600; }
.accountKindIcon { width: 1.1em; height: 1.1em; object-fit: contain; flex: none; }

.accountKindOption { display: flex; align-items: center; justify-content: flex-start; gap: .5em; width: 100%; text-align: left; font-weight: 600; }
.accountKindOption .accountKindIcon { width: 1.4em; height: 1.4em; }

/* The rule-scope picker's own list (not a Settings section, so not a .groupPanel) - same
   flat box-list convention as views/transactions. :not(.hidden) for the same specificity
   reason as #transactionList above. */
#ruleScopeList:not(.hidden) { display: flex; flex-direction: column; gap: .4em; padding-bottom: 1em; }
#ruleIconPicker:not(.hidden) { display: flex; flex-direction: column; gap: .5em; padding-bottom: 1em; }

/* Settings is several lists on one screen now, each named by its own settingsSectionToggle
   header (the .groupHeader button settingsSectionToggle() builds) - that needs no CSS of its
   own at all, since name/space/stat spans built the same way a real group header's are is
   what already matches its size, color and font exactly. */

/* A rule list (Renames/Icons/Ignored) groups its rows under a By ID/By name/By hint label
   (see RULE_GROUP_LABELS) instead of tagging each row with its own kind - same small muted
   uppercase style an account row's kind label already uses, just once per group instead of
   once per row. */
.ruleGroupLabel { font-size: .8em; color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; margin: .6em 0 .2em; }
.ruleGroupLabel:first-child { margin-top: 0; }

.ruleRow { display: flex; align-items: center; gap: .5em; min-width: 0; cursor: pointer; }
.rulePrefix, .ruleSubject { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ruleName { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; font-weight: 600; }
.ruleIcon { flex: none; font-size: 1.2em; }

.logRow { display: block; }
.logText { display: block; white-space: pre-wrap; overflow-wrap: anywhere; font-family: ui-monospace, monospace; font-size: .85em; }

.settingsField { display: flex; flex-direction: column; gap: .3em; }
.settingsField span { font-size: .85em; color: var(--text-dim); }
.settingsField input { margin: 0; }

/* An account's Name must be unique (and non-blank) across every saved account (see
   accountNameIsValid), and its From date must be in range (see accountFromDateIsValid) -
   the same red an error toast/band uses, so either problem reads as the same kind of thing. */
.fieldInvalid { border-color: var(--negative); }

.manualTxForm { display: flex; flex-direction: column; gap: .8em; padding: 1em 0; }

.accountStatus { padding: .6em .8em; border-radius: var(--radius-sm); background: var(--surface-alt); }
.accountStatus.statusOk { color: var(--positive); }
.accountStatus.statusError { color: var(--negative); }

/* The QR code a continental fetch/test puts up mid-flow (see autoFetchContinental and
   screens/continental-account-form.js) - square, capped so it never dominates the action bar
   or the account editor, and centered since both those containers are flex rows/columns
   where an image would otherwise just hug one edge. */
.continentalQrImage { display: block; width: 100%; max-width: 12em; aspect-ratio: 1; margin: 0 auto; border-radius: var(--radius-sm); }

/* Inline emoji picker (categorize flow) - replaces the transaction list in place */
.modalSearch { width: 100%; margin: 0; }

.emojiResults { overflow-y: auto; display: flex; flex-direction: column; gap: .1em; }

.emojiResult
{
	display: flex;
	align-items: center;
	gap: .7em;
	text-align: left;
	border: none;
	background: none;
	padding: .4em .4em;
	border-radius: var(--radius-sm);
}

.emojiResult:hover { background: var(--surface-hover); }
.emojiResult.selected { background: var(--surface-alt); color: var(--accent); }
/* Same picker, but reached from the grouping tab (picking a bin's icon) rather than
   transaction categorization - uses the view editor's pale selection color instead. */
#groupingTab .emojiResult.selected { color: var(--select-pale); }
.emojiResultIcon { font-size: 1.3em; flex: none; }
.emojiResultName { flex: 1; }

.emojiEmpty { color: var(--text-dim); text-align: center; padding: 1.5em 0; }

/* Generic select, matching input/button */
select
{
	appearance: none;
	-webkit-appearance: none;
	font-family: inherit;
	font-size: 1em;
	background: var(--surface);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: .6em .8em;
}

/* Views list, shown inline in the transactions screen in place of the transaction list.
   :not(.hidden) needed for the same specificity reason as #transactionList above. */
#viewsList:not(.hidden) { display: flex; flex-direction: column; gap: .2em; padding-bottom: 1em; }

/* .viewRow also carries .transactionSummary (see renderViewsList) for the same bordered-box
   look as a transaction row; display:flex here overrides that class's display:block since
   this rule comes later in source at equal specificity. Padding is dropped since the box
   already has it. */
.viewRow { display: flex; align-items: center; gap: .2em; cursor: pointer; }
.viewRowName { flex: 1; text-align: left; border: none; background: none; padding: 0; }
.viewRowName:hover { background: none; }

/* A long-press-selected row (grouping/sort/filter/view/transaction), highlighted while its
   actions are showing in the bottom bar. */
.rowSelected { border-color: var(--accent) !important; background: var(--surface-alt); }

/* Same highlight, but the view editor's own rows (filters/groupings/sorts/bin legend) use
   the pale selection color instead - these two classes combined beat the rule above on
   specificity despite both being !important. */
.filterRow.rowSelected, .groupingRow.rowSelected, .sortRow.rowSelected, .binLegendItem.rowSelected
{
	border-color: var(--select-pale) !important;
}

/* View editor screen */
.tabBar { display: flex; gap: .2em; margin: .8em 0; border-bottom: 1px solid var(--border); overflow-x: auto; }

.tabButton
{
	flex: 1;
	border: none;
	background: none;
	border-radius: 0;
	padding: .6em .3em;
	color: var(--text-dim);
	border-bottom: 2px solid transparent;
	font-size: .85em;
	white-space: nowrap;
}

.tabButton:hover { background: none; color: var(--text); }
.tabButton.active { color: var(--accent); border-bottom-color: var(--accent); }

.tabPanel:not(.hidden) { display: flex; flex-direction: column; gap: .7em; padding-bottom: 1em; }

.filterRow, .groupingRow
{
	display: flex;
	flex-direction: column;
	gap: .6em;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: .8em;
	transition: border-color .15s ease, background-color .15s ease;
}

.sortRow
{
	display: flex;
	align-items: center;
	gap: .4em;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: .6em .8em;
	transition: border-color .15s ease, background-color .15s ease;
}

.ruleHeader { display: flex; align-items: center; gap: .5em; }
.ruleHeader select { flex: 1; min-width: 0; }
.sortRow select { flex: 1; min-width: 0; }

.connectorToggle
{
	align-self: center;
	font-size: .8em;
	font-weight: 700;
	color: var(--accent);
	border-color: var(--accent-dim);
	padding: .25em .9em;
}

.directionToggle { flex: none; width: 2.2em; font-size: 1em; text-align: center; padding: .5em; }

.hintNote { color: var(--text-dim); font-size: .85em; margin: 0; }

/* Value grids: squared, uniform cells (not pills) so a cloud of values reads as an
   aligned grid rather than ragged flowing text. Compact dimensions (numbers/emoji) get
   small cells and many columns; text dimensions (merchant/direction) get wider
   cells and fall back toward a single column when the container is narrow. */
.enumGrid
{
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(3em, 1fr));
	gap: .35em;
	touch-action: pan-y;
}

.enumGrid.wide { grid-template-columns: repeat(auto-fill, minmax(8em, 1fr)); }

.enumOption
{
	font-size: .85em;
	padding: .35em .3em;
	border-radius: var(--radius-sm);
	user-select: none;
	text-align: center;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.enumGrid.wide .enumOption { text-align: left; padding-inline: .6em; }
.enumOption.emojiOption { font-size: 1.3em; padding: .3em; }
/* A bin color filter/sort option - the button's own background (set inline, see
   buildEnumPicker) is the value, so there's no text to size the cell around; .selected's own
   border-color still shows through normally on top of it. */
.enumOption.colorOption { min-height: 2.2em; padding: 0; }

.enumOption.selected { background: var(--select-pale); border-color: var(--select-pale); color: #0b0d10; font-weight: 600; }

.paintOption { color: #0b0d10; font-weight: 600; border-width: 2px; }

/* Selecting values never moves them into a bin by itself (see buildPaintGrouper) - the
   accent outline just marks what "Group" is about to act on. */
.paintOption.paintSelected { outline: 3px solid var(--select-pale); outline-offset: 1px; }

.paintGrouper { display: flex; flex-direction: column; gap: .6em; }

/* Collapsed by default (see buildBinLegendSection) - a real .groupPanel/.groupHeader/.groupBody,
   styled for free by the same rules a real transaction group uses. Each entry renders through
   renderGroupHeaderContent (see renderBinLegend), which needs the same flex layout a real
   .groupHeader gives its own name/space/stat spans - .transactionSummary itself doesn't provide
   that (a real transaction row lays its own fields out differently - see .txMain), so it's
   restated here. */
.binLegendItem { display: flex; align-items: center; gap: .4em; }
.binName { flex: 1; padding: .15em .35em; border-radius: var(--radius-sm); }

/* Dual-handle range slider */
.rangeSlider { padding: .3em 0; }
.rangeTrack { position: relative; height: 4px; background: var(--border); border-radius: 2px; margin: 1.4em .7em; }
.rangeFill { position: absolute; top: 0; bottom: 0; background: var(--accent); border-radius: 2px; }

.rangeThumb
{
	position: absolute;
	top: 50%;
	width: 1.3em;
	height: 1.3em;
	background: var(--accent);
	border: 2px solid var(--bg);
	border-radius: 50%;
	transform: translate(-50%, -50%);
	cursor: grab;
	touch-action: none;
}

.rangeInputs { display: flex; gap: .5em; }
.rangeInputs input { text-align: center; }

/* Continuous grouping: a divider line instead of a paint grid. Extra top/bottom margin
   makes room for the alternating value labels (see .divisorValueLabel) that sit just
   outside the track itself. */
.divisorLine
{
	position: relative;
	height: 2.2em;
	margin: 1.6em .2em 1.8em;
	border-radius: var(--radius-sm);
	overflow: visible;
	background: var(--surface-alt);
}

.divisorSegment { position: absolute; top: 0; bottom: 0; pointer-events: none; }
.divisorSegment:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.divisorSegment:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

.divisorHandle
{
	position: absolute;
	top: -.3em;
	bottom: -.3em;
	width: 4px;
	margin-left: -2px;
	background: var(--text);
	border-radius: 2px;
	cursor: grab;
	touch-action: none;
}

.divisorHandle.rowSelected { background: var(--select-pale); box-shadow: 0 0 0 4px var(--select-pale-dim); }

.divisorInput
{
	position: absolute;
	top: -2.6em;
	width: 5em;
	margin: 0;
	margin-left: -2.5em;
	text-align: center;
	z-index: 1;
}

/* Boundary values shown above/below the line in alternation (see renderLine), so adjacent
   labels don't collide when their handles are close together; clicking one opens the same
   precise numeric input a tap on its handle would. The overall max (.divisorMaxLabel) is
   informational only - no click handler. */
.divisorValueLabel
{
	position: absolute;
	transform: translateX(-50%);
	font-size: .75em;
	font-variant-numeric: tabular-nums;
	color: var(--text-dim);
	white-space: nowrap;
	cursor: pointer;
	padding: .1em .3em;
}

.divisorValueLabel.above { bottom: 100%; margin-bottom: .2em; }
.divisorValueLabel.below { top: 100%; margin-top: .2em; }
.divisorValueLabel.divisorMaxLabel { cursor: default; font-weight: 600; }

/* View tab: a keyboard of field/stat keys (see buildKeyboardGrid) + live preview. Fixed at 3
   columns (rather than auto-fill) so the whole tab - the current level's keys, preview - fits
   without scrolling. */
.fieldsGrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .35em; }
.fieldOption { font-size: .85em; padding: .35em .3em; border-radius: var(--radius-sm); }
.fieldOption:disabled { opacity: .35; cursor: default; }
.fieldBackspace { color: var(--negative); }
.fieldAlignment { color: var(--accent); }
.fieldOptionSelected { background: var(--accent); color: var(--bg); border-color: var(--accent); }
/* Picking a group aggregate is a two-step action: operation in the keyboard, then source
   below. Sources can grow quickly with nested grouping levels, so they deliberately stay one
   full-width row apiece and scroll inside a bounded list rather than squeezing their names. */
.aggregateTargetPicker { display: flex; flex-direction: column; gap: .35em; margin-top: .7em; }
.aggregateTargetPicker .hintNote { margin: 0; }
.aggregateTargetChoices { display: flex; flex-direction: column; gap: .35em; max-height: 12rem; overflow-y: auto; padding-right: .15em; }
.aggregateTargetOption { width: 100%; text-align: left; }
/* Nested group+transaction preview: one row per nest level - a group header per grouping,
   each nested inside the one above it, down to one transaction row at the bottom - exactly
   like a real view of that depth renders in the list, instead of a fixed two-row mockup. */
.fieldsPreview { display: flex; flex-direction: column; }

/* .txAccount (the name field) is otherwise the one plain-text field with no font-size/color
   of its own - every other one (.txField: year, account, ...) is dim and small. Scoped to
   the preview rather than changed on .txAccount itself: in the real ledger the name is the
   most-read field on a row and stays full-size/full-color there, this only keeps the Fields
   tab's own sample row from reading as one field emphasized over its neighbors for no reason. */
.fieldsPreview .txAccount { font-size: .85em; color: var(--text-dim); }

/* Each row is clickable (see selectLevel) - the only control for which level is being
   edited, so unlike every other .previewRow-style mockup in the app this one can't be
   pointer-events:none. Selection reuses the app's ordinary .rowSelected highlight (the same
   class a real long-pressed transaction/group row gets) rather than a bespoke style, so a
   selected preview row looks exactly like what selecting the real thing looks like. */
.previewRow { opacity: .9; border-style: dashed; cursor: pointer; }

/* Bin color picker: preset swatches (equidistant hues, same scheme as auto bin colors) plus
   an HSL slider trio - Apply/Cancel live in the action bar, see showApplyCancelBar. */
.colorPicker { display: flex; flex-direction: column; gap: .8em; }
.colorPreview { height: 3em; border-radius: var(--radius); border: 1px solid var(--border); }
.colorPresets { display: grid; grid-template-columns: repeat(6, 1fr); gap: .4em; }
.colorSwatchOption { height: 2.2em; border-radius: var(--radius-sm); border: 1px solid var(--border); padding: 0; }
.hslSliders { display: flex; flex-direction: column; gap: .6em; }
.hslSliderRow { display: flex; flex-direction: column; gap: .3em; font-size: .85em; color: var(--text-dim); }
.hslSliderRow input { margin: 0; }

/* Bottom action bar: fixed like .primaryAction, but content is swapped dynamically
   based on the current editing context instead of being a single static button. An
   explicit height (rather than sizing to content) is what keeps it constant across
   contexts - 1-4 buttons in the normal icon-over-label layout all size the same already,
   but .singleAction's icon-beside-label row is naturally shorter, and would shrink the
   bar (and everything pinned above it) on every screen that happens to land on exactly
   one action. align-items:stretch fills that fixed height back out to every child, so
   content stays centered instead of clipping.
   height/padding-bottom both add env(safe-area-inset-bottom) for the same reason #topNav
   adds safe-area-inset-top - with viewport-fit=cover the page draws under the gesture
   nav bar/home indicator instead of the browser reserving that strip, so the bar's
   background needs to reach all the way into it to actually meet the OS chrome. */
/* :not(.hidden) matters for #importerActionBar specifically - unlike the other three ids
   here, it starts hidden and is toggled at runtime (see updateTransactionsActionBar), and
   a plain id selector would otherwise beat the protected .hidden{display:none} class rule
   on specificity regardless of source order, making that toggle a no-op. */
#viewEditorActionBar, #transactionsActionBar, #settingsActionBar, #importerActionBar:not(.hidden), #renameActionBar, #ruleScopeActionBar
{
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	height: calc(var(--action-bar-height) + env(safe-area-inset-bottom));
	display: flex;
	align-items: stretch;
	gap: .4em;
	padding: .5em .7em calc(.5em + env(safe-area-inset-bottom));
	background: var(--bg);
	border-top: 1px solid var(--border);
	z-index: 100;
}

/* Sits above the action bar rather than over it: the bar is where the user's next tap is
   going, and a message that covers it would be in the way of the very thing it is reporting
   on. Centred and shrink-to-fit so a two-word summary doesn't stretch into a banner. */
#toast
{
	position: fixed;
	bottom: 5em;
	left: 50%;
	transform: translateX(-50%);
	max-width: calc(100% - 2em);
	z-index: 200;
	padding: .6em 1em;
	border-radius: var(--radius);
	border: 1px solid var(--border);
	background: var(--surface-alt);
	color: var(--text);
	font-size: .9em;
	text-align: center;
	white-space: pre-line;
	box-shadow: 0 .4em 1.2em rgba(0, 0, 0, .45);
	animation: toastIn .18s ease;
}
#toast.toastError { color: var(--negative); border-color: var(--negative); }
@keyframes toastIn
{
	from { opacity: 0; transform: translate(-50%, .5em); }
	to { opacity: 1; transform: translate(-50%, 0); }
}

/* Same "sits above the action bar" placement as #toast, just taller (the QR itself needs
   room) and pinned further up so the Cancel/Continue buttons underneath stay reachable. */
#continentalQrOverlay
{
	position: fixed;
	bottom: calc(var(--action-bar-height) + env(safe-area-inset-bottom) + 1em);
	left: 50%;
	transform: translateX(-50%);
	width: calc(100% - 2em);
	max-width: 16em;
	z-index: 200;
	padding: 1em;
	border-radius: var(--radius);
	border: 1px solid var(--border);
	background: var(--surface-alt);
	text-align: center;
	box-shadow: 0 .4em 1.2em rgba(0, 0, 0, .45);
}
#continentalQrOverlay .continentalQrImage { max-width: 100%; }

.barButton
{
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: .2em;
	font-size: 1em;
	font-weight: 600;
	padding: .5em .3em;
	color: var(--accent);
	background: none;
	border: none;
	border-radius: var(--radius-sm);
}

.barButton:hover { background: var(--accent-dim); }
.barButton.barRemove { color: var(--negative); }
.barButton.barRemove:hover { background: rgba(248, 113, 113, .15); }
/* Greyed out, and inert to the hover tint too - an edit that can't apply in the current view
   shouldn't light up under the pointer as though it were still a target. */
.barButton:disabled { opacity: .35; cursor: default; }
.barButton:disabled:hover { background: none; }
/* The generic *{-webkit-tap-highlight-color:transparent} rule should already cover this,
   but some mobile WebKit versions still flash their default blue tap overlay on <button>
   specifically unless it's reasserted here and any lingering :focus outline is suppressed. */
.barButton, .barButton:focus { -webkit-tap-highlight-color: transparent; outline: none; }

/* The auto-fetch password prompt (see updateTransactionsActionBar) sits inline among the
   bar's buttons rather than in a separate panel - fetching is already what the bar is
   showing, so asking for a password mid-fetch is just a variant of that same state. */
.actionBar input[type="password"]
{
	flex: 2;
	min-width: 0;
	background: var(--surface-alt);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	color: var(--text);
	padding: 0 .7em;
}

.fetchPrompt
{
	flex: 2;
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: .85em;
	color: var(--text);
	text-align: center;
}

.barButtonIcon { font-size: 1.3em; line-height: 1; }
.barButtonIcon svg { display: block; width: 1em; height: 1em; }
/* A ring rather than a glyph: the bar's icons are all emoji, and a spinning emoji reads as a
   rotating picture rather than as progress. 1.3em matches .barButtonIcon's font-size, which
   is what sizes the glyph box it stands in for - it deliberately doesn't carry that class,
   since 1.3em of a 1.3em box would come out half again too big. */
.barSpinner
{
	width: 1.3em;
	height: 1.3em;
	border: 2px solid var(--border);
	border-top-color: var(--accent);
	border-radius: 50%;
	animation: barSpin .7s linear infinite;
}
@keyframes barSpin
{
	to { transform: rotate(360deg); }
}
.barButtonLabel
{
	font-size: .7em;
	font-weight: 600;
	line-height: 1.1;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* A bar with only one action reads better as a single "icon label" line than the normal
   icon-over-label stack (see applySingleActionLayout, which toggles this class whenever
   an action bar ends up with exactly one .barButton). */
.actionBar.singleAction .barButton { flex-direction: row; gap: .5em; }
.actionBar.singleAction .barButtonLabel { font-size: 1em; }

/* A group panel is its header (clickable, collapses/expands) plus its body (nested panels
   or transaction rows) merged into one continuous shape - a single background/border/radius
   lives on this wrapper, not separately on the header and body, so an expanded group reads
   as one seamless surface instead of two boxes with a gap between them.
   Deliberately no horizontal padding/inset per nesting level anywhere in here - every panel
   and row spans the full width of its container at any depth (only the page's own outer
   margin bounds it), so the right-aligned aggregation stats land at the exact same
   horizontal position regardless of depth; background color alone marks how deep a group
   is nested.
   :not(.hidden) on the layout-bearing declarations only (not the background rule below,
   which doesn't compete with anything): a Settings section reuses this class on a container
   that's also toggled via .hidden (see showOnlyInSettings) - without the guard, .hidden{
   display:none} and this rule would tie on specificity and .groupPanel, being later in the
   file, would win regardless of the .hidden class actually being present. Real transaction
   group panels are never given .hidden at all, so this is a no-op there. */
.groupPanel:not(.hidden)
{
	display: flex;
	flex-direction: column;
	border: 1px solid var(--border);
	border-radius: var(--radius);
	overflow: hidden;
}

/* The one place the nesting ladder is applied. Both selectors take the same step function
   so the ramp continues unbroken from the outermost panel down through the transaction rows
   at the bottom (which are simply the deepest level, --depth = number of groupings, set in
   renderGroupLevel) - without this the rows fell back to the flat --surface and read as
   *darker* than the panel containing them.
   --depth is set once per panel (and once per grouped row); it is never derived from
   inheritance, so expanding or collapsing a group cannot shift any color. Rows in the flat,
   ungrouped list sit at depth 0, which is exactly --surface, so they look unchanged.
   :not(.rowSelected) keeps this from outweighing the long-press selection highlight, which
   is a plain single-class rule. */
.groupPanel, .groupBody > .transactionSummary:not(.rowSelected)
{
	background: hsl(
		var(--nest-hue),
		max(6%, calc(var(--nest-sat) - var(--depth, 0) * var(--nest-sat-step))),
		min(34%, calc(var(--nest-light) + var(--depth, 0) * var(--nest-light-step))));
}

.groupPanel.previewRow { border-style: dashed; margin-top: .4em; }

/* :not(.hidden) beats the protected .hidden{display:none} rule on specificity - without it,
   both are plain class selectors of equal specificity and this one being later in source
   would win even while hidden. Real toggling only ever happens on .groupBody (drives group
   collapse/expand); kept here too for the same specificity reason should that ever change.
   No arrow glyph marks the collapsed state (see renderGroupLevel/renderTransactions) - the
   header still toggles its body on click, it just isn't visually flagged as "collapsible"
   up front. */
.groupHeader:not(.hidden)
{
	display: flex;
	align-items: center;
	gap: .4em;
	width: 100%;
	text-align: left;
	background: none;
	border: none;
	font-weight: 700;
	font-size: 1em;
	color: var(--text);
	padding: .5em .7em;
	/* Reserves the same vertical space a swatch-bearing header takes so a header with no
	   icon/color - just centered text - is still exactly as tall as one that has both,
	   instead of shrinking to fit its shorter content. */
	min-height: 3.2em;
}

/* No :hover highlight on a group header, on purpose. A group's color means one thing only -
   how deep it is nested - so it has to stay fixed: with a hover rule, tapping a header on a
   touch device leaves the hover state stuck on it, making it look like opening the group
   recolored it (and on a mouse it recolors for as long as the pointer rests there after the
   click). The body sliding open is feedback enough. */

/* A long-pressed header. The generic .rowSelected highlight is a single class, and it works
   on transaction rows because they own a border and a background of their own - but a header
   has neither (the panel draws its edges, and .groupHeader:not(.hidden) sets its background
   with two classes), so that rule loses on specificity and the selection would be invisible.
   Restated here at matching weight, and after it in source order. */
.groupHeader.rowSelected { background: var(--accent-dim); }

/* Configured headers use equal-width field columns. The spacer class remains for
   fixed application chrome such as the grouping editor's Legend toggle. */
.groupHeaderName { flex: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.groupHeaderSpace { flex: 1; min-width: 0; }
.groupHeaderStat { flex: none; }
.groupHeaderStatSep { flex: none; color: var(--text-dim); }

/* Color and icon are independent stats now, each landing wherever its own entry sits in the
   list, rather than one swatch with the icon painted on top of the color square. Matched box
   sizes keep them aligned with each other on the occasions they are adjacent. */
.groupHeaderColor { flex: none; width: 1.8em; height: 1.8em; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.groupHeaderIcon { flex: none; width: 1.8em; height: 1.8em; display: flex; align-items: center; justify-content: center; font-size: 1.15em; line-height: 1; }

/* Holds a group's children (nested panels or transaction rows). No horizontal padding -
   children span the panel's full width, flush with the header above them. */
.groupBody:not(.hidden)
{
	display: flex;
	flex-direction: column;
	gap: .6em;
	padding: 0 0 .6em;
}

/* Children of a group sit flush against each other - no gap - so consecutive items are told
   apart only by their own borders touching, the same "one seamless surface" idea the panel
   already applies to its header/body. Squaring the corners off is what makes that work: a
   rounded corner between two flush items would leave a gap at the curve even at margin 0.
   The -1px pulls each item onto its predecessor's bottom border so the two share a single
   line instead of stacking into a 2px one. The .groupPanel's own border-radius plus its
   overflow:hidden still rounds the very top and bottom of the run, so the merged list reads
   as rounded overall despite every child being square.
   Dropping the right border is what makes a row's right-aligned amount land on the exact
   same x as its group header's right-aligned stats: children span the panel's full inner
   width, so a child's own right border would sit directly inside the panel's - a doubled
   line, and 1px of extra inset that the header (border-less, its edge owned by the panel)
   doesn't have. Left borders stay: on a row that edge is the 3px colored direction band,
   which is data, not a box edge. Written against every child rather than just rows so the
   inset can't accumulate a pixel per level down a nested tree.
   Scoped to a body that actually sits inside a panel, because renderTransactions wraps the
   whole top-level list in a .groupBody of its own: unscoped, these would square off the
   outermost panels and merge them into one borderless slab, when at that level they are
   still meant to be separate rounded cards with the list's usual gap between them. */
.groupPanel > .groupBody:not(.hidden) { gap: 0; }
.groupPanel > .groupBody:not(.hidden) > * { border-radius: 0; border-right: none; }
.groupPanel > .groupBody:not(.hidden) > * + * { margin-top: -1px; }

@media (max-width: 420px)
{
	body { padding-inline: .7em; }
}

/* #importerFooterButtons wraps the original standalone #submitImport (still
   .primaryAction) alongside the new #postponeImport - override its fixed full-width
   positioning so both sit side by side inside the shared fixed footer instead. */
#importerFooterButtons { position: fixed; bottom: 0; left: 0; right: 0; display: flex; z-index: 100; }
#importerFooterButtons .primaryAction, #postponeImport { position: static; flex: 1; width: auto; }
#postponeImport
{
	margin: 0;
	font-size: 1.05em;
	font-weight: 600;
	padding: .8em .8em calc(.8em + env(safe-area-inset-bottom));
	color: var(--text-dim);
	background: var(--bg);
	border: none;
	border-top: 1px solid var(--border);
	border-right: 1px solid var(--border);
	border-radius: 0;
}
#postponeImport:hover { background: var(--surface-hover); }

.savePasswordOption
{
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: .6em;
	margin-top: .2em;
	cursor: pointer;
}
.savePasswordOption input[type="checkbox"]
{
	appearance: auto;
	-webkit-appearance: auto;
	width: 1em;
	height: 1em;
	margin: 0;
	padding: 0;
	background: initial;
	border: initial;
	border-radius: initial;
	accent-color: var(--accent);
	flex: none;
}
.appVersion
{
	padding: 0.75rem 1rem 0.25rem;
	color: var(--text-dim, #9aa3af);
	font-size: 0.85rem;
}
