/* ============================================================================
   Šihterica — web frontend
   Design language: "modern minimal"
   Neutral off-white canvas, white cards with hairline borders and soft
   shadows, a single indigo accent, tinted status pills, and restrained
   motion (entrance, hover, focus, live pulse). See
   docs/ui-design-guidelines.md.
   ========================================================================== */

@font-face {
	font-family: roboto-font;
	src: url('../fonts/Roboto-VariableFont_wdth\,wght.ttf');
}

:root {
	--bg: #f7f8fa;
	--surface: #ffffff;
	--surface-2: #f9fafb;
	--border: #e4e7ec;
	--border-strong: #d0d5dd;

	--text-1: #101828;
	--text-2: #475467;
	--text-3: #98a2b3;

	--accent: #4f46e5;
	--accent-soft: #eef2ff;
	--accent-ring: rgba(79, 70, 229, 0.14);
	/* solid accent fills (buttons, brand mark, filled icon chips) — darker
	   than the accent text color so white labels keep their contrast */
	--accent-btn: #4f46e5;
	--accent-btn-hover: #4338ca;

	--ok: #12b76a;
	--ok-soft: #ecfdf3;
	--ok-text: #067647;
	--warn: #f79009;
	--warn-soft: #fffaeb;
	--warn-text: #b54708;
	--error: #f04438;
	--error-soft: #fef3f2;
	--error-text: #b42318;
	--danger: #d92d20;
	--danger-hover: #b42318;

	/* structural neutrals — the light/dark inversion redefines them */
	--glow: rgba(79, 70, 229, 0.06);
	--header-bg: rgba(255, 255, 255, 0.82);
	--hover: #f2f4f7;
	--fill: #eef0f3;
	--inset: #fcfcfd;

	--radius-sm: 8px;
	--radius-md: 12px;
	--radius-lg: 16px;

	--shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05);
	--shadow-md: 0 8px 24px -8px rgba(16, 24, 40, 0.14);
	--shadow-lg: 0 24px 48px -12px rgba(16, 24, 40, 0.28);

	--font-mono: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

* {
	box-sizing: border-box;
}

html {
	color-scheme: light;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

body {
	margin: 0;
	background: radial-gradient(1200px 500px at 50% -220px, var(--glow), transparent 60%), var(--bg);
	color: var(--text-1);
	font-family:
		roboto-font,
		-apple-system,
		BlinkMacSystemFont,
		'Segoe UI',
		sans-serif;
	font-size: 14px;
	font-weight: 400;
	line-height: 1.5;
}

[hidden] {
	display: none !important;
}

::selection {
	background: rgba(79, 70, 229, 0.18);
}

a:focus-visible,
button:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

h1 {
	margin: 0;
	font-size: 26px;
	font-weight: 650;
	letter-spacing: -0.02em;
	line-height: 1.25;
	color: var(--text-1);
}

h2 {
	margin: 0;
	font-size: 15px;
	font-weight: 600;
	letter-spacing: -0.01em;
}

h3 {
	margin: 0;
	font-size: 15.5px;
	font-weight: 600;
	letter-spacing: -0.01em;
}

/* ------------------------------------------------------------------ */
/* App header (sticky, translucent)                                    */
/* ------------------------------------------------------------------ */

.app-header {
	position: sticky;
	top: 0;
	z-index: 50;
	background: var(--header-bg);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	border-bottom: 1px solid var(--border);
}

/* While the admin banner is pinned above, the header pins right below it. */
body.has-admin-banner .app-header {
	top: 40px;
}

.header-inner {
	max-width: 960px;
	margin: 0 auto;
	padding: 0 24px;
	height: 56px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

.brand {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	text-decoration: none;
	color: var(--text-1);
}

.brand-mark {
	width: 28px;
	height: 28px;
	border-radius: 8px;
	background: var(--accent-btn);
	color: #ffffff;
	display: grid;
	place-items: center;
	flex: none;
}

.brand-mark svg {
	width: 16px;
	height: 16px;
}

.brand-name {
	font-size: 15px;
	font-weight: 650;
	letter-spacing: -0.01em;
}

nav.main {
	display: flex;
	flex-wrap: wrap;
	gap: 2px;
}

nav.main a {
	padding: 7px 12px;
	border-radius: var(--radius-sm);
	text-decoration: none;
	font-size: 13.5px;
	font-weight: 500;
	color: var(--text-2);
	transition:
		color 0.15s ease,
		background 0.15s ease;
}

nav.main a.active {
	color: var(--accent);
	background: var(--accent-soft);
	font-weight: 550;
}

/* ------------------------------------------------------------------ */
/* Page layout                                                         */
/* ------------------------------------------------------------------ */

.page {
	max-width: 960px;
	margin: 0 auto;
	padding: 36px 24px 80px;
}

.page.narrow {
	max-width: 600px;
}

/* Staggered entrance: each direct child of the page rises in. Sections
   that start hidden replay the animation when they are shown later
   (the connect → sign flow on the sign-in page). */
.page > * {
	animation: rise 0.5s var(--ease-out) both;
}

.page > *:nth-child(2) {
	animation-delay: 0.05s;
}

.page > *:nth-child(3) {
	animation-delay: 0.1s;
}

.page > *:nth-child(4) {
	animation-delay: 0.15s;
}

.page > *:nth-child(5) {
	animation-delay: 0.2s;
}

.page > *:nth-child(6) {
	animation-delay: 0.25s;
}

.page-head {
	margin-bottom: 24px;
}

.page-sub {
	margin: 6px 0 0;
	font-size: 13.5px;
	color: var(--text-2);
}

.page-foot {
	margin-top: 24px;
}

/* ------------------------------------------------------------------ */
/* Panels (cards)                                                      */
/* ------------------------------------------------------------------ */

.panel {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	padding: 20px;
}

.panel + .panel {
	margin-top: 16px;
}

.panel-title {
	margin-bottom: 14px;
}

.panel-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex-wrap: wrap;
	margin-bottom: 12px;
}

.panel-bar .panel-title {
	margin-bottom: 0;
}

.panel-tools {
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
}

/* ------------------------------------------------------------------ */
/* Forms                                                               */
/* ------------------------------------------------------------------ */

/* Stacked form: one field per row, full-width primary button. */
form.stack {
	display: grid;
	gap: 12px;
	max-width: 400px;
}

form.stack button {
	width: 100%;
}

/* Row form: fields and the button share one line. */
form.row {
	display: flex;
	align-items: flex-end;
	gap: 10px;
	flex-wrap: wrap;
}

form.row .field {
	flex: 1 1 220px;
}

form.row button {
	flex: none;
}

.field {
	display: block;
}

.field > span {
	display: block;
	margin-bottom: 6px;
	font-size: 12px;
	font-weight: 550;
	letter-spacing: 0.01em;
	color: var(--text-2);
}

input,
select {
	/* max-width wins over a native control's intrinsic min-width (e.g. the
	   iOS month picker) so an input can never overflow its panel */
	max-width: 100%;
	min-height: 38px;
	padding: 0 12px;
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	background: var(--surface);
	color: var(--text-1);
	font-family: inherit;
	font-size: 14px;
	line-height: 1.4;
	text-align: left;
	transition:
		border-color 0.15s ease,
		box-shadow 0.15s ease,
		background 0.15s ease;
}

select {
	min-width: 130px;
	padding-right: 28px;
}

input::placeholder {
	color: var(--text-3);
}

input:focus,
select:focus {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-ring);
}

.field input,
.field select {
	width: 100%;
}

/* The worker sign-in code — the single most prominent field in the app. */
.code-field input.big {
	min-height: 58px;
	width: 100%;
	font-size: 26px;
	font-weight: 500;
	letter-spacing: 0.32em;
	/* balances the trailing letter-spacing so the text reads centered */
	padding-left: calc(12px + 0.16em);
	text-align: center;
	border-radius: var(--radius-md);
}

#sign-form {
	display: grid;
	gap: 14px;
}

/* The connect form is the only form on the screen while the client isn't
   connected — it fills the narrow panel instead of keeping the 400px stack
   cap (which would leave an empty strip on the right). */
#connect-form {
	max-width: 100%;
}

#sign-form button {
	min-height: 50px;
	font-size: 15px;
	border-radius: var(--radius-md);
}

/* ------------------------------------------------------------------ */
/* Buttons                                                             */
/* ------------------------------------------------------------------ */

button {
	appearance: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	margin: 0;
	padding: 0 14px;
	min-height: 36px;
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	background: var(--surface);
	color: var(--text-1);
	font-family: inherit;
	font-size: 13px;
	font-weight: 550;
	line-height: 1.2;
	cursor: pointer;
	transition:
		background 0.15s ease,
		border-color 0.15s ease,
		color 0.15s ease,
		box-shadow 0.15s ease,
		transform 0.1s ease,
		opacity 0.15s ease;
}

button + button {
	margin-left: 8px;
}

button svg {
	width: 15px;
	height: 15px;
	flex: none;
}

button:active:enabled {
	transform: scale(0.98);
}

button:disabled {
	opacity: 0.55;
	cursor: not-allowed;
}

/* Primary — the one accent action per form. */
.btn.primary {
	min-height: 40px;
	padding: 0 18px;
	border: none;
	background: var(--accent-btn);
	color: #ffffff;
	font-size: 13.5px;
	box-shadow:
		var(--shadow-sm),
		inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* Solid danger — destructive confirmation inside dialogs. */
.btn.danger {
	border: none;
	background: var(--danger);
	color: #ffffff;
}

/* Ghost danger — destructive row actions and the logout button. */
button.danger {
	border-color: transparent;
	background: transparent;
	color: var(--error-text);
}

.btn.danger-ghost {
	border-color: transparent;
	background: transparent;
	color: var(--error-text);
}

/* Small icon-only button (the dialog close). */
.icon-btn {
	width: 30px;
	height: 30px;
	padding: 0;
	display: grid;
	place-items: center;
	border: none;
	background: transparent;
	color: var(--text-2);
	border-radius: var(--radius-sm);
}

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

/* Busy state — the report download button shows a spinner while disabled. */
.spinner {
	display: none;
	width: 14px;
	height: 14px;
	flex: none;
	border-radius: 50%;
	border: 2px solid rgba(255, 255, 255, 0.35);
	border-top-color: #ffffff;
	animation: spin 0.8s linear infinite;
}

#download-btn:disabled .spinner {
	display: inline-block;
}

#download-btn {
	min-height: 40px;
	padding: 0 18px;
	font-size: 13.5px;
}

/* ------------------------------------------------------------------ */
/* Tables                                                              */
/* ------------------------------------------------------------------ */

table {
	width: 100%;
	border-collapse: collapse;
	margin-top: 14px;
	font-size: 13px;
}

th,
td {
	padding: 10px 12px;
	text-align: left;
	border-bottom: 1px solid var(--border);
}

thead th {
	padding: 8px 12px;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--text-3);
	border-bottom: 1px solid var(--border-strong);
}

tbody tr {
	transition: background 0.12s ease;
}

tbody tr:last-child td,
tbody tr:last-child th {
	border-bottom: none;
}

th:last-child,
td:last-child {
	text-align: right;
}

td button {
	min-height: 30px;
	padding: 0 11px;
	font-size: 12px;
	border-radius: 7px;
}

/* Wide tables (clients, workers, pending shifts) are wrapped in
   div.table-scroll so narrow screens scroll the table horizontally
   instead of squeezing the columns. */
.table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

#clients-table {
	min-width: 640px;
}

#workers-table {
	min-width: 520px;
}

#shifts-table {
	min-width: 520px;
}

/* Key-value table (the license details). */
table.kv {
	width: auto;
	min-width: 260px;
}

table.kv th {
	width: 32%;
	text-transform: none;
	letter-spacing: normal;
	font-size: 13px;
	font-weight: 550;
	color: var(--text-2);
}

/* Empty states — shown only while the table body behind them is empty. */
.empty-note {
	display: none;
	margin: 0;
	padding: 16px 0 6px;
	text-align: center;
	font-size: 13px;
	color: var(--text-3);
}

#pending-section:has(#pending-body:empty) .empty-note,
#clients-section:has(#clients-body:empty) .empty-note,
#workers-section:has(#workers-body:empty) .empty-note,
#shifts-section:has(#shifts-body:empty) .empty-note {
	display: block;
}

/* ------------------------------------------------------------------ */
/* Chips, badges, hints, secrets                                       */
/* ------------------------------------------------------------------ */

.chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.chips:empty {
	display: none;
}

main > .chips:not(:empty) {
	margin: 0 0 20px;
}

.chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 4px 11px 4px 9px;
	border-radius: 999px;
	font-size: 12px;
	font-weight: 550;
	line-height: 1.4;
	background: var(--hover);
	color: var(--text-2);
}

.chip::before {
	content: '';
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: currentColor;
	flex: none;
}

.chip.ok {
	background: var(--ok-soft);
	color: var(--ok-text);
}

.chip.warn {
	background: var(--warn-soft);
	color: var(--warn-text);
}

.chip.error {
	background: var(--error-soft);
	color: var(--error-text);
}

.chip.muted {
	background: var(--hover);
	color: var(--text-2);
}

a.chip {
	text-decoration: none;
	cursor: pointer;
	transition: box-shadow 0.15s ease;
}

/* Status line — a colored dot and a short label (the license state). */
.state {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0;
	font-size: 13.5px;
	font-weight: 550;
}

.state::before {
	content: '';
	width: 8px;
	height: 8px;
	border-radius: 50%;
	flex: none;
}

.state.ok {
	color: var(--ok-text);
}

.state.ok::before {
	background: var(--ok);
}

.state.error {
	color: var(--error-text);
}

.state.error::before {
	background: var(--error);
}

.badge {
	display: inline-flex;
	align-items: center;
	padding: 2px 9px;
	border: 1px solid var(--border);
	border-radius: 999px;
	background: var(--fill);
	font-size: 11.5px;
	font-weight: 550;
	color: var(--text-2);
}

.hint {
	margin: 10px 0 0;
	font-size: 12.5px;
	line-height: 1.55;
	color: var(--text-2);
}

/* One-time credential box — the client secret, click to select all. */
.secret {
	display: inline-block;
	margin-top: 10px;
	padding: 10px 14px;
	background: var(--surface-2);
	border: 1px dashed var(--border-strong);
	border-radius: 10px;
	font-family: var(--font-mono);
	font-size: 13.5px;
	letter-spacing: 0.02em;
	user-select: all;
}

#new-client-secret {
	margin-top: 16px;
}

#new-client-secret:empty {
	display: none;
}

/* ------------------------------------------------------------------ */
/* Home page — navigation cards                                        */
/* ------------------------------------------------------------------ */

.cards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: 12px;
}

.nav-card {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	padding: 18px;
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	background: var(--surface);
	box-shadow: var(--shadow-sm);
	text-decoration: none;
	transition:
		transform 0.18s var(--ease-out),
		box-shadow 0.18s ease,
		border-color 0.18s ease;
}

.nav-card-icon {
	width: 38px;
	height: 38px;
	margin-bottom: 12px;
	border-radius: 10px;
	background: var(--accent-soft);
	color: var(--accent);
	display: grid;
	place-items: center;
	transition:
		background 0.2s ease,
		color 0.2s ease,
		transform 0.2s var(--ease-out);
}

.nav-card-icon svg {
	width: 19px;
	height: 19px;
}

.nav-card-title {
	font-size: 14.5px;
	font-weight: 600;
	color: var(--text-1);
}

.nav-card-desc {
	margin-top: 2px;
	font-size: 12.5px;
	line-height: 1.45;
	color: var(--text-2);
}

.nav-card::after {
	content: '→';
	position: absolute;
	top: 20px;
	right: 16px;
	font-size: 15px;
	color: var(--accent);
	opacity: 0;
	transform: translateX(-4px);
	transition:
		opacity 0.2s ease,
		transform 0.2s var(--ease-out);
}

/* Staggered card entrance on top of the page stagger. */
.cards .nav-card:nth-child(1) {
	animation-delay: 0.14s;
}

.cards .nav-card:nth-child(2) {
	animation-delay: 0.2s;
}

.cards .nav-card:nth-child(3) {
	animation-delay: 0.26s;
}

.cards .nav-card:nth-child(4) {
	animation-delay: 0.32s;
}

.cards .nav-card:nth-child(5) {
	animation-delay: 0.38s;
}

/* ------------------------------------------------------------------ */
/* Sign-in page — the live shift list                                  */
/* ------------------------------------------------------------------ */

.live {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	font-size: 12px;
	font-weight: 550;
	color: var(--ok-text);
}

.live-dot {
	position: relative;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--ok);
	flex: none;
}

.live-dot::after {
	content: '';
	position: absolute;
	inset: -3.5px;
	border-radius: 50%;
	background: var(--ok);
	animation: pulse 2s ease-out infinite;
}

/* ------------------------------------------------------------------ */
/* Monthly hours summary (the shifts page)                             */
/* ------------------------------------------------------------------ */

/* The two stat cells below the shift table: an inset card with a
   small-caps eyebrow caption above a large value (the section is hidden
   while there is no data — no registered worker, or a failed load). */
.summary-stats {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 12px;
}

.summary-stat {
	padding: 12px 16px;
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	background: var(--inset);
}

.summary-stat-label {
	display: block;
	margin-bottom: 4px;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--text-3);
}

.summary-stat-value {
	display: block;
	font-size: 22px;
	font-weight: 650;
	letter-spacing: -0.01em;
	color: var(--text-1);
	font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ */
/* Unbound sign events (the workers page)                              */
/* ------------------------------------------------------------------ */

.event-card {
	display: grid;
	gap: 12px;
	padding: 14px;
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	background: var(--inset);
	animation: rise 0.4s var(--ease-out) both;
}

.event-card + .event-card {
	margin-top: 10px;
}

/* The labeled fields of an event card: a small-caps eyebrow caption above
   each value, in a 4-column grid (the provider type and the external id
   span two columns each). */
.event-fields {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 12px 16px;
}

.event-field.wide {
	grid-column: span 2;
}

.event-field .event-label {
	display: block;
	margin-bottom: 4px;
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--text-3);
}

.event-value {
	display: block;
	font-size: 13px;
	color: var(--text-1);
}

.event-code {
	padding: 3px 8px;
	border: 1px solid var(--border);
	border-radius: 6px;
	background: var(--fill);
	font-family: var(--font-mono);
	font-size: 12.5px;
	font-weight: 500;
	color: var(--text-1);
	overflow-wrap: anywhere;
}

.event-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}

.event-actions select {
	min-width: 150px;
	min-height: 36px;
	font-size: 13px;
}

.event-actions input {
	width: 120px;
	min-height: 36px;
	font-size: 13px;
}

.event-actions button {
	min-height: 36px;
	font-size: 12.5px;
}

.event-actions button + button {
	margin-left: 0;
}

/* ------------------------------------------------------------------ */
/* Worker edit dialog                                                  */
/* ------------------------------------------------------------------ */

dialog {
	border: none;
	padding: 0;
	width: min(540px, 94vw);
	border-radius: var(--radius-lg);
	background: var(--surface);
	color: var(--text-1);
	box-shadow: var(--shadow-lg);
	opacity: 0;
	transform: translateY(10px) scale(0.97);
	transition:
		opacity 0.22s ease,
		transform 0.22s var(--ease-out);
}

dialog[open] {
	opacity: 1;
	transform: none;
}

dialog::backdrop {
	background: rgba(16, 24, 40, 0.45);
	-webkit-backdrop-filter: blur(3px);
	backdrop-filter: blur(3px);
	animation: backdrop-in 0.22s ease;
}

@starting-style {
	dialog[open] {
		opacity: 0;
		transform: translateY(10px) scale(0.97);
	}
}

.dialog-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 16px 20px;
	border-bottom: 1px solid var(--border);
}

.dialog-body {
	padding: 20px;
}

.dialog-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 14px 20px;
	border-top: 1px solid var(--border);
	background: var(--surface-2);
	border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.dialog-foot .hint {
	margin: 0;
}

/* The rename form built by workers.js. */
.dialog-form {
	display: grid;
	gap: 12px;
}

.dialog-form label {
	display: block;
}

.dialog-form label > span {
	display: block;
	margin-bottom: 6px;
	font-size: 12px;
	font-weight: 550;
	color: var(--text-2);
}

.dialog-form input {
	width: 100%;
}

.dialog-form button {
	justify-self: start;
}

/* The "Identiteti" section heading inside the dialog body. */
.dialog-body h3 {
	margin: 20px 0 10px;
	font-size: 11.5px;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--text-3);
}

/* One identity line: provider badge/select, value input, actions. A fixed
   track for the provider and the buttons keeps the inputs and buttons
   aligned across all lines. */
.identity-row {
	display: grid;
	grid-template-columns: 132px 1fr 84px 84px;
	gap: 8px;
	align-items: center;
	margin-bottom: 8px;
}

.identity-row input,
.identity-row select {
	width: 100%;
	min-width: 0;
	min-height: 36px;
	font-size: 13px;
	margin: 0;
}

.identity-row .badge {
	justify-content: center;
}

.identity-row button {
	width: 100%;
	min-height: 36px;
	padding: 0 8px;
	font-size: 12.5px;
}

.identity-row button + button {
	margin-left: 0;
}

/* ------------------------------------------------------------------ */
/* Toasts                                                              */
/* ------------------------------------------------------------------ */

#notifications {
	position: fixed;
	right: 16px;
	bottom: calc(16px + env(safe-area-inset-bottom));
	z-index: 100;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 8px;
	pointer-events: none;
}

.notification {
	pointer-events: auto;
	display: flex;
	align-items: center;
	gap: 9px;
	max-width: min(360px, calc(100vw - 32px));
	padding: 10px 14px;
	border-radius: 10px;
	background: #101828;
	color: #f9fafb;
	font-size: 13px;
	font-weight: 500;
	line-height: 1.45;
	box-shadow: var(--shadow-lg);
	opacity: 1;
	transform: none;
	transition:
		opacity 0.28s ease,
		transform 0.28s ease;
}

.notification::before {
	content: '';
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: #98a2b3;
	flex: none;
}

.notification.ok::before {
	background: var(--ok);
}

.notification.warn::before {
	background: var(--warn);
}

.notification.error::before {
	background: var(--error);
}

.notification.hidden {
	opacity: 0;
	transform: translateY(8px);
}

@starting-style {
	.notification {
		opacity: 0;
		transform: translateY(12px) scale(0.98);
	}
}

/* ------------------------------------------------------------------ */
/* Admin banner — pinned above every page while an admin is logged in  */
/* ------------------------------------------------------------------ */

#admin-banner {
	position: sticky;
	top: 0;
	z-index: 60;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	height: 40px;
	padding: 0 16px;
	background: #18181b;
	color: #f9fafb;
	font-size: 12.5px;
	font-weight: 550;
	animation: banner-in 0.4s var(--ease-out);
}

.banner-dot {
	position: relative;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--error);
	flex: none;
}

.banner-dot::after {
	content: '';
	position: absolute;
	inset: -4px;
	border-radius: 50%;
	background: var(--error);
	animation: pulse 1.8s ease-out infinite;
}

#admin-banner button {
	min-height: 26px;
	margin-left: 6px;
	padding: 0 12px;
	font-size: 12px;
	font-weight: 550;
	color: #ffffff;
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.22);
	border-radius: 7px;
	transition:
		background 0.15s ease,
		border-color 0.15s ease;
}

/* ------------------------------------------------------------------ */
/* Gate page (admin login)                                             */
/* ------------------------------------------------------------------ */

body.gate-body {
	min-height: 100vh;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 24px;
	background: radial-gradient(900px 420px at 50% -120px, rgba(79, 70, 229, 0.09), transparent 60%), var(--bg);
}

.gate-card {
	margin: auto;
	width: 100%;
	max-width: 380px;
	padding: 30px 28px 26px;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-md);
	animation: rise 0.5s var(--ease-out) both;
}

.gate-brand {
	justify-content: center;
	margin-bottom: 20px;
}

.gate-card h1 {
	text-align: center;
	font-size: 18px;
	margin-bottom: 18px;
}

.gate-card form {
	display: grid;
	gap: 12px;
}

.gate-card form button {
	width: 100%;
	min-height: 40px;
	font-size: 13.5px;
}

.gate-back {
	margin: 18px 0 0;
	text-align: center;
}

.nav-button {
	color: var(--text-2);
	font-size: 13px;
	text-decoration: none;
	transition: color 0.15s ease;
}

#login-error {
	display: flex;
	justify-content: center;
	width: 100%;
	margin: 14px 0 0;
	animation: shake 0.45s ease;
}

/* ------------------------------------------------------------------ */
/* Keyframes                                                           */
/* ------------------------------------------------------------------ */

@keyframes rise {
	from {
		opacity: 0;
		transform: translateY(10px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes spin {
	to {
		transform: rotate(360deg);
	}
}

@keyframes pulse {
	from {
		transform: scale(0.5);
		opacity: 0.55;
	}

	to {
		transform: scale(2);
		opacity: 0;
	}
}

@keyframes banner-in {
	from {
		transform: translateY(-100%);
	}

	to {
		transform: none;
	}
}

@keyframes backdrop-in {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

@keyframes shake {
	10%,
	90% {
		transform: translateX(-1px);
	}

	20%,
	80% {
		transform: translateX(2px);
	}

	30%,
	50%,
	70% {
		transform: translateX(-3px);
	}

	40%,
	60% {
		transform: translateX(3px);
	}
}

/* ------------------------------------------------------------------ */
/* Dark mode (prefers-color-scheme)                                    */
/* ------------------------------------------------------------------ */

/* The whole design runs on the tokens above, so the dark scheme is a
   single token redefinition: a near-black canvas with progressively
   lighter surfaces, lighter neutrals, and a lighter accent for text
   (the solid fills keep a darker shade for white labels). `color-scheme`
   lets the native scrollbars and form controls follow. */
@media (prefers-color-scheme: dark) {
	:root {
		color-scheme: dark;

		--bg: #0d1117;
		--surface: #161b22;
		--surface-2: #21262d;
		--border: #2d333b;
		--border-strong: #414b57;

		--text-1: #f2f4f7;
		--text-2: #a8b2c1;
		--text-3: #6e7a8a;

		--accent: #818cf8;
		--accent-soft: rgba(129, 140, 248, 0.15);
		--accent-ring: rgba(129, 140, 248, 0.25);
		--accent-btn: #6366f1;
		--accent-btn-hover: #4f46e5;

		--ok: #34d399;
		--ok-soft: rgba(52, 211, 153, 0.15);
		--ok-text: #6ee7b7;
		--warn: #fbbf24;
		--warn-soft: rgba(251, 191, 36, 0.15);
		--warn-text: #fcd34d;
		--error: #f87171;
		--error-soft: rgba(248, 113, 113, 0.15);
		--error-text: #fca5a5;
		--danger: #dc2626;
		--danger-hover: #b91c1c;

		--glow: rgba(129, 140, 248, 0.07);
		--header-bg: rgba(13, 17, 23, 0.82);
		--hover: #262c37;
		--fill: #232a35;
		--inset: #1c2129;

		--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
		--shadow-md: 0 8px 24px -8px rgba(0, 0, 0, 0.55);
		--shadow-lg: 0 24px 48px -12px rgba(0, 0, 0, 0.65);
	}

	::selection {
		background: rgba(129, 140, 248, 0.3);
	}

	body.gate-body {
		background: radial-gradient(900px 420px at 50% -120px, rgba(129, 140, 248, 0.1), transparent 60%), var(--bg);
	}

	/* the toasts stay dark in both schemes — a hairline keeps them off the
	   dark canvas */
	.notification {
		border: 1px solid rgba(255, 255, 255, 0.1);
	}

	#admin-banner {
		border-bottom: 1px solid var(--border);
	}

	dialog::backdrop {
		background: rgba(0, 0, 0, 0.65);
	}
}

/* ------------------------------------------------------------------ */
/* Hover — pointer devices only                                        */
/*                                                                     */
/* On a phone the first tap triggers :hover and it sticks until the    */
/* next tap, so every hover effect is gated behind a real pointer.     */
/* Touch screens get the pressed (:active) states from the Touch       */
/* section below instead.                                              */
/* ------------------------------------------------------------------ */

@media (hover: hover) and (pointer: fine) {
	nav.main a:hover {
		color: var(--text-1);
		background: var(--hover);
	}

	button:hover:enabled {
		background: var(--surface-2);
		border-color: var(--text-3);
	}

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

	.btn.danger:hover:enabled {
		background: var(--danger-hover);
		border-color: transparent;
	}

	button.danger:hover:enabled,
	.btn.danger-ghost:hover:enabled {
		background: var(--error-soft);
		border-color: transparent;
	}

	.icon-btn:hover:enabled {
		background: var(--hover);
		color: var(--text-1);
		border-color: transparent;
	}

	a.chip:hover {
		box-shadow: inset 0 0 0 1px currentColor;
	}

	.nav-card:hover {
		transform: translateY(-2px);
		box-shadow: var(--shadow-md);
		border-color: var(--border-strong);
	}

	.nav-card:hover .nav-card-icon {
		background: var(--accent-btn);
		color: #ffffff;
		transform: scale(1.06);
	}

	.nav-card:hover::after {
		opacity: 1;
		transform: none;
	}

	tbody tr:hover {
		background: var(--surface-2);
	}

	#admin-banner button:hover:enabled {
		background: rgba(255, 255, 255, 0.18);
		border-color: rgba(255, 255, 255, 0.35);
	}

	.nav-button:hover {
		color: var(--accent);
	}
}

/* ------------------------------------------------------------------ */
/* Touch — no hover, coarse pointer                                    */
/* ------------------------------------------------------------------ */

/* Pressed states carry the feedback on touch screens, the → arrow can't
   fade in so it stays visible as a static affordance, and the entrance
   stagger collapses into a single quick fade. */
@media (hover: none) {
	.nav-card:active {
		transform: scale(0.985);
		box-shadow: var(--shadow-sm);
		border-color: var(--border-strong);
	}

	nav.main a:active {
		color: var(--text-1);
		background: var(--fill);
	}

	a.chip:active {
		box-shadow: inset 0 0 0 1px currentColor;
	}

	.nav-button:active {
		color: var(--accent);
	}

	.nav-card::after {
		opacity: 0.4;
		transform: none;
	}

	.page > *:nth-child(n) {
		animation-delay: 0s;
	}

	.cards .nav-card:nth-child(n) {
		animation-delay: 0s;
	}
}

@media (pointer: coarse) {
	/* touch targets closer to the 44px guideline */
	nav.main a {
		padding: 10px 14px;
	}

	td button {
		min-height: 40px;
	}

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

	a.chip {
		padding: 7px 14px 7px 11px;
	}

	#admin-banner button {
		min-height: 32px;
	}

	/* iOS Safari zooms the page in on focus when the input font is under
	   16px — keep the form at its current zoom level */
	input,
	select {
		font-size: 16px;
	}
}

/* ------------------------------------------------------------------ */
/* Responsive                                                          */
/* ------------------------------------------------------------------ */

@media (max-width: 720px) {
	/* single-row header: the nav scrolls horizontally instead of wrapping
	   into a multi-line block (the active link is centered by
	   initNavScroll in web/js/nav.js) */
	.header-inner {
		flex-wrap: nowrap;
		height: 56px;
		padding: 0 16px;
		gap: 12px;
	}

	.brand {
		flex: none;
	}

	nav.main {
		flex: 1 1 auto;
		min-width: 0;
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
	}

	nav.main::-webkit-scrollbar {
		display: none;
	}

	nav.main a {
		flex: none;
	}

	.page {
		padding: 24px 16px calc(64px + env(safe-area-inset-bottom));
	}

	.panel {
		padding: 16px;
	}

	/* in the column layout the field's flex-basis would apply to the
	   vertical axis and stretch each field block to 220px tall */
	form.row {
		flex-direction: column;
		align-items: stretch;
	}

	form.row .field {
		flex: none;
	}

	form.row button {
		width: 100%;
	}

	.identity-row {
		grid-template-columns: 1fr;
	}

	.event-fields {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.summary-stats {
		grid-template-columns: 1fr;
	}

	.event-actions input {
		width: 100%;
	}

	.dialog-foot {
		flex-direction: column;
		align-items: stretch;
	}

	/* the banner keeps its 40px height (the header pins at top: 40px below
	   it) — the label ellipsizes instead of wrapping */
	#admin-banner {
		justify-content: flex-start;
	}

	#admin-banner .banner-label {
		flex: 1;
		min-width: 0;
		overflow: hidden;
		white-space: nowrap;
		text-overflow: ellipsis;
	}
}

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

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}
}
