/* ===== FOUNDATION =====
   Tokens, reset and typography. Everything downstream is expressed in these
   variables, so a palette change happens in exactly one place.

   The palette is near-monochrome with a single accent. That is the whole design
   rule: colour means "this is interactive" or "this needs attention", never
   decoration. Surfaces separate with a 1px border rather than a shadow, and
   shadows are reserved for things that genuinely float above the page. */

/* ===== TOKENS ===== */
:root {
	/* Light is the base definition. Dark only overrides the values that change,
	   further down — so no colour is ever defined in only one branch. */
	--bg:            #f7f7f9;
	--surface:       #ffffff;
	--surface-2:     #f2f2f5;
	--surface-3:     #e9e9ee;
	--overlay:       #ffffff;

	--border:        #e3e3e9;
	--border-strong: #d0d0d8;

	--text:          #17171c;
	--text-2:        #5a5a66;
	--text-3:        #8c8c99;
	--text-invert:   #ffffff;

	--accent:        #4f46e5;
	--accent-hover:  #4338ca;
	--accent-soft:   #eeecfe;
	--accent-text:   #4338ca;

	--danger:        #dc2626;
	--danger-soft:   #fdeaea;
	--success:       #15803d;
	--success-soft:  #e7f6ec;
	--warning:       #b45309;
	--warning-soft:  #fdf2e0;
	--info:          #0369a1;
	--info-soft:     #e5f2fb;

	--scrim:         rgba(15, 15, 22, .38);
	--shadow-sm:     0 1px 2px rgba(15, 15, 22, .05);
	--shadow-md:     0 4px 12px -2px rgba(15, 15, 22, .10), 0 2px 4px -2px rgba(15, 15, 22, .06);
	--shadow-lg:     0 16px 40px -8px rgba(15, 15, 22, .18), 0 4px 12px -4px rgba(15, 15, 22, .10);

	/* Type. A system stack means zero webfont bytes and native rendering on
	   every platform — the single cheapest performance decision in the app. */
	--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
	        "Noto Sans", Ubuntu, Cantarell, sans-serif;
	--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
	        "Liberation Mono", "Roboto Mono", monospace;

	--fs-xs:   .75rem;
	--fs-sm:   .8125rem;
	--fs-base: .875rem;
	--fs-md:   .9375rem;
	--fs-lg:   1.0625rem;
	--fs-xl:   1.3125rem;
	--fs-2xl:  1.75rem;

	/* Spacing on a 4px grid. */
	--s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
	--s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;

	--r-sm: 6px; --r-md: 9px; --r-lg: 13px; --r-xl: 18px; --r-full: 999px;

	--sidebar-w: 248px;
	--sidebar-w-collapsed: 68px;
	--topbar-h: 60px;
	--tabbar-h: calc(58px + env(safe-area-inset-bottom, 0px));

	--ease: cubic-bezier(.32, .72, 0, 1);
	--t-fast: 110ms;
	--t-base: 180ms;
}

:root:not([data-theme="light"]) {
	color-scheme: light;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--bg:            #0c0c10;
		--surface:       #141419;
		--surface-2:     #1b1b22;
		--surface-3:     #24242c;
		--overlay:       #1a1a20;

		--border:        #26262f;
		--border-strong: #35353f;

		--text:          #f1f1f4;
		--text-2:        #a2a2ae;
		--text-3:        #70707d;
		--text-invert:   #ffffff;

		--accent:        #6d63f5;
		--accent-hover:  #7c73ff;
		--accent-soft:   #1d1b3a;
		--accent-text:   #a49dff;

		--danger:        #ef4444;
		--danger-soft:   #2c1518;
		--success:       #34d399;
		--success-soft:  #10251f;
		--warning:       #fbbf24;
		--warning-soft:  #2a2011;
		--info:          #38bdf8;
		--info-soft:     #10222e;

		--scrim:         rgba(0, 0, 0, .6);
		--shadow-sm:     0 1px 2px rgba(0, 0, 0, .35);
		--shadow-md:     0 4px 12px -2px rgba(0, 0, 0, .5);
		--shadow-lg:     0 16px 40px -8px rgba(0, 0, 0, .65), 0 4px 12px -4px rgba(0, 0, 0, .4);

		color-scheme: dark;
	}
}

/* The explicit toggle wins in both directions, so it can override the OS. */
:root[data-theme="dark"] {
	--bg:            #0c0c10;
	--surface:       #141419;
	--surface-2:     #1b1b22;
	--surface-3:     #24242c;
	--overlay:       #1a1a20;

	--border:        #26262f;
	--border-strong: #35353f;

	--text:          #f1f1f4;
	--text-2:        #a2a2ae;
	--text-3:        #70707d;
	--text-invert:   #ffffff;

	--accent:        #6d63f5;
	--accent-hover:  #7c73ff;
	--accent-soft:   #1d1b3a;
	--accent-text:   #a49dff;

	--danger:        #ef4444;
	--danger-soft:   #2c1518;
	--success:       #34d399;
	--success-soft:  #10251f;
	--warning:       #fbbf24;
	--warning-soft:  #2a2011;
	--info:          #38bdf8;
	--info-soft:     #10222e;

	--scrim:         rgba(0, 0, 0, .6);
	--shadow-sm:     0 1px 2px rgba(0, 0, 0, .35);
	--shadow-md:     0 4px 12px -2px rgba(0, 0, 0, .5);
	--shadow-lg:     0 16px 40px -8px rgba(0, 0, 0, .65), 0 4px 12px -4px rgba(0, 0, 0, .4);

	color-scheme: dark;
}

/* ===== RESET ===== */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
	-webkit-text-size-adjust: 100%;
	-webkit-tap-highlight-color: transparent;
}

body {
	min-height: 100dvh;
	background: var(--bg);
	color: var(--text);
	font-family: var(--font);
	font-size: var(--fs-base);
	line-height: 1.55;
	font-synthesis-weight: none;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: -.011em;
}

button, input, select, textarea {
	font: inherit;
	color: inherit;
}

button { background: none; border: 0; cursor: pointer; }

a { color: var(--accent-text); text-decoration-color: color-mix(in srgb, currentColor 35%, transparent); text-underline-offset: 2px; }
a:hover { text-decoration-color: currentColor; }

img, svg, video, canvas { display: block; max-width: 100%; }

svg { width: 1em; height: 1em; flex: none; }

ul, ol { padding: 0; list-style: none; }

code, kbd, pre, samp { font-family: var(--mono); font-size: .9em; }

hr { border: 0; border-top: 1px solid var(--border); }

[hidden] { display: none !important; }

/* ===== FOCUS =====
   Visible only for keyboard users, and never suppressed. */
:focus { outline: none; }
:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: var(--r-sm);
}

/* ===== SCROLLBARS ===== */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
	background: var(--border-strong);
	border: 3px solid transparent;
	border-radius: var(--r-full);
	background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }

/* ===== SELECTION ===== */
::selection { background: color-mix(in srgb, var(--accent) 26%, transparent); }

/* ===== UTILITIES ===== */
.visually-hidden {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

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

.mono { font-family: var(--mono); font-variant-ligatures: none; }

.spacer { flex: 1 1 auto; }

/* Anything wide enough to overflow scrolls inside its own box, so the page
   itself never scrolls sideways on a phone. */
.scroll-x { overflow-x: auto; overscroll-behavior-x: contain; }

/* ===== MOTION =====
   Animation is used to explain where something came from, never to decorate.
   Anyone who has asked their system to stop moving gets a static interface. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ===== BOOT ===== */
.boot {
	position: fixed;
	inset: 0;
	display: grid;
	place-items: center;
	background: var(--bg);
	z-index: 100;
}

.boot-spinner {
	width: 22px; height: 22px;
	border: 2px solid var(--border-strong);
	border-top-color: var(--accent);
	border-radius: 50%;
	/* The delay is the point: a reply that arrives quickly never gets to show a
	   spinner at all, which reads as instant rather than as a flash of loading. */
	opacity: 0;
	animation: spin .7s linear infinite, fade-in .2s .35s forwards;
}

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fade-in { to { opacity: 1; } }
