/* ===== COMPONENTS =====
   The shared vocabulary: buttons, fields, cards, tables, menus, modals, toasts.
   A section should almost never need to invent one of these — if it does, the
   component belongs here instead. */

/* ===== BUTTONS ===== */
.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--s-2);
	height: 34px;
	padding: 0 var(--s-3);
	border: 1px solid var(--border);
	border-radius: var(--r-md);
	background: var(--surface);
	color: var(--text);
	font-size: var(--fs-base);
	font-weight: 500;
	white-space: nowrap;
	transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast), opacity var(--t-fast);
}
.btn svg { width: 16px; height: 16px; }
.btn:hover { background: var(--surface-2); border-color: var(--border-strong); }
.btn:active { transform: translateY(.5px); }
.btn:disabled { opacity: .5; pointer-events: none; }

.btn-primary {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--text-invert);
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-2); border-color: transparent; color: var(--text); }

.btn-danger { color: var(--danger); border-color: var(--border); }
.btn-danger:hover { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }

.btn-solid-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-solid-danger:hover { background: color-mix(in srgb, var(--danger) 85%, #000); border-color: transparent; }

.btn-sm { height: 28px; padding: 0 var(--s-2); font-size: var(--fs-sm); }
.btn-lg { height: 40px; padding: 0 var(--s-5); font-size: var(--fs-md); }
.btn-block { width: 100%; }

.icon-btn {
	display: inline-grid;
	place-items: center;
	width: 32px; height: 32px;
	/* A square target keeps its square. Inside a crowded flex row — the markdown
	   toolbar on a phone is eleven buttons across 390px — the default shrink
	   quietly ground these down to 23px wide and left the row looking fine while
	   nothing in it could be hit. The rows that hold them scroll instead. */
	flex: none;
	border-radius: var(--r-md);
	color: var(--text-2);
	transition: background var(--t-fast), color var(--t-fast);
}
.icon-btn svg { width: 17px; height: 17px; }
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn.is-active { background: var(--accent-soft); color: var(--accent-text); }
.icon-btn:disabled { opacity: .4; pointer-events: none; }

/* A row of buttons that behaves as one control (view switchers, modes). */
.segmented {
	display: inline-flex;
	padding: 2px;
	gap: 2px;
	background: var(--surface-2);
	border: 1px solid var(--border);
	border-radius: var(--r-md);
}
.segmented button {
	height: 26px;
	padding: 0 var(--s-3);
	border-radius: calc(var(--r-md) - 3px);
	color: var(--text-2);
	font-size: var(--fs-sm);
	font-weight: 500;
	transition: background var(--t-fast), color var(--t-fast);
}
.segmented button svg { width: 15px; height: 15px; }
.segmented button:hover { color: var(--text); }
.segmented button.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

/* ===== FIELDS ===== */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--s-4); }

.label { font-size: var(--fs-sm); font-weight: 500; color: var(--text-2); }

.input, .textarea, .select {
	width: 100%;
	min-height: 36px;
	padding: 7px var(--s-3);
	border: 1px solid var(--border);
	border-radius: var(--r-md);
	background: var(--surface);
	color: var(--text);
	font-size: var(--fs-base);
	transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
.input:focus, .textarea:focus, .select:focus {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
.input:disabled, .textarea:disabled { background: var(--surface-2); color: var(--text-3); }

.textarea { min-height: 96px; resize: vertical; line-height: 1.6; }

.select {
	appearance: none;
	padding-right: var(--s-8);
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
	background-size: 5px 5px;
	background-repeat: no-repeat;
	cursor: pointer;
}

.field-hint { font-size: var(--fs-xs); color: var(--text-3); }
.field-error { font-size: var(--fs-xs); color: var(--danger); }

/* An input with a button glued to its trailing edge (reveal, copy, generate). */
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap .input { padding-right: 38px; }
.input-affix {
	position: absolute;
	right: 4px;
	display: grid;
	place-items: center;
	width: 28px; height: 28px;
	border-radius: var(--r-sm);
	color: var(--text-3);
	transition: color var(--t-fast), background var(--t-fast);
}
.input-affix svg { width: 16px; height: 16px; }
.input-affix:hover { background: var(--surface-2); color: var(--text); }

.checkbox { display: inline-flex; align-items: center; gap: var(--s-2); cursor: pointer; user-select: none; }
.checkbox input {
	appearance: none;
	width: 16px; height: 16px;
	border: 1.5px solid var(--border-strong);
	border-radius: 5px;
	background: var(--surface);
	cursor: pointer;
	transition: background var(--t-fast), border-color var(--t-fast);
}
.checkbox input:checked {
	background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E") center / 11px no-repeat;
	border-color: var(--accent);
}

.switch { position: relative; display: inline-block; width: 36px; height: 20px; flex: none; }
.switch input { appearance: none; position: absolute; inset: 0; margin: 0; cursor: pointer; }
.switch input::before {
	content: "";
	position: absolute; inset: 0;
	background: var(--surface-3);
	border-radius: var(--r-full);
	transition: background var(--t-base) var(--ease);
}
.switch input::after {
	content: "";
	position: absolute;
	top: 2px; left: 2px;
	width: 16px; height: 16px;
	background: #fff;
	border-radius: 50%;
	box-shadow: var(--shadow-sm);
	transition: transform var(--t-base) var(--ease);
}
.switch input:checked::before { background: var(--accent); }
.switch input:checked::after { transform: translateX(16px); }

/* Search field with a leading icon — used at the top of most sections. */
.search {
	position: relative;
	display: flex;
	align-items: center;
	flex: 1 1 200px;
	max-width: 320px;
}
.search svg {
	position: absolute;
	left: 10px;
	width: 15px; height: 15px;
	color: var(--text-3);
	pointer-events: none;
}
.search input {
	width: 100%;
	height: 34px;
	padding: 0 var(--s-3) 0 32px;
	border: 1px solid var(--border);
	border-radius: var(--r-md);
	background: var(--surface);
	font-size: var(--fs-base);
}
.search input:focus {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* ===== SURFACES ===== */
.card {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
}

.card-pad { padding: var(--s-5); }

.panel-title {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--text-3);
}

/* ===== BADGES ===== */
.badge {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	height: 20px;
	padding: 0 7px;
	border-radius: var(--r-sm);
	background: var(--surface-2);
	color: var(--text-2);
	font-size: var(--fs-xs);
	font-weight: 500;
	white-space: nowrap;
}
.badge svg { width: 12px; height: 12px; }
.badge-accent  { background: var(--accent-soft);  color: var(--accent-text); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger); }
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-info    { background: var(--info-soft);    color: var(--info); }

kbd {
	display: inline-block;
	min-width: 18px;
	padding: 1px 5px;
	border: 1px solid var(--border);
	border-bottom-width: 2px;
	border-radius: 5px;
	background: var(--surface-2);
	color: var(--text-3);
	font-family: var(--font);
	font-size: 11px;
	line-height: 15px;
	text-align: center;
}

/* ===== TABLES ===== */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
.table th {
	padding: var(--s-2) var(--s-3);
	border-bottom: 1px solid var(--border);
	color: var(--text-3);
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
	text-align: left;
	white-space: nowrap;
}
.table td { padding: var(--s-3); border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background var(--t-fast); }
.table tbody tr:hover { background: var(--surface-2); }

/* ===== EMPTY & LOADING ===== */
.empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--s-3);
	padding: var(--s-12) var(--s-5);
	text-align: center;
}
.empty-icon {
	display: grid;
	place-items: center;
	width: 44px; height: 44px;
	border-radius: var(--r-lg);
	background: var(--surface-2);
	color: var(--text-3);
}
.empty-icon svg { width: 21px; height: 21px; }
.empty h3 { font-size: var(--fs-md); font-weight: 600; }
.empty p { max-width: 42ch; color: var(--text-2); font-size: var(--fs-base); }

.skeleton {
	background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
	background-size: 400% 100%;
	border-radius: var(--r-md);
	animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer { to { background-position: -135% 0; } }

.spinner {
	width: 15px; height: 15px;
	border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
	border-top-color: currentColor;
	border-radius: 50%;
	animation: spin .65s linear infinite;
}

/* ===== OVERLAY LAYERS ===== */
.layer { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.layer:empty { display: none; }
.layer > * { pointer-events: auto; }

/* ===== MODALS ===== */
.scrim {
	position: fixed;
	inset: 0;
	background: var(--scrim);
	backdrop-filter: blur(2px);
	animation: fade-in var(--t-base) var(--ease) forwards;
	opacity: 0;
}

.modal {
	position: fixed;
	inset: 0;
	display: grid;
	place-items: center;
	padding: var(--s-4);
	pointer-events: none;
}
.modal > * { pointer-events: auto; }

.modal-box {
	width: min(100%, 480px);
	max-height: calc(100dvh - var(--s-8));
	display: flex;
	flex-direction: column;
	background: var(--overlay);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: var(--shadow-lg);
	animation: modal-in var(--t-base) var(--ease);
}
.modal-box.is-wide { width: min(100%, 720px); }

@keyframes modal-in {
	from { opacity: 0; transform: translateY(8px) scale(.98); }
	to   { opacity: 1; transform: none; }
}

.modal-head {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	padding: var(--s-5) var(--s-5) var(--s-3);
}
.modal-head h2 { font-size: var(--fs-lg); }
.modal-head p { margin-top: 2px; font-size: var(--fs-sm); color: var(--text-2); }

.modal-body { padding: 0 var(--s-5); overflow-y: auto; flex: 1; }
.modal-body > :last-child { margin-bottom: 0; }

.modal-foot {
	display: flex;
	justify-content: flex-end;
	gap: var(--s-2);
	padding: var(--s-4) var(--s-5) var(--s-5);
}
.modal-foot .spacer { flex: 1; }

/* On a phone a dialog is a sheet: it comes up from the bottom edge, where the
   thumb already is, and keeps its full width. */
@media (max-width: 700px) {
	.modal { place-items: end center; padding: 0; }
	.modal-box {
		width: 100%;
		max-height: 92dvh;
		border-radius: var(--r-xl) var(--r-xl) 0 0;
		border-bottom: 0;
		padding-bottom: env(safe-area-inset-bottom, 0px);
		animation: sheet-in var(--t-base) var(--ease);
	}
	.modal-box.is-wide { width: 100%; }
	@keyframes sheet-in { from { transform: translateY(100%); } to { transform: none; } }

	/* The grab bar says "this came up from the bottom and goes back down",
	   which is the one thing a sheet has to say before anything is read. */
	.modal-box::before {
		content: "";
		width: 36px;
		height: 4px;
		flex: none;
		margin: 8px auto 0;
		border-radius: var(--r-full);
		background: var(--border-strong);
	}

	.modal-head { padding-top: var(--s-4); }

	/* Buttons on a sheet are reached with a thumb, so they get the full width
	   rather than huddling in the corner. */
	.modal-foot { padding-bottom: var(--s-5); }
	.modal-foot .btn { flex: 1 1 auto; }
	.modal-foot .btn-block { flex-basis: 100%; }
}

/* ===== MENUS ===== */
.menu {
	position: fixed;
	min-width: 178px;
	max-width: 260px;
	padding: 5px;
	background: var(--overlay);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	box-shadow: var(--shadow-lg);
	animation: menu-in var(--t-fast) var(--ease);
	transform-origin: var(--menu-origin, top left);
}
@keyframes menu-in {
	from { opacity: 0; transform: scale(.96); }
	to   { opacity: 1; transform: none; }
}

.menu-item {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	width: 100%;
	padding: 7px var(--s-2);
	border-radius: var(--r-sm);
	color: var(--text);
	font-size: var(--fs-base);
	text-align: left;
	transition: background var(--t-fast);
}
.menu-item svg { width: 16px; height: 16px; color: var(--text-3); }
.menu-item:hover { background: var(--surface-2); }
.menu-item:hover svg { color: var(--text-2); }
.menu-item kbd { margin-left: auto; }
.menu-item.is-danger { color: var(--danger); }
.menu-item.is-danger svg { color: var(--danger); }
.menu-item.is-danger:hover { background: var(--danger-soft); }
.menu-item.is-active svg.menu-check { color: var(--accent); }

.menu-sep { height: 1px; margin: 5px 0; background: var(--border); }
.menu-label { padding: 6px var(--s-2) 4px; font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }

/* ===== TOASTS ===== */
.toasts {
	position: fixed;
	right: var(--s-4);
	bottom: var(--s-4);
	z-index: 90;
	display: flex;
	flex-direction: column-reverse;
	gap: var(--s-2);
	pointer-events: none;
}

.toast {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	max-width: 360px;
	padding: 10px var(--s-4);
	background: var(--overlay);
	border: 1px solid var(--border);
	border-left: 3px solid var(--text-3);
	border-radius: var(--r-md);
	box-shadow: var(--shadow-lg);
	font-size: var(--fs-base);
	pointer-events: auto;
	animation: toast-in var(--t-base) var(--ease);
}
.toast svg { width: 16px; height: 16px; }
.toast.is-success { border-left-color: var(--success); }
.toast.is-success svg { color: var(--success); }
.toast.is-error { border-left-color: var(--danger); }
.toast.is-error svg { color: var(--danger); }
.toast.is-info { border-left-color: var(--info); }
.toast.is-info svg { color: var(--info); }
.toast.is-leaving { animation: toast-out var(--t-base) var(--ease) forwards; }

@keyframes toast-in  { from { opacity: 0; transform: translateY(10px) scale(.97); } }
@keyframes toast-out { to   { opacity: 0; transform: translateY(6px) scale(.97); } }

/* The tab bar exists from 900px down, so a toast has to clear it from 900px
   down too — not from 560px, which left one band of widths posting toasts
   behind the navigation. */
@media (max-width: 900px) {
	.toasts { bottom: calc(var(--tabbar-h) + var(--s-3)); }
}

@media (max-width: 560px) {
	.toasts { left: var(--s-3); right: var(--s-3); }
	.toast { max-width: none; }
}

/* ===== COMMAND PALETTE ===== */
.palette-wrap {
	position: fixed;
	inset: 0;
	display: grid;
	place-items: start center;
	padding: max(8vh, var(--s-6)) var(--s-4) var(--s-4);
	pointer-events: none;
}
.palette-wrap > * { pointer-events: auto; }

.palette {
	width: min(100%, 560px);
	max-height: 62vh;
	display: flex;
	flex-direction: column;
	background: var(--overlay);
	border: 1px solid var(--border);
	border-radius: var(--r-xl);
	box-shadow: var(--shadow-lg);
	overflow: hidden;
	animation: modal-in var(--t-base) var(--ease);
}

.palette-field {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	padding: var(--s-4);
	border-bottom: 1px solid var(--border);
}
.palette-field svg { width: 17px; height: 17px; color: var(--text-3); }
.palette-field input {
	flex: 1;
	border: 0;
	background: none;
	font-size: var(--fs-lg);
	outline: none;
}
.palette-field input::placeholder { color: var(--text-3); }

.palette-results { overflow-y: auto; padding: var(--s-2); }

.palette-group { padding: var(--s-3) var(--s-2) 4px; font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }

.palette-item {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	width: 100%;
	padding: 8px var(--s-2);
	border-radius: var(--r-md);
	text-align: left;
	transition: background var(--t-fast);
}
.palette-item svg { width: 16px; height: 16px; color: var(--text-3); }
.palette-item .pi-body { min-width: 0; flex: 1; }
.palette-item .pi-title { font-size: var(--fs-base); }
.palette-item .pi-sub { font-size: var(--fs-xs); color: var(--text-3); }
.palette-item[aria-selected="true"] { background: var(--surface-2); }
.palette-item[aria-selected="true"] svg { color: var(--accent); }

.palette-empty { padding: var(--s-8) var(--s-4); text-align: center; color: var(--text-3); font-size: var(--fs-base); }

/* On a phone the keyboard takes the bottom half of the screen the moment the
   palette opens, so it sits near the top and keeps its results in what's left
   rather than centring itself behind the keys. */
@media (max-width: 700px) {
	.palette-wrap { padding: var(--s-3) var(--s-3) var(--s-4); }
	.palette { max-height: min(70dvh, 520px); }
	.palette-field { padding: var(--s-3); }
	.palette-field input { font-size: var(--fs-lg); }
}

/* ===== TOUCH =====
   Everything above is sized for a cursor, which is accurate to the pixel. A
   fingertip is not: it covers about 9mm, so a 28px control is a coin toss and a
   32px one is only slightly better. On a phone the shared controls grow to the
   44px that a thumb actually needs, and the type inside form fields grows to
   16px — below that, iOS Safari zooms the whole page in the moment the field
   takes focus, and the layout never quite comes back. */
@media (max-width: 700px) {
	.btn { height: 40px; padding: 0 var(--s-4); }
	.btn-sm { height: 34px; padding: 0 var(--s-3); }
	.btn-lg { height: 46px; }

	.icon-btn { width: 40px; height: 40px; }
	.icon-btn svg { width: 19px; height: 19px; }

	.segmented button { height: 32px; }

	.input, .textarea, .select { min-height: 44px; font-size: 16px; }
	.textarea { min-height: 120px; }
	.search input { height: 40px; font-size: 16px; }
	.input-wrap .input { padding-right: 46px; }
	.input-affix { width: 36px; height: 36px; }

	.checkbox input { width: 20px; height: 20px; background-size: 13px; }

	.menu { min-width: 210px; }
	.menu-item { padding: 11px var(--s-3); }
	.menu-item svg { width: 18px; height: 18px; }

	/* The tap highlight is off globally, which is right — the grey box the
	   browser draws is nobody's design. But something has to answer a finger, so
	   the things that were relying on :hover to look alive get a pressed state
	   of their own. */
	.menu-item:active, .palette-item:active { background: var(--surface-3); }
	.icon-btn:active { background: var(--surface-3); }
	.btn:active { filter: brightness(.96); }

	.palette-item { padding: 11px var(--s-2); }
}

/* ===== PASSKEYS ===== */
.passkey-lede { margin-bottom: var(--s-3); color: var(--text-2); font-size: var(--fs-base); }

.passkey-row {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	padding: var(--s-3);
	margin-bottom: var(--s-2);
	background: var(--surface-2);
	border-radius: var(--r-md);
}
.passkey-row > svg { width: 20px; height: 20px; flex: none; color: var(--accent); }
.passkey-main { flex: 1; min-width: 0; }
.passkey-name { display: flex; align-items: center; gap: var(--s-2); font-weight: 500; }
.passkey-when { color: var(--text-3); font-size: var(--fs-xs); }

/* ===== PROGRESS ===== */
.meter { height: 5px; border-radius: var(--r-full); background: var(--surface-3); overflow: hidden; }
.meter > span {
	display: block;
	height: 100%;
	border-radius: inherit;
	background: var(--accent);
	transition: width var(--t-base) var(--ease), background var(--t-base);
}
.meter.is-danger  > span { background: var(--danger); }
.meter.is-warning > span { background: var(--warning); }
.meter.is-success > span { background: var(--success); }
