@charset "utf-8";
/* ==========================================================================
   Libretto Design System  –  "Editorial x Instrument"
   Cascade layers: reset < tokens < base < components.
   Fully self-contained: a compact element reset in the reset layer, design
   tokens (colours, type, spacing, radius, timing) in the tokens layer, and the
   base/component styles below. No external stylesheet or framework is loaded.
   Bulk component styles below stay unlayered, so they keep authority over this
   baseline. Self-hosted fonts; OS light/dark via light-dark().
   ========================================================================== */
@layer reset, tokens, base, components;

@layer reset {
	/* Compact cross-browser element reset (box-sizing, margin, border defaults,
	   media block-sizing, form-control inheritance). Zero-specificity :where()
	   selectors keep every app rule in charge; no external stylesheet required. */
	*, ::before, ::after { box-sizing: border-box; }
	:where(:not(dialog)) { margin: 0; }
	:where(:not(fieldset, progress, meter)) {
		background-origin: border-box;
		background-repeat: no-repeat;
		border-style: solid;
		border-width: 0;
	}
	:where(html) { -webkit-text-size-adjust: none; }
	:where(body) { min-block-size: 100%; }
	@media (prefers-reduced-motion: no-preference) {
		:where(html) { scroll-behavior: smooth; }
	}
	:where(h1, h2, h3, h4, h5, h6) { text-wrap: balance; }
	:where(p) { text-wrap: pretty; }
	:where(img, svg, video, canvas, audio, iframe, embed, object) { display: block; }
	:where(img, svg, video) { max-inline-size: 100%; block-size: auto; }
	:where(input, button, textarea, select) { color: inherit; font: inherit; letter-spacing: inherit; }
	:where(textarea) { resize: vertical; }
	::placeholder { color: var(--text-4); opacity: 0.75; }
}

/* ── Self-hosted typefaces (woff2, OFL) ─────────────────────────────────── */
@font-face {
	font-family: "Inter Variable"; font-style: normal; font-weight: 100 900;
	font-display: swap; src: url("/static/fonts/inter-latin-wght-normal.woff2") format("woff2-variations");
	unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
	font-family: "Inter Variable"; font-style: normal; font-weight: 100 900;
	font-display: swap; src: url("/static/fonts/inter-latin-ext-wght-normal.woff2") format("woff2-variations");
	unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
	font-family: "Playfair Display Variable"; font-style: normal; font-weight: 400 900;
	font-display: swap; src: url("/static/fonts/playfair-display-latin-wght-normal.woff2") format("woff2-variations");
	unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
	font-family: "Playfair Display Variable"; font-style: normal; font-weight: 400 900;
	font-display: swap; src: url("/static/fonts/playfair-display-latin-ext-wght-normal.woff2") format("woff2-variations");
	unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
	font-family: "Playfair Display Variable"; font-style: italic; font-weight: 400 900;
	font-display: swap; src: url("/static/fonts/playfair-display-latin-wght-italic.woff2") format("woff2-variations");
	unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
	font-family: "Playfair Display Variable"; font-style: italic; font-weight: 400 900;
	font-display: swap; src: url("/static/fonts/playfair-display-latin-ext-wght-italic.woff2") format("woff2-variations");
	unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
	font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400;
	font-display: swap; src: url("/static/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
	font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400;
	font-display: swap; src: url("/static/fonts/ibm-plex-mono-latin-ext-400-normal.woff2") format("woff2");
	unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+1E00-1E9F,U+2020,U+20A0-20AB,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
	font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600;
	font-display: swap; src: url("/static/fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2");
	unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@layer base {
	* { box-sizing: border-box; }
	input::-webkit-outer-spin-button,
	input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
	input[type=number] { -moz-appearance: textfield; appearance: textfield; }
	select option { background: var(--surface-raised); color: var(--text); }

	/* Prose / content links default to the accent colour with a legible
	   underline. Lives in @layer base (the lowest tier), so every classed link
	   -- .btn, .footer-link, .side-link, .activity-row, ... -- sets its own
	   colour/decoration and wins; only bare <a> in copy falls back to this. */
	a { color: var(--accent); text-underline-offset: 0.18em; text-decoration-thickness: from-font; }
	a:hover { text-decoration-thickness: 2px; }
}

@layer tokens {
:root {
	color-scheme: light dark;

	/* ── Type ────────────────────────────────────────────── */
	--font-serif: "Playfair Display Variable", "Playfair Display", Georgia, "Times New Roman", serif;
	--font-sans:  "Inter Variable", Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--font-mono:  "IBM Plex Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

	/* ── Surfaces (paper light / warm-ink dark) ──────────── */
	--surface:          light-dark(#faf9f5, #14130f);  /* page */
	--surface-raised:   light-dark(#ffffff, #1c1b16);  /* cards, modals */
	--surface-sunken:   light-dark(#f1efe8, #100f0b);  /* table head, wells */
	--bg:               var(--surface);                /* legacy alias */
	--bg-2:             color-mix(in oklab, var(--ink) 3%, transparent);
	--bg-3:             color-mix(in oklab, var(--ink) 4.5%, transparent);

	/* Surface tints – flip automatically because --ink flips with theme */
	--tint-xs:          color-mix(in oklab, var(--ink) 4%,  transparent);
	--tint-sm:          color-mix(in oklab, var(--ink) 7%,  transparent);
	--tint-md:          color-mix(in oklab, var(--ink) 12%, transparent);
	--tint-lg:          color-mix(in oklab, var(--ink) 20%, transparent);

	/* Dark scrims – always darken */
	--scrim-xs:         color-mix(in oklab, #000 5%,  transparent);
	--scrim-sm:         color-mix(in oklab, #000 10%, transparent);
	--scrim-md:         color-mix(in oklab, #000 18%, transparent);
	--scrim-lg:         color-mix(in oklab, #000 35%, transparent);
	/* Modal/sheet backdrop – theme-aware: a light frosted veil over the page in
	   light mode (the page is bright, so a black scrim looked wrong), a dark one
	   in dark mode. Pairs with backdrop-filter: blur() on the ::backdrop rules. */
	--modal-scrim:      light-dark(color-mix(in oklab, #faf9f5 62%, transparent), color-mix(in oklab, #000 82%, transparent));
	--sheet-scrim:      light-dark(color-mix(in oklab, #faf9f5 55%, transparent), color-mix(in oklab, #000 45%, transparent));

	/* ── Ink / text ──────────────────────────────────────── */
	--ink:              light-dark(#1b1815, #ece8df);
	--text:             var(--ink);
	--text-1:           var(--ink);
	--text-2:           light-dark(#3d3833, #c9c4b8);
	--text-3:           light-dark(#574f46, #a39d90);
	--text-4:           light-dark(#6a645a, #918a7e);
	--text-5:           light-dark(#a49e92, #5e594f);

	/* ── Borders ─────────────────────────────────────────── */
	--border:           color-mix(in oklab, var(--ink) 13%, transparent);
	--border-subtle:    color-mix(in oklab, var(--ink) 7%,  transparent);

	/* ── Accent (cultured forest) ────────────────────────── */
	--accent:           light-dark(#1f4d3a, #6fb894);
	--accent-ink:       light-dark(#faf9f5, #11130f);  /* text on accent fill */
	--accent-glow:      color-mix(in oklab, var(--accent) 16%, transparent);
	--accent-soft:      color-mix(in oklab, var(--accent) 9%,  transparent);

	/* ── Cost category colors (recalibrated, muted-editorial) ── */
	--clr-buy:          light-dark(#2f5e8c, #7fb0dc);
	--clr-sell:         light-dark(color-mix(in oklab, #2e7d52 84%, #000), #6fcb97);
	/* Light-mode slots are darkened (hue kept) so the colours clear 4.5:1 as
	   small text on paper; dark-mode slots already pass on the warm-ink ground. */
	--clr-service:      light-dark(color-mix(in oklab, #b6792a 74%, #000), #e0b062);
	--clr-repair:       light-dark(color-mix(in oklab, #b3423a 90%, #000), #e08b82);
	--clr-upgrade:      light-dark(color-mix(in oklab, #2a7e8c 84%, #000), #6fc2ce);
	--clr-asset:        light-dark(#6a4e9c, #b79fe0);
	--clr-fixed:        light-dark(color-mix(in oklab, #c2622e 80%, #000), #e89e6b);
	--clr-fuel:         light-dark(color-mix(in oklab, #b89134 70%, #000), #e3c768);

	/* ── Chart *fill* variants ───────────────────────────────
	   The tokens above are darkened in light mode to clear 4.5:1 as small text
	   (category pills, coloured figures). Chart areas are large fills that need
	   no text contrast, so on paper the darkened warms read as muddy browns.
	   These -fill slots restore the cleaner, brighter hue for chart series only;
	   the dark slots match the base tokens (already legible on warm-ink). */
	--clr-buy-fill:     light-dark(#3f7fbf, #7fb0dc);
	--clr-sell-fill:    light-dark(#2f9e63, #6fcb97);
	--clr-service-fill: light-dark(#e39a2c, #e0b062);
	--clr-repair-fill:  light-dark(#d95448, #e08b82);
	--clr-upgrade-fill: light-dark(#2aa5bb, #6fc2ce);
	--clr-asset-fill:   light-dark(#8a5fc9, #b79fe0);
	--clr-fixed-fill:   light-dark(#e0703a, #e89e6b);
	--clr-fuel-fill:    light-dark(#e6bf3c, #e3c768);

	--clr-buy-bg:       color-mix(in oklab, var(--clr-buy) 10%, transparent);
	--clr-buy-border:   color-mix(in oklab, var(--clr-buy) 26%, transparent);
	--clr-sell-bg:      color-mix(in oklab, var(--clr-sell) 10%, transparent);
	--clr-sell-border:  color-mix(in oklab, var(--clr-sell) 26%, transparent);
	--clr-service-bg:   color-mix(in oklab, var(--clr-service) 10%, transparent);
	--clr-service-border: color-mix(in oklab, var(--clr-service) 26%, transparent);
	--clr-repair-bg:    color-mix(in oklab, var(--clr-repair) 10%, transparent);
	--clr-repair-border: color-mix(in oklab, var(--clr-repair) 26%, transparent);
	--clr-upgrade-bg:   color-mix(in oklab, var(--clr-upgrade) 10%, transparent);
	--clr-upgrade-border: color-mix(in oklab, var(--clr-upgrade) 26%, transparent);
	--clr-asset-bg:     color-mix(in oklab, var(--clr-asset) 10%, transparent);
	--clr-asset-border: color-mix(in oklab, var(--clr-asset) 26%, transparent);
	--clr-fuel-bg:      color-mix(in oklab, var(--clr-fuel) 10%, transparent);
	--clr-fuel-border:  color-mix(in oklab, var(--clr-fuel) 26%, transparent);

	/* ── Energieetikette A–G (§107/§109) ─────────────────────
	   The official label's green→red ramp, kept for RECOGNITION – that sequence
	   is the whole reason a drawn A–G bar reads instantly – but put through the
	   same treatment the cost categories got: the light slot is darkened via
	   color-mix so a letter on the band clears 4.5:1 on paper, and the dark slot
	   is lifted so it clears on warm ink. Do not restore the raw saturated
	   values; they would be the only unmuted thing in the system and would fail
	   contrast as small text.
	   --clr-eff-ink is the letter colour ON a band: near-black in both schemes,
	   because these bands stay light-ish at both ends of the ramp. */
	--clr-eff-a:        light-dark(color-mix(in oklab, #2e7d32 82%, #000), #6fc98a);
	--clr-eff-b:        light-dark(color-mix(in oklab, #5f9e34 82%, #000), #a2cf6a);
	--clr-eff-c:        light-dark(color-mix(in oklab, #9cb02f 76%, #000), #cfd964);
	--clr-eff-d:        light-dark(color-mix(in oklab, #d0a92b 74%, #000), #ecd06a);
	--clr-eff-e:        light-dark(color-mix(in oklab, #dd8a26 76%, #000), #f0b06d);
	--clr-eff-f:        light-dark(color-mix(in oklab, #d95f27 80%, #000), #ef9270);
	--clr-eff-g:        light-dark(color-mix(in oklab, #c62828 86%, #000), #ea7d7d);
	--clr-eff-ink:      light-dark(#faf9f5, #14130f);

	/* ── Summary / result values ─────────────────────────── */
	--clr-tco:          var(--clr-sell);
	--clr-profit:       var(--clr-sell);
	--clr-cost:         var(--clr-repair);
	--clr-warn:         var(--clr-service);
	--clr-highlight:    var(--accent);
	--critical:         light-dark(#b3261e, #f2998f);  /* overdue / MFK red */

	/* ── Named color aliases ─────────────────────────────── */
	--clr-green:        var(--clr-sell);
	--clr-orange:       var(--clr-service);
	--clr-red:          var(--clr-repair);

	/* ── Legacy alias tokens (previously undefined → hardcoded fallbacks) ── */
	--clr-accent:         var(--accent);
	--clr-accent-subtle:  var(--accent-soft);
	--color-primary:      var(--accent);
	--text-primary:       var(--text);
	--text-secondary:     var(--text-2);
	--text-muted:         var(--text-4);
	--surface-1:          var(--surface-raised);

	/* ── Modal / dialog / tooltip ────────────────────────── */
	--modal-content-bg: linear-gradient(180deg, var(--surface-raised) 0%, var(--surface) 100%);
	--modal-border:     var(--border);
	--tooltip-bg:       #211f19;
	--tooltip-border:   color-mix(in oklab, #fff 12%, transparent);
	--tooltip-text:     #ece8df;

	/* ── Import preview surfaces ─────────────────────────── */
	--surface-2:        var(--tint-xs);
	--surface-3:        var(--tint-sm);

	/* ── Radius ──────────────────────────────────────────── */
	--radius-card:      10px;
	--radius-control:   7px;
	--radius-pill:      999px;

	/* ── Elevation (shadows) ─────────────────────────────── */
	/* Warm scrim-based so they read on paper (light) and warm-ink (dark). */
	--shadow-lg:    0 12px 40px var(--scrim-lg);
	--shadow-modal: 0 25px 50px -12px var(--scrim-lg), 0 0 0 1px var(--tint-sm) inset;

	/* ── Modal geometry (single source of truth for header/body/footer) ──── */
	--modal-pad-x: clamp(1.25rem, 3vw, 2rem);
	--modal-pad-y: 1.5rem;

	/* ── Layout ──────────────────────────────────────────── */
	/* Sidebar column width – the max of the .app-shell grid track, named so the
	   width is a single documented value rather than a bare number in the grid. */
	--sidebar-w: 260px;

	/* ── Animation timing ────────────────────────────────── */
	--timing-fast:   150ms;
	--timing-base:   250ms;
	--timing-slow:   400ms;
	--timing-slower: 600ms;
	--ease-out:      cubic-bezier(0.33, 1, 0.68, 1);
	--ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
	--ease-bounce:   cubic-bezier(0.34, 1.56, 0.64, 1);
	--ease-spring:   cubic-bezier(0.34, 1.4, 0.5, 1);
}
}

/* Playfair Display ships real ct/st/Th/sp ligatures via `dlig`, which the CSS
   spec leaves off by default – opt in to ALL ligature classes wherever the
   display serif renders (every heading). */
:is(.cmp-card__title, .section-head__title,
	.car-row__name, .car-hero__name, .car-hero__submodel,
	.form-title, .empty-state-title, .sidebar__wordmark, .topbar__greeting,
	.topbar__title, .haupt__name) {
	font-variant-ligatures: common-ligatures discretionary-ligatures contextual historical-ligatures;
}

/* ==========================================================================
   Keyframe Animations
   ========================================================================== */

@keyframes fadeIn {
	from {
		opacity: 0;
		transform: translateY(10px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@keyframes fadeInScale {
	from {
		opacity: 0;
		transform: scale(0.95);
	}
	to {
		opacity: 1;
		transform: scale(1);
	}
}

@keyframes slideDown {
	from {
		opacity: 0;
		transform: translateY(-10px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@keyframes pulse {
	0%, 100% {
		opacity: 1;
	}
	50% {
		opacity: 0.7;
	}
}

@keyframes shimmer {
	0% {
		background-position: -1000px 0;
	}
	100% {
		background-position: 1000px 0;
	}
}

@keyframes popIn {
	0% {
		transform: scale(0.8);
		opacity: 0;
	}
	50% {
		transform: scale(1.05);
	}
	100% {
		transform: scale(1);
		opacity: 1;
	}
}

@keyframes glow {
	0%, 100% {
		box-shadow: 0 0 5px color-mix(in oklab, var(--accent) 30%, transparent);
	}
	50% {
		box-shadow: 0 0 20px color-mix(in oklab, var(--accent) 60%, transparent);
	}
}

@keyframes ripple {
	0% {
		transform: scale(0);
		opacity: 0.6;
	}
	100% {
		transform: scale(4);
		opacity: 0;
	}
}

/* Background lives on the root so the page canvas is always --surface, even
   during view transitions and before <body> paints. Declaring it only on
   <body> relied on background propagation, which breaks the moment <body>
   gets opacity/transform (e.g. an entrance animation) – yielding a white flash. */
html {
	background: var(--surface);
	/* Always reserve the scrollbar gutter so short pages (no scrollbar) and tall
	   pages (scrollbar) have the same content width. Without this the centered
	   container shifts ~7px horizontally between pages, so the masthead appears
	   to jump on navigation. */
	scrollbar-gutter: stable;
}

body {
	background: var(--surface);
	color: var(--text);
	font-family: var(--font-sans);
	font-size: 14px;
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	padding: clamp(20px, 4vw, 40px) clamp(14px, 3vw, 24px) 48px;
	margin: 0;
	min-height: 100vh;
}

.container {
	max-width: 1180px;
	width: 100%;
	margin: 0 auto;
}

h1 {
	margin: 0;
	font-size: 28px;
	font-weight: 400;
	color: var(--text);
	letter-spacing: -0.5px;
}

/* ==========================================================================
   Central component primitives
   The reusable vocabulary every feature composes from – buttons, badges,
   callouts and modal structure. Add a variant here instead of inventing a
   one-off class in a feature block. See book/src/development/components.md.
   ========================================================================== */

/* ── Button – .btn + intent + shape + size ──────────────────────────────────
   Intent (fill/colour): --primary --secondary --danger --ghost
   Shape:                --icon (square, subtle) / --close (icon that rotates)
   Size:                 --sm --lg / --block (full width)
   Compose e.g. `btn btn--icon btn--danger` for a red icon button. */
.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	padding: 0.625rem 1.25rem;
	border: 1px solid transparent;
	border-radius: var(--radius-control);
	font: inherit;
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.2;
	white-space: nowrap;
	text-decoration: none;
	cursor: pointer;
	transition: background var(--timing-base) var(--ease-out),
	            border-color var(--timing-base) var(--ease-out),
	            color var(--timing-base) var(--ease-out),
	            box-shadow var(--timing-base) var(--ease-out),
	            transform var(--timing-base) var(--ease-out);
}
.btn:disabled { opacity: 0.6; pointer-events: none; }

/* §56 loading state – the clicked action button spins (colour adapts to intent
   via --btn-spinner); every other action button is disabled ($busy) and dims
   via .btn:disabled above. color:transparent hides the label + currentColor
   icon, leaving only the ::after ring. */
.btn          { --btn-spinner: var(--text-2); }
.btn--primary { --btn-spinner: var(--accent-ink); }
.btn--danger  { --btn-spinner: var(--critical); }
.btn--soft    { --btn-spinner: var(--accent); }
.btn--ghost   { --btn-spinner: var(--accent); }
.btn.is-loading {
	opacity: 1;
	color: transparent;
	position: relative;
	pointer-events: none;
}
.btn.is-loading::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 1em;
	height: 1em;
	margin: -0.5em 0 0 -0.5em;
	border: 2px solid var(--btn-spinner);
	border-right-color: transparent;
	border-radius: 50%;
	animation: btn-spin 0.6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

.btn--secondary {
	background: var(--tint-sm);
	color: var(--text-2);
	border-color: var(--border);
}
.btn--secondary:hover {
	background: var(--tint-md);
	color: var(--text);
	border-color: var(--tint-lg);
}

.btn--primary {
	background: var(--accent);
	color: var(--accent-ink);
	font-weight: 600;
	box-shadow: 0 2px 10px var(--accent-glow);
}
.btn--primary:hover {
	transform: translateY(-1px);
	background: color-mix(in oklab, var(--accent) 88%, #000);
	box-shadow: 0 4px 16px color-mix(in oklab, var(--accent) 40%, transparent);
}
.btn--primary:active { transform: translateY(0); }

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

.btn--ghost {
	background: transparent;
	color: var(--accent);
	border-color: color-mix(in oklab, var(--accent) 40%, transparent);
}
.btn--ghost:hover { background: var(--accent-soft); }

/* Soft accent fill – the resting-accent look used by the primary toolbar action
   ("+ Eintrag") without the weight of a full primary fill. */
.btn--soft {
	background: var(--accent-soft);
	color: var(--accent);
	border-color: color-mix(in oklab, var(--accent) 30%, transparent);
	box-shadow: none;
}
.btn--soft:hover { background: color-mix(in oklab, var(--accent) 16%, transparent); }

/* §56 – modal submit error slot. Empty by default → hidden; the SSE loop patches
   the failed submit's message into the open dialog's slot, leaving it open. */
.form-error {
	margin: 0 0 0.75rem;
	padding: 0.6rem 0.8rem;
	border-radius: var(--radius-control);
	background: var(--clr-repair-bg);
	color: var(--clr-repair);
	border: 1px solid color-mix(in oklab, var(--critical) 40%, transparent);
	font-size: 0.85rem;
}
.form-error:empty { display: none; }

.btn--sm { padding: 0.4rem 0.8rem; font-size: 0.78rem; }
.btn--lg { padding: 1rem 2rem; font-size: 1.125rem; font-weight: 600; }
.btn--block { width: 100%; }

/* Square, low-chrome icon button. Neutral by default; compose with an intent
   modifier for accent (--primary) or red (--danger) tint. */
.btn--icon {
	padding: 0.35rem;
	min-width: 2rem;
	min-height: 2rem;
	background: transparent;
	border-color: transparent;
	color: var(--text-3);
	font-size: 1rem;
	line-height: 1;
	box-shadow: none;
}
.btn--icon:hover {
	background: var(--tint-md);
	color: var(--text);
	transform: none;
	box-shadow: none;
}
.btn--icon.btn--primary { color: var(--accent); font-weight: inherit; }
.btn--icon.btn--primary:hover { background: var(--accent-soft); color: var(--accent); }
.btn--icon.btn--danger { color: var(--clr-repair); }
.btn--icon.btn--danger:hover { background: var(--clr-repair-bg); color: var(--clr-repair); }
/* §56 – row quick-action (mark done / confirm paid): a soft-filled affirmative
   chip, so it reads as a distinct role from the bare accent edit icon and the
   bare danger delete icon in the same row. */
.btn--icon.btn--quick { color: var(--accent); background: var(--accent-soft); --btn-spinner: var(--accent); }
.btn--icon.btn--quick:hover { background: color-mix(in oklab, var(--accent) 16%, transparent); color: var(--accent); }

/* Modal close glyph – icon button that spins on hover. */
.btn--close {
	min-width: 2.5rem;
	min-height: 2.5rem;
	font-size: 1.5rem;
}
.btn--close:hover { transform: rotate(90deg); }

/* ── Badge – .badge, colour driven by [data-cat] ────────────────────────────
   `<span class="badge" data-cat="service">`. --soft (default, tinted chip) or
   --solid (filled). One category table feeds badges, swatches and amounts. */
.badge {
	display: inline-block;
	border-radius: 4px;
	padding: 2px 7px;
	font-size: 9px;
	font-weight: 600;
	letter-spacing: 1px;
	line-height: 1.4;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--cat, var(--text-2));
	background: var(--cat-bg, var(--tint-sm));
	border: 1px solid var(--cat-border, var(--border));
}
.badge--solid {
	color: var(--accent-ink);
	background: var(--cat, var(--accent));
	border-color: transparent;
}

/* Category palette – the single source of truth for cost-category colour.
   Sets custom properties only (renders nothing itself), consumed by .badge,
   .charge-swatch and category-coloured amounts via var(--cat*). */
[data-cat="buy"]     { --cat: var(--clr-buy);     --cat-bg: var(--clr-buy-bg);     --cat-border: var(--clr-buy-border); }
[data-cat="sell"]    { --cat: var(--clr-sell);    --cat-bg: var(--clr-sell-bg);    --cat-border: var(--clr-sell-border); }
[data-cat="service"] { --cat: var(--clr-service); --cat-bg: var(--clr-service-bg); --cat-border: var(--clr-service-border); }
[data-cat="repair"]  { --cat: var(--clr-repair);  --cat-bg: var(--clr-repair-bg);  --cat-border: var(--clr-repair-border); }
[data-cat="upgrade"] { --cat: var(--clr-upgrade); --cat-bg: var(--clr-upgrade-bg); --cat-border: var(--clr-upgrade-border); }
[data-cat="asset"]   { --cat: var(--clr-asset);   --cat-bg: var(--clr-asset-bg);   --cat-border: var(--clr-asset-border); }
[data-cat="energy"]  { --cat: var(--clr-fuel);    --cat-bg: var(--clr-fuel-bg);    --cat-border: var(--clr-fuel-border); }
[data-cat="fixed"]   { --cat: var(--clr-fixed); }
[data-cat="tco"]     { --cat: var(--clr-tco); }

/* ── Callout – tinted advisory box, .callout + tone ─────────────────────────
   Tone (--info --warn --danger --success) sets bg + border from a --clr token,
   so every callout is theme-correct (light-dark) for free. --bar adds a left
   accent rule. Replaces the per-feature hint/notice/warning boxes. */
.callout {
	padding: 0.65rem 0.85rem;
	border-radius: var(--radius-control);
	border: 1px solid var(--callout-border, var(--border));
	background: var(--callout-bg, var(--tint-xs));
	color: var(--text-2);
	font-size: 0.85rem;
	line-height: 1.5;
}
.callout--info    { --callout-bg: var(--accent-soft);                                    --callout-border: color-mix(in oklab, var(--accent) 22%, transparent); }
.callout--warn    { --callout-bg: color-mix(in oklab, var(--clr-service) 12%, transparent); --callout-border: color-mix(in oklab, var(--clr-service) 40%, transparent); color: var(--text-1); }
.callout--danger  { --callout-bg: color-mix(in oklab, var(--clr-repair) 12%, transparent);  --callout-border: color-mix(in oklab, var(--clr-repair) 40%, transparent); }
.callout--success { --callout-bg: color-mix(in oklab, var(--clr-sell) 12%, transparent);    --callout-border: color-mix(in oklab, var(--clr-sell) 40%, transparent); }
.callout--bar {
	border-left-width: 3px;
	border-left-color: var(--callout-accent, var(--accent));
}
/* Inline icon + text status strip (e.g. §58 replication status). */
.callout--row {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-bottom: 0.85rem;
}
.callout--row .icon { flex: none; }
/* §71 gated value-tracking nudge – a /billing link with an accent icon and a
   stacked title/body. Without this the base .callout lays the icon and both text
   lines out inline, so the bold title runs straight into the body. margin-top
   lifts it clear of the value chart above (a fixed-height <tco-chart>). */
.callout--upsell {
	display: flex;
	align-items: flex-start;
	gap: 0.6rem;
	margin-top: 0.85rem;
	text-decoration: none;
	color: var(--text-2);
	transition: border-color 0.15s ease, background 0.15s ease;
}
.callout--upsell:hover {
	border-color: color-mix(in oklab, var(--accent) 45%, var(--border));
	background: var(--accent-soft);
}
.callout--upsell .icon { font-size: 1.15rem; margin-top: 0.05rem; color: var(--accent); }
.callout--upsell .callout__text { display: flex; flex-direction: column; gap: 0.12rem; min-width: 0; }
.callout--upsell .callout__text strong { color: var(--text-1); font-weight: 600; }

/* §59 "Your data & privacy" page – a single, readable column of stacked panels.
   Provides its own padding (the layout content slot has none; each section
   supplies its own, e.g. .settings-content). */
.data-privacy {
	padding: clamp(1.1rem, 2.4vw, 2.2rem);
	max-width: 820px;
	display: flex;
	flex-direction: column;
	gap: 1rem;
}
.data-privacy > .panel { margin: 0; }

/* §46 onboarding nudge – completion prompt (text + actions) inside a .callout */
.onboarding-nudge {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem 1rem;
	margin-bottom: 0.75rem;
}
.onboarding-nudge__text { flex: 1 1 15rem; min-width: 0; }
.onboarding-nudge__title { margin: 0; font-weight: 600; color: var(--text-1); }
.onboarding-nudge__body { margin: 0.15rem 0 0; }
.onboarding-nudge__actions { display: flex; flex-shrink: 0; gap: 0.5rem; }

/* ── Modal structure – self-padded header/body/footer ───────────────────────
   Direct children of .form-modal-content. Padding comes from --modal-pad-*,
   so a footer is correct wherever it sits and never needs a one-off padding
   fix (the reason the old .intake-footer existed). */
.modal__body { padding: var(--modal-pad-y) var(--modal-pad-x); }
.modal__footer {
	display: flex;
	justify-content: flex-end;
	align-items: center;
	gap: 0.75rem;
	padding: var(--modal-pad-y) var(--modal-pad-x);
	border-top: 1px solid var(--border);
}
.modal__footer--split { justify-content: space-between; }

/* ==========================================================================
   Demo Banner
   ========================================================================== */

.demo-banner {
	background: rgba(251, 191, 36, 0.12);
	border-bottom: 1px solid rgba(251, 191, 36, 0.3);
	color: var(--text-2);
	font-size: 0.8rem;
	font-weight: 500;
	text-align: center;
	padding: 0.55rem 1rem;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.6rem;
	flex-wrap: wrap;
}

/* §47: the demo → signup CTA sitting inline in the reset-notice banner. */
.demo-banner__cta {
	flex: none;
	font-weight: 600;
	color: var(--accent, #1f4d3a);
	text-decoration: none;
	border: 1px solid color-mix(in oklab, var(--accent, #1f4d3a) 45%, transparent);
	border-radius: 999px;
	padding: 0.15rem 0.7rem;
	white-space: nowrap;
	transition: background 0.15s ease, color 0.15s ease;
}

.demo-banner__cta:hover {
	background: var(--accent, #1f4d3a);
	color: #fff;
}

/* ==========================================================================
   Impersonation Banner (§40 operator console)
   ========================================================================== */

.impersonation-banner {
	background: color-mix(in oklab, var(--clr-repair) 14%, transparent);
	border-bottom: 1px solid color-mix(in oklab, var(--clr-repair) 40%, transparent);
	color: var(--clr-repair);
	font-size: 0.8rem;
	font-weight: 600;
	text-align: center;
	padding: 0.55rem 1rem;
	position: sticky;
	top: 0;
	z-index: 100;
}
.impersonation-banner form { display: inline; margin-left: 0.6rem; }
.impersonation-banner button {
	font: inherit;
	font-weight: 600;
	color: inherit;
	background: none;
	border: 1px solid currentColor;
	border-radius: 4px;
	padding: 0.1rem 0.5rem;
	cursor: pointer;
}
.impersonation-banner button:hover { background: color-mix(in oklab, var(--clr-repair) 16%, transparent); }

.header-description {
	margin: 5px 0 0;
	color: var(--text-4);
	font-size: 12px;
}

.header-actions-left {
	display: flex;
	gap: 0.7rem;
	flex-wrap: wrap;
	align-items: center;
	flex: 1;
}

.header-actions-right {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-left: auto;
}

.profile-switcher {
	display: flex;
	align-items: center;
	gap: 0.375rem;
	flex-wrap: wrap;
}

.profile-switcher-label {
	font-size: 0.75rem;
	color: var(--text-muted);
	margin-right: 0.25rem;
	white-space: nowrap;
}

.profile-switcher-active {
	font-size: 0.8rem;
	font-weight: 600;
	color: var(--accent);
	padding: 0.3rem 0.75rem;
	border-radius: var(--radius-pill);
	background: var(--accent-soft);
	border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
	white-space: nowrap;
}

.profile-switcher-item {
	display: inline-flex;
	align-items: center;
}

.profile-switcher-btn {
	font-size: 0.78rem;
	padding: 0.28rem 0.7rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--border);
	background: transparent;
	color: var(--text-3);
	cursor: pointer;
	transition: all 0.15s ease;
	white-space: nowrap;
}
.profile-switcher-btn:hover {
	border-color: color-mix(in oklab, var(--accent) 45%, transparent);
	color: var(--ink);
	background: var(--accent-soft);
}
.profile-switcher-btn .icon {
	margin-right: 0.3rem;
	color: var(--text-4);
}

.profile-switcher-add {
	color: var(--text-3);
	border-style: dashed;
}
.profile-switcher-add:hover {
	color: var(--accent);
	border-color: color-mix(in oklab, var(--accent) 45%, transparent);
	border-style: solid;
}

.profile-switcher-login {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	padding: 0.2rem 0.4rem 0.2rem 0.55rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--border);
	background: transparent;
}
.profile-switcher-login .icon {
	width: 0.85em;
	height: 0.85em;
	color: var(--text-4);
	flex-shrink: 0;
}
.profile-switcher-login-input {
	width: 6rem;
	font-size: 0.78rem;
	padding: 0.2rem 0.4rem;
	border: none;
	background: transparent;
	color: var(--ink);
}
.profile-switcher-login-input:focus {
	outline: none;
}
.profile-switcher-login .profile-switcher-btn {
	padding: 0.2rem 0.6rem;
	border: none;
}

.profile-switcher-delete {
	font-size: 0.7rem;
	line-height: 1;
	display: inline-grid;
	place-items: center;
	min-width: 24px;
	min-height: 24px;
	margin-left: 0.1rem;
	border-radius: 50%;
	border: none;
	background: transparent;
	color: var(--text-4);
	cursor: pointer;
	transition: all 0.15s ease;
}
.profile-switcher-delete:hover {
	background: color-mix(in oklab, var(--critical) 18%, transparent);
	color: var(--critical);
}
.car-photo-upload {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 20px;
	cursor: pointer;
	opacity: 0;
	transition: opacity var(--timing-base) var(--ease-out);
	background: rgba(0,0,0,0.35);
	border-radius: 10px;
}

.car-photo-wrap:hover .car-photo-upload {
	opacity: 1;
}

/* Show upload icon on placeholder immediately (no image to obscure) */
.car-photo-wrap:has(.car-photo-placeholder) .car-photo-upload {
	opacity: 0.6;
	background: transparent;
}

.car-photo-wrap:has(.car-photo-placeholder):hover .car-photo-upload {
	opacity: 1;
}

.car-photo-delete {
	position: absolute;
	top: 3px;
	right: 3px;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background: rgba(0,0,0,0.7);
	border: none;
	color: #fff;
	font-size: 13px;
	line-height: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	opacity: 0;
	transition: opacity var(--timing-base) var(--ease-out);
	z-index: 1;
	padding: 0;
}

.car-photo-wrap:hover .car-photo-delete {
	opacity: 1;
}

.car-photo-delete:hover {
	background: var(--clr-sell);
}
.car-category {
	background: var(--tint-sm);
	padding: 2px 6px;
	border-radius: 4px;
	font-weight: 600;
	color: var(--text-2);
	border: 1px solid var(--border);
	transition: all var(--timing-base) var(--ease-out);
	display: inline-block;
}

.car-category:hover {
	background: var(--tint-md);
	border-color: var(--tint-lg);
	transform: scale(1.05);
}

.car-status-sold {
	color: var(--clr-sell);
}

.car-status-owned {
	color: var(--text-2);
}

/* §108: a listed car reads as active/promoted, not muted like sold. */
.car-status-forsale {
	color: var(--accent);
	background: var(--tint-md);
	border: 1px solid var(--accent);
	border-radius: 999px;
	padding: 1px 8px;
	font-weight: 600;
}

/* MFK status (§8) */
.car-status-mfk-ok {
	color: var(--clr-green);
}

.car-status-mfk-soon {
	color: var(--clr-orange);
}

.car-status-mfk-overdue {
	color: var(--clr-red);
}

/* §99 Inc 6a: MFK schedule estimate passed, no Aufgebot yet – awaiting the (late)
   summons, not a failure. Neutral/muted, distinct from soon (act) and overdue (fail). */
.car-status-mfk-awaiting {
	color: var(--text-muted);
}

/* ==========================================================================
   Sharing (§1)
   ========================================================================== */

/* "Geteilt" badge on shared-in cars (detail hero eyebrow + list row meta). */
.car-badge-shared {
	display: inline-flex;
	align-items: center;
	gap: 0.25em;
	color: var(--text-2);
}

.car-badge-shared .icon {
	width: 0.95em;
	height: 0.95em;
}

/* Kennzeichen badge (§14) – list row meta + detail hero title. */
.car-badge-plate {
	display: inline-block;
	font-family: var(--font-mono, monospace);
	font-size: 0.8em;
	letter-spacing: 0.03em;
	padding: 0.1em 0.5em;
	border: 1px solid var(--border);
	border-radius: 4px;
	color: var(--text-2);
	vertical-align: middle;
}

/* Energieeffizienz pair (§107 Inc 7) – the category the car carried at first
   registration next to the one today's scale gives the same car. The letters are chips
   in the official A–G ramp so they read as Energieetikette categories rather than as
   grades in some Libretto-invented scheme; the surrounding words carry the scale each
   belongs to, because a bare letter is exactly the ambiguity this line exists to remove. */
.eff-pair {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4rem;
	margin: 0.75rem 0 0;
	font-size: 0.8125rem;
	color: var(--text-3);
}

.eff-pair__term {
	font-weight: 600;
	color: var(--text-2);
}

.eff-pair__sep { color: var(--text-5); }

.eff-chip {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.6em;
	padding: 0.05em 0.35em;
	border-radius: 4px;
	font-family: var(--font-mono, monospace);
	font-weight: 700;
	/* Neutral until a band modifier lands, so an unexpected letter degrades to a plain
	   chip instead of silently borrowing another category's colour. */
	color: var(--text-2);
	background: var(--surface-sunken);
}

.eff-chip--a { color: var(--clr-eff-ink); background: var(--clr-eff-a); }
.eff-chip--b { color: var(--clr-eff-ink); background: var(--clr-eff-b); }
.eff-chip--c { color: var(--clr-eff-ink); background: var(--clr-eff-c); }
.eff-chip--d { color: var(--clr-eff-ink); background: var(--clr-eff-d); }
.eff-chip--e { color: var(--clr-eff-ink); background: var(--clr-eff-e); }
.eff-chip--f { color: var(--clr-eff-ink); background: var(--clr-eff-f); }
.eff-chip--g { color: var(--clr-eff-ink); background: var(--clr-eff-g); }

/* Read-only view of a shared car: hide every mutate affordance. The server also
   rejects writes (defense in depth); this just keeps the UI honest. */
.car-detail--readonly .entry-actions,
.car-detail--readonly .th-actions {
	display: none;
}

/* Share picker (ShareModal) – one row per profile with an access selector. */
.share-list {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin: 0.75rem 0;
}

.share-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}

.share-row__name {
	font-weight: 500;
}

.share-row__select {
	width: auto;
	min-width: 11rem;
}

/* ==========================================================================
   Pills
   ========================================================================== */

.pills {
	display: flex;
	gap: 14px;
	align-items: center;
	flex-shrink: 0;
	flex-wrap: wrap;
}

.car-actions {
	display: flex;
	gap: 6px;
	align-items: center;
}
/* Primary-vehicle star toggle (§14) – outline by default, filled once set. */
.car-action-btn--primary .icon {
	color: var(--text-4);
	transition: color var(--timing-base) var(--ease-out), fill var(--timing-base) var(--ease-out);
}

.car-action-btn--primary.is-primary .icon {
	color: var(--clr-fuel);
}

.pill {
	text-align: right;
	transition: transform var(--timing-base) var(--ease-spring);
}

.pill:hover {
	transform: scale(1.08);
}

.pill-label {
	font-size: 9px;
	color: var(--text-3);
	letter-spacing: 1.5px;
	margin-bottom: 1px;
	transition: color var(--timing-base) var(--ease-out);
	font-weight: 500;
	text-transform: uppercase;
}

.pill:hover .pill-label {
	color: var(--text-2);
}

.pill-value {
	font-size: 18px;
	font-weight: 700;
	font-family: var(--font-mono);
	line-height: 1;
	transition: all var(--timing-base) var(--ease-out);
}

.pill:hover .pill-value {
	text-shadow: 0 0 20px currentColor;
}

/* ==========================================================================
   Details / Logbook
   ========================================================================== */

details {
	border-top: 1px solid var(--border-subtle);
}

details[open] > summary {
	background: var(--scrim-sm);
}

details summary {
	cursor: pointer;
	padding: 9px 22px;
	background: var(--scrim-xs);
	list-style: none;
	user-select: none;
	transition: all var(--timing-base) var(--ease-out);
}

details summary::-webkit-details-marker {
	display: none;
}

details summary:hover {
	background: var(--scrim-sm);
	padding-left: 26px;
}
/* ==========================================================================
   Entry Table
   ========================================================================== */

.entry-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 12px;
}

.entry-table thead th {
	padding: 7px 14px;
	text-align: left;
	font-size: 9px;
	letter-spacing: 2px;
	color: var(--text-3);
	font-weight: 600;
	background: var(--scrim-md);
	border-bottom: 1px solid var(--border-subtle);
	text-transform: uppercase;
}

.entry-table tbody tr {
	border-bottom: 1px solid var(--border-subtle);
	transition: all var(--timing-base) var(--ease-out);
}

.entry-table tbody tr:hover {
	background: var(--tint-sm);
	transform: scale(1.005);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

.entry-table tbody td {
	padding: 8px 14px;
	transition: all var(--timing-base) var(--ease-out);
}

.entry-table tbody tr:hover td {
	color: var(--text);
}

.entry-date,
.entry-km {
	color: var(--text-2);
	font-family: var(--font-mono);
	white-space: nowrap;
}

.entry-desc {
	color: var(--text-2);
}
/* invoice issuer / garage ("Aussteller") shown under the description */
.entry-vendor {
	display: block;
	margin-top: 1px;
	font-size: 12px;
	color: var(--text-4);
}
/* §11 energy fill quantity chip in the journal description cell */
.entry-energy-qty {
	display: inline-block;
	margin-left: 0.5rem;
	padding: 1px 6px;
	border-radius: 4px;
	font-family: var(--font-mono);
	font-size: 10px;
	color: var(--clr-fuel);
	background: var(--clr-fuel-bg);
	white-space: nowrap;
}

/* §12 driving-style slider on the car form */
.driving-style-slider {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}
.driving-style-slider input[type="range"] { flex: 1; min-width: 0; }
.driving-style-slider .form-label-hint { white-space: nowrap; }

/* §11 charge-sources editor in settings */
.charge-source-list { display: flex; flex-direction: column; gap: 0.5rem; }
.charge-source-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.charge-source-edit { display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 0; }
.charge-source-edit .form-input { min-width: 0; }
.charge-source-edit > .form-input:first-child { flex: 1; }
.charge-source-price { width: 6rem; flex: 0 0 auto; text-align: right; font-family: var(--font-mono); }
.charge-source-unit { color: var(--text-3); font-size: 11px; white-space: nowrap; }
.charge-source-del {
	width: 32px; height: 32px; flex: 0 0 auto;
	border: 1px solid var(--border); border-radius: var(--radius-control);
	background: var(--tint-sm); color: var(--text-3);
	font-size: 1.1rem; line-height: 1; cursor: pointer;
	transition: all var(--timing-base) var(--ease-out);
}
.charge-source-del:hover { background: var(--clr-repair-bg); color: var(--clr-repair); border-color: var(--clr-repair-border); }

/* §11 erfasst-vs-geschätzt fuel split, shown above the cost breakdown */
.energy-split {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem 0.85rem;
	margin: 0 0 1rem;
	font-size: 12px;
	color: var(--text-2);
}
.energy-split__label { color: var(--text-3); text-transform: uppercase; letter-spacing: 1px; font-size: 9px; font-weight: 600; }
.energy-split__total { font-family: var(--font-mono); color: var(--text); font-weight: 600; }
.energy-split__part { font-family: var(--font-mono); }
.energy-split__part--actual { color: var(--clr-sell); }
.energy-split__part--est { color: var(--clr-fuel); }
.energy-split__cons { margin-left: auto; color: var(--text-3); font-family: var(--font-mono); }
.energy-split--mix { gap: 0.5rem 0.6rem; }
.energy-split__mixitem {
	font-family: var(--font-mono);
	color: var(--clr-upgrade);
	background: color-mix(in oklab, var(--clr-upgrade) 10%, transparent);
	border-radius: 4px;
	padding: 1px 7px;
}

.entry-amount {
	font-family: var(--font-mono);
	text-align: right;
	white-space: nowrap;
	color: var(--text);
}

.entry-amount--sell { color: var(--clr-tco); }
.entry-amount--fixed { color: var(--clr-fixed); }

/* Recurring-charge category swatch (§10), mirrors the cost-pie legend dot. */
.charge-swatch {
	display: inline-block;
	width: 10px;
	height: 10px;
	border-radius: 2px;
	margin-right: 7px;
	vertical-align: baseline;
}

/* ==========================================================================
   Summary Row
   ========================================================================== */

.summary-row {
	display: flex;
	gap: 16px;
	justify-content: flex-end;
	flex-wrap: wrap;
	padding: 10px 22px;
	border-top: 1px solid var(--border);
	font-size: 11px;
}

.summary-label {
	color: var(--text-2);
}

.summary-value--service { color: var(--clr-service); font-family: var(--font-mono); }
.summary-value--upgrade { color: var(--clr-upgrade); font-family: var(--font-mono); }
.summary-value--asset { color: var(--clr-asset); font-family: var(--font-mono); }
.summary-value--fixed { color: var(--clr-fixed); font-family: var(--font-mono); }
.summary-value--tco {
	color: var(--clr-tco);
	font-weight: 700;
	font-family: var(--font-mono);
}

/* ==========================================================================
   Charts
   ========================================================================== */

.chart-container {
	margin-top: 20px;
	padding: 0 10px;
}

tco-chart {
	display: block;
	width: 100%;
	height: 300px;
}

.comparison-chart {
	display: block;
	width: 100%;
	height: 250px;
}

/* ==========================================================================
   Comparison Panel
   ========================================================================== */

/* View Transitions: enable for same-origin nav (sort changes) */
@view-transition {
	navigation: auto;
}

/* Cross-document page transitions: the old content fades out fast, the new page
   fades in with a slight lift, so navigation feels like a soft settle rather than
   a hard swap. Card repositioning stays the focus in the comparison panel. */
::view-transition-old(root) {
	animation: vt-page-out 130ms ease-out both;
}
::view-transition-new(root) {
	animation: vt-page-in 260ms var(--ease-out, ease-out) both;
}
@keyframes vt-page-out { to { opacity: 0; } }
@keyframes vt-page-in {
	from { opacity: 0; transform: translateY(10px); }
	to { opacity: 1; transform: none; }
}

/* Hold the sidebar as its own group: its identical brand + primary nav cross-fade
   invisibly, so only the contextual per-section subnav actually animates. */
::view-transition-group(app-sidebar) {
	animation-duration: 220ms;
	animation-timing-function: ease-out;
}

/* Respect reduced-motion: skip the page fade/lift entirely (instant swap). */
@media (prefers-reduced-motion: reduce) {
	::view-transition-old(root),
	::view-transition-new(root) { animation: none; }
}

.comparison-panel {
	margin-bottom: 26px;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	padding: clamp(1rem, 2.2vw, 1.5rem);
}

.comparison-header {
	font-family: var(--font-mono);
	font-size: 10px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--text-4);
	margin-bottom: 14px;
	font-weight: 600;
}

.comparison-cards {
	display: grid;
	gap: clamp(0.6rem, 1.4vw, 0.9rem);
	grid-template-columns: repeat(auto-fill, minmax(clamp(210px, 24%, 280px), 1fr));
}

/* §24 vehicle-group separator in Vergleich panel */
.comparison-group { margin-top: 1.75rem; }
.comparison-group:first-child { margin-top: 0; }
.comparison-group__heading {
	display: flex;
	align-items: center;
	gap: 0.45em;
	margin: 0 0 0.75rem;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 520;
	font-size: clamp(16px, 1.8vw, 19px);
	letter-spacing: -0.01em;
	line-height: 1.1;
	color: var(--ink);
	padding-bottom: 0.5rem;
	border-bottom: 1px solid var(--border-subtle);
}
.comparison-group__heading .icon { color: var(--text-3); }

/* ── Ranking card: photo band + instrument metrics, links to detail ─────── */
.cmp-card {
	display: flex;
	flex-direction: column;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	overflow: hidden;
	text-decoration: none;
	color: inherit;
	transition:
		transform    var(--timing-base) var(--ease-out),
		box-shadow   var(--timing-base) var(--ease-out),
		border-color var(--timing-base) var(--ease-out);
}
.cmp-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 12px 28px var(--scrim-md);
	border-color: var(--tint-lg);
}

.cmp-card__media {
	position: relative;
	aspect-ratio: 16 / 10;
	background: var(--surface-sunken);
	overflow: hidden;
}
.cmp-card__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform var(--timing-slow) var(--ease-out);
}
.cmp-card:hover .cmp-card__img { transform: scale(1.04); }
.cmp-card__img--ph {
	display: grid;
	place-items: center;
	color: var(--text-5);
}
/* Scrim only over the lower band, so the title stays legible without dulling the photo. */
.cmp-card__media::after {
	content: '';
	position: absolute;
	inset: 40% 0 0;
	background: linear-gradient(to bottom, transparent, color-mix(in oklab, #000 72%, transparent));
	pointer-events: none;
}
.cmp-card__title {
	position: absolute;
	left: 0.85rem;
	right: 0.85rem;
	bottom: 0.7rem;
	z-index: 1;
	font-family: var(--font-serif);
	font-weight: 540;
	font-size: 14px;
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: #fff;
	text-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.cmp-card__rank {
	position: absolute;
	top: 0.6rem;
	left: 0.6rem;
	z-index: 1;
	display: inline-grid;
	place-items: center;
	min-width: 1.55rem;
	height: 1.55rem;
	padding: 0 0.4rem;
	border-radius: var(--radius-pill);
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	color: var(--ink);
	background: color-mix(in oklab, var(--surface-raised) 88%, transparent);
	backdrop-filter: blur(4px);
	box-shadow: 0 1px 3px var(--scrim-md);
}
.cmp-card__rank .icon { color: var(--accent); font-size: 0.95rem; }

.cmp-card--winner { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
.cmp-card--winner .cmp-card__rank {
	background: var(--accent);
	color: var(--accent-ink);
}
.cmp-card--winner .cmp-card__rank .icon { color: var(--accent-ink); }

.cmp-card__metrics {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	padding: 0.9rem 1rem 0.7rem;
}

/* Hero: the single all-in comparable number that the ranking sorts by. */
.cmp-hero {
	display: flex;
	align-items: baseline;
	gap: 0.4rem;
}
.cmp-hero__val {
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: 27px;
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--text-1);
	font-variant-numeric: tabular-nums slashed-zero;
}
.cmp-hero__unit {
	font-family: var(--font-mono);
	font-size: 9.5px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-4);
}
.cmp-hero__month {
	margin-left: auto;
	align-self: baseline;
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--text-3);
	font-variant-numeric: tabular-nums slashed-zero;
	white-space: nowrap;
}

/* Cost-DNA: one stacked bar whose segments sum to the hero, so the composition
   reads at a glance (a thirsty car shows a fat energy band, etc.). */
.cmp-bar {
	display: flex;
	height: 7px;
	gap: 1px;
	border-radius: var(--radius-pill);
	overflow: hidden;
	background: var(--surface-sunken);
}
.cmp-bar__seg {
	height: 100%;
	min-width: 2px;
	background: var(--seg-clr);
}

/* Legend carries each segment's *real* per-km value, so fuel/upkeep are legible
   on their own rather than hidden between two cumulative totals. */
.cmp-legend {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 0.28rem 0.8rem;
	margin: 0;
	padding: 0;
	list-style: none;
}
.cmp-legend__item {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	font-family: var(--font-mono);
}
.cmp-legend__dot {
	width: 7px;
	height: 7px;
	border-radius: 2px;
	flex: none;
	background: var(--seg-clr);
}
.cmp-legend__lbl {
	font-size: 9px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cmp-legend__val {
	margin-left: auto;
	font-size: 11px;
	color: var(--text-2);
	font-variant-numeric: tabular-nums slashed-zero;
}

/* Shared per-segment colour, used by both the bar segment and the legend dot –
   both fills, so they take the brighter -fill hue (matching the charts). */
.cmp-seg--depreciation { --seg-clr: var(--clr-buy-fill); }
.cmp-seg--upkeep       { --seg-clr: var(--clr-service-fill); }
.cmp-seg--invest       { --seg-clr: var(--clr-upgrade-fill); }
.cmp-seg--fixed        { --seg-clr: var(--clr-fixed-fill); }
.cmp-seg--energy       { --seg-clr: var(--clr-fuel-fill); }
.cmp-seg--capital      { --seg-clr: var(--clr-asset-fill); }
.cmp-seg--appreciation { --seg-clr: var(--clr-sell-fill); } /* §71 lens pill (no bar segment) */
/* §71 Inc 3: a net-negative all-in (appreciation gain exceeds costs) reads as a gain. */
.cmp-hero__val--gain { color: var(--clr-sell); }
.cmp-hero__gain {
	display: block;
	margin-top: 0.15rem;
	font-size: 11px;
	color: var(--clr-sell);
	font-variant-numeric: tabular-nums;
}

/* Car-detail overview: a larger single-car cost-DNA header (all-in figure +
   monthly + the same stacked bar and legend as the comparison cards). */
.cost-dna {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	max-width: 460px;
	margin: 0.25rem 0 1.4rem;
}
.cost-dna .cmp-hero__val { font-size: 34px; }
.cost-dna__bar { height: 9px; }
/* The four segments as a tidy 2×2 grid of tiles (detail always has exactly the
   four cash segments – capital is Vergleich-only). */
.cost-dna__legend { gap: 0.5rem; }
.cost-dna__legend .cmp-legend__item {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: baseline;
	gap: 0.5rem;
	padding: 0.5rem 0.7rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
}
.cost-dna__legend .cmp-legend__dot { align-self: center; }
.cost-dna__legend .cmp-legend__val { margin-left: 0; font-size: 13px; }

/* Car-detail overview: cost-DNA+summary, pie, yearly breakdown, and cost/km
   trend as four tiles in a 2×2 grid instead of one long vertical stack. */
.overview-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp(1rem, 2vw, 1.5rem);
}
.overview-tile {
	min-width: 0;
	padding: clamp(0.9rem, 1.8vw, 1.25rem);
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
}
.tile-head {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	margin-bottom: 0.75rem;
}
.tile-head__title {
	font-size: 0.95rem;
	font-weight: 600;
	line-height: 1.25;
	color: var(--text-1);
	margin: 0;
}
.tile-head__sub {
	font-size: 0.8rem;
	line-height: 1.3;
	color: var(--text-3);
	margin: 0;
}
/* §71 value tile: title block + a "+ Bewertung" action on one row. */
.tile-head--row {
	flex-direction: row;
	align-items: flex-start;
	justify-content: space-between;
	gap: 0.75rem;
}
.tile-head--row .tile-head__titles {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}
/* §71 logged-valuations list under the value curve. */
.value-log {
	list-style: none;
	margin: 0.85rem 0 0;
	padding: 0;
}
.value-log__row {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.4rem 0;
	border-top: 1px solid var(--border-subtle);
	font-size: 0.85rem;
}
.value-log__date { color: var(--text-3); font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.value-log__val { font-weight: 600; color: var(--text-1); font-variant-numeric: tabular-nums; }
.value-log__src { color: var(--text-3); }
.value-log__row .btn { margin-left: auto; }
/* §71 Inc 2: equity / net-position scorecard in the value tile. */
.equity { margin: 0.6rem 0 0.9rem; }
.equity__stats {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 1.5rem;
	align-items: baseline;
}
.equity__stat { display: flex; flex-direction: column; gap: 0.1rem; }
.equity__label {
	font-size: 11px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
}
.equity__val {
	font-family: var(--font-mono);
	font-size: 1rem;
	font-weight: 600;
	color: var(--text-1);
	font-variant-numeric: tabular-nums;
}
.equity__val--asset { color: var(--clr-asset); }
.equity__val--pos { color: var(--clr-sell); }
.equity__val--neg { color: var(--clr-repair); }
.equity__bar {
	margin-top: 0.6rem;
	height: 6px;
	border-radius: 999px;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	overflow: hidden;
}
.equity__bar-fill {
	display: block;
	height: 100%;
	background: var(--text-4);
	transition: width var(--timing-base) var(--ease-out);
}
.equity__bar-fill--pos { background: var(--clr-sell); }
.equity__hint {
	margin: 0.4rem 0 0;
	font-size: 0.78rem;
	line-height: 1.35;
	color: var(--text-3);
}
/* §71 Inc 5: collection worth in the Vergleich "Sammlung" section head. */
.collection__worth {
	margin-left: auto;
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	text-align: right;
}
.collection__worth-label {
	font-size: 11px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
}
.collection__worth-val {
	font-family: var(--font-mono);
	font-size: 1.35rem;
	font-weight: 600;
	color: var(--clr-asset);
	font-variant-numeric: tabular-nums;
}
.collection__yoy {
	font-family: var(--font-mono);
	font-size: 0.85rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}
.collection__yoy--pos { color: var(--clr-sell); }
.collection__yoy--neg { color: var(--clr-repair); }
.collection__subhead { font-size: 0.95rem; font-weight: 600; color: var(--text-1); margin: 1.2rem 0 0.15rem; }
/* §71 Inc 10: Serviceheft coverage timeline (documented span vs gaps). */
.booklet-tl { margin: 0.4rem 0 0.9rem; }
.booklet-tl__track {
	position: relative;
	height: 10px;
	border-radius: 999px;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	overflow: hidden;
}
.booklet-tl__covered { position: absolute; top: 0; bottom: 0; background: var(--clr-service); opacity: 0.5; }
.booklet-tl__covered--complete { background: var(--clr-sell); opacity: 0.65; }
.booklet-tl__gap { position: absolute; top: 0; bottom: 0; background: var(--clr-repair); opacity: 0.8; }
.booklet-tl__legend { display: flex; gap: 1rem; margin-top: 0.45rem; font-size: 0.75rem; color: var(--text-3); }
.booklet-tl__key { display: inline-flex; align-items: center; gap: 0.35rem; }
.booklet-tl__key::before { content: ""; width: 10px; height: 10px; border-radius: 3px; }
.booklet-tl__key--covered::before { background: var(--clr-sell); }
.booklet-tl__key--gap::before { background: var(--clr-repair); }
@media (max-width: 900px) {
	.overview-grid { grid-template-columns: 1fr; }
}

/* §34 per-car cost narrative: a quiet instrument note above the cost DNA. */
.cost-insight {
	max-width: 460px;
	margin: 0 0 1.4rem;
	padding: 0.7rem 0.9rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-left: 2px solid var(--accent);
	border-radius: var(--radius-control);
}
.cost-insight__eyebrow { margin: 0 0 0.3rem; }
.cost-insight__text {
	margin: 0;
	color: var(--text-secondary);
	font-size: 14px;
	line-height: 1.5;
}
.cost-insight__updating {
	margin-left: 0.4rem;
	color: var(--text-muted);
	font-style: italic;
	font-size: 13px;
}

.cmp-card__foot {
	margin-top: auto;
	padding: 0.6rem 1rem 0.85rem;
	border-top: 1px solid var(--border-subtle);
	font-family: var(--font-mono);
	font-size: 10.5px;
	color: var(--text-4);
	font-variant-numeric: tabular-nums slashed-zero;
}

.comparison-sort-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 14px;
	gap: 12px;
	flex-wrap: wrap;
	view-transition-name: comparison-sort-bar;
}

/* ==========================================================================
   Car List Sort Bar
   ========================================================================== */

.car-list-sort-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 6px 0;
	margin-bottom: 12px;
	border-bottom: 1px solid var(--border-subtle);
	flex-wrap: wrap;
}

.car-list-sort-label {
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-3);
	white-space: nowrap;
}

.comparison-sort-controls {
	display: flex;
	align-items: center;
	gap: 6px;
}

.sort-select-label {
	color: var(--text-3);
	white-space: nowrap;
}

.sort-select {
	font-size: 11px;
	padding: 3px 8px;
	border-radius: 6px;
	border: 1px solid var(--border-subtle);
	background: var(--tint-xs);
	color: var(--text-2);
	cursor: pointer;
	outline: none;
}

.sort-select:focus {
	border-color: var(--clr-accent);
}

.sort-dir-btn {
	font-size: 12px;
	padding: 3px 9px;
	border-radius: 6px;
	border: 1px solid var(--border-subtle);
	background: var(--tint-xs);
	color: var(--text-2);
	cursor: pointer;
	transition: background 0.15s;
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}

.sort-dir-btn:hover {
	background: var(--tint-sm, var(--tint-xs));
}

/* ==========================================================================
   Comparison cost-DNA filter pills
   A labelled, colour-matched pill per cost segment; the row doubles as the
   legend for the stacked cost bar. On = filled with the segment colour; off =
   hollow + muted. Each pill carries a .cmp-seg--<key> class that sets --seg-clr.
   ========================================================================== */

.cmp-filters {
	display: flex;
	align-items: center;
	gap: 6px;
	flex-wrap: wrap;
	margin-bottom: 14px;
}

.cmp-filters__label {
	color: var(--text-3);
	margin-right: 2px;
	white-space: nowrap;
}

.cmp-filter {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 3px 10px 3px 8px;
	border-radius: 999px;
	border: 1px solid color-mix(in oklab, var(--seg-clr, var(--text-3)) 45%, transparent);
	background: color-mix(in oklab, var(--seg-clr, var(--text-3)) 12%, transparent);
	color: var(--text-1);
	font-size: 11px;
	font-weight: 600;
	line-height: 1.4;
	text-decoration: none;
	cursor: pointer;
	transition: opacity 0.15s, background 0.15s, border-color 0.15s;
}

.cmp-filter__dot {
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var(--seg-clr, var(--text-3));
	flex: none;
}

.cmp-filter:hover {
	border-color: var(--seg-clr, var(--text-3));
}

.cmp-filter--off {
	border-color: var(--border-subtle);
	background: transparent;
	color: var(--text-3);
	opacity: 0.7;
}

.cmp-filter--off .cmp-filter__lbl {
	text-decoration: line-through;
	text-decoration-thickness: 1px;
}

.cmp-filter--off .cmp-filter__dot {
	background: transparent;
	border: 1.5px solid var(--text-3);
}

.cmp-filter--off:hover {
	opacity: 1;
	border-color: var(--seg-clr, var(--text-3));
}

.comparison-chart-wrapper {
	margin-top: 20px;
}

/* Auswertungen › Kosten year selector (Alle Jahre + each ownership year). */
.auswertungen-yearbar {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin: 0 0 1.25rem;
}

/* The category donut's default layout is width:100% × 210px – fine in the cockpit's
   narrow rail, but on the full-width Auswertungen panel the canvas stretches wide
   and short, shrinking the pie into a lot of dead space. Bound the block, centre it,
   and give the chart a squarer box so the donut fills it; the legend wraps below on
   a phone. */
.auswertungen .cost-pie-container {
	max-width: 640px;
	margin-inline: auto;
	flex-wrap: wrap;
	justify-content: center;
}
.auswertungen .cost-pie-echarts {
	flex: 0 1 320px;
	width: 320px;
	height: 300px;
}
.auswertungen .cost-pie-legend {
	flex: 1 1 200px;
}

/* ==========================================================================
   Import Modal (native <dialog> element)
   ========================================================================== */

/* Import Modal - specific styles (uses form-modal base) */

.import-body {
	padding: 1.5rem 2rem 2rem;
}

.import-textarea {
	font-family: var(--font-mono);
	font-size: 0.875rem;
	resize: vertical;
	min-height: 160px;
}

/* Recognized-category chips shown above the paste field so the user knows what
   values the optional "type" column accepts (all four languages, §10 kinds). */
.import-categories {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4rem;
	margin-bottom: 1rem;
}

.import-categories__intro {
	color: var(--text-2);
	font-size: 0.8125rem;
	margin-right: 0.15rem;
}

/* "Keep the header row" tip below the paste field – the header presence is now
   auto-detected, so this nudge replaces the old skip-first-row checkbox. */
.import-header-hint {
	display: flex;
	align-items: baseline;
	gap: 0.4rem;
	margin-top: 0.75rem;
}

.import-header-hint .icon {
	flex-shrink: 0;
	color: var(--accent);
	transform: translateY(0.15em);
}

.import-checkbox-label {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	color: var(--text-2);
	cursor: pointer;
	transition: all var(--timing-base) var(--ease-out);
	padding: 0.25rem;
	border-radius: 4px;
}

.import-checkbox-label:hover {
	color: var(--text-1);
	background: var(--tint-sm);
	transform: translateX(2px);
}

.import-checkbox-label input[type="checkbox"] {
	cursor: pointer;
	transition: transform var(--timing-fast) var(--ease-out);
}

.import-checkbox-label:active input[type="checkbox"] {
	transform: scale(0.9);
}

.import-preview-section {
	display: none;
	opacity: 0;
	transform: translateY(-10px);
}

.import-preview-section.is-visible {
	display: block;
	animation: fadeIn var(--timing-slow) var(--ease-out) forwards;
}

.import-preview-table-container {
	overflow-x: auto;
	margin-bottom: 1.5rem;
}

.import-preview-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.875rem;
}

.import-preview-table thead {
	background: var(--surface-2);
}

.import-preview-table th {
	padding: 0.75rem;
	text-align: left;
	border-bottom: 2px solid var(--surface-3);
	color: var(--text-2);
	font-weight: 600;
}

.import-preview-table th.align-right {
	text-align: right;
}

.import-preview-table tbody tr {
	border-bottom: 1px solid var(--surface-2);
	transition: all var(--timing-base) var(--ease-out);
}

.import-preview-table tbody tr:hover {
	background: var(--tint-sm);
	transform: scale(1.002);
}

.import-preview-table td {
	padding: 0.75rem;
	color: var(--text-1);
	transition: color var(--timing-fast) var(--ease-out);
}

.import-preview-table tr:hover td {
	color: var(--text);
}

.import-preview-table td.align-right {
	text-align: right;
	font-family: var(--font-mono);
}

.import-preview-table .preview-more-rows {
	text-align: center;
	color: var(--text-2);
	font-style: italic;
}

.import-preview-summary {
	padding: 1rem;
	background: var(--surface-2);
	border-radius: 4px;
	margin-bottom: 1rem;
	color: var(--text-1);
}

.import-preview-summary strong {
	color: var(--text);
}

.import-preview-summary .error-count {
	color: var(--clr-repair);
}

.import-errors {
	display: none;
	padding: 1rem;
	background: light-dark(
		color-mix(in oklab, var(--clr-repair) 8%, white),
		color-mix(in oklab, var(--clr-repair) 12%, #1c1b16)
	);
	border-left: 3px solid var(--clr-repair);
	border-radius: 4px;
	margin-bottom: 1.5rem;
	color: var(--ink);
}

.import-errors.is-visible {
	display: block;
}

.import-errors ul {
	margin: 0.5rem 0 0 0;
	padding-left: 1.5rem;
}

.import-errors li {
	margin-bottom: 0.25rem;
}

.import-errors .more-errors {
	font-style: italic;
	color: var(--text-2);
}

/* ==========================================================================
   Car Form Modal
   ========================================================================== */

.form-modal {
	border: none;
	border-radius: 16px;
	padding: 0;
	max-width: 600px;
	width: calc(100vw - 2rem);
	/* The inner .form-modal-content owns the 90vh cap + scroll. The <dialog>
	   itself must NOT be a scroll container, or tall modals (the journal entry
	   form) show a SECOND scrollbar: Chrome's UA stylesheet gives every open
	   dialog `dialog:modal { overflow: auto; max-height: calc(100% - 2em - 6px) }`,
	   so dropping our explicit max-height wasn't enough – the UA overflow:auto
	   still made the dialog scroll independently of its content. Neutralise both:
	   overflow:visible stops the dialog from ever scrolling (or clipping the
	   content's box-shadow), max-height:none lets it size to its already-capped
	   child. */
	overflow: visible;
	max-height: none;
	background: transparent;
	opacity: 0;
	transform: scale(0.9) translateY(-20px);
	transition: opacity var(--timing-slow) var(--ease-spring),
	            transform var(--timing-slow) var(--ease-spring);
}

.form-modal[open] {
	opacity: 1;
	transform: scale(1) translateY(0);
	animation: popIn var(--timing-slow) var(--ease-spring);
}

/* Lock background scroll while a modal is open so the page's own scrollbar can't
   sit alongside the modal's – the reported "double scrollbar". html keeps its
   reserved scrollbar-gutter (set above), so hiding overflow causes no layout
   shift. Native <dialog> gains [open] on showModal(). */
html:has(.form-modal[open]) { overflow: hidden; }

/* §56 – styled dialog (window.__confirm/__prompt/__notify; replaces native
   confirm()/prompt()/alert()). The card surface/border/shadow come from
   .form-modal-content and the spring pop-in from .form-modal[open]; this layers
   on the "Editorial x Instrument" treatment -- a Playfair serif prompt over an
   Inter action row -- with generous, consistent padding and a flush, right-
   aligned footer (no hard separator) so the whole thing reads as one composed
   card. */
.confirm-dialog {
	max-width: 27rem;
	min-width: min(23rem, calc(100vw - 2rem));
}

/* Compound selector (both classes sit on the same element) so this beats the
   later `.form-modal-content { padding: 0 }` rule -- equal specificity would
   otherwise let the source-order-later zero win and flatten the padding. */
.form-modal-content.confirm-dialog__content {
	padding: 2rem;
}

/* An accent hairline eyebrow above the prompt -- a small editorial flourish
   that ties the card to the brand accent (the same green as the primary btn). */
.confirm-dialog__content::before {
	content: "";
	display: block;
	width: 2.25rem;
	height: 2px;
	margin: 0 0 1.15rem;
	border-radius: var(--radius-pill);
	background: var(--confirm-accent, var(--accent));
	opacity: 0.9;
}

/* §56 notice severity: recolour the eyebrow (and, for warn/error/success, swap
   the flourish for a tinted icon) from the callout tone tokens, so an error
   notice no longer reads like a neutral one. 'info' (the default, incl. every
   confirm/prompt) keeps today's accent hairline and shows no icon.
   The icon sits in a soft tone-tinted disc (the design system's .icon-chip
   pattern) so the severity reads as a coloured *area*, not a thin hairline
   stroke -- a bare stroke in the black-mixed light-mode callout tones is nearly
   indistinguishable at icon scale. Disc tint + solid-tone glyph per data-level. */
#ui-dialog .confirm-dialog__icon {
	display: none;
	place-items: center;
	width: 2.4rem;
	height: 2.4rem;
	margin: 0 0 1rem;
	border-radius: 50%;
	background: var(--confirm-accent, var(--accent)); /* solid tone disc -- reads as colour at a glance, unlike a faint tint or thin stroke */
}
/* #ui-dialog-scoped so the glyph's size/colour beat the base `.icon` rule
   (defined later in the sheet -- equal class specificity would let it win on
   source order and shrink the glyph to 1em / the inherited text colour). The
   glyph is --surface (the card/page colour): near-white on light, near-black on
   dark, so it always contrasts the solid tone disc in either theme. */
#ui-dialog .confirm-dialog__icon .icon {
	width: 1.25rem;
	height: 1.25rem;
	color: var(--surface);
}
#ui-dialog[data-level="warn"]    { --confirm-accent: var(--clr-service); }
#ui-dialog[data-level="error"]   { --confirm-accent: var(--critical); } /* --critical: the app's saturated alert red */
#ui-dialog[data-level="success"] { --confirm-accent: var(--clr-sell); }
/* Wash the whole card with a hint of the severity tone (and tint its border a
   touch more) so the colour extends past the badge. --modal-content-bg is a
   gradient, so the tone can't be color-mix'd into it directly; instead overlay a
   flat tone layer *above* the gradient via background-image (theme-correct via
   the light-dark tone tokens). 'info' is untouched. */
#ui-dialog:not([data-level="info"]) .confirm-dialog__content {
	background-image:
		linear-gradient(color-mix(in oklab, var(--confirm-accent) 8%, transparent), color-mix(in oklab, var(--confirm-accent) 8%, transparent)),
		var(--modal-content-bg);
	border-color: color-mix(in oklab, var(--confirm-accent) 24%, var(--modal-border));
}
/* When a severity icon is present it takes the eyebrow slot -- hide the hairline
   so the two accent marks don't stack. */
#ui-dialog:not([data-level="info"]) .confirm-dialog__content::before { display: none; }
#ui-dialog:not([data-level="info"]) .confirm-dialog__icon { display: grid; }

/* The prompt carries the editorial voice: high-contrast display serif at a
   headline scale, balanced wrapping so a short question keeps no orphan word. */
.confirm-dialog__msg {
	margin: 0 0 1.5rem;
	font-family: var(--font-serif);
	font-size: 1.3rem;
	font-weight: 500;
	line-height: 1.35;
	letter-spacing: -0.01em;
	color: var(--text);
	text-wrap: balance;
}

/* Prompt input: full-width well with room to breathe. CSS owns the spacing now
   (dialogs.ts only toggles display), so no inline margin fights this. */
.confirm-dialog__content .form-input {
	width: 100%;
	margin: 0 0 1.5rem;
}

/* §73 Inc: pick-one record-mode chooser rendered by __choose() into the shared
   dialog. Each option is a titled + described full-width button. */
.confirm-dialog__choices {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	width: 100%;
	margin: 0.25rem 0 1rem;
	text-align: left;
}
.record-choice {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	width: 100%;
	padding: 0.7rem 0.85rem;
	border: 1px solid var(--border);
	background: none;
	border-radius: var(--radius-control);
	text-align: left;
	font: inherit;
	color: var(--text);
	cursor: pointer;
}
.record-choice:hover,
.record-choice:focus-visible {
	background: var(--tint-sm);
	border-color: var(--accent);
}
.record-choice__title {
	font-weight: 600;
}
.record-choice__desc {
	font-size: 13px;
	line-height: 1.35;
	color: var(--text-2);
}

/* §73 named-locations manager in the Fahrten panel. */
.fahrten-places {
	margin-top: 1.5rem;
	padding-top: 1rem;
	border-top: 1px solid var(--border);
}
.places-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-bottom: 0.5rem;
}
.place-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}
.place-list__item {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.25rem 0;
}
.place-list__item .icon {
	width: 1.05em;
	height: 1.05em;
	color: var(--accent);
	flex: none;
}
.place-list__name {
	font-weight: 500;
}
.place-list__item .btn--icon {
	margin-left: auto;
}

/* §73 kept-track map: a tile-less, server-projected SVG polyline (no basemap). */
.trip-map-wrap {
	background: var(--surface-sunken, color-mix(in oklab, var(--surface) 94%, var(--ink)));
	border: 1px solid var(--border);
	border-radius: var(--radius-md, 8px);
	padding: 0.5rem;
}
.trip-map {
	display: block;
	width: 100%;
	height: auto;
}
.trip-map__line {
	stroke: var(--accent);
	stroke-width: 2.5;
	stroke-linejoin: round;
	stroke-linecap: round;
	vector-effect: non-scaling-stroke;
}
.trip-map__pt--start {
	fill: var(--surface);
	stroke: var(--accent);
	stroke-width: 2.5;
}
.trip-map__pt--end {
	fill: var(--accent);
}
.trip-map-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 1.75rem;
	margin-top: 0.85rem;
}
.trip-map-meta div {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
}
.trip-map-meta dt {
	font-size: 0.75rem;
	color: var(--ink-subtle, var(--muted));
	text-transform: uppercase;
	letter-spacing: 0.03em;
}
.trip-map-meta dd {
	font-weight: 500;
}

/* §73 Inc 5 trip billing */
.trip-billing {
	margin-top: 0.75rem;
	padding-top: 0.85rem;
	border-top: 1px solid var(--border);
}
.form-check {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	cursor: pointer;
	font-weight: 500;
}
.form-check input {
	width: 1.05rem;
	height: 1.05rem;
	accent-color: var(--accent);
}
.trip-bill-tag {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	margin-top: 0.25rem;
	font-size: 0.8rem;
	color: var(--ink-subtle, var(--muted));
	/* Stay one line – the trip table h-scrolls on mobile, so the client name must
	   not char-wrap inside the narrow route cell. */
	white-space: nowrap;
}
.trip-bill-tag .place-list__name,
.trip-bill-tag > span {
	white-space: nowrap;
}
.trip-bill-tag .icon {
	width: 0.85em;
	height: 0.85em;
}
.trip-bill-tag__done {
	color: var(--accent);
	font-weight: 500;
}

/* Footer flush with the card: drop .form-actions' separator + top inset so the
   dialog reads as one block; keep the buttons right-aligned with a snug gap. */
.confirm-dialog .form-actions {
	padding-top: 0;
	margin-top: 0;
	border-top: 0;
	gap: 0.6rem;
}

.form-modal::backdrop {
	background: rgba(0, 0, 0, 0);
	transition: background var(--timing-slow) var(--ease-out);
}

.form-modal[open]::backdrop {
	background: var(--modal-scrim);
	backdrop-filter: blur(4px);
	animation: fadeIn var(--timing-slow) var(--ease-out);
}

.form-modal--wide {
	max-width: 800px;
}

.form-modal-content {
	background: var(--modal-content-bg);
	border: 1px solid var(--modal-border);
	border-radius: 16px;
	padding: 0;
	max-height: 90vh;
	overflow-y: auto;
	box-shadow: var(--shadow-modal);
	/* Animate height changes when step content swaps */
	interpolate-size: allow-keywords;
	transition: height 0.38s cubic-bezier(0.4, 0, 0.2, 1);
	height: auto;
}

.form-body {
	padding: 1.5rem 2rem 2rem;
}

.form-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 1.5rem 2rem;
	border-bottom: 1px solid var(--border);
	background: var(--tint-xs);
}

.form-title {
	margin: 0;
	font-size: 1.5rem;
	font-weight: 600;
	color: var(--text);
	letter-spacing: -0.02em;
}
#car-form,
#charge-form {
	padding: 1.5rem 2rem 2rem;
}

.form-section {
	margin-bottom: 1.5rem;
}

.settings-profile-hint {
	font-size: 0.8rem;
	color: var(--text-muted);
	background: var(--accent-soft);
	border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
	border-radius: 6px;
	padding: 0.5rem 0.875rem;
	margin-bottom: 1rem;
}

.form-section:last-of-type {
	margin-bottom: 0;
}

.form-section-title {
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--text-3);
	margin-bottom: 0.75rem;
	padding-bottom: 0.5rem;
	border-bottom: 1px solid var(--border-subtle);
}

/* Tabbed car form (§5 form-layout): underline tabs mirroring .car-tab, panels
   toggled by the $form_tab Datastar signal. All fields stay in one <form>. */
.form-tabs {
	display: flex;
	gap: 0.25rem;
	flex-wrap: wrap;
	margin-bottom: 1.5rem;
	border-bottom: 1px solid var(--border-subtle);
}

.form-tab {
	appearance: none;
	background: none;
	border: none;
	border-bottom: 2px solid transparent;
	margin-bottom: -1px;
	padding: 0.55rem 0.9rem;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.1px;
	color: var(--text-4);
	white-space: nowrap;
	cursor: pointer;
	transition: color var(--timing-fast) var(--ease-out), border-color var(--timing-fast) var(--ease-out);
}

.form-tab:hover {
	color: var(--text-2);
}

.form-tab--active {
	color: var(--ink);
	border-bottom-color: var(--accent);
}

@media (max-width: 640px) {
	.form-tabs {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
	}
}

/* §35 scanned-form intro: the source-image preview + the hint/notices summary,
   inset to match the form body's horizontal padding (the block sits between the
   header and the padding-0 modal content, so it must carry its own inset). */
.scan-intro {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem 1.5rem;
	align-items: flex-start;
	padding: 1.5rem 2rem 0;
}

.scan-intro-text {
	flex: 1 1 260px;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

/* §35 source-image preview – the scanned Fahrzeugausweis the model saw, shown
   next to the prefilled form so the user can verify field-by-field. */
.scan-source {
	flex: 1 1 200px;
	max-width: 260px;
	margin: 0;
}

.scan-source-img {
	width: 100%;
	height: auto;
	max-height: 40vh;
	object-fit: contain;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface-sunken);
	display: block;
}

.scan-source-caption {
	margin-top: 0.4rem;
	font-size: 0.72rem;
	text-align: center;
	color: var(--text-3);
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

.scan-hint {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.75rem;
	margin: 0;
}

.scan-hint .form-hint {
	margin: 0;
}

.scan-discard-confirm {
	align-items: center;
	gap: 0.75rem;
}

.scan-discard-confirm .form-hint {
	margin-right: auto;
}

/* §35 Phase 2: validator warnings + smart-default hints on the scanned form. */
.scan-notices {
	list-style: none;
	margin: 0;
	padding: 0.65rem 0.85rem;
	border: 1px solid color-mix(in srgb, var(--clr-service) 45%, transparent);
	border-radius: 8px;
	background: color-mix(in srgb, var(--clr-service) 10%, transparent);
	font-size: 0.85rem;
	color: var(--text-2);
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}

.scan-notices li {
	padding-left: 1.1rem;
	position: relative;
}

.scan-notices li::before {
	content: "⚠";
	position: absolute;
	left: 0;
	color: var(--clr-service);
}

/* §35 per-field highlighting: an input prefilled from the Fahrzeugausweis scan
   (accent). Warned fields override this with .form-input--warn (see below). */
.form-input--scan {
	border-color: color-mix(in oklab, var(--clr-accent) 55%, transparent);
	background: color-mix(in oklab, var(--clr-accent) 6%, transparent);
}

.form-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 1rem;
}

.form-field {
	display: flex;
	flex-direction: column;
	gap: 0.375rem;
}

.form-field--full {
	grid-column: 1 / -1;
}

.form-label {
	font-size: 0.8rem;
	font-weight: 500;
	color: var(--text-2);
	display: flex;
	align-items: center;
	gap: 0.25rem;
}

.form-label-required {
	color: var(--clr-repair);
}

.form-label-hint {
	font-weight: 400;
	color: var(--text-2);
	font-size: 0.8em;
}

.form-field--checkbox {
	display: flex;
	align-items: center;
}

.form-label--checkbox {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	cursor: pointer;
	font-weight: 500;
	color: var(--text-2);
}

.form-input {
	padding: 0.625rem 0.875rem;
	font-size: 0.9rem;
	border: 1px solid var(--border);
	border-radius: 8px;
	background: var(--scrim-md);
	color: var(--text);
	transition: all var(--timing-base) var(--ease-out);
	font-family: inherit;
}

.form-input::placeholder {
	color: var(--text-4);
}

.form-input:hover {
	border-color: var(--tint-lg);
	background: var(--scrim-lg);
}

.form-input:focus {
	outline: none;
	border-color: var(--accent);
	background: var(--scrim-lg);
	box-shadow: 0 0 0 3px var(--accent-glow),
	            0 0 20px var(--accent-glow);
}

.form-input[type="number"] {
	font-family: var(--font-mono);
}

select.form-input {
	cursor: pointer;
	appearance: none;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%239ca3af' d='M2.5 4.5L6 8L9.5 4.5'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.75rem center;
	padding-right: 2.5rem;
}

.form-hint {
	font-size: 0.75rem;
	color: var(--text-4);
	margin-top: 0.25rem;
}

.form-hint__icon { color: var(--accent); }

.form-actions {
	display: flex;
	justify-content: flex-end;
	gap: 0.75rem;
	padding-top: 1.5rem;
	margin-top: 1.5rem;
	border-top: 1px solid var(--border);
}
/* Responsive */
@media (max-width: 480px) {
	.form-modal-content {
		padding: 0;
	}
	
	.form-header {
		padding: 1rem 1.25rem;
	}
	
	#car-form,
	#charge-form {
		padding: 1rem 1.25rem 1.5rem;
	}
	
	.form-grid {
		grid-template-columns: 1fr;
	}
	
	.form-actions {
		flex-direction: column-reverse;
	}
	
	.form-actions .btn,
	.modal__footer .btn {
		width: 100%;
		justify-content: center;
	}
}/* Inline entry editing */
.entry-row {
	position: relative;
	transition: all var(--timing-base) var(--ease-out);
}

.entry-row:hover {
	background: var(--tint-sm) !important;
}

.th-actions {
	width: 60px;
}

.entry-actions {
	text-align: center;
	white-space: nowrap;
}

.entry-actions--view {
	opacity: 0;
	transition: opacity var(--timing-base) var(--ease-out);
}

.entry-row:hover .entry-actions--view {
	opacity: 1;
}
/* §11 phase-3: synthetic gap-segment row – muted/dashed, never interactive
   (no edit button, so no hover affordance). */
.entry-row--gap {
	font-style: italic;
}

.entry-row--gap:hover {
	background: transparent !important;
}

.entry-row--gap td {
	color: var(--text-4);
	border-bottom-style: dashed;
}

/* §99 #3: a journal row the analysis does not count – a §85 prior-owner import,
   an entry dated outside the ownership window, a duplicate Kauf. Still fully
   editable (that is often how you fix it), so this only recedes: it must read as
   "shown but not counted", never as disabled. The reason rides along as a chip
   plus the row's title. */
.entry-row--uncounted td {
	color: var(--text-3);
}
.entry-row--uncounted .entry-amount {
	opacity: 0.6;
}
.entry-excl {
	display: inline-block;
	margin-left: 0.4rem;
	padding: 1px 7px;
	border-radius: var(--radius-pill);
	border: 1px dashed var(--border);
	background: transparent;
	font-family: var(--font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.02em;
	color: var(--text-3);
	white-space: nowrap;
	vertical-align: middle;
}

.entry-amount--gap {
	font-family: var(--font-mono);
}
.entry-actions {
	white-space: nowrap;
	text-align: center;
}
/* ==========================================================================
   Cost Pie Chart Component
   ========================================================================== */

.cost-pie-container {
	display: flex;
	gap: 1.5rem;
	align-items: center;
	padding: 1rem;
	background: var(--tint-xs);
	border-radius: 8px;
	margin: 1rem 0;
}

.cost-pie-chart {
	width: 120px;
	height: 120px;
	flex-shrink: 0;
}

.cost-pie-chart path {
	transition: opacity 0.2s;
	cursor: pointer;
}

.cost-pie-chart path:hover {
	opacity: 0.8;
}

/* §13 two-ring comparison donut rendered via <tco-chart> (ECharts), so it shares
   the bar chart's styled hover tooltips. Sized squarer than the bar chart. */
.cost-pie-echarts { display: block; width: 100%; height: 210px; }

.cost-pie-legend {
	flex: 1;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
	gap: 0.5rem;
	font-size: 0.75rem;
}

.legend-item {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

.legend-color {
	width: 12px;
	height: 12px;
	border-radius: 2px;
	flex-shrink: 0;
}

.legend-label {
	color: var(--text-2);
	flex: 1;
}

.legend-value {
	color: var(--text-1);
	font-family: var(--font-mono);
	font-weight: 600;
}

/* ==========================================================================
   Empty State (first-run welcome, §35 Fahrzeugausweis dropzone)
   ========================================================================== */

.empty-state {
	max-width: 640px;
	margin: clamp(2rem, 6vw, 4.5rem) auto;
	padding: clamp(1.75rem, 4vw, 3rem);
	text-align: center;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	box-shadow: var(--shadow-lg);
	animation: fadeInScale var(--timing-slower) var(--ease-out);
}

.empty-state-icon {
	display: inline-grid;
	place-items: center;
	width: 4.25rem;
	height: 4.25rem;
	margin: 0 auto 1rem;
	border-radius: 50%;
	color: var(--accent);
	background: var(--accent-soft);
}
.empty-state-icon .icon { font-size: 1.9rem; stroke-width: 1.6; }

.empty-state .eyebrow { margin-bottom: 0.6rem; }

.empty-state-title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 560;
	font-size: clamp(1.6rem, 4vw, 2.15rem);
	letter-spacing: -0.015em;
	line-height: 1.15;
	color: var(--ink);
	margin-bottom: 0.85rem;
}

.empty-state-description {
	font-size: 1rem;
	color: var(--text-2);
	line-height: 1.65;
	max-width: 30rem;
	margin: 0 auto 2rem;
}

.empty-state-actions {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.1rem;
}

.empty-state-divider {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	width: 100%;
	max-width: 20rem;
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--text-4);
}
.empty-state-divider::before, .empty-state-divider::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--border-subtle);
}

.empty-state-hint {
	font-size: 0.85rem;
	color: var(--text-4);
	font-style: italic;
	margin: 0;
}

/* ── §68 free first-ausweis "welcome scan" badge (above the dropzone) ───── */
.empty-state-free {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	margin: 0;
	padding: 0.32rem 0.72rem;
	border-radius: 999px;
	background: var(--accent-soft);
	color: var(--accent);
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.03em;
	line-height: 1;
}
.empty-state-free .icon { stroke-width: 2; }

/* ── §35 Fahrzeugausweis dropzone (the welcome screen's primary CTA) ────── */
.empty-dropzone {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.4rem;
	width: 100%;
	padding: clamp(1.75rem, 4vw, 2.5rem) 1.5rem;
	border: 1.5px dashed var(--border);
	border-radius: var(--radius-card);
	color: var(--text-3);
	cursor: pointer;
	transition: color var(--timing-base) var(--ease-out), border-color var(--timing-base) var(--ease-out), background var(--timing-base) var(--ease-out), transform var(--timing-base) var(--ease-out);
}
.empty-dropzone:hover, .empty-dropzone.is-dragging {
	color: var(--accent);
	border-color: var(--accent);
	background: var(--tint-sm);
}
.empty-dropzone.is-dragging { transform: scale(1.015); }
/* Children never intercept drag events – dragover/drop always hit .empty-dropzone. */
.empty-dropzone * { pointer-events: none; }
.empty-dropzone__prompt { display: flex; flex-direction: column; align-items: center; gap: 0.4rem; }
.empty-dropzone__title { font-family: var(--font-serif); font-size: 1.1rem; color: var(--text); }
.empty-dropzone__hint { font-size: 0.85rem; }
.empty-dropzone__types { font-size: 0.72rem; color: var(--text-4); letter-spacing: 0.02em; margin-top: 0.15rem; }

/* Add-car modal: the same §35 dropzone, compacted to sit atop the manual form.
   Like .scan-intro, this block lives in the padding-0 modal content between the
   header and #car-form, so it carries its own inset to match the form body's
   horizontal padding (2rem); #car-form's own padding-top handles the gap below. */
.car-form-scan { padding: 1.5rem 2rem 0; }
.car-form-dropzone { padding: 1.1rem 1.25rem; }
.car-form-scan__divider {
	text-align: center;
	font-size: 0.74rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-4);
	margin-top: 0.55rem;
}

/* ── §104 identifier lookup – "…or type the TG-Nr / VIN" beside the scan dropzone ── */
.ausweis-lookup {
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
	width: 100%;
	max-width: 22rem;
}
.ausweis-lookup__row { display: flex; gap: 0.5rem; align-items: stretch; }
.ausweis-lookup__input {
	flex: 1;
	min-width: 0;
	font-family: var(--font-mono);
	text-transform: uppercase;
	letter-spacing: 0.03em;
}
.ausweis-lookup__input::placeholder {
	font-family: var(--font-sans);
	text-transform: none;
	letter-spacing: normal;
}
.ausweis-lookup__btn { flex-shrink: 0; white-space: nowrap; }
.ausweis-lookup__btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.ausweis-lookup__msg {
	margin: 0;
	font-size: 0.8rem;
	color: var(--danger, #c0392b);
}
/* Empty-state: centre it among the stacked empty-state actions. */
.empty-lookup { align-items: center; }
/* Add-car modal: the block already sits inside .car-form-scan's 2rem inset. */
.car-form-lookup { max-width: none; margin-top: 0.55rem; }
/* Mobile capture sheet (§63): full width, matching the action rows' inset + touch target. */
.capture-sheet__lookup { max-width: none; padding: 0.35rem 0.75rem 0.15rem; }
.capture-sheet__lookup .ausweis-lookup__btn { min-height: 44px; }

/* ── §35 scanner overlay: while the dropped Fahrzeugausweis is being OCR'd ──
   A skeleton card of the document with a sweeping "scanner beam", a live
   status line, and an indeterminate progress bar. Driven by $ausweisScan
   (set on drop/pick, released by the LiveSSE loop on done/error). */
.empty-dropzone.is-scanning {
	border-style: solid;
	border-color: color-mix(in oklab, var(--accent) 55%, transparent);
	background: var(--tint-xs);
	cursor: default;
	pointer-events: none; /* no second file while a scan is in flight */
	transform: none;
	min-height: 12rem;
	justify-content: center;
}

.ausweis-scan {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	width: 100%;
	animation: fadeIn var(--timing-slow) var(--ease-out);
}

.ausweis-scan__doc {
	position: relative;
	width: 9.5rem;
	height: 6rem;
	padding: 0.6rem;
	display: flex;
	flex-direction: column;
	gap: 0.42rem;
	border-radius: 7px;
	overflow: hidden;
	background: linear-gradient(180deg, color-mix(in oklab, var(--accent) 6%, var(--surface-raised)), var(--surface-raised));
	border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
	box-shadow: 0 6px 18px color-mix(in oklab, var(--accent) 14%, transparent);
}
.ausweis-scan__chip {
	width: 1.5rem;
	height: 1.1rem;
	border-radius: 3px;
	background: color-mix(in oklab, var(--accent) 26%, transparent);
}
.ausweis-scan__line {
	height: 0.42rem;
	border-radius: 3px;
	background: linear-gradient(90deg, var(--tint-md), var(--tint-sm), var(--tint-md));
	background-size: 200% 100%;
	animation: shimmer 1.8s linear infinite;
}
.ausweis-scan__line--short { width: 62%; }

/* The beam: a soft accent band wiping top→bottom, clipped to the doc. */
.ausweis-scan__beam {
	position: absolute;
	left: -10%;
	right: -10%;
	top: 0;
	height: 40%;
	transform: translateY(-120%);
	background: linear-gradient(180deg,
		transparent,
		color-mix(in oklab, var(--accent) 30%, transparent) 42%,
		color-mix(in oklab, var(--accent) 65%, transparent) 50%,
		color-mix(in oklab, var(--accent) 30%, transparent) 58%,
		transparent);
	animation: ausweis-beam 1.9s var(--ease-in-out) infinite;
}
@keyframes ausweis-beam {
	0%   { transform: translateY(-120%); opacity: 0; }
	14%  { opacity: 1; }
	86%  { opacity: 1; }
	100% { transform: translateY(280%); opacity: 0; }
}

.ausweis-scan__copy { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; text-align: center; }
.ausweis-scan__title {
	display: inline-flex;
	align-items: baseline;
	font-family: var(--font-serif);
	font-size: 1.05rem;
	color: var(--accent);
}
.ausweis-scan__hint { font-size: 0.82rem; color: var(--text-3); }

.ausweis-scan__dots { display: inline-flex; gap: 0.15rem; margin-left: 0.25rem; }
.ausweis-scan__dots i {
	width: 0.24rem;
	height: 0.24rem;
	border-radius: 50%;
	background: currentColor;
	opacity: 0.25;
	animation: ausweis-dot 1.4s ease-in-out infinite;
}
.ausweis-scan__dots i:nth-child(2) { animation-delay: 0.18s; }
.ausweis-scan__dots i:nth-child(3) { animation-delay: 0.36s; }
@keyframes ausweis-dot {
	0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
	40%           { opacity: 1;    transform: translateY(-0.14rem); }
}

.ausweis-scan__bar {
	position: relative;
	width: min(16rem, 82%);
	height: 3px;
	border-radius: 2px;
	overflow: hidden;
	background: var(--tint-sm);
}
.ausweis-scan__bar > span {
	position: absolute;
	top: 0;
	bottom: 0;
	width: 40%;
	border-radius: 2px;
	background: linear-gradient(90deg, transparent, var(--accent), transparent);
	animation: ausweis-indeterminate 1.4s var(--ease-in-out) infinite;
}
@keyframes ausweis-indeterminate {
	0%   { left: -42%; }
	100% { left: 100%; }
}

@media (prefers-reduced-motion: reduce) {
	.ausweis-scan__beam, .ausweis-scan__line, .ausweis-scan__dots i, .ausweis-scan__bar > span { animation: none; }
	.ausweis-scan__beam { opacity: 0.45; transform: translateY(75%); }
	.ausweis-scan__bar > span { left: 0; width: 100%; opacity: 0.6; }
	.ausweis-scan__dots i { opacity: 0.6; }
}

/* ==========================================================================
   App Footer
   ========================================================================== */

.app-footer {
	margin-top: 4rem;
	/* A quiet "plinth" band that closes the page. min-height + flex centering
	   keep the content vertically centred within the band instead of flush
	   against the very bottom edge on short pages (where #carlist's flex-grow pins
	   the footer to the viewport bottom). padding-block gives symmetric room. */
	min-height: 5rem;
	padding-block: 1.6rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-top: 1px solid var(--border-subtle);
	background: var(--surface-sunken);
}

.footer-content {
	max-width: 980px;
	margin: 0 auto;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.15rem 0;
	text-align: center;
	font-size: 0.85rem;
	line-height: 1.6;
	color: var(--text-3);
}

.footer-version {
	color: var(--text-3);
	font-weight: 500;
}

/* §63 the version rendered as a quiet mono "build stamp" pill – leans into the
   Instrument half of the design language. */
.footer-badge {
	margin-left: 0.4rem;
	font-family: var(--font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.02em;
	line-height: 1;
	color: var(--text-4);
	background: var(--tint-xs);
	border: 1px solid var(--border-subtle);
	padding: 0.14rem 0.45rem;
	border-radius: var(--radius-pill);
	vertical-align: middle;
}

.footer-divider {
	margin: 0 0.7rem;
	color: var(--text-5);
	opacity: 0.7;
}

.footer-link {
	color: var(--text-3);
	text-decoration: none;
	transition: all var(--timing-base) var(--ease-out);
	position: relative;
	display: inline-block;
}

.footer-link::after {
	content: '';
	position: absolute;
	bottom: -2px;
	left: 0;
	width: 0;
	height: 1px;
	background: var(--accent);
	transition: width var(--timing-base) var(--ease-out);
}

.footer-link:hover {
	color: var(--accent);
	transform: translateY(-1px);
}

.footer-link:hover::after {
	width: 100%;
}

/* §52 self-hosted update check: the badge replaces .footer-link's <a> with a
   <button> (it triggers the release-notes modal, not a navigation), so it
   needs its own reset -- plain browser button chrome would otherwise show. */
.footer-link--update {
	background: none;
	border: none;
	padding: 0;
	font: inherit;
	cursor: pointer;
	color: var(--accent);
	font-weight: 600;
}

.footer-link--update:hover {
	color: var(--accent);
}

.update-modal-entry {
	padding: 0.85rem 0;
	border-bottom: 1px solid var(--border-subtle);
}

.update-modal-entry:last-child {
	border-bottom: 0;
}

.update-modal-entry__head {
	display: flex;
	align-items: baseline;
	gap: 0.6rem;
}

.update-modal-entry__version {
	font-family: var(--font-mono);
	font-weight: 600;
	color: var(--accent);
}

.update-modal-entry__date {
	font-size: 0.8rem;
	color: var(--text-4);
}

.update-modal-entry__items {
	margin: 0.4rem 0 0;
	padding-left: 1.25rem;
	color: var(--text-3);
	font-size: 0.9rem;
}

.update-modal-entry__items li {
	margin-bottom: 0.2rem;
}

/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}
}

/* ==========================================================================
   Import Column Mapping
   ========================================================================== */

.import-mapping-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.8rem;
	margin-bottom: 1rem;
}

.import-mapping-table th,
.import-mapping-table td {
	padding: 0.5rem;
	border: 1px solid var(--border);
	text-align: left;
}

.import-mapping-table th {
	background: var(--bg-2);
	font-weight: 600;
}

.import-mapping-table tr:nth-child(even) {
	background: var(--bg-2);
}

.mapping-select {
	width: 100%;
	padding: 0.25rem 0.5rem;
	font-size: 0.75rem;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: 4px;
	color: var(--text);
}

.mapping-select:focus {
	outline: none;
	border-color: var(--accent);
}

.mapping-highlight {
	background: var(--accent-glow) !important;
	border-color: var(--accent) !important;
}

/* ==========================================================================
   TCO Wizard Modal
   ========================================================================== */

.wiz-subtitle {
	margin: 0.2rem 0 0;
	font-size: 0.8rem;
	color: var(--text-3);
}

/* §104 Inc 6 – make/model autocomplete dropdowns */
.wiz-autocomplete {
	position: relative;
}

.wiz-suggest {
	position: absolute;
	z-index: 30;
	top: 100%;
	left: 0;
	right: 0;
	margin-top: 0.25rem;
	max-height: 15rem;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	padding: 0.25rem;
	background: var(--surface-1);
	border: 1px solid var(--border);
	border-radius: var(--radius-control);
	box-shadow: var(--shadow-lg);
}

.wiz-suggest__row {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	width: 100%;
	text-align: left;
	padding: 0.45rem 0.6rem;
	border: 0;
	border-radius: var(--radius-control);
	background: transparent;
	color: var(--text-1);
	cursor: pointer;
	transition: background var(--timing-fast) var(--ease-out);
}

.wiz-suggest__row:hover,
.wiz-suggest__row:focus-visible {
	background: var(--surface-3);
	outline: none;
}

.wiz-suggest__make,
.wiz-suggest__model {
	font-weight: 600;
	font-size: 0.9rem;
}

.wiz-suggest__title {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.5rem;
}

.wiz-suggest__years {
	font-size: 0.74rem;
	color: var(--text-3);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.wiz-suggest__spec {
	font-size: 0.78rem;
	color: var(--text-3);
}

.wiz-suggest__empty {
	padding: 0.55rem 0.6rem;
	font-size: 0.82rem;
	color: var(--text-4);
}

/* Progress pills */
.wiz-progress {
	display: flex;
	align-items: center;
	gap: 0;
	padding: 1rem 2rem;
	border-bottom: 1px solid var(--border-subtle);
	background: var(--scrim-md);
}

.wiz-step-pill {
	padding: 0.3rem 0.9rem;
	border-radius: 20px;
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	background: var(--tint-sm);
	color: var(--text-4);
	border: 1px solid var(--border-subtle);
	transition: all var(--timing-base) var(--ease-out);
	white-space: nowrap;
}

.wiz-step-pill--active {
	background: var(--clr-buy-bg);
	color: var(--clr-highlight);
	border-color: var(--clr-buy-border);
}

.wiz-step-connector {
	flex: 1;
	height: 1px;
	background: var(--border-subtle);
	min-width: 0.5rem;
}

/* Body */
.wiz-body {
	padding: 1.5rem 2rem 0.5rem;
}

/* Finance type selector */
.wiz-fin-selector {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 0.75rem;
	margin-bottom: 0.5rem;
}

.wiz-fin-option {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.3rem;
	padding: 1rem 0.75rem;
	border-radius: 12px;
	border: 1px solid var(--border);
	background: var(--tint-xs);
	cursor: pointer;
	transition: all var(--timing-base) var(--ease-out);
	text-align: center;
}

.wiz-fin-option input[type="radio"] {
	display: none;
}

.wiz-fin-option:hover {
	border-color: color-mix(in oklab, var(--accent) 30%, transparent);
	background: color-mix(in oklab, var(--accent) 5%, transparent);
}

.wiz-fin-option--active {
	border-color: color-mix(in oklab, var(--accent) 50%, transparent) !important;
	background: color-mix(in oklab, var(--accent) 10%, transparent) !important;
	box-shadow: 0 0 16px color-mix(in oklab, var(--accent) 15%, transparent);
}

.wiz-fin-icon {
	font-size: 1.75rem;
	line-height: 1;
}

.wiz-fin-label {
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--text);
}

.wiz-fin-desc {
	font-size: 0.7rem;
	color: var(--text-3);
	line-height: 1.4;
}

/* Tips & Callouts */
.wiz-tip {
	margin-top: 0.75rem;
	padding: 0.6rem 0.9rem;
	border-radius: 8px;
	background: var(--tint-xs);
	border-left: 3px solid color-mix(in oklab, var(--accent) 40%, transparent);
	font-size: 0.775rem;
	color: var(--text-3);
	line-height: 1.5;
}

/* ── Residual value estimate hint ───────────────────────────────────────── */
.wiz-estimate-hint {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 0.3rem;
	flex-wrap: wrap;
}

.wiz-estimate-label {
	font-size: 0.73rem;
	color: var(--text-3);
	white-space: nowrap;
}
.wiz-callout {
	margin-top: 1rem;
	padding: 0.9rem 1rem;
	border-radius: 10px;
	font-size: 0.8rem;
	line-height: 1.6;
}

.wiz-callout--info {
	background: color-mix(in oklab, var(--accent) 7%, transparent);
	border: 1px solid color-mix(in oklab, var(--accent) 20%, transparent);
}

.wiz-callout-title {
	font-weight: 700;
	margin-bottom: 0.4rem;
	color: var(--text);
}

.wiz-callout-body {
	color: var(--text-2);
}

.wiz-callout-body ul {
	margin: 0.4rem 0 0 1rem;
	padding: 0;
}

.wiz-callout-body li {
	margin-bottom: 0.2rem;
}

/* Result header */
.wiz-result-header {
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: 1rem 0 1.25rem;
	border-bottom: 1px solid var(--border-subtle);
	margin-bottom: 1.25rem;
}

.wiz-result-car-name {
	font-size: 1.35rem;
	font-weight: 700;
	color: var(--text);
	letter-spacing: -0.02em;
}

.wiz-result-fin-badge {
	padding: 0.25rem 0.75rem;
	border-radius: 20px;
	background: var(--clr-buy-bg);
	border: 1px solid var(--clr-buy-border);
	color: var(--clr-highlight);
	font-size: 0.75rem;
	font-weight: 600;
}

/* Result table */
.wiz-result-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.875rem;
}

.wiz-result-table tbody tr {
	border-bottom: 1px solid var(--border-subtle);
}

.wiz-result-table tbody td {
	padding: 0.6rem 0.5rem;
	color: var(--text-2);
}

.wiz-result-table tfoot tr {
	border-top: 1px solid var(--border);
}

.wiz-result-table tfoot td {
	padding: 0.65rem 0.5rem;
	font-weight: 600;
	color: var(--text);
}

.wiz-result-total-row--secondary td {
	color: var(--text-2);
	font-size: 0.85rem;
}

.wiz-result-total-row--highlight td {
	color: var(--clr-highlight);
	font-size: 1rem;
	font-weight: 700;
}

.wiz-result-amount {
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* ── Inline row edit controls ─────────────────────────────────────────────── */
.wiz-edit-cell {
	width: 1.75rem;
	text-align: center;
	padding: 0 0.15rem;
}

.wiz-edit-btn {
	background: none;
	border: none;
	cursor: pointer;
	color: var(--text-4);
	font-size: 0.75rem;
	padding: 0.2rem 0.25rem;
	border-radius: 4px;
	line-height: 1;
	opacity: 0.5;
	transition: opacity 0.15s, color 0.15s;
}

.wiz-result-table tbody tr:hover .wiz-edit-btn {
	opacity: 1;
}

.wiz-edit-btn:hover,
.wiz-edit-btn:focus-visible {
	color: var(--clr-highlight);
	opacity: 1;
	outline: none;
}

.wiz-amount-input {
	width: 5.5rem;
	text-align: right;
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	padding: 0.15rem 0.35rem;
	border: 1px solid var(--clr-highlight);
	border-radius: 4px;
	background: var(--bg-2);
	color: var(--text);
}

.wiz-result-extra-row td {
	color: var(--text-3);
	font-style: italic;
}

/* Step panel entry animation – @starting-style fires on display:none→block */
/* No allow-discrete = exit is instant, entry fades in. No double-animation. */
.wiz-step {
	opacity: 1;
	transform: translateY(0);
	transition: opacity 0.25s ease, transform 0.25s ease;
}

@starting-style {
	.wiz-step {
		opacity: 0;
		transform: translateY(10px);
	}
}

/* Comparison bars */
.wiz-comparison-list {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
}

.wiz-comparison-row {
	display: grid;
	grid-template-columns: 200px 1fr 80px;
	align-items: center;
	gap: 0.75rem;
	padding: 0.5rem 0;
	border-bottom: 1px solid var(--border-subtle);
}

.wiz-comparison-row--new {
	background: color-mix(in oklab, var(--accent) 5%, transparent);
	border-radius: 6px;
	padding: 0.5rem 0.5rem;
	border: 1px solid color-mix(in oklab, var(--accent) 15%, transparent);
	border-bottom-color: color-mix(in oklab, var(--accent) 15%, transparent);
	margin-bottom: 0.3rem;
}

.wiz-compare-name {
	font-size: 0.8rem;
	color: var(--text-2);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.wiz-comparison-row--new .wiz-compare-name {
	color: var(--clr-highlight);
	font-weight: 600;
}

.wiz-compare-bar-wrap {
	height: 12px;
	background: var(--tint-sm);
	border-radius: 6px;
	overflow: hidden;
}

@keyframes growBar {
	from { transform: scaleX(0); }
	to   { transform: scaleX(1); }
}

@keyframes fadeInRow {
	from { opacity: 0; transform: translateX(-6px); }
	to   { opacity: 1; transform: translateX(0); }
}

.wiz-compare-bar {
	height: 100%;
	border-radius: 6px;
	background: linear-gradient(90deg, color-mix(in oklab, var(--accent) 60%, transparent), color-mix(in oklab, var(--accent) 90%, transparent));
	width: var(--w, 0%);
	transform-origin: left center;
	animation: growBar 0.5s cubic-bezier(0.4, 0, 0.2, 1) both;
	animation-delay: var(--wiz-bar-delay, 0s);
}

.wiz-compare-bar--new {
	background: linear-gradient(90deg, color-mix(in oklab, var(--accent) 70%, transparent), color-mix(in oklab, var(--accent) 100%, transparent));
}

.wiz-comparison-row {
	animation: fadeInRow 0.3s var(--ease-out, ease-out) both;
	animation-delay: var(--wiz-bar-delay, 0s);
}

.wiz-compare-value {
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	text-align: right;
	color: var(--text-2);
}

.wiz-comparison-row--new .wiz-compare-value {
	color: var(--clr-highlight);
	font-weight: 700;
}

/* ── Tooltip (cost row info buttons) ──────────────────────── */
.wiz-tip-wrap {
	position: relative;
	display: inline-flex;
	align-items: baseline;
	gap: 0.3em;
}

.wiz-tip-btn {
	appearance: none;
	background: none;
	border: none;
	padding: 0;
	font-size: 0.7rem;
	line-height: 1;
	color: var(--text-4);
	cursor: help;
	transition: color 0.15s;
	vertical-align: middle;
}

.wiz-tip-btn:hover,
.wiz-tip-btn:focus-visible {
	color: var(--accent);
	outline: none;
}

/* Base tooltip – absolute fallback for non-supporting browsers */
.wiz-tooltip {
	position: absolute;
	bottom: calc(100% + 8px);
	left: 50%;
	transform: translateX(-50%) translateY(4px);
	z-index: 200;
	width: 220px;
	max-width: min(260px, 90vw);
	background: var(--tooltip-bg);
	border: 1px solid var(--tooltip-border);
	border-radius: 8px;
	padding: 0.55rem 0.75rem;
	font-size: 0.76rem;
	line-height: 1.5;
	color: var(--tooltip-text);
	box-shadow: var(--shadow-lg);
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.15s, transform 0.15s;
}

.wiz-tip-btn:hover + .wiz-tooltip,
.wiz-tip-btn:focus-visible + .wiz-tooltip {
	opacity: 1;
	pointer-events: auto;
	transform: translateX(-50%) translateY(0);
}

/* Modern CSS anchor positioning – Chrome/Edge 125+, overrides the absolute */
@supports (anchor-name: --x) {
	.wiz-tooltip {
		position: fixed;
		bottom: unset;
		left: unset;
		transform: translateY(4px);
		top: anchor(bottom);
		left: anchor(center);
		translate: -50% 8px;
		position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
	}

	.wiz-tip-btn:hover + .wiz-tooltip,
	.wiz-tip-btn:focus-visible + .wiz-tooltip {
		transform: none;
		translate: -50% 0;
	}
}

/* Navigation – reuses the general modal footer's horizontal/bottom padding
   tokens (see .modal__footer) so the wizard's footer isn't flush against the
   modal edges; keeps its own tighter top gap + subtle divider. */
.wiz-actions {
	border-top: 1px solid var(--border-subtle);
	padding: 1rem var(--modal-pad-x) var(--modal-pad-y);
}

/* Responsive */
@media (max-width: 600px) {
	.wiz-progress {
		padding: 0.75rem 1rem;
		gap: 0;
	}
	.wiz-step-pill {
		font-size: 0.62rem;
		padding: 0.25rem 0.5rem;
	}
	.wiz-body {
		padding: 1rem 1rem 0.5rem;
	}
	.wiz-fin-selector {
		grid-template-columns: 1fr;
	}
	.wiz-comparison-row {
		grid-template-columns: 130px 1fr 65px;
	}
}

/* ── OCR Invoice Scan ─────────────────────────────────────────────────────── */

.ocr-notice {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        flex-wrap: wrap;
        background: var(--surface-2);
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-control);
        padding: 0.5rem 0.75rem;
        margin-bottom: 1rem;
        font-size: 0.85rem;
}

.ocr-ai-label {
        font-weight: 600;
        color: var(--text-2);
}

.ocr-confidence {
        font-size: 0.8rem;
        padding: 0.15rem 0.5rem;
        border-radius: 999px;
        font-weight: 600;
}

.ocr-confidence--high  { background: var(--clr-sell-bg); color: var(--clr-sell); }
.ocr-confidence--medium { background: color-mix(in oklab, var(--clr-service) 14%, transparent); color: var(--clr-service); }
.ocr-confidence--low   { background: var(--clr-repair-bg); color: var(--clr-repair); }

/* §33 – shared inline AI transparency notice, rendered before every model call. */
.ai-disclaimer {
        display: flex;
        align-items: flex-start;
        gap: 0.5rem;
        flex-wrap: wrap;
        background: var(--surface-2);
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-control);
        padding: 0.5rem 0.75rem;
        margin-bottom: 1rem;
        font-size: 0.8rem;
        line-height: 1.5;
        color: var(--text-2);
}

.ai-disclaimer__icon { flex: none; font-size: 1.05rem; color: var(--accent); margin-top: 0.05rem; }

.ai-disclaimer__body { flex: 1 1 12rem; min-width: 0; }

.ai-disclaimer__warn { color: var(--clr-repair); font-weight: 600; }

.ai-disclaimer__link {
        flex: none;
        white-space: nowrap;
        text-decoration: underline;
        color: var(--accent);
}

/* Shown in place of an AI affordance when the master ai_enabled switch is off. */
.ai-disabled-hint {
        display: inline-flex;
        align-items: center;
        gap: 0.4rem;
        font-size: 0.8rem;
        color: var(--text-3);
}

.ocr-vendor {
        font-size: 0.9rem;
        color: var(--text-2);
        margin: 0 0 0.75rem;
}

.ocr-lineitems-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 0.85rem;
        margin-top: 0.25rem;
}

.ocr-lineitems-table th,
.ocr-lineitems-table td {
        padding: 0.25rem 0.5rem;
        border-bottom: 1px solid var(--border-subtle);
        text-align: left;
}

/* §99 #7: the entry form's editable variant gained a per-line Grund column, which
   pushed Art and Grund past the modal's edge (a dialog does not scroll sideways,
   so they were simply unreachable). Tighter gutters plus a scroll container keep
   all five columns inside a ~600px modal; the read-only OCR preview table, which
   has no Grund column and more room, keeps the roomier padding above. */
.ocr-lineitems-table--editor th,
.ocr-lineitems-table--editor td {
        padding: 0.25rem 0.25rem;
}
.ocr-lineitems-table--editor .form-input {
        padding-inline: 0.4rem;
}
/* table-layout: fixed, because auto layout let the description input's min-width
   win and squeezed the two selects to ~50px – narrow enough that you could not
   read which Art or Grund was selected. Fixed makes the widths below binding, so
   the selects get what they need and the description absorbs the remainder. */
.ocr-lineitems-table--editor {
        table-layout: fixed;
        width: 100%;
}
.ocr-lineitems-table--editor select.form-input {
        width: 100%;
        min-width: 0;
        font-size: 0.8rem;
}
/* headers wrap rather than overrun their column – "Betrag (CHF)" is wider than
   the input it labels and was colliding with the next heading. */
.ocr-lineitems-table--editor th {
        white-space: normal;
        line-height: 1.15;
        vertical-align: bottom;
}
.ocr-lineitems-table--editor .ocr-lineitems-amount { width: 5.5rem; }
.ocr-lineitems-table--editor .ocr-lineitems-kind { width: 7rem; }
.ocr-lineitems-table--editor .pos-desc { min-width: 0; width: 100%; }
.ocr-lineitems-table--editor .pos-amount { width: 100%; }

.ocr-lineitems-table th {
        font-weight: 600;
        color: var(--text-2);
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
}

.ocr-lineitems-amount {
        text-align: right !important;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
}

.ocr-usage {
        font-size: 0.8rem;
        color: var(--text-3);
        text-align: right;
        margin: 0.5rem 0 0;
}

.ocr-reconcile-warning {
        margin: 0.75rem 0 0;
        padding: 0.5rem 0.75rem;
        border-radius: var(--radius-control);
        background: color-mix(in oklab, var(--clr-service) 14%, transparent);
        color: var(--clr-service);
        border: 1px solid color-mix(in oklab, var(--clr-service) 45%, transparent);
        font-size: 0.82rem;
        font-weight: 600;
}

/* ── OCR two-pane modal layout ────────────────────────────────────────────── */

.ocr-modal-body {
        display: flex;
        gap: 1.5rem;
        align-items: flex-start;
        padding: 1.5rem 2rem 2rem;
}

.ocr-image-pane {
        flex: 0 0 42%;
        max-width: 42%;
}

.ocr-invoice-img {
        width: 100%;
        height: auto;
        max-height: 72vh;
        object-fit: contain;
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-control);
        background: var(--surface-sunken);
        display: block;
        position: sticky;
        top: 0.5rem;
}

.ocr-form-pane {
        flex: 1;
        min-width: 0;
}

/* ── OCR multi-invoice batch modal (§29) ─────────────────────────────────── */

.ocr-batch-list {
        display: flex;
        flex-direction: column;
        gap: 1rem;
        padding: 0 2rem;
        max-height: 64vh;
        overflow-y: auto;
}

.ocr-batch-card {
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-control);
        padding: 1rem 1.25rem;
        transition: opacity 0.15s ease;
}

.ocr-batch-card--excluded {
        opacity: 0.45;
}

/* ── §30 service-booklet confirm modal ────────────────────────────────────── */

.booklet-warnings {
        margin: 0 0 0.75rem;
        padding: 0.5rem 0.75rem 0.5rem 1.5rem;
        border-radius: var(--radius-control);
        background: color-mix(in oklab, var(--clr-service) 14%, transparent);
        color: var(--clr-service);
        border: 1px solid color-mix(in oklab, var(--clr-service) 45%, transparent);
        font-size: 0.8rem;
        font-weight: 600;
        list-style: disc;
}

.booklet-warnings li + li {
        margin-top: 0.25rem;
}

/* highlight the odometer input when the record carries a plausibility warning */
.form-input--warn {
        border-color: var(--clr-service);
        background: color-mix(in oklab, var(--clr-service) 8%, transparent);
}

.booklet-next {
        display: inline-flex;
        align-items: center;
        font-size: 0.9rem;
        font-weight: 600;
        color: var(--text-secondary);
}

/* ── §30 Serviceheft history on the Wartung tab ───────────────────────────── */

.booklet-section {
        margin-top: 2rem;
        padding-top: 1.5rem;
        border-top: 1px solid var(--border-subtle);
}

.section-head--sub {
        margin-bottom: 0.75rem;
}

.booklet-audit-head {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        flex-wrap: wrap;
        font-size: 1rem;
}

.booklet-audit-notes {
        margin: 0 0 1rem;
        padding: 0.5rem 0.75rem 0.5rem 1.5rem;
        border-radius: var(--radius-control);
        background: color-mix(in oklab, var(--clr-service) 8%, transparent);
        border: 1px solid color-mix(in oklab, var(--clr-service) 45%, transparent);
        font-size: 0.82rem;
        list-style: disc;
}

.booklet-audit-notes li + li {
        margin-top: 0.25rem;
}

.booklet-audit-flag {
        color: #b91c1c;
        font-weight: 600;
}

.booklet-audit-gap {
        color: var(--clr-service);
}

.booklet-late {
        display: inline-block;
        margin-left: 0.4rem;
        padding: 0.05rem 0.4rem;
        border-radius: 999px;
        background: color-mix(in oklab, var(--clr-service) 14%, transparent);
        color: var(--clr-service);
        border: 1px solid color-mix(in oklab, var(--clr-service) 45%, transparent);
        font-size: 0.72rem;
        font-weight: 600;
        white-space: nowrap;
}

/* §99 Inc 3b – the merged service history's evidence chip. A garage's stamp is
   third-party evidence; a self-typed row is a claim. The merge is only safe to
   make if the row never stops saying which it is, so the three levels are
   visually ranked: stamped reads as a real badge, invoice as a quiet one,
   self-reported as an outline. */
.visit-prov {
        display: inline-block;
        padding: 0.05rem 0.45rem;
        border-radius: 999px;
        font-family: var(--font-mono);
        font-size: 0.68rem;
        letter-spacing: 0.02em;
        white-space: nowrap;
        border: 1px solid transparent;
}
.visit-prov[data-prov="stamped"] {
        background: color-mix(in oklab, var(--clr-sell) 16%, transparent);
        color: var(--clr-sell);
        border-color: color-mix(in oklab, var(--clr-sell) 45%, transparent);
        font-weight: 600;
}
.visit-prov[data-prov="invoice"] {
        background: var(--surface-3);
        color: var(--text-2);
        border-color: var(--border);
}
.visit-prov[data-prov="self_reported"] {
        color: var(--text-3);
        border-style: dashed;
        border-color: var(--border);
}
/* the cost of a visit, when a journal entry backs it – subordinate to the
   service description it trails, since this is the work surface, not the ledger */
.visit-amount {
        margin-left: 0.5rem;
        font-family: var(--font-mono);
        font-size: 0.78rem;
        color: var(--text-3);
        white-space: nowrap;
}

.ocr-batch-card-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        margin-bottom: 0.75rem;
}

.ocr-batch-include {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        cursor: pointer;
}

.ocr-batch-title {
        font-weight: 700;
        font-size: 0.95rem;
}

.ocr-batch-pages {
        color: var(--text-3);
        font-weight: 400;
        margin-left: 0.25rem;
}

.ocr-batch-card .ocr-modal-body {
        padding: 0;
        gap: 1rem;
}

.ocr-image-pane--sm {
        flex: 0 0 28%;
        max-width: 28%;
}

.ocr-image-pane--sm .ocr-invoice-img {
        max-height: 40vh;
        position: static;
}


/* ── OCR Setup Callout (settings page) ───────────────────────────────────── */

.ocr-setup-callout {
        background: var(--accent-soft);
        border: 1px solid var(--clr-accent-subtle);
        border-radius: var(--radius-control);
        padding: 1rem 1.25rem;
        margin-bottom: 1.25rem;
}

.ocr-setup-callout-title {
        font-weight: 700;
        font-size: 0.95rem;
        color: var(--accent);
        margin-bottom: 0.75rem;
}

.ocr-setup-steps {
        margin: 0 0 0.75rem 1.25rem;
        padding: 0;
        display: flex;
        flex-direction: column;
        gap: 0.4rem;
        font-size: 0.9rem;
        color: var(--text-2);
}

.ocr-setup-steps a {
        color: var(--accent);
        font-weight: 600;
}

.ocr-setup-steps a:hover { text-decoration: underline; }

.ocr-setup-callout-note {
        margin: 0;
        font-size: 0.8rem;
        color: var(--text-3);
}

.ocr-error-message {
        margin: 1rem 0;
        padding: 0.75rem 1rem;
        background: var(--clr-repair-bg);
        color: var(--clr-repair);
        border-radius: 6px;
        font-size: 0.9rem;
        line-height: 1.5;
        word-break: break-word;
}

@media (max-width: 680px) {
        .ocr-modal-body {
                flex-direction: column;
        }
        .ocr-image-pane {
                flex: none;
                max-width: 100%;
        }
        .ocr-invoice-img {
                max-height: 45vh;
                position: static;
        }
}

/* Entry positions badge (number indicator on description cell) */
.entry-positions-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.2em;
  padding: 0 0.35em;
  margin-left: 0.35rem;
  border-radius: 999px;
  background: var(--color-primary);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  border: none;
  vertical-align: middle;
  transition: opacity 0.15s;
}
.entry-positions-badge:hover {
  opacity: 0.82;
}

/* §21 "view retained original" affordance – an eye icon-link on entries / booklet
   rows / the car hero (only shown when a source image was retained). */
.asset-view-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: 0.4rem;
  color: var(--text-4);
  vertical-align: middle;
  transition: color 0.15s;
  /* Used on both <a> and <button> (the ausweis viewer trigger, the journal edit
     pencil); reset button chrome so the two render identically. No-op for <a>. */
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.asset-view-link:hover {
  color: var(--color-primary);
}
.asset-view-link .icon {
  width: 1em;
  height: 1em;
}
.asset-view-link--labeled {
  font-size: 0.85rem;
}

/* Split form-actions (delete left, save/cancel right) */
.form-actions--split {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.form-actions-right {
  display: flex;
  gap: 0.5rem;
  margin-left: auto;
}
/* Car-detail tab strip (§20) – same visual language as the top nav, sits below
   the persistent hero + stat header; horizontally scrollable on small screens. */
.car-tabs {
	display: flex;
	gap: 0.25rem;
	margin: 1.5rem 0 1.25rem;
	flex-wrap: wrap;
	border-bottom: 1px solid var(--border-subtle);
}

/* Tab/view switchers are full-reload <a> links (car-detail tabs, settings rail,
   cockpit trend toggle); the #content-top fragment lands the reload on the switched
   content rather than the page top. scroll-margin clears the 56px sticky mobile
   topbar (+ a little breathing room) so the anchor isn't hidden under it. A cheap
   stopgap until these morph in place. */
#content-top {
	scroll-margin-top: 4.5rem;
}

.car-tab {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	padding: 0.55rem 0.9rem;
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.1px;
	color: var(--text-4);
	text-decoration: none;
	border-bottom: 2px solid transparent;
	margin-bottom: -1px;
	white-space: nowrap;
	transition: color var(--timing-fast) var(--ease-out), border-color var(--timing-fast) var(--ease-out);
}

.car-tab .icon {
	width: 1.05em;
	height: 1.05em;
	color: var(--text-5);
	transition: color var(--timing-fast) var(--ease-out);
}

.car-tab:hover {
	color: var(--text-2);
}

.car-tab:hover .icon {
	color: var(--text-3);
}

.car-tab--active {
	color: var(--ink);
	border-bottom-color: var(--accent);
}

.car-tab--active .icon {
	color: var(--accent);
}

.car-tab__count {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.25rem;
	height: 1.25rem;
	padding: 0 0.35rem;
	border-radius: 999px;
	background: var(--surface-3, var(--border-subtle));
	color: var(--text-3);
	font-size: 11px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: 1;
}

.car-tab--active .car-tab__count {
	background: var(--accent);
	color: var(--surface-1);
}

@media (max-width: 640px) {
	.car-tabs {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
	}

	.car-tabs::-webkit-scrollbar {
		display: none;
	}
}

/* Vergleich chart sub-navigation */
.vergleich-subnav {
	display: flex;
	gap: 0.5rem;
	margin: 1rem 0;
	flex-wrap: wrap;
}

/* The Auswertungen subnav wears both .vergleich-subnav and .segmented. The former
   carries flex-wrap:wrap (a leftover from its flat-link origins), which makes the
   4-tab .segmented capsule wrap to two rows on a phone – the active pill highlight
   then sits oddly across the break. Keep it a single row and scroll horizontally
   when it doesn't fit (desktop still shows all four; scrollbar hidden, the clipped
   trailing tab is the affordance), same treatment as .documents__kind-filter but
   preserving the capsule. Two-class selector wins over the single-class bases. */
.vergleich-subnav.segmented {
	flex-wrap: nowrap;
	max-width: 100%;
	overflow-x: auto;
	scrollbar-width: none;
}
.vergleich-subnav.segmented::-webkit-scrollbar { display: none; }
.vergleich-subnav.segmented .segmented__item { flex: none; }

.section-hint {
	color: var(--text-4);
	font-size: 13px;
	padding: 1rem 0;
}

/* ───────────────────────── Übersicht (dashboard) ───────────────────── */

.dashboard {
	display: flex;
	flex-direction: column;
	gap: clamp(1.1rem, 2.4vw, 1.75rem);
}

/* Cheapest-car stat doubles as a link to its detail page. */
a.stat { text-decoration: none; }
a.stat:hover { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }

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

/* Inline "more →" link in section heads. */
.text-link {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	color: var(--accent);
	text-decoration: none;
}
.text-link .icon { font-size: 0.95em; transition: transform var(--timing-base) var(--ease-out); }
.text-link:hover .icon { transform: translateX(3px); }

/* Quick-link cards under the dashboard. */
.quick-links {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 0.75rem;
}
.quick-link {
	display: flex;
	align-items: center;
	gap: 0.85rem;
	padding: 0.9rem 1.1rem;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	text-decoration: none;
	color: inherit;
	transition: border-color var(--timing-base) var(--ease-out), transform var(--timing-base) var(--ease-out);
}
.quick-link:hover {
	border-color: color-mix(in oklab, var(--accent) 40%, transparent);
	transform: translateY(-2px);
}
.quick-link__body { display: flex; flex-direction: column; gap: 0.05rem; flex: 1; min-width: 0; }
.quick-link__label { font-weight: 600; color: var(--ink); font-size: 14px; }
.quick-link__sub {
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.02em;
	color: var(--text-4);
}
.quick-link > .icon { color: var(--text-5); transition: transform var(--timing-base) var(--ease-out); }
.quick-link:hover > .icon { color: var(--accent); transform: translateX(3px); }

.settings-content {
	padding: clamp(1.1rem, 2.4vw, 2.2rem);
}

/* ==========================================================================
   Design system additions  (icons, tabular figures, polish, a11y)
   Unlayered + appended last, so these win over earlier component rules.
   ========================================================================== */

/* Inline SVG icon from the Lucide sprite. Sized in em so it tracks font-size;
   stroke colour follows currentColor. */
.icon {
	width: 1em;
	height: 1em;
	flex: none;
	display: inline-block;
	vertical-align: -0.14em;
	color: currentColor;
	stroke-width: 2;
}
.icon--lg { font-size: 1.35em; }
.icon--xl { font-size: 2em; stroke-width: 1.75; }

/* Tabular, slashed-zero figures everywhere money/distance/dates are shown, so
   columns align. Zero specificity (:where) – purely additive. */
:where(
	.pill-value,
	[class*="summary-value"], .cost-pie-legend, .entry-table td,
	.entry-table-component td, .footer-version
) {
	font-variant-numeric: tabular-nums slashed-zero;
}
/* Respect the OS "reduce motion" setting – kill the decorative entrances. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   Editorial × Instrument – shared component primitives + responsive system
   Appended last (unlayered) so it composes over the legacy component blocks.
   Vocabulary: .eyebrow / .section-head, .stat(-grid), .icon-chip,
   .activity-list/.activity-row, .segmented. Reused by every redesigned view.
   ========================================================================== */

/* ── Eyebrow + section header ───────────────────────────────────────────── */
.eyebrow {
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--text-4);
	margin: 0;
}

.section-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem 1.5rem;
	flex-wrap: wrap;
	margin-bottom: 1.1rem;
}

.section-head__titles { display: flex; flex-direction: column; gap: 0.3rem; }

.section-head__title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 520;
	font-size: clamp(18px, 2.4vw, 23px);
	letter-spacing: -0.012em;
	line-height: 1.1;
	color: var(--ink);
	margin: 0;
}

/* ── Stat block (instrument readout) ────────────────────────────────────── */
.stat-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	gap: clamp(0.6rem, 1.4vw, 1rem);
}

.stat {
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
	padding: clamp(1rem, 2vw, 1.4rem) clamp(1rem, 2vw, 1.5rem);
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	transition: border-color var(--timing-base) var(--ease-out);
}

.stat__value {
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: clamp(21px, 2.7vw, 29px);
	line-height: 1.05;
	letter-spacing: -0.01em;
	color: var(--ink);
	font-variant-numeric: tabular-nums slashed-zero;
}

.stat__unit {
	font-family: var(--font-mono);
	font-size: 0.5em;
	font-weight: 600;
	color: var(--text-4);
	letter-spacing: 0.04em;
	margin-left: 0.3em;
}

.stat__label {
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--text-4);
	line-height: 1.45;
}

/* ── Icon-chip (colored round category glyph) ───────────────────────────── */
.icon-chip {
	display: inline-grid;
	place-items: center;
	width: 2.3rem;
	height: 2.3rem;
	border-radius: 50%;
	flex: none;
	color: var(--chip-fg, var(--text-2));
	background: var(--chip-bg, var(--tint-sm));
}
.icon-chip .icon { font-size: 1.05rem; stroke-width: 2; }
.icon-chip--sm { width: 1.9rem; height: 1.9rem; }
.icon-chip--sm .icon { font-size: 0.95rem; }
.icon-chip--service { --chip-fg: var(--clr-service); --chip-bg: var(--clr-service-bg); }
.icon-chip--repair  { --chip-fg: var(--clr-repair);  --chip-bg: var(--clr-repair-bg); }
.icon-chip--accent  { --chip-fg: var(--accent);      --chip-bg: var(--accent-soft); }
.icon-chip--muted   { --chip-fg: var(--text-3);      --chip-bg: var(--tint-sm); }

/* ── Activity list (the mockups' "recent activity" pattern) ─────────────── */
.activity-list { display: flex; flex-direction: column; }

.activity-row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	gap: 0.85rem;
	padding: 0.7rem 0;
	border-bottom: 1px solid var(--border-subtle);
	text-decoration: none;
	color: inherit;
	transition: padding-left var(--timing-base) var(--ease-out);
}
.activity-row:last-child { border-bottom: 0; }
a.activity-row:hover { padding-left: 0.35rem; }

.activity-row__body { min-width: 0; }
.activity-row__title {
	font-weight: 600;
	color: var(--ink);
	font-size: 13.5px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.activity-row__meta {
	font-family: var(--font-mono);
	font-size: 11px;
	color: var(--text-4);
	font-variant-numeric: tabular-nums slashed-zero;
	margin-top: 0.12rem;
}
/* §12 reminders: secondary car name on the title line + open-count badge */
.activity-row__sub { font-weight: 400; color: var(--text-3); }
.termine-open-badge {
	font-size: 11px;
	font-weight: 600;
	padding: 3px 10px;
	border-radius: 999px;
	color: var(--clr-service);
	background: var(--clr-service-bg);
	border: 1px solid var(--clr-service-border);
	white-space: nowrap;
}

/* ── Segmented control ──────────────────────────────────────────────────── */
.segmented {
	display: inline-flex;
	align-items: center;
	padding: 3px;
	gap: 2px;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-pill);
}
.segmented__item {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.42rem 0.95rem;
	font-size: 12px;
	font-weight: 600;
	color: var(--text-3);
	text-decoration: none;
	border: 0;
	background: transparent;
	cursor: pointer;
	border-radius: var(--radius-pill);
	white-space: nowrap;
	transition: background var(--timing-fast) var(--ease-out), color var(--timing-fast) var(--ease-out);
}
.segmented__item:hover { color: var(--text); }
.segmented__item--active {
	background: var(--surface-raised);
	color: var(--ink);
	box-shadow: 0 1px 2px var(--scrim-sm);
}
.segmented__item .icon { color: currentColor; }

/* ── Card surface primitive (panels around lists/tables) ─────────────────── */
.panel {
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	padding: clamp(1rem, 2.2vw, 1.5rem);
}

/* ==========================================================================
   §31 Streamlined Upload – Journal list-as-dropzone (Phase 1)
   The panel is the drop target; the annotated two-zone overlay is drag-only
   (data-show), and the resting hint is the at-rest affordance on an empty list.
   ========================================================================== */
.journal-panel { position: relative; }


/* ==========================================================================
   §31 Streamlined Upload – multi-file intake prepare modal (Phase 2)
   The dialog reuses the .form-modal chrome; these style the thumbnail rail, the
   per-file status chips, and the object-URL previews the client builds on drop.
   ========================================================================== */
.intake-remaining { margin-left: auto; font-size: 0.8rem; color: var(--text-3); }
/* §31: two footer states (progress+scan vs discard-confirm) toggled by
   $intakeConfirm; each is a full-width flex row so only one shows at a time. */
.intake-footer__main,
.intake-footer__confirm { display: flex; align-items: center; gap: 0.75rem; flex: 1 1 100%; }
.intake-progress { margin-right: auto; font-size: 0.8rem; color: var(--text-3); }
.intake-confirm-msg { margin-right: auto; font-size: 0.85rem; color: var(--text-2); }
.intake-rail {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
	gap: 0.75rem;
	max-height: 55vh;
	overflow-y: auto;
	padding: 0.25rem;
	margin-bottom: 1rem;
}
.intake-card {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: 0.5rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface-sunken);
}
.intake-card__thumb {
	aspect-ratio: 4 / 3;
	display: grid;
	place-items: center;
	overflow: hidden;
	border-radius: calc(var(--radius-control) - 2px);
	background: var(--surface);
}
.intake-card__thumb img { width: 100%; height: 100%; object-fit: cover; }
.intake-card__thumb--pdf {
	font-size: 0.85rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	color: var(--text-4);
}
.intake-card__name {
	font-size: 0.72rem;
	color: var(--text-3);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.intake-chip {
	align-self: flex-start;
	font-size: 0.7rem;
	padding: 0.1rem 0.45rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--border);
	color: var(--text-3);
}
.intake-chip--uploading { color: var(--clr-buy);    border-color: color-mix(in oklab, var(--clr-buy) 40%, transparent); }
.intake-chip--ready     { color: var(--accent);     border-color: color-mix(in oklab, var(--accent) 45%, transparent); }

/* §87 Inc 2: intake renders the shared ui.UploadCard now. Keep intake's larger
   review-card sizing + 4:3 document thumbnail (vs the §86 gallery's small square
   card) by scoping overrides to the #intake-rail grid; the shared card's fixed
   width yields to the grid cell here. */
/* Flex column so name + status pin to the card bottom regardless of thumb height. */
.intake-rail .upl-card { width: auto; font-size: 0.72rem; display: flex; flex-direction: column; }
/* Default thumb shape (DIN A4 portrait) for a pending/PDF card; a ready image sets its
   OWN aspect-ratio inline, clamped to [A4 … 1:1], so a wide scan shows square (cover)
   rather than squeezed into a narrow A4 strip. */
.intake-rail .upl-card__thumb { aspect-ratio: 210 / 297; }
.intake-rail .upl-card__name { margin-top: auto; }
.intake-rail .upl-card__phase { padding-bottom: 0.4rem; }
/* §64: the uploading card's byte ring loads inside the 4:3 thumb box (grid cell →
   the ProgressRingSignal span is blockified + centered), so an uploading card has the
   same shape as a ready one, the preview just resolves in place. */
.intake-rail .upl-card__thumb .progress-ring { width: 2.6rem; height: 2.6rem; margin: 0; }

/* §87 in-modal drop-more: a trailing tile in the rail grid to append files to the
   OPEN batch. Stretches to card height when it shares a row, min-height otherwise. */
.intake-add {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.35rem;
	min-height: 5rem;
	padding: 0.5rem;
	border: 1px dashed var(--border);
	border-radius: var(--radius-control);
	background: var(--surface-sunken);
	color: var(--text-3);
	font-size: 0.72rem;
	text-align: center;
	cursor: pointer;
	transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
/* Hover (pointer) and drag-over (a file dragged onto the tile, $_addDrag) share the
   lift: accent border + text and a faint accent wash; the drag state also goes solid. */
.intake-add:hover,
.intake-add--drag {
	border-color: var(--accent);
	color: var(--accent);
	background: color-mix(in oklab, var(--accent) 8%, var(--surface-sunken));
}
.intake-add--drag { border-style: solid; }
/* Let drag events target the tile itself – a child (icon/text) receiving them fires
   spurious dragleave on the label and flickers the highlight off mid-tile. */
.intake-add > * { pointer-events: none; }
.intake-add__icon { width: 1.25rem; height: 1.25rem; }

/* §87: the modal's bottom block – one hairline demotes the §33 AI notice, combining
   it with the footer actions instead of floating as a boxed note in the body flow.
   The footer's own border-top is dropped so there's a single rule, not two. */
.intake-foot { border-top: 1px solid var(--border); }
.intake-foot .ai-disclaimer {
	border: 0;
	background: transparent;
	border-radius: 0;
	margin: 0;
	padding: 0.85rem var(--modal-pad-x) 0;
	font-size: 0.75rem;
}
.intake-foot .modal__footer { border-top: 0; padding-top: 0.6rem; }

/* §31 Phase 3 – pre-scan editor: rail (left) + editor pane (right). */
.intake-body { display: flex; gap: 1rem; align-items: flex-start; padding: 1.5rem 2rem 0; }
.intake-body .intake-rail { flex: 1 1 52%; min-width: 0; margin-bottom: 0; }
.intake-card--editable { cursor: pointer; transition: border-color 0.12s ease; }
.intake-card--editable:hover { border-color: var(--accent); }
.intake-card--sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.intake-card__thumb { position: relative; }
.intake-card__edited {
	position: absolute; top: 0.25rem; right: 0.25rem;
	width: 1.2rem; height: 1.2rem; display: grid; place-items: center;
	font-size: 0.8rem; line-height: 1;
	border-radius: var(--radius-pill);
	background: color-mix(in oklab, var(--accent) 88%, black); color: #fff;
}
.intake-editor {
	flex: 1 1 44%; display: flex; flex-direction: column; gap: 0.75rem;
	padding: 0.75rem; border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control); background: var(--surface-sunken);
}
.intake-edit-stage {
	position: relative; height: 46vh; overflow: hidden;
	touch-action: none; user-select: none;
	border-radius: calc(var(--radius-control) - 2px); background: var(--surface);
	/* faint checker so white rotation corners / margins read against the stage */
	background-image:
		linear-gradient(45deg, var(--border-subtle) 25%, transparent 25%),
		linear-gradient(-45deg, var(--border-subtle) 25%, transparent 25%),
		linear-gradient(45deg, transparent 75%, var(--border-subtle) 75%),
		linear-gradient(-45deg, transparent 75%, var(--border-subtle) 75%);
	background-size: 16px 16px; background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}
/* zoom/pan container fills the stage (transform driven by the editor controller); */
/* the image is centered inside and only rotates (that transform is Datastar-driven). */
.intake-edit-zoom { position: absolute; inset: 0; display: grid; place-items: center; will-change: transform; }
.intake-edit-img { max-width: 94%; max-height: 94%; object-fit: contain; transition: transform 0.08s linear; }
/* crop rectangle: a dashed frame whose big spread-shadow dims everything outside it. */
.intake-crop {
	position: absolute; pointer-events: none;
	border: 2px dashed var(--accent);
	box-shadow: 0 0 0 9999px color-mix(in oklab, #000 45%, transparent);
}
.intake-edit-controls { display: flex; flex-direction: column; gap: 0.6rem; }
.intake-edit-row { display: flex; align-items: center; gap: 0.5rem; }
.intake-edit-slider { flex: 1; min-width: 0; }
.intake-edit-nudge { padding: 0.25rem 0.6rem; font-variant-numeric: tabular-nums; }
.intake-edit-hint { margin: 0; font-size: 0.72rem; color: var(--text-3); }
.intake-edit-zoomlabel { min-width: 3rem; text-align: center; font-variant-numeric: tabular-nums; color: var(--text-2); }
.intake-edit-angle { min-width: 3.2rem; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }
.intake-edit-actions { display: flex; gap: 0.5rem; justify-content: flex-end; margin-left: auto; }
/* §64: per-file upload progress in a pending rail card renders as .progress-ring
   (see the reusable widget below); the LiveSSE loop morphs it by id. */
/* §31: scan-in-progress feedback – a spinner on the "Alle scannen" button label and
   a live per-file status line the batch handler streams into. */
.intake-scanprogress { margin-right: auto; font-size: 0.8rem; color: var(--accent); }
.intake-btn-busy::before {
	content: ""; display: inline-block; width: 0.8em; height: 0.8em;
	margin-right: 0.45em; vertical-align: -0.1em;
	border: 2px solid currentColor; border-right-color: transparent;
	border-radius: 50%; animation: intake-spin 0.7s linear infinite;
}
@keyframes intake-spin { to { transform: rotate(360deg); } }

/* §31: booklet review – each entry shows its source page; hover to magnify it in
   place (eBay-style inner zoom), so there is no overlay to fight the dialog's top
   layer. The scale is pure CSS; a one-line data-on:mousemove sets transform-origin
   to the cursor so it zooms toward that point. */
/* align-items: stretch so the photo fills the card's full height (matching the
   fields beside it); the flex stretch gives .booklet-photo a definite height that
   the image's height:100% resolves against. */
.booklet-card-body { display: flex; gap: 1rem; align-items: stretch; }
.booklet-card-body .ocr-form-pane { flex: 1 1 auto; min-width: 0; }
.booklet-photo {
	position: relative; flex: 0 0 auto; width: 240px; min-height: 220px; padding: 0; overflow: hidden;
	border: 1px solid var(--border-subtle); border-radius: var(--radius-control);
	background: var(--surface-sunken); cursor: crosshair;
}
.booklet-photo:hover { border-color: var(--accent); }
.booklet-photo img {
	display: block; width: 100%; height: 100%; object-fit: contain;
	transition: transform 0.12s ease; transform-origin: center; will-change: transform;
}
.booklet-photo:hover img { transform: scale(3.4); }
.booklet-photo__zoom {
	position: absolute; bottom: 0.3rem; right: 0.3rem;
	width: 1.5rem; height: 1.5rem; display: grid; place-items: center;
	border-radius: 50%; background: rgba(0, 0, 0, 0.55); color: #fff; font-size: 1rem; line-height: 1;
	transition: opacity 0.12s;
}
.booklet-photo:hover .booklet-photo__zoom { opacity: 0; }
@media (max-width: 640px) {
	.booklet-card-body { flex-direction: column; }
	.booklet-photo { width: 100%; height: 46vh; min-height: 0; }
}
@media (max-width: 720px) {
	.intake-body { flex-direction: column; padding: 1rem 1rem 0; }
	.intake-body .intake-rail, .intake-editor { flex-basis: auto; width: 100%; }
	.intake-edit-stage { height: 38vh; }
}

@media (max-width: 640px) {
	/* Leave room for the fixed bottom nav + iOS safe area. */
	body { padding: 18px 14px calc(76px + env(safe-area-inset-bottom)); }
	.profile-switcher { gap: 0.3rem; }
	.header-actions-right { margin-left: 0; width: 100%; }
	.header-actions-right .btn { width: 100%; }

	/* Cards collapse to a single comfortable column. */
	.stat-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Fahrzeuge list – scannable index rows (link to per-car detail)
   ========================================================================== */

.car-row {
	position: relative;
	display: flex;
	align-items: center;
	gap: clamp(0.85rem, 2vw, 1.25rem);
	padding: clamp(0.85rem, 1.8vw, 1.1rem) clamp(1rem, 2vw, 1.35rem);
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	margin-bottom: 0.7rem;
	transition: border-color var(--timing-base) var(--ease-out), transform var(--timing-base) var(--ease-out), box-shadow var(--timing-base) var(--ease-out);
}
.car-row:hover {
	border-color: var(--tint-lg);
	transform: translateY(-2px);
	box-shadow: 0 10px 28px var(--scrim-sm);
}

.car-row__photo {
	flex: none;
	width: 64px;
	height: 64px;
	border-radius: var(--radius-control);
	overflow: hidden;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
}
.car-row__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.car-row__img--ph { display: grid; place-items: center; color: var(--text-5); }

.car-row__main { flex: 1; min-width: 0; }
.car-row__name {
	display: inline-block;
	max-width: 100%;
	font-family: var(--font-serif);
	font-weight: 540;
	font-size: clamp(15px, 1.8vw, 18px);
	letter-spacing: -0.01em;
	color: var(--ink);
	text-decoration: none;
}
/* Stretched link: clicking anywhere on the row (except buttons) opens detail. */
.car-row__name::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.car-row__name:hover { color: var(--accent); }

/* Make/Model kept visible (smaller, muted) alongside a nickname (§14). */
.car-row__submodel {
	font-family: var(--font-sans);
	font-size: 0.6em;
	font-weight: 400;
	letter-spacing: 0;
	color: var(--text-4);
	margin-left: 0.5em;
}

.car-row__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.3rem 0.65rem;
	margin-top: 0.4rem;
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.01em;
	color: var(--text-3);
}
.car-row__journal { color: var(--text-4); }

.car-row__metrics {
	flex: none;
	gap: clamp(0.75rem, 1.6vw, 1.25rem);
	z-index: 1;
}

/* /fahrzeuge row: one all-in figure + a compact cost-DNA bar (no visible legend;
   the exact per-segment values are in the bar's hover title). Shares the .cmp-bar
   / .cmp-seg--* colours with the comparison cards. */
.cost-mini {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.4rem;
	min-width: 128px;
}
.cost-mini__hero { display: flex; align-items: baseline; gap: 0.35rem; }
.cost-mini__val {
	font-family: var(--font-mono);
	font-weight: 700;
	font-size: 22px;
	line-height: 1;
	letter-spacing: -0.01em;
	color: var(--text-1);
	font-variant-numeric: tabular-nums slashed-zero;
}
.cost-mini__unit {
	font-family: var(--font-mono);
	font-size: 9px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-4);
}
.cost-mini__bar { width: 100%; }
/* Desktop: the foot wrapper is transparent so metrics + actions stay inline flex
   items of the row; on phones it becomes the bordered footer (see @640 below). */
.car-row__foot { display: contents; }
.car-row__actions { z-index: 1; }
.car-row__chevron { flex: none; color: var(--text-5); transition: transform var(--timing-base) var(--ease-out); }
.car-row:hover .car-row__chevron { color: var(--accent); transform: translateX(3px); }

/* ==========================================================================
   Per-car detail page
   ========================================================================== */

.car-detail { display: flex; flex-direction: column; gap: clamp(1.1rem, 2.4vw, 1.75rem); }

.back-link {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	align-self: flex-start;
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
	text-decoration: none;
}
.back-link .icon { transition: transform var(--timing-base) var(--ease-out); }
.back-link:hover { color: var(--accent); }
.back-link:hover .icon { transform: translateX(-3px); }

.car-hero {
	display: grid;
	grid-template-columns: minmax(220px, 320px) 1fr;
	/* §86: the cover and its (collapsed) gallery share the left column, stacked, so
	   they read as one media unit; the identity sits in col 2, sized to the cover row
	   (the empty "." keeps the gallery's expansion from stretching the identity). */
	grid-template-areas:
		"media info"
		"gallery .";
	column-gap: clamp(1.1rem, 2.6vw, 2rem);
	row-gap: 0.6rem;
	align-items: stretch;
}
.car-hero__media {
	grid-area: media;
	position: relative;
	/* align-self:start keeps the media at its aspect-ratio height for the column
	   width; without it the grid's stretch forces the height to match a taller
	   info column and the 16/10 ratio blows the width past the track, overlapping
	   the title (visible once the info column wraps on a narrower content area). */
	align-self: start;
	aspect-ratio: 16 / 10;
	border-radius: var(--radius-card);
	overflow: hidden;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
}
.car-hero__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.car-hero__img--ph { display: grid; place-items: center; color: var(--text-5); }

/* Empty-state silhouette doubling as the upload drop-zone (§14). */
.car-hero__img--dropzone {
	width: 100%;
	height: 100%;
	cursor: pointer;
	transition: color var(--timing-base) var(--ease-out), background var(--timing-base) var(--ease-out);
}
.car-hero__img--dropzone:hover {
	color: var(--accent);
	background: var(--tint-sm);
}

/* §64/§41: determinate upload ring scrimmed over the hero while a (possibly
   multi-MB phone) car photo uploads. data-show toggles it via $photoUp. */
.car-photo-progress {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 2;
	background: color-mix(in oklab, var(--surface-sunken) 74%, transparent);
	backdrop-filter: blur(2px);
	animation: fadeIn var(--timing-base) var(--ease-out);
}

.car-hero__info { grid-area: info; display: flex; flex-direction: column; justify-content: center; gap: 0.55rem; min-width: 0; }
.car-hero__info .eyebrow { display: flex; align-items: center; gap: 0.35rem; }
.car-hero__name {
	margin: 0;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 540;
	font-size: clamp(24px, 4vw, 38px);
	line-height: 1.05;
	letter-spacing: -0.018em;
	color: var(--ink);
}
.car-hero__name .car-make { font-weight: 400; color: var(--text-3); margin-right: 0.3em; }

/* Make/Model kept visible (smaller, muted) alongside a nickname (§14). */
.car-hero__submodel {
	margin: -0.35rem 0 0;
	font-family: var(--font-sans);
	font-size: 13px;
	color: var(--text-4);
}
.car-hero__meta {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 12px;
	color: var(--text-3);
	font-variant-numeric: tabular-nums slashed-zero;
}
.car-hero__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 0.4rem; align-items: center; }
/* §88 – the overflow "Mehr" menu floats to the right edge of the action row so the
   inline quick-actions + Edit stay left-aligned and the danger delete (now inside
   the menu) sits well apart from every everyday action. */
.car-hero__menu { margin-left: auto; }

/* ── §88 action overflow menu ────────────────────────────────────────────────
   A native <details> dropdown reused for low-frequency / lifecycle / danger
   actions (the car-detail hero was a wall of ~9 inline buttons). The <summary>
   is styled as a secondary button; the panel + items reuse the avatar-menu
   visual language. Explicit :hover / [open] rules are needed to beat the global
   `details summary` accordion chrome (padding, scrim bg, hover padding-shift). */
.action-menu { position: relative; display: inline-flex; border-top: 0; }
.action-menu > summary.action-menu__trigger {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.625rem 1.25rem;
	border: 1px solid var(--border);
	border-radius: var(--radius-control);
	background: var(--tint-sm);
	color: var(--text-2);
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.2;
	white-space: nowrap;
	list-style: none;
	user-select: none;
	cursor: pointer;
	transition: background var(--timing-base) var(--ease-out), border-color var(--timing-base) var(--ease-out), color var(--timing-base) var(--ease-out);
}
.action-menu > summary.action-menu__trigger:hover,
.action-menu[open] > summary.action-menu__trigger {
	/* re-declare padding to cancel the global `details summary:hover` shift */
	padding: 0.625rem 1.25rem;
	background: var(--tint-md);
	color: var(--text);
	border-color: var(--tint-lg);
}
.action-menu__trigger::-webkit-details-marker { display: none; }
.action-menu__trigger::marker { content: ""; }
.action-menu__trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.action-menu__panel {
	position: absolute;
	right: 0;
	top: calc(100% + 6px);
	z-index: 70;
	min-width: 232px;
	padding: 0.4rem;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	box-shadow: 0 12px 32px var(--scrim-sm);
	display: flex;
	flex-direction: column;
	gap: 2px;
	animation: fadeIn var(--timing-base) var(--ease-out);
}
.action-menu__item {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	width: 100%;
	padding: 0.55rem 0.6rem;
	border: 0;
	background: transparent;
	color: var(--text-2);
	font: inherit;
	font-size: 13.5px;
	text-align: left;
	text-decoration: none;
	border-radius: var(--radius-control);
	cursor: pointer;
	transition: background var(--timing-base) var(--ease-out), color var(--timing-base) var(--ease-out);
}
.action-menu__item .icon { width: 1.05em; height: 1.05em; color: var(--text-4); flex: none; }
.action-menu__item:hover { background: var(--tint-sm); color: var(--ink); }
.action-menu__item:hover .icon { color: var(--text-2); }
/* Active toggle (this car is already primary / public): tint the leading glyph. */
.action-menu__item.is-active .icon { color: var(--accent); }
/* The isolated destructive item, foot of the menu below a divider. */
.action-menu__item--danger, .action-menu__item--danger .icon { color: var(--critical); }
.action-menu__item--danger:hover {
	background: color-mix(in oklab, var(--critical) 12%, transparent);
	color: var(--critical);
}
.action-menu__item--danger:hover .icon { color: var(--critical); }
.action-menu__divider { height: 1px; background: var(--border-subtle); margin: 0.3rem 0; }

/* Icon + label stat variant used on the detail at-a-glance row. §88 – larger,
   more present than the app-wide 10px stat label: the header reads first, and the
   leading glyph carries real weight instead of a faint 1.3em hint. */
.stat__label--icon { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 11px; }
.stat__label--icon .icon { color: var(--text-3); font-size: 1.65em; }

/* Journal toolbar on the detail page. */
.journal-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }

/* ── §64 progress ring: a reusable "simple upload/download with progress" widget.
   A circle (r=15.915 → circumference exactly 100) whose stroke-dashoffset is
   100 − pct, with the percent inside. Bound to a Datastar signal via
   data-attr:stroke-dashoffset; the offset transitions smoothly as it updates. ── */
.progress-ring { position: relative; width: 2rem; height: 2rem; margin: 0.35rem auto 0; }
.progress-ring__svg { width: 100%; height: 100%; transform: rotate(-90deg); display: block; }
.progress-ring__track { fill: none; stroke: color-mix(in oklab, currentColor 18%, transparent); stroke-width: 3; }
.progress-ring__bar {
	fill: none;
	stroke: var(--accent);
	stroke-width: 3;
	stroke-linecap: round;
	stroke-dasharray: 100;
	transition: stroke-dashoffset 0.25s var(--ease-out);
	filter: drop-shadow(0 0 2px color-mix(in oklab, var(--accent) 45%, transparent));
}
.progress-ring__num {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 0.62rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--text);
	letter-spacing: -0.02em;
}
@media (prefers-reduced-motion: reduce) { .progress-ring__bar { transition: none; } }

/* §87: at 100% the upload is in but a step still runs (PDF→thumbnail, validate/swap).
   The determinate ring flips to an indeterminate spinner – same widget, now a loader –
   so a card/button never reads as frozen on a full ring. Toggled by data-class off the
   bound pct (>= 100). A short quarter-arc spins; the "100" number hides. */
.progress-ring--busy .progress-ring__svg { animation: progress-ring-spin 0.85s linear infinite; }
.progress-ring--busy .progress-ring__bar { stroke-dasharray: 25 100; transition: none; }
.progress-ring--busy .progress-ring__num { opacity: 0; }
@keyframes progress-ring-spin { from { transform: rotate(-90deg); } to { transform: rotate(270deg); } }
@media (prefers-reduced-motion: reduce) { .progress-ring--busy .progress-ring__svg { animation: none; } }

/* §35 two-phase overlay: the upload ring is scaled up (dropzone-sized) and its
   number enlarged; each phase stacks the ring/beam + its label. */
.progress-ring--xl { width: 4rem; height: 4rem; }
.progress-ring--xl .progress-ring__num { font-size: 1.05rem; }
.ausweis-scan__phase { display: flex; flex-direction: column; align-items: center; gap: 1rem; width: 100%; }

/* §57 restore: a compact inline ring inside the "Wiederherstellen" button while
   the .db uploads. */
.progress-ring--sm { width: 1.15rem; height: 1.15rem; margin: 0; }
.progress-ring--sm .progress-ring__num { font-size: 0.5rem; }
.restore-progress { display: inline-flex; align-items: center; gap: 0.4rem; }


/* ── Mobile: list rows + hero stack ─────────────────────────────────────── */
@media (max-width: 720px) {
	.car-hero {
		grid-template-columns: 1fr;
		grid-template-areas:
			"media"
			"gallery"
			"info";
	}
}
@media (max-width: 640px) {
	/* §63 – phone car card: photo + identity span the top, cost + actions share a
	   single bordered footer row. Keeps the action buttons from squeezing the name
	   into a 3-line wrap (the old flex-wrap layout). */
	.car-row {
		display: grid;
		grid-template-columns: 56px 1fr;
		grid-template-areas:
			"photo main"
			"foot  foot";
		align-items: center;
		column-gap: 0.85rem;
		row-gap: 0.7rem;
	}
	.car-row__photo { grid-area: photo; width: 56px; height: 56px; }
	.car-row__main { grid-area: main; }
	/* Truncate long identities to one line with an ellipsis instead of wrapping. */
	.car-row__name {
		display: block;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.car-row__foot {
		grid-area: foot;
		display: flex;
		align-items: center;
		gap: 0.85rem;
		width: 100%;
		padding-top: 0.7rem;
		border-top: 1px solid var(--border-subtle);
	}
	.car-row__metrics { flex: 1; min-width: 0; }
	.car-row__actions { margin-left: auto; }
	.cost-mini { flex-direction: row; align-items: center; min-width: 0; }
	.cost-mini__bar { flex: 1; }
	.car-row__chevron { display: none; }
}

/* Calm the legacy row hover (no jiggle/shadow). */
.entry-table tbody tr:hover {
	transform: none;
	box-shadow: none;
	background: var(--tint-xs);
}
.entry-table thead th {
	font-family: var(--font-mono);
	letter-spacing: 0.12em;
	background: var(--surface-sunken);
}

/* Horizontal scroll instead of clipping on narrow screens. */
.table-scroll { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 640px) {
	.table-scroll > .entry-table { min-width: 480px; }
	.summary-row { padding-inline: 0; }
	/* §99 #13: the journal's 480px floor pushed Art and – worse – Betrag off a
	   390px screen, so the money column of the money table sat behind a
	   horizontal scroll while Datum and km held the visible width. Shed columns
	   by how load-bearing they are instead: the odometer first (recoverable by
	   opening the entry), then Art on the narrowest phones, so Datum ·
	   Beschreibung · Betrag always survive. Scoped to the journal: .entry-table
	   also dresses the Energie/Wartung/Fixkosten tables, whose 2nd column is
	   something else entirely.
	   Stopgap, not the destination – the real answer is §63's stacked-card
	   treatment (see .recent-cards), which keeps every field on a phone. */
	.table-scroll > .entry-table--journal { min-width: 0; }
	.entry-table--journal .th-km,
	.entry-table--journal .entry-km { display: none; }
}
@media (max-width: 34rem) {
	.entry-table--journal .th-art,
	.entry-table--journal .entry-type { display: none; }
}

/* §63 – "Letzte Einträge": table on desktop, stacked activity cards on phones.
   The 5-column table wraps the car name to 4 lines at phone widths; the cards
   lead with vehicle + amount, then a muted date · category · description line. */
.recent-cards { display: none; }
@media (max-width: 640px) {
	.recent-table { display: none; }
	.recent-cards {
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
		list-style: none;
		margin: 0;
		padding: 0;
	}
	.recent-card {
		border: 1px solid var(--border-subtle);
		border-radius: var(--radius-control);
		background: var(--surface-raised);
	}
	.recent-card__link {
		display: flex;
		flex-direction: column;
		gap: 0.3rem;
		padding: 0.7rem 0.85rem;
		text-decoration: none;
		color: inherit;
	}
	.recent-card__top {
		display: flex;
		align-items: baseline;
		justify-content: space-between;
		gap: 0.75rem;
	}
	.recent-card__car {
		min-width: 0;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		font-family: var(--font-serif);
		font-weight: 540;
		font-size: 14px;
		letter-spacing: -0.01em;
		color: var(--ink);
	}
	.recent-card__amount {
		flex: none;
		font-family: var(--font-mono);
		font-variant-numeric: tabular-nums slashed-zero;
		font-size: 13px;
		color: var(--text-2);
	}
	.recent-card__meta {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 0.3rem 0.55rem;
		font-family: var(--font-mono);
		font-size: 11px;
		color: var(--text-4);
	}
	.recent-card__desc { color: var(--text-3); }
}

/* ==========================================================================
   Modals / forms – Editorial × Instrument polish (shared by car form,
   entry-detail modal, TCO wizard, import, OCR, settings)
   ========================================================================== */

.form-modal-content { border-radius: var(--radius-card); }
.form-header { background: var(--surface-sunken); }
.form-title {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 540;
	font-size: clamp(20px, 2.4vw, 26px);
	letter-spacing: -0.015em;
}
.form-section-title {
	font-family: var(--font-mono);
	font-weight: 600;
	letter-spacing: 0.16em;
}
.form-input {
	border-radius: var(--radius-control);
	background: var(--surface-sunken);
}
.form-input:hover { background: var(--surface-sunken); border-color: var(--tint-lg); }
.form-input:focus {
	background: var(--surface-raised);
	box-shadow: 0 0 0 3px var(--accent-glow);
}
.settings-profile-hint {
	color: var(--text-3);
	background: var(--accent-soft);
	border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
	border-radius: var(--radius-control);
}
/* ── a11y utilities + small-text legibility ─────────────────────────────── */
.visually-hidden {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap; border: 0;
}.cmp-legend__lbl { font-size: 10px; }

/* §74 Inc 4 – the visible-collector identity marker (ui.CollectorMark). A discreet
   verified-status mark shared across the community profile, public garage, feed and
   trophy case; understated by design so it reads as status, not gamification. */
.collector-mark {
	display: inline-flex; align-items: center; gap: .32rem; vertical-align: middle;
	padding: .16rem .5rem; border-radius: var(--radius-pill);
	font-size: .7rem; font-weight: 600; letter-spacing: .02em; line-height: 1;
	color: var(--accent); background: var(--accent-soft);
	border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
}
.collector-mark .icon { width: .9em; height: .9em; color: var(--accent); }
.collector-mark--icon { padding: .2rem; border-radius: 50%; }
.collector-mark__label { text-transform: uppercase; letter-spacing: .1em; }

/* ==========================================================================
   §13 Cockpit app-shell – sidebar + top bar + dashboard grid.
   Layout only; reuses the Editorial × Instrument tokens/primitives.
   ========================================================================== */

body { padding: 0; }

.app-shell {
	display: grid;
	grid-template-columns: minmax(214px, var(--sidebar-w)) minmax(0, 1fr);
	min-height: 100vh;
}

/* ── Sidebar ─────────────────────────────────────────────────────────────── */
.sidebar {
	position: sticky;
	top: 0;
	align-self: start;
	height: 100vh;
	/* Held as its own view-transition group so the brand/nav don't flicker on
	   navigation – only the contextual subnav fades (see app-sidebar rules). */
	view-transition-name: app-sidebar;
	/* Scroll within the rail when the expanded subnav pushes the nav past the
	   viewport height (short laptops); the brand stays put via sticky. */
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	gap: 1.4rem;
	padding: clamp(1.1rem, 1.6vw, 1.5rem) clamp(0.85rem, 1.1vw, 1.15rem);
	/* Tighter bottom padding: the privacy chip sat too high above the base now
	   that the footer plinth anchors the page bottom – let it settle lower. */
	padding-bottom: 0.8rem;
	background: var(--surface-raised);
	border-right: 1px solid var(--border-subtle);
	overflow-y: auto;
}

.sidebar__brand {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: 0.3rem 0.55rem 0.2rem;
	text-decoration: none;
	container-type: inline-size; /* size .sidebar__tagline against the rail width (cqi) */
}
.sidebar__wordmark {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	/* Scale with the brand container (which sets container-type: inline-size),
	   like .sidebar__tagline does – at the 260px rail this resolves to ~60px, but
	   it scales down (never overflows) if the rail narrows. 28cqi ≈ 60px against
	   the brand's ~213px content box (padding-excluded). */
	font-size: clamp(38px, 28cqi, 62px);
	letter-spacing: -0.015em;
	line-height: 1;
	color: var(--ink);
}
.sidebar__tagline {
	font-family: var(--font-serif);
	font-style: italic;
	/* Grow with the rail width but stay on one line. Measured against the
	   real Playfair-italic metrics: the longest language (FR "Le carnet
	   d'entretien qui compte") fits up to ~14.7px at the 260px rail, and
	   its cqi limit is 7.13 -- so 7cqi + a 14px ceiling keep a margin.
	   ellipsis is a safety net for future strings, not expected to trip. */
	font-size: clamp(11px, 7cqi, 14px);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	font-weight: 500;
	letter-spacing: 0;
	color: var(--text-4);
}

.sidebar__nav { display: flex; flex-direction: column; gap: 2px; }
.side-link {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	padding: 0.5rem 0.7rem;
	border-radius: var(--radius-control);
	color: var(--text-2);
	text-decoration: none;
	font-weight: 500;
	font-size: 13.5px;
	transition: background var(--timing-fast) var(--ease-out), color var(--timing-fast) var(--ease-out);
}
.side-link .icon { width: 1.15em; height: 1.15em; color: var(--text-4); flex: none; }
.side-link:hover { background: var(--tint-sm); color: var(--ink); }
.side-link:hover .icon { color: var(--text-2); }
.side-link--active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.side-link--active .icon { color: var(--accent); }
.side-link__label { min-width: 0; }

/* §53 public-garage link: a "leaves the app" nav entry. A hairline above it sets
   it apart from the in-app destinations, and the trailing external-link glyph
   (pushed to the right, muted and smaller) signals it opens in a new tab. */
.side-link--external { margin-top: 0.35rem; padding-top: 0.7rem; border-top: 1px solid var(--border-subtle); }
.side-link--external .icon:last-child { margin-left: auto; width: 0.95em; height: 0.95em; color: var(--text-4); }
.side-link--external:hover .icon:last-child { color: var(--text-2); }

/* §20 layout prototype: contextual per-car subnav nested under the Fahrzeuge
   nav item (the car-detail sections live in the sidebar on desktop). */
.side-subnav {
	display: flex;
	flex-direction: column;
	gap: 1px;
	margin: 0.1rem 0 0.4rem 1.35rem;
	padding-left: 0.6rem;
	border-left: 1px solid var(--border-subtle);
}
.side-subnav__group {
	font-size: 10px;
	letter-spacing: 0.07em;
	text-transform: uppercase;
	color: var(--text-4);
	margin: 0.5rem 0 0.1rem 0.55rem;
}
.side-subnav__group:first-child { margin-top: 0.15rem; }
.side-sublink {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	padding: 0.38rem 0.55rem;
	border-radius: var(--radius-control);
	color: var(--text-2);
	text-decoration: none;
	font-weight: 500;
	font-size: 12.5px;
	transition: background var(--timing-fast) var(--ease-out), color var(--timing-fast) var(--ease-out);
}
.side-sublink .icon { width: 1em; height: 1em; color: var(--text-4); flex: none; }
.side-sublink:hover { background: var(--tint-sm); color: var(--ink); }
.side-sublink:hover .icon { color: var(--text-2); }
.side-sublink--active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.side-sublink--active .icon { color: var(--accent); }
.side-sublink__label { min-width: 0; flex: 1; }
.side-sublink__count {
	margin-left: auto;
	font-size: 11px;
	color: var(--text-4);
	font-variant-numeric: tabular-nums;
}
/* On desktop the section nav lives in the sidebar subnav, so hide the in-page
   car-detail tab strip and let the content span full width; below 900px the
   sidebar is hidden and the strip takes over. (The settings-rail equivalent lives
   next to its own base rule so it wins on source order – see .settings-shell.) */
@media (min-width: 901px) {
	.car-tabs { display: none; }
}

.sidebar__foot { margin-top: auto; display: flex; flex-direction: column; gap: 0.9rem; }
.sidebar__privacy {
	display: flex;
	gap: 0.55rem;
	align-items: flex-start;
	padding: 0.7rem 0.65rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
}
.sidebar__privacy .icon { color: var(--accent); width: 1.05em; height: 1.05em; margin-top: 1px; flex: none; }
.sidebar__privacy-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sidebar__privacy-text strong { font-size: 12px; color: var(--ink); font-weight: 600; }
.sidebar__privacy-sub { font-size: 10.5px; color: var(--text-4); }

/* ── Main column + top bar ───────────────────────────────────────────────── */
.shell-main { min-width: 0; display: flex; flex-direction: column; min-height: 100vh; }

.topbar {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 1rem 1.5rem;
	flex-wrap: wrap;
	padding: clamp(1.1rem, 2vw, 1.9rem) clamp(1.1rem, 2.4vw, 2.2rem) 0;
}
.topbar__eyebrow {
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--text-4);
	margin: 0 0 0.35rem;
}
.topbar__greeting {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 500;
	font-size: clamp(24px, 3vw, 34px);
	letter-spacing: -0.015em;
	line-height: 1.05;
	color: var(--ink);
	margin: 0;
}
.topbar__sub { margin: 0.4rem 0 0; color: var(--text-3); font-size: 14px; }
.topbar__title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 520;
	font-size: clamp(22px, 2.6vw, 28px);
	letter-spacing: -0.012em;
	color: var(--ink);
	margin: 0;
}
.topbar__actions { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; }
.avatar {
	display: inline-grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 50%;
	background: var(--accent-soft);
	color: var(--accent);
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: 13px;
	letter-spacing: 0.03em;
	flex: none;
}

#carlist { flex: 1; padding: clamp(1.1rem, 2.4vw, 2.2rem); }
.shell-main > .app-footer { padding-inline: clamp(1.1rem, 2.4vw, 2.2rem); }

/* ── Cockpit dashboard grid ──────────────────────────────────────────────── */
.cockpit {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(288px, 340px);
	gap: clamp(1rem, 2vw, 1.5rem);
	align-items: start;
}
.cockpit__main { display: flex; flex-direction: column; gap: clamp(1rem, 2vw, 1.5rem); min-width: 0; }
.cockpit__rail { display: flex; flex-direction: column; gap: clamp(1rem, 2vw, 1.5rem); min-width: 0; position: sticky; top: 1rem; }

.cockpit__charts {
	display: grid;
	grid-template-columns: minmax(0, 1.7fr) minmax(240px, 1fr);
	gap: clamp(1rem, 2vw, 1.5rem);
	align-items: stretch; /* both chart panels share the taller one's height */
}
/* Let each panel fill its (now equal-height) grid cell and stack its content. */
.cockpit__charts > .panel { display: flex; flex-direction: column; }
/* Solo modifier: the cockpit keeps a single full-width trend hero (the deep
   charts moved to Auswertungen), so the two-column chart grid collapses to one. */
.cockpit__charts--solo { grid-template-columns: 1fr; }
.cockpit-trend__more { align-self: flex-end; margin-top: 0.75rem; }

/* ── Overview summary cards (section previews) ───────────────────────────── */
/* One card per section (Garage / Vergleich / Dokumente), same auto-fit
   discipline as the KPI strip so it collapses cleanly on narrow screens. */
.cockpit-summary {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	gap: clamp(0.6rem, 1.4vw, 1rem);
}
.cockpit-card {
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
	padding: clamp(0.9rem, 1.8vw, 1.15rem) clamp(1rem, 2vw, 1.2rem);
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	text-decoration: none;
	color: inherit;
	transition: border-color var(--timing-base) var(--ease-out);
}
.cockpit-card:hover { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
.cockpit-card__head { display: flex; align-items: center; gap: 0.5rem; }
.cockpit-card__label {
	flex: 1;
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--text-4);
}
.cockpit-card__head > .icon { color: var(--text-5); transition: color var(--timing-base) var(--ease-out), transform var(--timing-base) var(--ease-out); }
.cockpit-card:hover .cockpit-card__head > .icon { color: var(--accent); transform: translateX(3px); }
.cockpit-card__value {
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: clamp(19px, 2.4vw, 26px);
	line-height: 1.05;
	letter-spacing: -0.01em;
	color: var(--ink);
	font-variant-numeric: tabular-nums slashed-zero;
}
.cockpit-card__unit { font-size: 0.5em; font-weight: 600; color: var(--text-4); margin-left: 0.2em; letter-spacing: 0.04em; }
.cockpit-card__sub {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.3rem;
	font-size: 12px;
	color: var(--text-3);
	font-variant-numeric: tabular-nums;
}
.cockpit-card__sub > .icon { width: 0.95em; height: 0.95em; color: var(--clr-service); flex: none; }

/* ── KPI strip ───────────────────────────────────────────────────────────── */
.kpi-strip {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
	gap: clamp(0.6rem, 1.4vw, 1rem);
}
.kpi {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: clamp(0.9rem, 1.8vw, 1.2rem) clamp(1rem, 2vw, 1.25rem);
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	text-decoration: none;
	color: inherit;
}
a.kpi--link { transition: border-color var(--timing-base) var(--ease-out); }
a.kpi--link:hover { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
.kpi__label {
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--text-4);
	line-height: 1.4;
}
.kpi__value {
	font-family: var(--font-mono);
	font-weight: 600;
	font-size: clamp(19px, 2.4vw, 26px);
	line-height: 1.05;
	letter-spacing: -0.01em;
	color: var(--ink);
	font-variant-numeric: tabular-nums slashed-zero;
}
.kpi__unit { font-size: 0.5em; font-weight: 600; color: var(--text-4); margin-left: 0.3em; letter-spacing: 0.04em; }
.kpi-delta {
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	font-variant-numeric: tabular-nums slashed-zero;
	display: flex;
	align-items: baseline;
	gap: 0.4rem;
	flex-wrap: wrap;
}
.kpi-delta__note { color: var(--text-4); font-weight: 500; }
.kpi-delta--good { color: var(--clr-sell); }
.kpi-delta--bad { color: var(--clr-repair); }
.kpi-delta--neutral { color: var(--text-3); }
.kpi-delta--warn { color: var(--clr-service); }
/* Cumulative line sparkline pinned to the tile bottom (aligned across tiles). */
.kpi-spark { margin-top: auto; padding-top: 0.5rem; height: 30px; }
/* Reveal the line + its endpoint dot with a left-to-right wipe. The settled state
   is inset(0) – geometry identical to the un-animated spark, so nothing looks
   different once it lands. The global prefers-reduced-motion block collapses it. */
@keyframes spark-wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.kpi-spark__svg {
	width: 100%; height: 100%; display: block; opacity: 0.85;
	animation: spark-wipe var(--timing-slower) var(--ease-out) both;
}
/* Hauptfahrzeug bar spark grows up from the baseline. */
@keyframes spark-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.haupt-spark rect {
	transform-box: fill-box;
	transform-origin: bottom;
	animation: spark-grow var(--timing-slow) var(--ease-out) both;
}
/* Prior-period comparison curve (e.g. last year): a muted second line behind the
   live series on every cockpit spark. Colour/opacity are inlined on the element;
   this just fades it in so it doesn't pop while the bars grow / the line wipes. */
@keyframes spark-base-in { from { opacity: 0; } to { opacity: 1; } }
.spark__base { animation: spark-base-in var(--timing-slower) var(--ease-out) both; }

/* ── Year picker ─────────────────────────────────────────────────────────── */
.year-picker {
	font-family: var(--font-mono);
	font-size: 12px;
	font-weight: 600;
	color: var(--text-2);
	padding: 0.4rem 0.7rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-pill);
	cursor: pointer;
}
.haupt__name {
	font-family: var(--font-serif);
	font-weight: 540;
	font-size: 17px;
	letter-spacing: -0.01em;
	color: var(--ink);
	margin: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.activity-empty { display: flex; align-items: center; gap: 0.85rem; padding: 0.35rem 0; }

/* Distribution donut sits in a narrow column: stack chart over a full-width
   legend so long category labels never overflow the panel. */
/* Drop the tinted box + wide gap: the donut sits directly in the panel like the
   bar chart, with only a small gap to its legend. */
.cockpit__charts .cost-pie-container { flex: 1; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; margin: 0; padding: 0; background: none; border-radius: 0; }
/* Two concentric rings need more room than the single per-car pie. */
.cockpit__charts .cost-pie-chart { width: 168px; height: 168px; }
.cockpit__charts .cost-pie-legend { width: 100%; grid-template-columns: 1fr; gap: 0.4rem; }
.legend-amount {
	font-family: var(--font-mono);
	font-weight: 600;
	color: var(--text-2);
	font-variant-numeric: tabular-nums slashed-zero;
	white-space: nowrap;
}
.cost-pie-legend .legend-value { min-width: 3ch; text-align: right; }

/* ── Hauptfahrzeug rail card (enlarged, vertical) ────────────────────────── */
.haupt { display: flex; flex-direction: column; gap: 1rem; position: relative; transition: border-color var(--timing-base) var(--ease-out); }
.haupt:hover { border-color: color-mix(in oklab, var(--accent) 35%, transparent); }
.haupt > .eyebrow { margin: 0; }

/* The whole card is the affordance: a stretched link over the car name covers
   the panel. Interactive children (onboarding nudge CTA) are raised above it. */
.haupt__link { color: inherit; text-decoration: none; }
.haupt__link:hover { text-decoration: none; }
.haupt__link::after { content: ""; position: absolute; inset: 0; }
.haupt .onboarding-nudge { position: relative; z-index: 1; }
.haupt__media-lg { border-radius: var(--radius-control); overflow: hidden; background: var(--surface-sunken); }
.haupt__img-lg { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.haupt__img-lg--ph { display: grid; place-items: center; aspect-ratio: 16 / 10; color: var(--text-4); }
.haupt__head { display: flex; flex-direction: column; gap: 0.15rem; }
.haupt__name {
	font-family: var(--font-serif);
	font-weight: 560;
	font-size: 22px;
	letter-spacing: -0.015em;
	line-height: 1.12;
	color: var(--ink);
	margin: 0;
}
.haupt__submodel { margin: 0; font-size: 13px; color: var(--text-3); }
.haupt__vin { margin: 0; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: var(--text-4); }

.haupt__status {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	padding: 0.7rem 0.8rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	text-decoration: none;
	color: inherit;
	transition: border-color var(--timing-base) var(--ease-out);
}
.haupt__status-body { flex: 1; min-width: 0; }
.haupt__status-title { font-weight: 600; font-size: 13.5px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.haupt__status-sub { font-family: var(--font-mono); font-size: 11px; color: var(--text-4); }
.haupt__status > .icon { color: var(--text-4); flex: none; }

.haupt__specs { margin: 0; display: flex; flex-direction: column; }
.haupt__spec { display: flex; justify-content: space-between; gap: 1rem; padding: 0.5rem 0; border-bottom: 1px solid var(--border-subtle); }
.haupt__spec:last-child { border-bottom: 0; }
.haupt__spec dt { font-size: 12.5px; color: var(--text-3); }
.haupt__spec dd {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 12.5px;
	font-weight: 600;
	color: var(--ink);
	font-variant-numeric: tabular-nums slashed-zero;
	text-align: right;
}

.haupt__cost { border-top: 1px solid var(--border-subtle); padding-top: 0.9rem; display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; }
.haupt__cost-head { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.haupt-spark-wrap { width: 132px; height: 40px; flex: none; }
.haupt-spark { width: 100%; height: 100%; display: block; }

/* Profile rename affordance on the active profile pill. */
.profile-switcher-active { display: inline-flex; align-items: center; gap: 0.35rem; }
.profile-switcher-rename {
	display: inline-grid;
	place-items: center;
	padding: 2px;
	background: transparent;
	border: 0;
	color: var(--text-4);
	cursor: pointer;
	border-radius: var(--radius-control);
}
.profile-switcher-rename .icon { width: 0.85em; height: 0.85em; }
.profile-switcher-rename:hover { color: var(--accent); }

/* Top-bar year picker – a page-level control styled to match .btn--secondary
   (same height, radius, colours). Native appearance is dropped for a custom
   chevron so the padding is even and predictable across browsers (not a pill). */
.year-picker--topbar {
	appearance: none;
	-webkit-appearance: none;
	font-family: var(--font-mono, inherit);
	font-size: 0.8rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.01em;
	line-height: 1.2;
	padding: 0.5rem 1.85rem 0.5rem 0.85rem;
	border-radius: var(--radius-control);
	color: var(--accent);
	background-color: var(--accent-soft);
	border: 1px solid transparent;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23808080' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.6rem center;
	background-size: 13px;
	cursor: pointer;
}
.year-picker--topbar:hover { background-color: color-mix(in oklab, var(--accent-soft) 82%, var(--accent)); }

/* Avatar dropdown (profile chip → app-level backup actions). The summary IS the
   circular avatar: force grid centering (over the UA `list-item`), drop the
   disclosure marker, and keep it NEUTRAL grey so it doesn't clash with the green
   primary button beside it. */
/* Reset the legacy generic `details`/`summary` accordion styling (border-top,
   scrim background, 22px/26px padding) that would otherwise deform the avatar. */
.avatar-menu { position: relative; display: inline-flex; align-items: center; flex: none; border-top: 0; }
/* The summary is a bare, marker-less trigger; the circular avatar is an inner
   <span> so its shape/centering can't be disturbed by the disclosure marker. */
.avatar-menu > summary,
.avatar-menu > summary:hover,
.avatar-menu[open] > summary {
	display: flex;
	list-style: none;
	cursor: pointer;
	padding: 0;
	background: transparent;
	transition: none;
}
.avatar-menu > summary::-webkit-details-marker { display: none; }
.avatar-menu > summary::marker { content: ""; }
.avatar-menu > summary:focus-visible { outline: none; }
.avatar-menu > summary:focus-visible .avatar { outline: 2px solid var(--accent); outline-offset: 2px; }
.avatar-menu .avatar { transition: filter var(--timing-base) var(--ease-out); }
.avatar-menu > summary:hover .avatar { filter: brightness(0.96); }
.avatar-menu__panel {
	position: absolute;
	right: 0;
	top: calc(100% + 8px);
	z-index: 70;
	min-width: 220px;
	padding: 0.4rem;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	box-shadow: 0 12px 32px var(--scrim-sm);
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.avatar-menu__name {
	padding: 0.45rem 0.6rem 0.5rem;
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--text-4);
	border-bottom: 1px solid var(--border-subtle);
	margin-bottom: 0.2rem;
}
.avatar-menu__item {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	width: 100%;
	padding: 0.55rem 0.6rem;
	border: 0;
	background: transparent;
	color: var(--text-2);
	font: inherit;
	font-size: 13.5px;
	text-align: left;
	text-decoration: none;
	border-radius: var(--radius-control);
	cursor: pointer;
}
.avatar-menu__item .icon { width: 1.05em; height: 1.05em; color: var(--text-4); flex: none; }
.avatar-menu__item:hover { background: var(--tint-sm); color: var(--ink); }
.avatar-menu__item:hover .icon { color: var(--text-2); }
/* forms wrap the switch buttons but must not disturb the flex column */
.avatar-menu__form { display: contents; }
.avatar-menu__divider { height: 1px; background: var(--border-subtle); margin: 0.3rem 0; }
.avatar-menu__section {
	padding: 0.5rem 0.6rem 0.25rem;
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--text-4);
}
.avatar-menu__langs { display: flex; gap: 4px; padding: 0 0.6rem 0.3rem; }
.avatar-menu__lang {
	flex: 1;
	padding: 0.35rem 0;
	border: 1px solid var(--border-subtle);
	background: transparent;
	color: var(--text-3);
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.06em;
	border-radius: var(--radius-control);
	cursor: pointer;
	transition: background var(--timing-base) var(--ease-out), color var(--timing-base) var(--ease-out);
}
.avatar-menu__lang:hover { background: var(--tint-sm); color: var(--ink); }
.avatar-menu__lang--active {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--accent-ink);
	cursor: default;
}

/* ── §44 feedback widget ──────────────────────────────────────────────────
   A small fixed edge tab opens a centered .form-modal <dialog> -- the same
   overlay every other modal in the app uses (pop-in + backdrop blur), just
   narrower and a bit more intimate than the multi-tab car-edit form. */
/* §44 – feedback trigger lives inside the sidebar foot (above the privacy chip),
   a full-width soft-accent button rather than a fixed edge-tab: over the sidebar
   a fixed tab covered the nav, and outside it read as detached. On mobile the
   sidebar is hidden and the More sheet carries its own feedback item. */
.sidebar__feedback {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	width: 100%;
	padding: 0.55rem 0.7rem;
	border: 1px solid color-mix(in oklab, var(--accent) 28%, transparent);
	border-radius: var(--radius-control);
	background: var(--accent-soft);
	color: var(--accent);
	cursor: pointer;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	transition: background var(--timing-fast) var(--ease-out), border-color var(--timing-fast) var(--ease-out);
}
.sidebar__feedback .icon { width: 1.05em; height: 1.05em; flex: none; }
.sidebar__feedback:hover {
	background: color-mix(in oklab, var(--accent) 15%, var(--surface-raised));
	border-color: color-mix(in oklab, var(--accent) 45%, transparent);
}

.feedback-modal { max-width: 440px; }
.feedback-modal-body {
	padding: 0.5rem 2rem 2rem;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 0.25rem;
}
.feedback-modal-icon {
	display: inline-grid;
	place-items: center;
	width: 3.5rem;
	height: 3.5rem;
	margin-bottom: 0.5rem;
	border-radius: 50%;
	color: var(--accent);
	background: var(--accent-soft);
}
.feedback-modal-icon .icon { font-size: 1.6rem; stroke-width: 1.6; }
.feedback-modal-intro {
	color: var(--text-2);
	font-size: 0.9rem;
	line-height: 1.5;
	margin: 0 0 1rem;
	max-width: 34ch;
}
.feedback-modal-body > div { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 0.75rem; }
.feedback-modal-textarea,
.feedback-modal-body input[type="email"] { width: 100%; }
.feedback-modal-textarea { resize: vertical; min-height: 7rem; text-align: left; }
.feedback-modal-body .form-actions { width: 100%; justify-content: center; padding-top: 0.25rem; margin-top: 0; }
.feedback-modal-thanks { padding: 0.5rem 0 1rem; }
.feedback-modal-thanks p { color: var(--text-2); font-size: 0.95rem; }
/* §44 local (self-hosted) contact variant: stacked mailto / issue links in
   place of the submission form. */
.feedback-contact-actions { width: 100%; display: flex; flex-direction: column; gap: 0.5rem; }
.feedback-contact-actions .btn { width: 100%; justify-content: center; gap: 0.5rem; }
.feedback-contact-actions .icon { width: 1.05em; height: 1.05em; }

/* ── Cockpit responsive ──────────────────────────────────────────────────── */
@media (max-width: 1080px) {
	.cockpit { grid-template-columns: 1fr; }
	.cockpit__rail { position: static; }
	.cockpit__charts { grid-template-columns: 1fr; }
}

/* At/below the §63 mobile-chrome breakpoint (≤900px, tablet portrait and down)
   the desktop Sidebar is hidden (see the mobile chrome block below), so the
   shell is a single content column with tighter padding. The old horizontal
   sidebar-strip collapse that used to live here is gone – tablet portrait now
   gets the bottom-bar chrome, not a stacked masthead. */
@media (max-width: 900px) {
	.app-shell { grid-template-columns: 1fr; }
	.topbar { padding: 1.2rem 1rem 0; }
	#carlist { padding: 1.1rem 1rem; }
	.shell-main > .app-footer { padding-inline: 1rem; }
}

/* ==========================================================================
   §6 Auth pages – login / signup / forgot / reset / message
   Chrome-less, shell-less pages (reached before any tenant is resolved): a
   two-panel masthead with the wordmark on an accent field (left) and the form
   on paper (right). Collapses to a single column with a slim brand header
   below ~820px. Uses only design tokens, so it flips light/dark for free.
   ========================================================================== */
.auth-body {
	margin: 0;
	padding: 0;
	min-height: 100dvh;
	display: grid;
	grid-template-columns: 1.05fr 1fr;
}

/* ── Brand panel (left) ─────────────────────────────────────────────────── */
.auth-brand {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: clamp(2.5rem, 6vw, 5rem);
	color: var(--accent-ink);
	background:
		radial-gradient(120% 90% at 12% 0%, color-mix(in oklab, #fff 16%, transparent) 0%, transparent 55%),
		linear-gradient(155deg, var(--accent) 0%, color-mix(in oklab, var(--accent) 70%, #000) 100%);
}
/* Oversized faint serif glyph, purely decorative. */
.auth-brand::after {
	content: "L";
	position: absolute;
	right: -0.12em;
	bottom: -0.3em;
	font-family: var(--font-serif);
	font-weight: 600;
	font-size: clamp(20rem, 34vw, 34rem);
	line-height: 1;
	color: color-mix(in oklab, var(--accent-ink) 9%, transparent);
	pointer-events: none;
	user-select: none;
}
.auth-brand__inner {
	position: relative;
	z-index: 1;
	max-width: 30rem;
}
.auth-brand__wordmark {
	display: block;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	font-size: clamp(3.25rem, 6vw, 4.75rem);
	letter-spacing: -0.02em;
	line-height: 0.95;
	font-variant-ligatures: common-ligatures discretionary-ligatures contextual;
}
/* The wordmark links back to the marketing site; keep it looking like the
   wordmark, not a default link. */
a.auth-brand__wordmark { color: inherit; text-decoration: none; width: max-content; transition: opacity 0.15s ease; }
a.auth-brand__wordmark:hover { opacity: 0.85; }
.auth-brand__tagline {
	display: block;
	margin-top: 0.95rem;
	font-family: var(--font-serif);
	font-style: italic;
	font-size: 1.05rem;
	font-weight: 500;
	letter-spacing: 0;
	color: color-mix(in oklab, var(--accent-ink) 74%, transparent);
}
.auth-brand__lead {
	margin: 2.25rem 0 0;
	font-family: var(--font-serif);
	font-style: italic;
	font-size: clamp(1.25rem, 2vw, 1.6rem);
	line-height: 1.35;
	max-width: 24ch;
	color: color-mix(in oklab, var(--accent-ink) 94%, transparent);
}
.auth-brand__points {
	list-style: none;
	margin: 2rem 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
}
.auth-brand__points li {
	position: relative;
	padding-left: 1.5rem;
	font-size: 0.9rem;
	line-height: 1.4;
	color: color-mix(in oklab, var(--accent-ink) 84%, transparent);
}
.auth-brand__points li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.5em;
	width: 0.45rem;
	height: 0.45rem;
	border-radius: 50%;
	background: currentColor;
	opacity: 0.5;
}

/* ── Form panel (right) ─────────────────────────────────────────────────── */
.auth-main {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	gap: 2.5rem;
	padding: clamp(2rem, 5vw, 4rem) clamp(1.25rem, 4vw, 3rem);
	background: var(--surface);
}
.auth-card {
	width: 100%;
	max-width: 24rem;
	animation: fadeIn var(--timing-slow) var(--ease-out) both;
}
.auth-card__head { margin-bottom: 1.75rem; }
.auth-card__title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	font-size: 2rem;
	letter-spacing: -0.01em;
	line-height: 1.1;
	color: var(--ink);
}
.auth-card__sub {
	margin-top: 0.5rem;
	font-size: 0.9rem;
	line-height: 1.45;
	color: var(--text-3);
}

.auth-form { display: flex; flex-direction: column; gap: 1.1rem; }
.auth-field { display: flex; flex-direction: column; gap: 0.4rem; }
.auth-label {
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.02em;
	color: var(--text-2);
}
.auth-input {
	width: 100%;
	padding: 0.7rem 0.9rem;
	font: inherit;
	font-size: 0.95rem;
	color: var(--text);
	background: var(--surface-raised);
	border: 1px solid var(--border);
	border-radius: var(--radius-control);
	transition: border-color var(--timing-base) var(--ease-out),
	            box-shadow var(--timing-base) var(--ease-out),
	            background var(--timing-base) var(--ease-out);
}
.auth-input::placeholder { color: var(--text-4); }
.auth-input:hover { border-color: var(--tint-lg); }
.auth-input:focus {
	outline: none;
	border-color: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-glow);
}
.auth-submit { margin-top: 0.4rem; }

.auth-divider {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	margin: 1.4rem 0;
	color: var(--text-4);
	font-size: 0.7rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}
.auth-divider::before,
.auth-divider::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--border-subtle);
}
.auth-passkey { gap: 0.5rem; }
.auth-passkey svg { flex: none; }

.auth-alert {
	margin-bottom: 1.25rem;
	padding: 0.7rem 0.9rem;
	border-radius: var(--radius-control);
	border: 1px solid color-mix(in oklab, var(--critical) 42%, transparent);
	background: color-mix(in oklab, var(--critical) 10%, transparent);
	color: var(--critical);
	font-size: 0.85rem;
	line-height: 1.4;
}

.auth-msg {
	font-size: 0.95rem;
	line-height: 1.55;
	color: var(--text-2);
	margin-bottom: 1.3rem;
}

/* Section heading for the §85 claim "what you'll receive" list. A proper
   subheading (the shared .auth-label it first borrowed is a tiny, margin-less
   form-field label). */
.claim-receive-head {
	margin: 1.6rem 0 0.7rem;
	font-size: 0.95rem;
	font-weight: 600;
	color: var(--text-1);
}

/* Claim action buttons: a stacked group (confirm, or sign-up/sign-in, or the
   buyback merge/separate choice) set off from the content above with a gap
   between the buttons – some live inside their own POST <form>, so space the
   forms, not just the buttons. */
.claim-actions {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	margin-top: 1.5rem;
}
.claim-actions form { margin: 0; }

.auth-links {
	display: flex;
	flex-direction: column;
	gap: 0.55rem;
	margin-top: 1.6rem;
	padding-top: 1.4rem;
	border-top: 1px solid var(--border-subtle);
	font-size: 0.875rem;
}
.auth-links .auth-link {
	color: var(--text-3);
	text-decoration: none;
	transition: color var(--timing-fast) var(--ease-out);
}
.auth-links .auth-link:hover { color: var(--accent); }
.auth-links .auth-link--em { color: var(--text-2); font-weight: 500; }

@media (max-width: 820px) {
	.auth-body { grid-template-columns: 1fr; }
	.auth-brand {
		padding: clamp(1.75rem, 7vw, 2.75rem);
		justify-content: flex-start;
	}
	.auth-brand__lead,
	.auth-brand__points { display: none; }
	.auth-brand__inner { max-width: none; }
	.auth-brand::after { font-size: 15rem; bottom: -0.4em; }
	.auth-main { gap: 2rem; }
}

/* ==========================================================================
   Status pages – "off the logbook" (chrome-less full-screen states)
   Same token-only, chrome-less footing as the auth pages: a single full-bleed
   accent field with an exaggerated editorial masthead (an oversized Playfair
   code over a decorative ghost glyph) plus an instrument-style mono readout.
   Flips light/dark for free (tokens only). Two variants share these .sp-* rules:
     - 404 (base) – router.RenderNotFound, "?" glyph, brand-green field.
     - 5xx (.sp-body--error) – router.RenderServerError, "!" glyph, red field;
       mirrored self-contained by the Caddy proxy page (deploy/caddy/errors/).
   ========================================================================== */
.sp-body {
	margin: 0;
	min-height: 100dvh;
	display: grid;
	place-items: center;
	padding: clamp(2rem, 6vw, 5rem);
	position: relative;
	overflow: hidden;
	color: var(--accent-ink);
	background:
		radial-gradient(130% 100% at 15% 0%, color-mix(in oklab, #fff 18%, transparent) 0%, transparent 55%),
		linear-gradient(155deg, var(--accent) 0%, color-mix(in oklab, var(--accent) 62%, #000) 100%);
}
/* Oversized faint serif glyph, purely decorative – echoes the auth field's "L". */
.sp-body::after {
	content: "?";
	position: absolute;
	right: -0.06em;
	bottom: -0.32em;
	font-family: var(--font-serif);
	font-weight: 600;
	font-size: clamp(24rem, 44vw, 46rem);
	line-height: 1;
	color: color-mix(in oklab, var(--accent-ink) 8%, transparent);
	pointer-events: none;
	user-select: none;
}
/* Server-error (5xx) variant: same masthead, re-toned to a saturated red field
   with a "!" ghost glyph. It remaps the two accent tokens the rules above read,
   so every .sp-* child recolours for free; the field stays a deep red in both
   themes (an error is an error) with light ink. */
.sp-body--error {
	--accent: light-dark(#8a2b23, #6e211b);
	--accent-ink: #faf9f5;
}
.sp-body--error::after { content: "!"; }
.sp-inner {
	position: relative;
	z-index: 1;
	max-width: 42rem;
	text-align: center;
	animation: fadeIn var(--timing-slow) var(--ease-out) both;
}
.sp-eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 0.85rem;
	font-family: var(--font-mono);
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.3em;
	text-transform: uppercase;
	color: color-mix(in oklab, var(--accent-ink) 72%, transparent);
}
.sp-eyebrow::before,
.sp-eyebrow::after {
	content: "";
	width: 2rem;
	height: 1px;
	background: color-mix(in oklab, var(--accent-ink) 38%, transparent);
}
.sp-code {
	margin: 1.5rem 0 0;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	font-size: clamp(7rem, 27vw, 19rem);
	line-height: 0.92;
	letter-spacing: -0.045em;
	font-variant-ligatures: common-ligatures discretionary-ligatures contextual;
	text-shadow: 0 0 70px color-mix(in oklab, #000 24%, transparent);
}
.sp-lead {
	margin: clamp(1.9rem, 4vw, 3rem) 0 0;
	font-family: var(--font-serif);
	font-style: italic;
	font-weight: 500;
	font-size: clamp(1.4rem, 3.4vw, 2.15rem);
	line-height: 1.28;
	color: var(--accent-ink);
}
.sp-sub {
	margin: 0.95rem auto 0;
	max-width: 38ch;
	font-size: 0.98rem;
	line-height: 1.55;
	color: color-mix(in oklab, var(--accent-ink) 80%, transparent);
}
/* Instrument readout: the failed route / support reference on a mono "dashboard" strip. */
.sp-readout {
	margin: 1.9rem auto 0;
	display: inline-flex;
	align-items: center;
	gap: 0.7rem;
	max-width: 100%;
	padding: 0.5rem 0.95rem;
	border-radius: var(--radius-pill);
	border: 1px solid color-mix(in oklab, var(--accent-ink) 24%, transparent);
	background: color-mix(in oklab, #000 14%, transparent);
	font-family: var(--font-mono);
	font-size: 0.82rem;
	color: color-mix(in oklab, var(--accent-ink) 88%, transparent);
}
.sp-readout__lamp {
	flex: none;
	width: 0.55rem;
	height: 0.55rem;
	border-radius: 50%;
	background: var(--accent-ink);
	animation: spPulse 2.4s var(--ease-out) infinite;
}
.sp-readout__path {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	letter-spacing: 0.02em;
}
.sp-actions {
	margin-top: 2.4rem;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.8rem;
}
/* Paper-solid CTA tuned for the accent field (the token --primary would sink
   into it). */
.sp-btn--solid {
	background: var(--accent-ink);
	color: var(--accent);
	border-color: var(--accent-ink);
	font-weight: 600;
	box-shadow: 0 6px 22px color-mix(in oklab, #000 30%, transparent);
}
.sp-btn--solid:hover {
	transform: translateY(-1px);
	background: color-mix(in oklab, var(--accent-ink) 90%, #fff);
	box-shadow: 0 10px 28px color-mix(in oklab, #000 40%, transparent);
}
/* Secondary action on the field – outline of the paper ink, no fill. */
.sp-btn--outline {
	background: transparent;
	color: var(--accent-ink);
	border-color: color-mix(in oklab, var(--accent-ink) 55%, transparent);
	font-weight: 600;
}
.sp-btn--outline:hover {
	transform: translateY(-1px);
	border-color: var(--accent-ink);
	background: color-mix(in oklab, var(--accent-ink) 12%, transparent);
}

@keyframes spPulse {
	0%   { opacity: 1;    box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent-ink) 55%, transparent); }
	70%  { opacity: 0.5;  box-shadow: 0 0 0 0.5rem transparent; }
	100% { opacity: 1;    box-shadow: 0 0 0 0 transparent; }
}

@media (max-width: 620px) {
	.sp-body::after { font-size: 22rem; bottom: -0.2em; }
	.sp-actions { flex-direction: column; align-items: stretch; }
	.sp-actions .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
	.sp-inner { animation: none; }
	.sp-readout__lamp { animation: none; }
}

/* ── §36 Billing page ──────────────────────────────────────────────────────
   Shares the pre-tenant page shell (chrome-less, token-only) but is a
   post-login account surface -- so a single centered card widened for the
   plan/add-on rows, with a "remnant" of the auth brand field: the accent
   gradient + wordmark carried as a header band rather than a full panel. */
.bill-body {
	margin: 0;
	min-height: 100dvh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp(1.5rem, 5vw, 3.5rem) clamp(1rem, 4vw, 2rem);
	background: var(--surface);
}
.bill-card {
	width: 100%;
	max-width: 38rem;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	box-shadow: var(--shadow-lg);
	overflow: hidden;
	animation: fadeIn var(--timing-slow) var(--ease-out) both;
}
/* Accent remnant of the two-panel brand field, as a masthead band. */
.bill-head {
	position: relative;
	overflow: hidden;
	padding: clamp(1.75rem, 4vw, 2.5rem);
	color: var(--accent-ink);
	background:
		radial-gradient(120% 130% at 8% 0%, color-mix(in oklab, #fff 16%, transparent) 0%, transparent 55%),
		linear-gradient(155deg, var(--accent) 0%, color-mix(in oklab, var(--accent) 70%, #000) 100%);
}
.bill-head::after {
	content: "L";
	position: absolute;
	right: -0.05em;
	bottom: -0.42em;
	font-family: var(--font-serif);
	font-weight: 600;
	font-size: clamp(9rem, 22vw, 13rem);
	line-height: 1;
	color: color-mix(in oklab, var(--accent-ink) 10%, transparent);
	pointer-events: none;
	user-select: none;
}
.bill-head__inner { position: relative; z-index: 1; }
.bill-head__wordmark {
	display: block;
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	font-size: clamp(2rem, 5vw, 2.6rem);
	letter-spacing: -0.02em;
	line-height: 0.95;
}
.bill-head__tagline {
	display: block;
	margin-top: 0.5rem;
	font-family: var(--font-mono);
	font-size: 0.68rem;
	font-weight: 600;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: color-mix(in oklab, var(--accent-ink) 74%, transparent);
}
.bill-content {
	padding: clamp(1.5rem, 4vw, 2.25rem);
	display: flex;
	flex-direction: column;
	gap: 1.4rem;
}
.bill-summary {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	padding-bottom: 1.4rem;
	border-bottom: 1px solid var(--border-subtle);
}
.bill-summary__plan {
	font-family: var(--font-serif);
	font-weight: 600;
	font-size: 1.35rem;
	line-height: 1.15;
	color: var(--ink);
}
.bill-summary__meta { font-size: 0.875rem; color: var(--text-3); }

.bill-note {
	padding: 0.7rem 0.9rem;
	border-radius: var(--radius-control);
	border: 1px solid var(--border-subtle);
	background: var(--surface-sunken);
	color: var(--text-2);
	font-size: 0.85rem;
	line-height: 1.45;
}
.bill-note a { color: inherit; font-weight: 500; }
.bill-note--ok {
	border-color: color-mix(in oklab, var(--accent) 42%, transparent);
	background: var(--accent-soft);
	color: var(--text-1);
}
.bill-note--danger {
	border-color: color-mix(in oklab, var(--critical) 42%, transparent);
	background: color-mix(in oklab, var(--critical) 10%, transparent);
	color: var(--critical);
}

.bill-section__label {
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--text-4);
	margin-bottom: 0.75rem;
}

/* §80 payment-method row: brand-tinted card glyph + brand name + masked number. */
.bill-pm {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	padding: 0.7rem 0.9rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface-2);
}
.bill-pm__icon {
	font-size: 1.5rem; /* the sprite icon is sized in em */
	flex: none;
	color: var(--text-3); /* generic fallback tint; brand modifiers override below */
}
.bill-pm__card { flex: 1; display: flex; align-items: baseline; gap: 0.4rem; min-width: 0; }
.bill-pm__brand { font-weight: 600; color: var(--text); }
.bill-pm__text { color: var(--text-2); font-variant-numeric: tabular-nums; }
.bill-pm__action { flex: none; }
/* Brand tints – a card glyph in the scheme's colour, theme-safe via light-dark(). */
.bill-pm__icon--mastercard { color: light-dark(#eb5b00, #ff7a29); }
.bill-pm__icon--visa { color: light-dark(#1a1f71, #6d78ff); }
.bill-pm__icon--amex { color: light-dark(#016fd0, #4aa8ff); }
.bill-pm__icon--twint { color: light-dark(#111111, #f0f0f0); }
.bill-pm__icon--postfinance { color: light-dark(#a37a00, #ffcc00); }

/* §80 Inc 3: the subscription panel groups current plan + status + saved card +
   cancel into one card; the payment row flattens inside it (the panel is the card). */
.bill-panel {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	padding: 1.1rem 1.2rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface-2);
	margin-bottom: 1.5rem;
}
.bill-panel .bill-summary { padding-bottom: 1rem; }
.bill-panel .bill-pm { padding: 0; border: 0; background: none; }
.bill-panel .bill-action { margin-top: 0; }
.bill-panel__sublabel {
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--text-4);
	margin-bottom: -0.5rem;
}
.bill-note--action {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.8rem;
}
.bill-note--action .btn { flex: none; }

/* §80 Inc 3: once subscribed, the plan grid collapses into this disclosure. */
.bill-disclosure {
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	margin-bottom: 1.5rem;
}
.bill-disclosure__summary {
	cursor: pointer;
	padding: 0.85rem 1.1rem;
	font-weight: 600;
	color: var(--text-2);
	list-style: none;
	display: flex;
	align-items: center;
}
.bill-disclosure__summary::-webkit-details-marker { display: none; }
.bill-disclosure__summary::after {
	content: "\25be"; /* ▾ */
	margin-left: auto;
	color: var(--text-4);
	transition: transform 0.15s ease;
}
.bill-disclosure[open] .bill-disclosure__summary::after { transform: rotate(180deg); }
.bill-disclosure .bill-plans { padding: 0 1.1rem 1.1rem; }

.bill-rows { display: flex; flex-direction: column; gap: 0.6rem; }
.bill-row {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	margin: 0;
	padding: 0.8rem 1rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface);
}
.bill-row--current {
	border-color: color-mix(in oklab, var(--accent) 45%, transparent);
	background: var(--accent-soft);
}
.bill-row__name { flex: 1; font-size: 0.95rem; color: var(--text); }
.bill-row__price {
	font-family: var(--font-mono);
	font-size: 0.88rem;
	color: var(--text-2);
	white-space: nowrap;
}
.bill-row__action { flex: none; }
.bill-row__badge {
	flex: none;
	padding: 0.3rem 0.6rem;
	border-radius: var(--radius-pill);
	background: color-mix(in oklab, var(--accent) 14%, transparent);
	color: var(--accent);
	font-size: 0.68rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}
.bill-action { margin-top: 0.9rem; }

/* Plan comparison: one card per tier, benefit bullets + cadence options. */
.bill-plans { display: flex; flex-direction: column; gap: 0.7rem; }
.bill-plan {
	padding: 1rem 1.1rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	background: var(--surface);
}
.bill-plan--current {
	border-color: color-mix(in oklab, var(--accent) 45%, transparent);
	background: var(--accent-soft);
}
.bill-plan__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
}
.bill-plan__name {
	font-family: var(--font-serif);
	font-weight: 600;
	font-size: 1.15rem;
	color: var(--ink);
}
.bill-plan__tag {
	margin: 0.15rem 0 0;
	font-size: 0.8rem;
	color: var(--text-3);
}
.bill-plan__benefits {
	list-style: none;
	margin: 0.85rem 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}
.bill-plan__benefits li {
	position: relative;
	padding-left: 1.4rem;
	font-size: 0.875rem;
	line-height: 1.4;
	color: var(--text-2);
}
.bill-plan__benefits li::before {
	content: "";
	position: absolute;
	left: 0.15rem;
	top: 0.32em;
	width: 0.5rem;
	height: 0.28rem;
	border-left: 1.75px solid var(--accent);
	border-bottom: 1.75px solid var(--accent);
	transform: rotate(-45deg);
}
.bill-plan__offer {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	margin: 0.7rem 0 0;
	padding-top: 0.7rem;
	border-top: 1px solid var(--border-subtle);
}
.bill-plan__price {
	flex: 1;
	font-family: var(--font-mono);
	font-size: 0.9rem;
	color: var(--text-2);
}
.bill-plan__cta { flex: none; }

/* Muted, non-purchasable teaser for the not-yet-available B2B tiers. */
.bill-plan--soon {
	border-style: dashed;
	background: transparent;
}
.bill-plan--soon .bill-plan__name { font-size: 1.05rem; color: var(--text-3); }
.bill-plan--soon .bill-plan__tag { color: var(--text-4); }
.bill-soon {
	flex: none;
	align-self: center;
	padding: 0.22rem 0.55rem;
	border-radius: var(--radius-pill);
	background: var(--tint-sm);
	color: var(--text-4);
	font-size: 0.64rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	white-space: nowrap;
}

.bill-foot {
	margin-top: 0.3rem;
	padding-top: 1.2rem;
	border-top: 1px solid var(--border-subtle);
	font-size: 0.875rem;
}
.bill-back {
	color: var(--text-3);
	text-decoration: none;
	transition: color var(--timing-fast) var(--ease-out);
}

/* ==========================================================================
   §41 Documents – Rows/Grid + by-car groups. Reuses .panel/.activity-list/
   .icon-chip/.section-head/.segmented; only what those primitives don't
   already cover lives here.
   ========================================================================== */
.documents__controls { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }

/* Kind filter (7 kinds): the shared pill-shaped .segmented capsule looks broken
   once it wraps to 2-3 lines, so drop the capsule and give each item its own
   independent chip. Rather than wrap, the strip stays on one line and scrolls
   horizontally at every width (all chips fit on a wide desktop; narrower
   viewports swipe) – a consistent, compact treatment instead of a variable-
   height header. Scrollbar hidden; the partly-clipped trailing chip is the
   scroll affordance. */
.documents__kind-filter {
	/* Block-level (not the inherited inline-flex): an inline-flex box shrink-wraps
	   to its content, so it would grow past the viewport and never scroll. As a
	   block it fills the column, and the nowrap overflow scrolls inside it. */
	display: flex;
	max-width: 100%;
	flex-wrap: nowrap;
	overflow-x: auto;
	scrollbar-width: none;
	height: auto;
	margin-top: 0.75rem;
	margin-bottom: 1rem;
	padding: 0;
	gap: 0.4rem;
	background: none;
	border: 0;
	border-radius: 0;
}
.documents__kind-filter::-webkit-scrollbar { display: none; }
.documents__kind-filter .segmented__item {
	flex: none;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
}
.documents__kind-filter .segmented__item--active {
	background: var(--accent-soft);
	color: var(--accent);
	border-color: var(--accent);
	box-shadow: none;
}

/* Phone: tighten the header spacing (the eyebrow now rides in the top bar), and
   drop the Upload button – its action lives in the tab-bar ＋ capture sheet on
   mobile (§63), reached via /dokumente?upload=1. */
@media (max-width: 640px) {
	.documents__head { margin-bottom: 0.75rem; }
	.documents__kind-filter { margin-top: 0.5rem; margin-bottom: 0.75rem; }
	.documents__upload { display: none; }
}

/* §101 fix #10: the empty state's own CTA stays on phones. The header button
   above hides there (its action lives in the §63 tab-bar ＋ sheet), which left a
   first-time phone user with an empty page whose only instruction was about a
   settings toggle. */
.documents__empty-upload { margin-top: 1rem; }

/* Tighter than the generic .panel padding – a car's own group is often a
   single row, so the shared clamp(1rem, 2.2vw, 1.5rem) reads as dead air. */
.documents__car-group { padding: clamp(0.7rem, 1.6vw, 1.1rem) clamp(0.85rem, 2vw, 1.35rem); }
.documents__car-group + .documents__car-group { margin-top: 0.55rem; }
/* Compact single-row header: small car avatar + ellipsised name + count on one
   line. The inherited section-head (baseline-align, flex-wrap, 23px serif title)
   pushed the photo, name and count each onto their own line – a tall header for
   what is often a single document. */
.documents__car-head {
	align-items: center;
	flex-wrap: nowrap;
	gap: 0.7rem;
	margin-bottom: 0.7rem;
}
.documents__car-head .section-head__titles { flex: 1; min-width: 0; }
.documents__car-name {
	font-size: clamp(15px, 1.9vw, 18px);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.documents__car-count {
	flex: none;
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	color: var(--text-4);
	white-space: nowrap;
}

.doc-group__photo {
	flex: none;
	width: 44px;
	height: 44px;
	border-radius: var(--radius-control);
	overflow: hidden;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
}
.doc-group__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.doc-group__img--ph { display: grid; place-items: center; color: var(--text-5); }

/* Row: two independent links (view the document / jump to its owning car
   object) rather than nested anchors – activity-row's grid-template-columns
   (auto 1fr auto) assumed one link with three children, so override to flex. */
.doc-row { display: flex; align-items: center; gap: 0.85rem; }
.doc-row__open {
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: center;
	gap: 0.85rem;
	flex: 1;
	min-width: 0;
	text-decoration: none;
	color: inherit;
}
.doc-row__link {
	flex: none;
	display: inline-flex;
	color: var(--text-5);
	transition: color var(--timing-base) var(--ease-out), transform var(--timing-base) var(--ease-out);
}
.doc-row__link:hover { color: var(--accent); transform: translateX(3px); }

/* Rows mode (default): icon-chip glyph, no thumbnail. */
.doc-row__thumb { display: none; }

/* Grid mode: same markup, CSS-only relayout – bigger photographic thumbnails
   instead of the small glyph (every §21-retained kind has a real image
   behind OpenURL), icon-chip becomes the no-thumbnail fallback look. */
.activity-list.docs-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	gap: 0.75rem;
}
.activity-list.docs-grid .doc-row {
	flex-direction: column;
	border-bottom: 0;
	padding: 0.75rem;
	background: var(--surface-sunken);
	border-radius: var(--radius-card);
	border: 1px solid var(--border-subtle);
}
.activity-list.docs-grid .doc-row__open {
	grid-template-columns: 1fr;
	justify-items: center;
	text-align: center;
	gap: 0.5rem;
}
.activity-list.docs-grid .icon-chip { display: none; }
.activity-list.docs-grid .doc-row__thumb {
	display: block;
	width: 100%;
	height: 120px;
	object-fit: cover;
	border-radius: var(--radius-control);
}
.activity-list.docs-grid .activity-row__title { white-space: normal; }
.activity-list.docs-grid .activity-row__sub { display: block; }
.activity-list.docs-grid .doc-row__link { margin-top: 0.2rem; }
.doc-row__delete { flex: none; } /* §56 – colour now owned by btn--danger */
/* §101 Inc 5 – expiry legibility. The status word rides the meta line in the
   §12 reminder engine's own vocabulary, and the instrument strip's urgency
   cards only colour when they are non-zero, so a clean archive reads as calm. */
.doc-row__expiry {
	margin-left: 0.4rem;
	font-family: var(--font-mono);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	padding: 0.1rem 0.35rem;
	border-radius: var(--radius-control);
}
.doc-row__expiry--overdue { color: var(--clr-repair); background: color-mix(in srgb, var(--clr-repair) 12%, transparent); }
.doc-row__expiry--soon { color: var(--clr-service); background: color-mix(in srgb, var(--clr-service) 12%, transparent); }

.documents__stats { margin-bottom: 0.25rem; }
.documents__stats .stat--overdue .stat__value { color: var(--clr-repair); }
.documents__stats .stat--soon .stat__value { color: var(--clr-service); }

.doc-row__unlink { flex: none; color: var(--text-5); }
.doc-row__unlink:hover { color: var(--ink); }

/* The row's own open affordance is a <button> now (it opens the §101 viewer
   rather than navigating to the blob), so it has to shed the UA button chrome
   and keep the grid layout the anchor had. */
.doc-row__open {
	appearance: none;
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

/* ==========================================================================
   §101 Inc 2 – document viewer. Media rule lifted verbatim from the glovebox
   card (the one surface that already rendered a document in-app): <img> for an
   image, same-origin <iframe> for a PDF.
   ========================================================================== */
/* The base .form-modal caps the dialog at 600px; the viewer wants the room a
   scan needs, so widen the dialog itself (viewport-bound on mobile) -- otherwise
   the __content max-width below is dead, clamped by the 600px parent. */
.doc-viewer { max-width: min(920px, calc(100vw - 2rem)); }
.doc-viewer__content { max-width: 100%; }
/* The header pads itself (.form-header); everything below it lives in this body
   so the media, metadata and edit fields share the modal's 2rem gutter instead
   of sitting flush against the dialog edge. */
.doc-viewer__body { padding: 1.25rem 2rem 1.5rem; }
.doc-viewer__media {
	display: grid;
	/* minmax(0,1fr) not an auto track: an auto grid column sizes to the image's
	   intrinsic width, so `max-width:100%` resolves against THAT and never shrinks
	   -- a large scan then overflowed the dialog and showed only its top-left
	   corner on mobile. A 0-floored 1fr track is the container width, so the cap
	   bites. justify-items centres a portrait scan within it. */
	grid-template-columns: minmax(0, 1fr);
	justify-items: center;
	margin: 0 0 1.25rem;
}
.doc-viewer__img {
	max-width: 100%;
	max-height: 60vh;
	border-radius: var(--radius-card);
	object-fit: contain;
	background: var(--surface-sunken);
}
.doc-viewer__frame {
	width: 100%;
	height: 60vh;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	background: var(--surface-sunken);
}
.doc-viewer__meta {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: 0.5rem 1.25rem;
	margin: 0;
}
.doc-viewer__metarow dt {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
}
.doc-viewer__metarow dd {
	margin: 0.15rem 0 0;
	font-size: 14px;
	color: var(--ink);
}
.doc-viewer__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	/* Full-bleed top border, but its own content shares the modal's 2rem gutter
	   (the body above pads to the same edge). */
	padding: 0.75rem 2rem 1.5rem;
	border-top: 1px solid var(--border-subtle);
}
.doc-viewer__nav { display: flex; gap: 0.25rem; margin-right: auto; }

/* §101 Inc 4: the edit pane shares the dialog with the media rather than
   stacking a second modal over it – you keep looking at the document while
   retyping the title off it. Padding comes from .doc-viewer__body now. */
.doc-viewer__edit { padding: 0; }

@media (max-width: 640px) {
	.doc-viewer__img, .doc-viewer__frame { max-height: 46vh; height: auto; }
	.doc-viewer__frame { height: 46vh; }
	/* Tighter gutters on a phone so the media gets the width. */
	.doc-viewer__body { padding: 1rem 1.25rem 1.25rem; }
	.doc-viewer__actions { padding: 0.75rem 1.25rem 1.25rem; }
	.doc-viewer__actions > .btn { flex: 1 1 auto; justify-content: center; }
}

/* §87: the .doc-upload-drop dropzone was retired – the §41 document modal now
   renders the shared @ui.Uploader (panel variant); its dashed-→-solid visual
   language lives on in .uploader. The metadata chrome below (car-link chips) is
   unchanged. */

.doc-upload-cars { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.doc-upload-car {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.4rem 0.75rem;
	font-size: 13px;
	color: var(--text-2);
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: 999px;
	cursor: pointer;
	transition: color var(--timing-fast) var(--ease-out), border-color var(--timing-fast) var(--ease-out), background var(--timing-fast) var(--ease-out);
}
.doc-upload-car:hover { border-color: var(--tint-lg); color: var(--ink); }
.doc-upload-car:has(input:checked) {
	background: var(--accent-soft);
	border-color: var(--accent);
	color: var(--accent);
}
.bill-back:hover { color: var(--accent); }

/* ==========================================================================
   §41 Phase 3.2 – "Papiere" glovebox carousel. Bypasses the shared app
   Layout entirely (GloveboxCarousel is its own standalone HTML document,
   not app-shell content) – a full-bleed, swipeable card-per-document view
   (Apple/Google Wallet idiom): tap the icon, see the paper you need
   immediately, swipe for the next one. Pure CSS scroll-snap drives the
   swipe; no JS beyond the mandatory service-worker registration.
   ========================================================================== */
.glovebox-body {
	margin: 0;
	background: var(--surface);
	overscroll-behavior-y: contain;
}
.glovebox-close {
	position: fixed;
	top: max(14px, env(safe-area-inset-top));
	left: max(14px, env(safe-area-inset-left));
	z-index: 10;
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border-radius: var(--radius-pill);
	background: var(--tint-md);
	color: var(--ink);
	font-size: 22px;
	line-height: 1;
	text-decoration: none;
	backdrop-filter: blur(6px);
}
.glovebox-carousel {
	display: flex;
	gap: 12px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-padding-inline: 6vw;
	height: 100dvh;
	padding: 0 6vw;
	box-sizing: border-box;
	-webkit-overflow-scrolling: touch;
}
.glovebox-card {
	flex: 0 0 82vw;
	max-width: 460px;
	scroll-snap-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 16px;
	padding: max(24px, env(safe-area-inset-top)) 0 max(24px, env(safe-area-inset-bottom));
	box-sizing: border-box;
}
.glovebox-card__media {
	max-width: 100%;
	max-height: 72vh;
	border-radius: var(--radius-card);
	object-fit: contain;
	box-shadow: 0 12px 32px rgba(0, 0, 0, .18);
	background: var(--surface-sunken);
}
.glovebox-card__frame {
	width: 100%;
	height: 72vh;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	background: var(--surface-sunken);
}
.glovebox-card__caption {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 13px;
	color: var(--text-3);
	text-align: center;
}
.glovebox-empty {
	height: 100dvh;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 12px;
	text-align: center;
	padding: 0 24px;
	box-sizing: border-box;
}
.glovebox-empty a { color: var(--accent); }

/* ==========================================================================
   §60 Settings UI overhaul – editorial header, section rail, panel cards,
   toggle switch, setting rows, sticky save bar. Appended + unlayered so it
   wins over the legacy .form-section styling.
   ========================================================================== */

/* Two-column shell: sticky section rail + content column. Collapses to a
   horizontal scroll rail (the pre-§60 .car-tabs behaviour) below 720px. */
.settings-shell {
	display: grid;
	grid-template-columns: minmax(190px, 230px) minmax(0, 1fr);
	gap: clamp(1.25rem, 3vw, 2.5rem);
	align-items: start;
}

.settings-main {
	min-width: 0;
	max-width: 720px;
	display: flex;
	flex-direction: column;
	gap: clamp(1rem, 2vw, 1.4rem);
}
/* Top-level settings forms are flex columns with the SAME gap, so panels stacked
   inside a form (calc/AI/notifications/server) are spaced identically to panels
   that are direct .settings-main children (account) – one uniform panel margin
   everywhere. The `>` keeps this off nested password/charge-source forms. */
.settings-main > form {
	display: flex;
	flex-direction: column;
	gap: clamp(1rem, 2vw, 1.4rem);
}

/* ── Section rail (desktop vertical nav) ─────────────────────────────────── */
.settings-rail {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	position: sticky;
	top: 1.5rem;
}

/* Mirrors the sidebar .side-link so the two navs read as one system: tinted
   pill on active/hover, accent text – no left border. */
.settings-rail__item {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	padding: 0.5rem 0.7rem;
	border-radius: var(--radius-control);
	font-size: 13.5px;
	font-weight: 500;
	color: var(--text-2);
	text-decoration: none;
	transition: color var(--timing-fast) var(--ease-out), background var(--timing-fast) var(--ease-out);
}
.settings-rail__item .icon { width: 1.15em; height: 1.15em; color: var(--text-4); flex: none; transition: color var(--timing-fast) var(--ease-out); }
.settings-rail__item:hover { color: var(--ink); background: var(--tint-sm); }
.settings-rail__item:hover .icon { color: var(--text-2); }
.settings-rail__item--active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
.settings-rail__item--active .icon { color: var(--accent); }

/* ── Editorial header ────────────────────────────────────────────────────── */
.settings-header { margin-bottom: 0.25rem; }
.settings-header .eyebrow { margin-bottom: 0.5rem; }
.settings-header__title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 520;
	font-size: clamp(24px, 4vw, 34px);
	letter-spacing: -0.015em;
	line-height: 1.05;
	color: var(--ink);
	margin: 0;
}
.settings-header__desc {
	margin: 0.5rem 0 0;
	color: var(--text-3);
	font-size: 14px;
	max-width: 52ch;
}

/* ── Panel card head (serif, replaces the .form-section-title micro-label) ── */
.settings-panel__head { margin-bottom: 1rem; }
.settings-panel__title {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 520;
	font-size: clamp(17px, 2.2vw, 20px);
	letter-spacing: -0.01em;
	line-height: 1.15;
	color: var(--ink);
	margin: 0;
}
.settings-panel__desc { margin: 0.3rem 0 0; color: var(--text-3); font-size: 13px; }
/* Sub-head inside a panel (e.g. a second grouping within one card). */
.settings-panel__subhead {
	font-family: var(--font-serif);
	font-weight: 520;
	font-size: 15px;
	color: var(--ink);
	margin: 1.4rem 0 0.6rem;
}

/* ── Setting row (label + hint left, control right) ──────────────────────── */
.setting-row {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: center;
	gap: 0.6rem 1.25rem;
	padding: 0.7rem 0;
	border-bottom: 1px solid var(--border-subtle);
}
.setting-row:last-child { border-bottom: 0; padding-bottom: 0; }
.setting-row__label { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.setting-row__label .form-label { margin: 0; }
.setting-row__label .form-hint { margin: 0; }
.setting-row__control { justify-self: end; }
.setting-row > .toggle { justify-self: end; }
/* Compact controls (select / number) sit right in a fixed-width column. */
.setting-row__control:where(select, input:not([type="range"])) { width: 11rem; max-width: 100%; }
/* Full-width variant: control drops beneath the label (wide inputs, sliders). */
.setting-row--stack { grid-template-columns: 1fr; }
.setting-row--stack .setting-row__control { justify-self: stretch; width: 100%; }
.setting-row--stack > .form-label { margin: 0; }
.setting-slider { display: flex; align-items: center; gap: 0.75rem; }
.setting-slider input[type="range"] { flex: 1; }
/* Theme every range slider to the brand accent instead of the UA blue (thumb +
   filled track + focus ring, both light and dark via the light-dark() token). */
input[type="range"] { accent-color: var(--accent); }
.setting-slider__value {
	min-width: 3.5rem;
	text-align: right;
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	color: var(--text-2);
	font-size: 13px;
}

/* ── Toggle switch (replaces yes/no <select>) ────────────────────────────── */
.toggle {
	appearance: none;
	border: 0;
	background: none;
	padding: 0;
	cursor: pointer;
	display: inline-flex;
	flex: none;
}
.toggle__track {
	position: relative;
	width: 2.6rem;
	height: 1.5rem;
	border-radius: 999px;
	background: var(--surface-3);
	border: 1px solid var(--border);
	transition: background var(--timing-base) var(--ease-out), border-color var(--timing-base) var(--ease-out);
}
.toggle__thumb {
	position: absolute;
	top: 50%;
	left: 0.18rem;
	transform: translateY(-50%);
	width: 1.05rem;
	height: 1.05rem;
	border-radius: 50%;
	background: var(--surface-raised);
	box-shadow: 0 1px 2px var(--scrim-sm);
	transition: transform var(--timing-base) var(--ease-out), background var(--timing-base) var(--ease-out);
}
.toggle--on .toggle__track { background: var(--accent); border-color: var(--accent); }
.toggle--on .toggle__thumb { transform: translate(1.1rem, -50%); background: var(--accent-ink); }
.toggle:focus-visible { outline: none; }
.toggle:focus-visible .toggle__track { outline: 2px solid var(--accent); outline-offset: 2px; }
.toggle[disabled] { cursor: not-allowed; opacity: 0.45; }

/* §60 server-driven save status inside the thumb: spinner while in flight
   ($svi_<key>), a brief tick on a confirmed save ($sv_<key>='ok'), ✕ on error.
   Never optimistic – these classes are toggled only by the server's response. */
.toggle__thumb::after {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	font-size: 0.62rem;
	font-weight: 700;
	line-height: 1;
}
.toggle.is-saving .toggle__thumb::after {
	content: "";
	width: 0.6rem;
	height: 0.6rem;
	border-radius: 50%;
	border: 2px solid color-mix(in oklab, var(--accent) 35%, transparent);
	border-top-color: var(--accent);
	animation: btn-spin 0.6s linear infinite;
}
.toggle.is-saved .toggle__thumb::after { content: "✓"; color: var(--accent); animation: settings-tick 1.4s ease forwards; }
.toggle.is-error .toggle__thumb::after { content: "✕"; color: var(--critical); }
@keyframes settings-tick { 0%, 65% { opacity: 1; } 100% { opacity: 0; } }

/* Inline save-error reason (data-show/data-text off $sv_/$svmsg_ signals). */
.setting-row__err { margin-top: 0.15rem; font-size: 12px; color: var(--critical); }

/* §60 value-field save status (server-driven, same signals as the toggle): a
   faint accent border while in flight, a brief outline flash on a confirmed
   save, a steady red outline on error. */
.form-input.is-saving { border-color: var(--accent); }
.form-input.is-saved { outline: 2px solid var(--accent); outline-offset: 1px; animation: settings-flash 1.3s ease forwards; }
.form-input.is-error { outline: 2px solid var(--critical); outline-offset: 1px; }
@keyframes settings-flash { 0%, 55% { outline-color: var(--accent); } 100% { outline-color: transparent; } }
/* Slider readout flashes accent on save (an outline round the number looks odd). */
.setting-slider__value.is-saving { color: var(--accent); }
.setting-slider__value.is-saved { animation: settings-readout-flash 1.3s ease forwards; }
.setting-slider__value.is-error { color: var(--critical); }
@keyframes settings-readout-flash { 0%, 55% { color: var(--accent); } 100% { color: var(--text-2); } }

/* Nested AI sub-switches under the master toggle. */
.setting-substack {
	margin-top: 0.5rem;
	padding-left: 1rem;
	border-left: 2px solid var(--border-subtle);
}

/* ── Save bar (non-sticky, sits just below the editorial header) ─────────── */
.settings-actions {
	display: flex;
	justify-content: flex-end;
	gap: 0.6rem;
}

/* ── Responsive: collapse the rail to a horizontal scroll strip ──────────── */
@media (max-width: 720px) {
	.settings-shell { grid-template-columns: 1fr; gap: 1rem; }
	.settings-rail {
		position: static;
		flex-direction: row;
		gap: 0.25rem;
		overflow-x: auto;
		scrollbar-width: none;
		border-bottom: 1px solid var(--border-subtle);
	}
	.settings-rail::-webkit-scrollbar { display: none; }
	.settings-rail__item { white-space: nowrap; }
}

/* §20: on desktop the settings sections live in the sidebar subnav, so drop the
   in-page rail and let the content span the full width. Placed after the base
   .settings-shell/.settings-rail rules so it wins on source order (below 900px
   the sidebar is hidden and the in-page rail above is the section nav). */
@media (min-width: 901px) {
	.settings-shell { grid-template-columns: 1fr; }
	.settings-rail { display: none; }
}

/* ── §25 Security panel (password + passkeys) ────────────────────────────── */
/* One shared column width so every field (change-password, remove-password,
   passkey label) lines up – replaces the old per-form max-width:360px that
   left the same "current password" field rendering at two different widths. */
.security-body { max-width: 26rem; display: flex; flex-direction: column; gap: 1.6rem; }
.security-section { display: flex; flex-direction: column; }
.security-section .settings-panel__subhead { margin-top: 0; }

.security-form { display: flex; flex-direction: column; gap: 0.9rem; }
/* The "remove password" form is a lighter sub-action under the change form,
   set off by a hairline rather than a heavy separator. */
.security-form--sub {
	margin-top: 1.1rem;
	padding-top: 1.1rem;
	border-top: 1px solid var(--border-subtle);
}
.security-form .form-input { width: 100%; }
/* Left-aligned actions sit directly under their field – no border-topped,
   right-floated bar that reads as detached from the form. */
.security-form__actions { display: flex; justify-content: flex-start; }

/* Passkey list: name + inline bare-icon delete. The name is plain text, not an
   input, so it is NOT wrapped in .form-input; the delete is an icon button with
   no box until hover. */
.security-passkey-list { list-style: none; margin: 0 0 1rem; padding: 0; display: flex; flex-direction: column; }
.security-passkey {
	display: flex;
	align-items: center;
	gap: 0.65rem;
	padding: 0.55rem 0;
	border-bottom: 1px solid var(--border-subtle);
}
.security-passkey:first-child { border-top: 1px solid var(--border-subtle); }
.security-passkey__icon { width: 1rem; height: 1rem; color: var(--text-3); flex: none; }
.security-passkey__name {
	flex: 1;
	min-width: 0;
	font-size: 0.875rem;
	color: var(--text);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.security-passkey__del {
	flex: none;
	display: inline-grid;
	place-items: center;
	width: 1.9rem;
	height: 1.9rem;
	padding: 0;
	border: 0;
	background: none;
	color: var(--text-4);
	cursor: pointer;
	border-radius: var(--radius-control);
	transition: color var(--timing-base) var(--ease-out), background var(--timing-base) var(--ease-out);
}
.security-passkey__del .icon { width: 1rem; height: 1rem; }
.security-passkey__del:hover { color: var(--clr-repair); background: var(--clr-repair-bg); }

/* Add row: the label spans the full width on its own line (it is long – "e.g.
   «MacBook Touch ID»" – and shouldn't fight the input for horizontal space);
   below it the input grows and the add button sits beside it, so the button
   belongs to the passkeys section instead of floating below a divider. */
.security-passkey-add { display: flex; flex-direction: column; gap: 0.375rem; }
.security-passkey-add__row { display: flex; align-items: center; gap: 0.6rem; }
.security-passkey-add__input { flex: 1; min-width: 0; }
.security-passkey-add__btn { flex: none; white-space: nowrap; }

@media (max-width: 480px) {
	.security-passkey-add__row { flex-direction: column; align-items: stretch; }
	.security-passkey-add__btn { width: 100%; }
}

/* ==========================================================================
   §63 Mobile chrome – top app bar + fixed bottom tab bar + "Mehr" sheet
   Below --mobile-bp (700px) the desktop Sidebar is hidden and replaced by a
   slim sticky top bar (compact wordmark + avatar) and a thumb-reachable fixed
   bottom tab bar; the four secondary destinations move into a "Mehr" bottom
   sheet. Desktop (> breakpoint) is untouched: both bars are display:none. The
   scan-heavy standalone pages (glovebox, auth) render their own <body> class
   and keep their own chrome -- the body-padding reset is scoped via :has() to
   app-shell pages only.
   ========================================================================== */
.mobile-topbar,
.tabbar { display: none; }

/* ── Mobile top app bar ──────────────────────────────────────────────────── */
.mobile-topbar {
	position: sticky;
	top: 0;
	z-index: 40;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	height: 56px;
	padding: 0 clamp(1rem, 4vw, 1.25rem);
	background: var(--surface-raised);
	border-bottom: 1px solid var(--border-subtle);
}
.mobile-topbar__brand {
	font-family: var(--font-serif);
	font-optical-sizing: auto;
	font-weight: 600;
	font-size: 22px;
	letter-spacing: -0.015em;
	line-height: 1;
	color: var(--ink);
	text-decoration: none;
}

/* ── Bottom tab bar ──────────────────────────────────────────────────────── */
.tabbar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 50;
	align-items: stretch;
	/* Items cap + centre so the bar doesn't stretch awkwardly wide on tablets
	   (up to the ≤900px breakpoint); on a phone they just fill the width. */
	justify-content: center;
	gap: clamp(2px, 2vw, 1.5rem);
	padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
	background: var(--surface-raised);
	border-top: 1px solid var(--border-subtle);
}
.tabbar__item {
	flex: 1 1 0;
	max-width: 132px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 3px;
	min-height: 48px;
	padding: 4px 2px;
	border: 0;
	background: none;
	border-radius: var(--radius-control);
	color: var(--text-3);
	text-decoration: none;
	font: inherit;
	font-size: 10.5px;
	font-weight: 500;
	line-height: 1;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}
.tabbar__item .icon { width: 22px; height: 22px; color: var(--text-3); flex: none; }
.tabbar__item:active { background: var(--tint-sm); }
.tabbar__item--active { color: var(--accent); }
.tabbar__item--active .icon { color: var(--accent); }
.tabbar__label {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* ── "Mehr" bottom sheet ─────────────────────────────────────────────────── */
.more-sheet {
	border: 0;
	padding: 0;
	background: transparent;
}
.more-sheet[open] {
	position: fixed;
	inset: auto 0 0 0;
	margin: 0;
	width: 100%;
	max-width: 100%;
	max-height: 85vh;
}
.more-sheet::backdrop { background: var(--sheet-scrim); }
.more-sheet__panel {
	background: var(--surface-raised);
	border-top: 1px solid var(--border-subtle);
	border-top-left-radius: var(--radius-card);
	border-top-right-radius: var(--radius-card);
	padding: 0.5rem clamp(1rem, 4vw, 1.25rem) calc(1.25rem + env(safe-area-inset-bottom));
	box-shadow: 0 -12px 32px -12px color-mix(in oklab, #000 40%, transparent);
}
.more-sheet__grabber {
	width: 36px;
	height: 4px;
	margin: 0.35rem auto 0.75rem;
	border-radius: 999px;
	background: var(--border-strong, var(--text-4));
	opacity: 0.4;
}
.more-sheet__nav { display: flex; flex-direction: column; gap: 2px; }
.more-sheet__link {
	display: flex;
	align-items: center;
	gap: 0.85rem;
	min-height: 48px;
	padding: 0.6rem 0.65rem;
	border-radius: var(--radius-control);
	color: var(--text-2);
	text-decoration: none;
	font-weight: 500;
	font-size: 15px;
}
.more-sheet__link .icon { width: 1.2em; height: 1.2em; color: var(--text-4); flex: none; }
.more-sheet__link:active { background: var(--tint-sm); }
.more-sheet__link--active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.more-sheet__link--active .icon { color: var(--accent); }
/* §53 public-garage link: right-align the trailing external-link glyph, mirroring .side-link--external */
.more-sheet__link--external .icon:last-child { margin-left: auto; width: 0.95em; height: 0.95em; color: var(--text-4); }
.more-sheet__privacy {
	display: flex;
	gap: 0.55rem;
	align-items: flex-start;
	margin-top: 0.75rem;
	padding: 0.7rem 0.65rem;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
}
.more-sheet__privacy .icon { color: var(--accent); width: 1.05em; height: 1.05em; margin-top: 1px; flex: none; }

/* ── Activate the mobile chrome ──────────────────────────────────────────── */
/* Up to 900px (tablet portrait – iPad 768/834 – and down). Above it the desktop
   Sidebar stands; below it the top app bar + bottom tab bar take over. */
@media (max-width: 900px) {
	/* Full-bleed app chrome; content padding comes from #carlist / .topbar. Scoped
	   to app-shell pages so the standalone glovebox/auth bodies keep their own
	   padding (incl. the glovebox's own fixed-nav gutter). */
	body:has(.app-shell) { padding: 0; }
	.sidebar { display: none; }
	.mobile-topbar { display: flex; }
	.tabbar { display: flex; }
	/* Clear the fixed bottom tab bar. */
	.shell-main { padding-bottom: calc(58px + env(safe-area-inset-bottom)); }
	/* The avatar lives in the mobile top bar now; drop the duplicate in the
	   per-page editorial header (this also ends the stranded-avatar wrapping). */
	.topbar .avatar-menu { display: none; }
	.topbar__actions { width: 100%; }
	/* Add-car / scan / TCO-estimator header buttons are covered by the capture
	   FAB on mobile – hide them so the page header isn't a wall of buttons. The
	   year picker (also in .topbar__actions) stays. */
	.header-actions-left,
	.header-actions-right { display: none; }
}

/* ── §63 center capture FAB + quick-capture sheet ────────────────────────── */
.tabbar__capture {
	flex: 0 0 auto;
	align-self: center;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 52px;
	height: 52px;
	margin: 0 6px;
	border: 0;
	border-radius: 999px;
	background: var(--accent);
	color: var(--accent-ink);
	cursor: pointer;
	box-shadow: 0 6px 16px -4px color-mix(in oklab, var(--accent) 55%, transparent);
	-webkit-tap-highlight-color: transparent;
}
.tabbar__capture .icon { width: 26px; height: 26px; color: var(--accent-ink); flex: none; }
.tabbar__capture:active { transform: translateY(1px); }

.capture-sheet { border: 0; padding: 0; background: transparent; }
.capture-sheet[open] {
	position: fixed;
	inset: auto 0 0 0;
	margin: 0;
	width: 100%;
	max-width: 100%;
	max-height: 85vh;
}
.capture-sheet::backdrop { background: var(--sheet-scrim); }
.capture-sheet__panel {
	background: var(--surface-raised);
	border-top: 1px solid var(--border-subtle);
	border-top-left-radius: var(--radius-card);
	border-top-right-radius: var(--radius-card);
	padding: 0.5rem clamp(1rem, 4vw, 1.25rem) calc(1.25rem + env(safe-area-inset-bottom));
	box-shadow: 0 -12px 32px -12px color-mix(in oklab, #000 40%, transparent);
}
.capture-sheet__title {
	margin: 0 0 0.75rem;
	font-family: var(--font-serif);
	font-size: 19px;
	font-weight: 600;
	color: var(--ink);
}
.capture-sheet__carpick { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.6rem; }
.capture-sheet__carlabel { font-size: 12px; font-weight: 600; color: var(--text-3); }
.capture-sheet__scanform { margin: 0; }
.capture-sheet__file { display: none; }
.capture-sheet__action {
	display: flex;
	align-items: center;
	gap: 0.85rem;
	width: 100%;
	min-height: 52px;
	padding: 0.7rem 0.75rem;
	border: 0;
	background: none;
	border-radius: var(--radius-control);
	color: var(--text-2);
	text-align: left;
	text-decoration: none;
	font: inherit;
	font-size: 15px;
	font-weight: 500;
	cursor: pointer;
}
.capture-sheet__action .icon { width: 1.3em; height: 1.3em; color: var(--accent); flex: none; }
.capture-sheet__action:active { background: var(--tint-sm); }
.capture-sheet__divider { height: 1px; margin: 0.5rem 0; background: var(--border-subtle); }
/* §35 two-phase scan overlay hosted inside the sheet while a Fahrzeugausweis is
   uploading/OCR'ing – centered, with room for the XL ring and the scanner beam. */
.capture-sheet__scanstate {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 14rem;
	padding: 0.75rem 0 0.5rem;
}

/* ── §63 phone polish: compact car-detail hero actions + footer tap targets ── */
@media (max-width: 640px) {
	/* §88: the inline hero actions are now the affirmative quick-actions
	   (odometer / MFK / Abgas) + Edit; the rest live in the "Mehr" overflow menu.
	   On a phone collapse the inline .btn set to icon-only so they stay one tidy
	   row. Labels are visually-hidden (not removed), so each button keeps its
	   accessible name; button colour still encodes intent. The .action-menu
	   trigger is a <summary>, not a .btn, so it keeps its "Mehr" label. */
	.car-hero__actions .btn {
		padding: 0.55rem;
		gap: 0;
	}
	.car-hero__actions .btn > span {
		position: absolute;
		width: 1px; height: 1px;
		padding: 0; margin: -1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
		border: 0;
	}
	/* Give the small footer links a ≥24px tap target (Lighthouse target-size). */
	.footer-content .footer-link { padding: 0.4rem 0.3rem; }
	/* When the row wraps on a phone, drop the middot separators and let the
	   flex gap space the items – avoids a middot dangling at a line end. */
	.footer-content { gap: 0.1rem 0.35rem; }
	.footer-content .footer-divider { display: none; }
}

/* ============================================================================
   §27 Shareable TCO cards (Story teilen)
   The story sheet: a swipeable carousel of server-rendered card PNGs (1080×1920,
   tdewolff/canvas), shown as <img> scaled to fit. Rendering is server-side, so
   there is no on-screen rasterization target – the <img> IS the shared export.
   ============================================================================ */

.story-modal .form-body { padding-top: 0.75rem; }

/* §95 no-vertical-scroll: the sheet must fit the viewport (the card is height-capped
   against --story-chrome, the non-card height of the tallest slide). dvh cap so a
   mobile URL-bar can't push the sheet off-screen. */
.story-modal .form-modal-content { max-height: 90dvh; }
:root { --story-chrome: 372px; }
@media (max-width: 640px) {
	/* Reclaim chrome on a phone (hide the intro, tighten the body) so the height-capped
	   card stays usable, and re-budget --story-chrome to the trimmed non-card height of
	   the tallest slide (the comparison card ≈ 325px measured) plus slack – the card is
	   then as large as fits with no vertical scroll. */
	:root { --story-chrome: 340px; }
	.story-modal .form-body { padding: 0.5rem 1rem 1rem; }
	.story-modal .form-hint { display: none; }
}

.story-carousel {
	display: flex;
	gap: 20px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	padding: 8px 4px 12px;
	-webkit-overflow-scrolling: touch;
}
.story-slide {
	flex: 0 0 auto;
	scroll-snap-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 12px;
}
.story-slide__name {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--text-3);
}
/* The card frame carries the size + a centered loading spinner; the <img> lays
   over it and, once its opaque PNG has loaded, covers the spinner – so no JS or
   load event is needed, and the amounts-toggle re-fetch shows the spinner too.
   §95: the width is ALSO capped by the available height so the tall (1080×1920)
   portrait card can't push the sheet past the viewport – the modal must never
   scroll vertically. --story-chrome is the measured non-card height of the tallest
   slide (the comparison card, which adds a vs-picker); the third min() term is the
   widest card whose derived height still leaves room for that chrome within 90dvh.
   dvh (not vh) tracks the mobile URL-bar so the cap is honest on a phone. */
.story-card-frame {
	position: relative;
	width: min(74vw, 300px, calc((90dvh - var(--story-chrome, 372px)) * 1080 / 1920));
	aspect-ratio: 1080 / 1920;
	border-radius: var(--radius-card);
	box-shadow: 0 12px 32px rgba(0, 0, 0, .18);
	background: var(--surface-sunken);
	overflow: hidden;
}
@media (min-width: 720px) {
	.story-card-frame { width: min(340px, calc((90dvh - var(--story-chrome, 372px)) * 1080 / 1920)); }
}
.story-card-frame::before {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 34px;
	height: 34px;
	margin: -17px 0 0 -17px;
	border: 3px solid color-mix(in oklab, var(--ink) 15%, transparent);
	border-top-color: var(--accent);
	border-radius: 50%;
	animation: sc-spin 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .story-card-frame::before { animation: none; } }
@keyframes sc-spin { to { transform: rotate(360deg); } }
.story-card-img {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}
.story-slide__share { align-self: stretch; justify-content: center; }
.story-toggle {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: var(--font-mono);
	font-size: 13px;
	color: var(--text-2);
	margin: 0 4px 10px;
	cursor: pointer;
}
.story-toggle input { accent-color: var(--accent); }

/* §95 gallery tabs – the form-tab segmented control, tightened for the story modal
   (less bottom margin so the toggle sits close under it). */
.story-tabs { margin-bottom: 0.75rem; }
.story-tab__lock {
	--icon-size: 0.8em;
	margin-inline-start: 0.35em;
	vertical-align: -0.05em;
	opacity: 0.7;
}

/* §95 locked upsell tile – occupies the same frame footprint as a card, but shows
   the lock + a plans CTA instead of a PNG (a locked slide carries no <img src>). */
.story-card-frame--locked {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--surface-sunken);
	border: 1px dashed var(--border-subtle);
}
.story-card-frame--locked::before { content: none; } /* no loading spinner */
.story-locked {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
	padding: 24px;
	text-align: center;
}
.story-locked__glyph {
	--icon-size: 34px;
	color: var(--text-3);
}
.story-locked__title {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 12px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-2);
	line-height: 1.4;
}
.story-locked__cta { align-self: stretch; justify-content: center; }

/* §95 Inc 2 comparison card vs-picker: a compact label + select under the card. */
.story-compare-picker {
	display: flex;
	align-items: center;
	gap: 8px;
	align-self: stretch;
}
.story-compare-picker__label {
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-3);
	white-space: nowrap;
}
.story-compare-picker__select {
	flex: 1;
	min-width: 0;
	padding: 0.4rem 0.5rem;
	font: inherit;
	font-size: 13px;
	color: var(--ink);
	background: var(--surface);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-sm);
}

/* Toast – the app's shared non-blocking notification (see internal/ui/toast.templ).
   A small card pinned bottom-centre, above the mobile tab bar, that auto-dismisses
   and optionally carries a single action button. Distinct from window.__notify,
   which is a centred modal dialog. */
/* Toast stack (§88): one viewport-fixed, bottom-centred container holds every
   toast. column-reverse anchors the newest (prepended → DOM-first) at the bottom,
   older ones stacking upward – so a second toast never hides behind the first.
   pointer-events: none lets clicks pass through the gaps; each toast re-enables. */
.toast-stack {
	position: fixed;
	left: 50%;
	bottom: 20px;
	transform: translateX(-50%);
	z-index: 60;
	display: flex;
	flex-direction: column-reverse;
	align-items: center;
	gap: 10px;
	max-width: min(92vw, 460px);
	pointer-events: none;
}
.toast {
	pointer-events: auto;
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	padding: 10px 12px 10px 18px;
	background: var(--surface-raised);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	box-shadow: 0 12px 40px rgba(0, 0, 0, .22);
	animation: toast-in 0.3s ease;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(12px); } }
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }
.toast__icon { color: var(--accent); display: inline-flex; }
.toast__text { margin: 0; font-size: 14px; color: var(--text-1); flex: 1 1 auto; }
.toast__action, .toast__close { flex: 0 0 auto; }
/* Clear the fixed bottom tab bar (shown ≤900px). */
@media (max-width: 900px) { .toast-stack { bottom: calc(72px + env(safe-area-inset-bottom)); } }

/* ── §73 Inc 6 Drive view (realtime GPS instrument) ─────────────────────────
   A full-screen dialog the driver looks at while a GPS-live trip records. Shell
   is server-rendered; trip-recorder.ts writes the live numerals. Token-driven so
   it flips with the OS theme – a cream day-instrument in light, a night HUD in
   dark. Mobile-first: safe-area insets, thumb-reachable controls at the bottom. */
.drive {
	position: fixed;
	inset: 0;
	margin: 0;
	padding: 0;
	width: 100vw;
	height: 100dvh;
	max-width: 100vw;
	max-height: 100dvh;
	border: 0;
	background: var(--surface);
	color: var(--text-1);
	overflow: hidden;
}
.drive::backdrop { background: var(--surface); }
.drive__inner {
	position: relative;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	gap: 1rem;
	height: 100dvh;
	padding: max(0.9rem, env(safe-area-inset-top)) max(1.1rem, env(safe-area-inset-right)) max(1.1rem, env(safe-area-inset-bottom)) max(1.1rem, env(safe-area-inset-left));
}
.drive__map { position: absolute; inset: 0; z-index: -2; display: block; width: 100%; height: 100%; }
.drive__scrim {
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background:
		radial-gradient(130% 90% at 50% 4%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 58%),
		radial-gradient(120% 70% at 50% 100%, color-mix(in oklab, var(--ink) 6%, transparent), transparent 60%);
}
.drive__bar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: nowrap; }
.drive__rec { display: inline-flex; align-items: center; gap: 0.5rem; min-width: 0; }
.drive__rec-dot {
	width: 0.6rem;
	height: 0.6rem;
	border-radius: 50%;
	background: var(--clr-repair);
	animation: drive-pulse 1.9s ease-out infinite;
}
.drive__elapsed {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: 1.05rem;
	font-weight: 600;
	letter-spacing: 0.02em;
}
.drive__rec-label {
	font-size: 0.68rem;
	text-transform: uppercase;
	letter-spacing: 0.09em;
	color: var(--text-3);
	white-space: nowrap;
}
/* The dot + running clock already say "recording"; drop the label on narrow phones
   so the status bar never wraps or overflows. */
@media (max-width: 400px) { .drive__rec-label { display: none; } }
.drive__status { margin-left: auto; display: inline-flex; align-items: center; gap: 0.55rem; flex: 0 0 auto; }
.drive__signal {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: 0.74rem;
	padding: 0.16rem 0.55rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--border);
	color: var(--text-3);
	white-space: nowrap;
}
.drive__signal[data-state="good"] { color: var(--clr-sell); border-color: color-mix(in oklab, var(--clr-sell) 45%, transparent); }
.drive__signal[data-state="ok"] { color: var(--clr-fuel); border-color: color-mix(in oklab, var(--clr-fuel) 45%, transparent); }
.drive__signal[data-state="weak"] { color: var(--clr-repair); border-color: color-mix(in oklab, var(--clr-repair) 45%, transparent); }
.drive__wake { display: inline-flex; color: var(--text-5); }
.drive__wake.is-on { color: var(--accent); }
.drive__wake svg { width: 1rem; height: 1rem; }
/* Server-connectedness beacon: green when the /points link is up, amber when a gap
   is buffering. Distinct from the (satellite) GPS chip – link ≠ GPS. */
.drive__link {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--clr-fuel);
	transition: background 0.3s ease;
}
.drive__link.is-online { background: var(--clr-sell); }
.drive__offline-bar {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	margin-top: -0.35rem;
	padding: 0.35rem 0.6rem;
	border-radius: var(--radius-control);
	font-size: 0.78rem;
	color: var(--clr-fuel);
	background: color-mix(in oklab, var(--clr-fuel) 13%, transparent);
	border: 1px solid color-mix(in oklab, var(--clr-fuel) 32%, transparent);
}
.drive__offline-bar svg { width: 0.9rem; height: 0.9rem; flex: 0 0 auto; }
/* The server figures dim while offline so a frozen value reads as "paused", not broken. */
.drive .is-stale { opacity: 0.42; transition: opacity 0.3s ease; }
.drive__min {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.1rem;
	height: 2.1rem;
	border-radius: 50%;
	border: 1px solid var(--border);
	background: var(--surface-raised);
	color: var(--text-2);
	cursor: pointer;
}
.drive__min svg { width: 1.15rem; height: 1.15rem; }
.drive__hero { margin-top: auto; display: flex; flex-direction: column; align-items: flex-start; gap: 0.15rem; }
.drive__distance {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: clamp(4rem, 27vw, 8.5rem);
	font-weight: 600;
	line-height: 0.92;
	letter-spacing: -0.03em;
}
.drive__unit { font-size: 0.85rem; letter-spacing: 0.02em; color: var(--text-3); }
.drive__metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.55rem; }
.drive__metric {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: 0.7rem 0.8rem;
	border-radius: var(--radius-card);
	background: color-mix(in oklab, var(--surface-raised) 72%, transparent);
	border: 1px solid var(--border-subtle);
}
.drive__metric-val {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: 1.35rem;
	font-weight: 600;
	white-space: nowrap;
}
.drive__metric-val small { font-size: 0.68rem; font-weight: 500; color: var(--text-3); }
.drive__metric-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-4); }
.drive__purpose {
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.35rem 0.8rem;
	border-radius: var(--radius-pill);
	background: color-mix(in oklab, var(--accent) 15%, transparent);
	color: var(--accent);
	font-size: 0.82rem;
	font-weight: 550;
}
.drive__purpose svg { width: 0.95rem; height: 0.95rem; }
.drive__client {
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.35rem 0.8rem;
	border-radius: var(--radius-pill);
	background: color-mix(in oklab, var(--fg) 10%, transparent);
	color: var(--fg);
	font-size: 0.82rem;
	font-weight: 500;
}
.drive__client svg { width: 0.95rem; height: 0.95rem; opacity: 0.8; }
.drive__client strong { font-weight: 650; }
.drive__controls { display: grid; grid-template-columns: 1fr 1.7fr; gap: 0.7rem; }
.drive__controls .btn { justify-content: center; padding-block: 0.9rem; font-size: 1rem; }
@keyframes drive-pulse {
	0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--clr-repair) 55%, transparent); }
	70% { box-shadow: 0 0 0 0.7rem transparent; }
	100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .drive__rec-dot { animation: none; } }

/* §73 Inc C – auto night palette: the cockpit is always the dark instrument,
   regardless of the page theme (less glare on a dash-mounted phone). light-dark()
   tokens resolve dark under this; the <drive-map> accent probe follows in-context. */
.drive,
.drive-summary { color-scheme: dark; }

/* Entry flourish (reduced-motion gated). */
@media (prefers-reduced-motion: no-preference) {
	.drive[open] { animation: drive-enter 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); }
	.drive::backdrop { animation: drive-backdrop 0.35s ease; }
	.drive-summary[open] { animation: drive-enter 0.42s cubic-bezier(0.2, 0.85, 0.2, 1); }
}
@keyframes drive-enter { from { opacity: 0; transform: translateY(1.6%); } to { opacity: 1; transform: none; } }
@keyframes drive-backdrop { from { opacity: 0; } to { opacity: 1; } }

/* Odometer-roll hero: mono/tabular digits -> uniform 0-9 strips that slide on change. */
odo-meter.drive__distance { display: inline-flex; align-items: flex-end; line-height: 1; }
.odo-col { display: inline-block; height: 1em; overflow: hidden; }
.odo-strip { display: block; will-change: transform; }
.odo-strip > span { display: block; height: 1em; line-height: 1em; text-align: center; }
.odo-static { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
	.odo-strip { transition: transform 0.55s cubic-bezier(0.2, 0.85, 0.25, 1); }
}

/* Stop summary – full-screen dark card with the final figures + kept-track map. */
.drive-summary {
	position: fixed;
	inset: 0;
	margin: 0;
	padding: 0;
	width: 100vw;
	height: 100dvh;
	max-width: 100vw;
	max-height: 100dvh;
	border: 0;
	background: var(--surface);
	color: var(--text-1);
	overflow: hidden;
}
.drive-summary::backdrop { background: var(--surface); }
.drive-summary__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	height: 100dvh;
	text-align: center;
	padding: max(1.4rem, env(safe-area-inset-top)) 1.4rem max(1.4rem, env(safe-area-inset-bottom));
}
.drive-summary__check {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 3.4rem;
	height: 3.4rem;
	border-radius: 50%;
	background: color-mix(in oklab, var(--clr-sell) 18%, transparent);
	color: var(--clr-sell);
}
.drive-summary__check svg { width: 1.8rem; height: 1.8rem; }
.drive-summary__title { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-3); }
.drive-summary__map { width: min(88vw, 340px); }
.drive-summary__map .trip-map { width: 100%; height: auto; display: block; }
.drive-summary__hero { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; margin-top: 0.3rem; }
.drive-summary__dist {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: clamp(3.4rem, 22vw, 6rem);
	font-weight: 600;
	line-height: 0.92;
	letter-spacing: -0.03em;
}
.drive-summary__unit { font-size: 0.9rem; color: var(--text-3); }
.drive-summary__meta { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 1.1rem; color: var(--text-2); font-size: 0.9rem; }
.drive-summary__stat { display: inline-flex; align-items: center; gap: 0.35rem; }
.drive-summary__stat svg { width: 0.95rem; height: 0.95rem; color: var(--text-4); }
.drive-summary__done { margin-top: 1rem; min-width: 12rem; justify-content: center; padding-block: 0.9rem; }
@media (prefers-reduced-motion: no-preference) {
	.drive-summary[open] .drive-summary__check { animation: drive-check-pop 0.5s 0.08s backwards cubic-bezier(0.2, 1.3, 0.4, 1); }
}
@keyframes drive-check-pop { from { transform: scale(0.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* ── §70 Auszeichnungen – per-car strip + trophy case ──────────────────────
   Earned ownership milestones as editorial "logbook landmarks" (not gamified):
   a compact strip on the car Überblick, and a per-subject trophy-case page.
   Theme-aware via the shared tokens (no hard-coded colour). */
.achv-strip {
	margin: 0 0 1.25rem;
	padding: 0.85rem 1rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	background: var(--surface-sunken);
}
.achv-strip__eyebrow { margin: 0 0 0.55rem; }
.achv-chips { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.achv-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.3rem 0.75rem 0.3rem 0.3rem;
	border: 1px solid var(--accent-soft, var(--border));
	border-radius: var(--radius-pill);
	background: var(--surface-1);
	color: var(--text-1);
	font-size: 0.8rem;
	font-weight: 600;
	white-space: nowrap;
}
.achv-chip__medal {
	display: inline-flex; align-items: center; justify-content: center;
	width: 1.75rem; height: 1.75rem; flex: none;
	border-radius: var(--radius-pill);
	background: var(--accent-soft, var(--surface-2)); color: var(--accent);
}
.achv-chip__medal .icon { font-size: 1.05rem; stroke-width: 2; }
.achv-chip--status { border-style: dashed; color: var(--text-2); }
.achv-chip--status .achv-chip__medal { background: var(--surface-2); color: var(--text-3); }
.achv-chip__label { line-height: 1; }

.achv-next { margin-top: 0.85rem; }
.achv-next__head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 0.75rem;
	margin-bottom: 0.35rem;
	font-size: 0.78rem;
	color: var(--text-2);
}
.achv-next__pct { font-variant-numeric: tabular-nums; color: var(--text-3); }
.achv-bar {
	height: 7px;
	border-radius: var(--radius-pill);
	overflow: hidden;
	background: var(--surface-sunken);
	border: 1px solid var(--border-subtle);
}
.achv-bar__fill {
	height: 100%;
	background: var(--accent);
	border-radius: var(--radius-pill);
	transition: width 0.5s ease;
}

/* Trophy-case page. A two-column grid on tablet/desktop: the number of columns
   tracks the CONTENT width (auto-fit + a 320px floor), so it accounts for the
   sidebar without a viewport breakpoint, and max-width caps it at two columns
   (three would need >1000px, which max-width forbids). The intro, empty state,
   and the fleet block span both columns; per-car blocks fill the cells. Narrow
   widths collapse to one column automatically. */
.achv-page { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start; gap: 1.25rem;
  padding: clamp(1.1rem, 2.4vw, 2.2rem); max-width: 940px; }
.achv-page__identity { grid-column: 1 / -1; margin: 0 0 -.35rem; } /* §74 Inc 4 collector mark */
.achv-page__intro { grid-column: 1 / -1; margin: 0; color: var(--text-2); font-size: 0.92rem; }
.achv-block--wide { grid-column: 1 / -1; }
.achv-empty {
	grid-column: 1 / -1;
	display: flex; flex-direction: column; align-items: center; gap: 0.85rem;
	padding: 3rem 1.5rem; text-align: center; color: var(--text-2);
	border: 1px dashed var(--border); border-radius: var(--radius-card);
	background: var(--surface-sunken);
}
.achv-empty .icon { font-size: 2.2rem; color: var(--text-4); }
.achv-empty p { max-width: 42ch; margin: 0; }

.achv-block__head { display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.9rem; }
.achv-block__head .icon { color: var(--accent); font-size: 1.15rem; }
.achv-block__title { margin: 0; font-family: var(--font-serif); font-size: 1.15rem; font-weight: 600; }
.achv-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; }
.achv-item { display: flex; align-items: center; gap: 0.75rem; }
.achv-item__icon {
	display: inline-flex; align-items: center; justify-content: center;
	width: 2.1rem; height: 2.1rem; flex: none;
	border-radius: var(--radius-pill);
	background: var(--accent-soft, var(--surface-2)); color: var(--accent);
}
.achv-item__icon .icon { font-size: 1.2rem; stroke-width: 2; }
.achv-item--status .achv-item__icon { background: var(--surface-2); color: var(--text-3); }
.achv-item__body { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.achv-item__name { font-weight: 600; color: var(--text-1); }
.achv-item__date { font-size: 0.78rem; color: var(--text-3); font-variant-numeric: tabular-nums; }
.achv-block .achv-next { margin-top: 1rem; }

/* ===== §84 per-car review – shared prose (public detail page + editor preview) =====
   Defined here (not in the standalone showcase CSS) so the in-app editor's live
   preview, which loads only this stylesheet, renders identically to the public page. */
.sc-review { max-width: 40rem; font-size: 1.1875rem; line-height: 1.72; color: var(--text-2); }
.sc-review > * + * { margin-top: 1.15em; }
.sc-review > p:first-of-type { font-size: 1.28rem; line-height: 1.6; color: var(--text-1); }
.sc-review > p:first-of-type::first-letter { float: left; font-family: var(--font-serif);
  font-weight: 600; font-size: 3.4em; line-height: .82; padding: .04em .1em 0 0; color: var(--accent); }
.sc-review h1, .sc-review h2, .sc-review h3 { font-family: var(--font-serif); font-weight: 600;
  letter-spacing: -.01em; line-height: 1.15; color: var(--ink); }
.sc-review h1 { font-size: 2.15rem; letter-spacing: -.02em; margin-top: 2.1em; }
.sc-review h1:first-child { margin-top: 0; }
.sc-review h2 { font-size: 1.7rem; margin-top: 1.9em; }
.sc-review h3 { font-size: 1.35rem; margin-top: 1.55em; }
.sc-review a { color: var(--accent); text-decoration-line: underline; text-underline-offset: 2px;
  text-decoration-thickness: 1px; transition: text-decoration-thickness .12s ease; }
.sc-review a:hover { text-decoration-thickness: 2px; }
.sc-review strong { color: var(--text-1); }
.sc-review ul, .sc-review ol { padding-left: 1.35em; }
.sc-review li + li { margin-top: .4em; }
.sc-review li::marker { color: var(--accent); }
.sc-review blockquote { margin: 1.4em 0; padding: .15em 0 .15em 1.25em;
  border-left: 2px solid var(--accent); font-family: var(--font-serif); font-style: italic;
  font-size: 1.2em; color: var(--text-1); }
.sc-review blockquote p { margin: 0; }
.sc-review code { font-family: var(--font-mono); font-size: .88em;
  background: var(--surface-raised); padding: .12em .38em; border-radius: var(--radius-control); }
.sc-review hr { border: 0; height: auto; margin: 2em auto; text-align: center; }
.sc-review hr::before { content: "\00b7\00b7\00b7"; letter-spacing: .55em; font-size: 1.1rem; color: var(--text-4); }
/* GFM tables (spec sheets). display:block + max-content lets a wide table scroll
   inside its own box on narrow screens instead of pushing the page sideways. */
.sc-review table { display: block; width: max-content; max-width: 100%; overflow-x: auto;
  border-collapse: collapse; font-size: .95em; line-height: 1.5; }
.sc-review thead th { font-family: var(--font-serif); font-weight: 600; text-align: left;
  color: var(--ink); border-bottom: 2px solid var(--accent); }
.sc-review thead th:empty { border-bottom: 0; padding-top: 0; padding-bottom: 0; } /* headerless spec tables */
.sc-review th, .sc-review td { padding: .5em .95em; vertical-align: top;
  border-bottom: 1px solid var(--border-subtle); }
.sc-review th:first-child, .sc-review td:first-child { padding-left: 0; }
.sc-review tbody tr:last-child td { border-bottom: 0; }
.sc-review tbody tr:nth-child(even) { background: color-mix(in oklab, var(--surface-raised) 55%, transparent); }
.sc-review tbody td:first-child { color: var(--text-1); font-weight: 500; }
.sc-review img { max-width: 100%; } /* defensive – images are dropped server-side */

/* ===== §84 review editor modal ===== */
.review-modal .form-body { display: flex; flex-direction: column; gap: 1rem; }
.review-toolbar { display: flex; flex-wrap: wrap; gap: .35rem; }
.review-tool { display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.1rem; height: 2.1rem; padding: 0 .55rem; cursor: pointer;
  font: inherit; font-size: .85rem; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-control); transition: background .12s ease, color .12s ease, border-color .12s ease; }
.review-tool:hover { color: var(--accent); border-color: color-mix(in oklab, var(--accent) 40%, var(--border-subtle)); }
.review-tool--bold { font-weight: 800; }
.review-tool--italic { font-style: italic; font-family: var(--font-serif); }
.review-editor { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: start; }
.review-editor__src { width: 100%; min-height: 20rem; resize: vertical; box-sizing: border-box;
  padding: .8rem .9rem; font-family: var(--font-mono); font-size: .92rem; line-height: 1.6;
  color: var(--text-1); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-control); }
.review-editor__src:focus { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft); }
.review-editor__preview { min-height: 20rem; padding: .8rem 1rem; overflow-y: auto; max-height: 28rem;
  background: var(--surface-2); border: 1px solid var(--border-subtle); border-radius: var(--radius-control); }
.review-preview__label { margin: 0 0 .6rem; font-size: .7rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-4); }
.review-editor__preview .sc-review { max-width: none; font-size: 1rem; }
.review-editor__preview .sc-review > p:first-of-type { font-size: 1.06rem; }
.review-preview__empty { color: var(--text-4); font-style: italic; }
@media (max-width: 720px) {
  .review-editor { grid-template-columns: 1fr; }
  .review-editor__preview { max-height: 16rem; }
}

/* §85 transfer-out modal */
.transfer-crosses { list-style: none; padding: 0; margin: 0.75rem 0; font-size: 0.9rem; }
.transfer-crosses li { padding: 0.35rem 0; border-bottom: 1px solid var(--border-subtle); }
.transfer-crosses li:last-child { border-bottom: 0; }
.transfer-crosses__excl { color: var(--text-4); }
.transfer-modal .check-row { display: flex; align-items: center; gap: 0.5rem; margin: 0.4rem 0; cursor: pointer; }
.transfer-note { margin-top: 0.75rem; }
.transfer-result:empty { display: none; }
.transfer-link { margin-top: 0.75rem; padding: 0.75rem; border: 1px solid var(--border); border-radius: var(--radius, 0.5rem); }
.transfer-link__label { font-size: 0.85rem; color: var(--text-4); margin: 0 0 0.4rem; }
.transfer-link__url { width: 100%; box-sizing: border-box; font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.85rem; padding: 0.45rem 0.55rem; border: 1px solid var(--border); border-radius: 0.3rem; color: var(--ink); background: transparent; }

/* §87 unified upload manager – one dropzone at three size variants (inline /
   panel / rail). Reuses the doc-upload-drop visual language (dashed → solid
   accent on fill). Children never intercept drag events so dragover/drop always
   land on the label. */
.uploader {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	border: 1.5px dashed var(--border);
	border-radius: var(--radius-control);
	color: var(--text-3);
	cursor: pointer;
	transition: color var(--timing-base) var(--ease-out), border-color var(--timing-base) var(--ease-out), background var(--timing-base) var(--ease-out);
}
.uploader > * { pointer-events: none; }
.uploader:hover { color: var(--accent); border-color: var(--accent); background: var(--tint-sm); }
/* Drag-over: a file is being dragged onto the dropzone ($_upl_<ID>_drag) – a clear
   active target (solid accent border + accent wash), stronger than the pointer hover. */
.uploader--dragover { color: var(--accent); border-color: var(--accent); border-style: solid; background: color-mix(in oklab, var(--accent) 10%, transparent); }
.uploader--filled { color: var(--ink); border-style: solid; border-color: var(--accent); background: var(--accent-soft); }
.uploader__body { display: flex; flex-direction: column; min-width: 0; }
.uploader__name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploader__types { font-size: 0.8rem; color: var(--text-4); }

/* inline – one form row; matches form-input height, single line. */
.uploader--inline { padding: 0.55rem 0.8rem; }
.uploader--inline .uploader__icon { flex: none; }
.uploader--inline .uploader__hint,
.uploader--inline .uploader__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* panel – block dropzone: centred column, generous padding, larger icon. */
.uploader--panel {
	flex-direction: column;
	justify-content: center;
	text-align: center;
	gap: 0.5rem;
	padding: 1.6rem 1rem;
}
.uploader--panel .uploader__icon { font-size: 1.5rem; }
.uploader--panel .uploader__body { align-items: center; }

/* §87 rail – multi-file surface: a drop target over a per-file cards container
   the server patches. The dropzone reuses .uploader; the cards flow-wrap below. */
.uploader--rail { flex-direction: column; justify-content: center; text-align: center; gap: 0.5rem; padding: 1.1rem 1rem; }
.uploader-rail { display: flex; flex-direction: column; gap: 0.75rem; }
.uploader-rail__cards { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.uploader-rail__cards:empty { display: none; }

/* §87 gated – the §31 intake dropzone as a prominent block above the journal /
   serviceheft table (pick/drop → __intakeStart; no cards, intake's rail is in the
   modal). Panel-like: centred column, generous padding, larger icon. */
.uploader--gated { flex-direction: column; justify-content: center; text-align: center; gap: 0.5rem; padding: 1.6rem 1rem; margin-bottom: 1rem; }
.uploader--gated .uploader__icon { font-size: 1.6rem; }
.uploader--gated .uploader__body { align-items: center; }
.upl-card {
	position: relative;
	width: 6.5rem;
	border: 1px solid var(--border);
	border-radius: var(--radius-control);
	overflow: hidden;
	background: var(--surface-sunken);
	font-size: 0.75rem;
}
.upl-card__thumb { position: relative; aspect-ratio: 1 / 1; background: var(--surface-sunken); display: grid; place-items: center; overflow: hidden; color: var(--text-4); }
/* Fill an absolute layer so the image never dictates the box height (an in-flow
   height:100% img makes the grid row auto-size to the image, defeating aspect-ratio);
   aspect-ratio then owns the shape and object-fit: cover crops to it. */
.upl-card__thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.upl-card__name { padding: 0.25rem 0.4rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upl-card__phase { padding: 0 0.4rem 0.3rem; color: var(--text-3); }
.upl-card__phase--err { color: var(--danger, #c0392b); }
.upl-card__bar { height: 3px; background: var(--tint-sm); }
.upl-card__bar > span { display: block; height: 100%; background: var(--accent); transition: width var(--timing-base) var(--ease-out); }
/* §87 Inc 2 – the richer states an intake (staging) rail renders through the card. */
.upl-card__pdf { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.03em; color: var(--text-4); }
.upl-card__edited { position: absolute; top: 0.2rem; right: 0.2rem; display: grid; place-items: center; width: 1.15rem; height: 1.15rem; border-radius: 50%; background: var(--accent); color: #fff; font-size: 0.7rem; line-height: 1; }
/* §31 OCR read: a scanner beam sweeps the staged document thumbnail while $_scanning
   – reuses the ausweis-scan beam (keyframes ausweis-beam), over the real doc image. */
.upl-card__scan { position: absolute; inset: 0; overflow: hidden; pointer-events: none; background: color-mix(in oklab, var(--accent) 8%, transparent); }
.upl-card__beam { position: absolute; left: -10%; right: -10%; top: 0; height: 40%; transform: translateY(-120%); background: linear-gradient(180deg, transparent, color-mix(in oklab, var(--accent) 30%, transparent) 42%, color-mix(in oklab, var(--accent) 65%, transparent) 50%, color-mix(in oklab, var(--accent) 30%, transparent) 58%, transparent); animation: ausweis-beam 1.9s var(--ease-in-out) infinite; }
@media (prefers-reduced-motion: reduce) { .upl-card__beam { animation: none; opacity: 0.45; transform: translateY(75%); } }
.upl-card--editable { cursor: pointer; }
.upl-card--editable:hover { border-color: var(--accent); }
.upl-card--sel { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* §86 Inc 2 – gallery manager strip beneath the car-detail hero. A persistent row
   of the car's photos (cover-first) with per-photo set-cover/delete, plus the §87
   rail uploader as the add tile. Distinct from the transient rail it embeds. */
/* §86: the gallery is a collapsible <details> grouped under the cover (hero grid
   area "gallery"). These override the global details/summary accordion chrome
   (border-top, scrim bg, hover padding-shift) – same reason .action-menu does. */
.car-gallery { grid-area: gallery; margin: 0; border-top: 0; }
.car-gallery__summary {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	padding: 0.4rem 0.1rem;
	background: none;
	list-style: none;
	cursor: pointer;
	font-family: var(--font-mono);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--text-4);
	transition: color var(--timing-base) var(--ease-out);
}
.car-gallery__summary::-webkit-details-marker { display: none; }
.car-gallery__summary:hover { background: none; padding-left: 0.1rem; color: var(--accent); }
.car-gallery[open] > summary { background: none; }
/* a self-contained caret (the sprite has no chevron) – points right when collapsed,
   rotates down when open. */
.car-gallery__chev {
	width: 0;
	height: 0;
	border-top: 4px solid transparent;
	border-bottom: 4px solid transparent;
	border-left: 5px solid currentColor;
	transition: transform var(--timing-base) var(--ease-out);
}
.car-gallery[open] .car-gallery__chev { transform: rotate(90deg); }
.car-gallery__count { color: var(--text-3); }
.car-gallery__count::before { content: "\00b7\00a0"; }
/* first-few-thumbs peek, right-aligned in the summary; hidden once expanded. */
.car-gallery__peek { display: inline-flex; gap: 0.2rem; margin-left: auto; }
.car-gallery__peek img {
	width: 1.4rem;
	height: 1.4rem;
	object-fit: cover;
	border-radius: 3px;
	border: 1px solid var(--border-subtle);
	display: block;
}
.car-gallery[open] .car-gallery__peek { display: none; }
/* flex-start, NOT stretch: while a file uploads the rail grows (dropzone + card),
   and stretch would inflate every already-uploaded thumbnail to that height. */
/* §86: a fixed 3-up grid (was a 6.5rem flex-wrap that fell to 2-up on a phone and
   is now boxed into the ≤320px hero media column on desktop – 3-up fits both). */
.car-gallery__strip { display: grid; grid-template-columns: repeat(3, 1fr); align-items: start; gap: 0.5rem; margin-top: 0.4rem; }
.gallery-thumb {
	position: relative;
	width: auto;
	aspect-ratio: 1 / 1;
	border: 1px solid var(--border);
	border-radius: var(--radius-control);
	overflow: hidden;
	background: var(--surface-sunken);
}
.gallery-thumb__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-thumb--cover { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.gallery-thumb__badge {
	position: absolute; top: 0; left: 0;
	padding: 0.1rem 0.4rem;
	font-size: 0.62rem; font-weight: 600; letter-spacing: 0.02em;
	color: #fff; background: var(--accent);
	border-bottom-right-radius: var(--radius-control);
}
.gallery-thumb__actions {
	position: absolute; top: 0.25rem; right: 0.25rem;
	display: flex; gap: 0.2rem;
	opacity: 0; transition: opacity var(--timing-base) var(--ease-out);
}
.gallery-thumb:hover .gallery-thumb__actions,
.gallery-thumb:focus-within .gallery-thumb__actions { opacity: 1; }
@media (hover: none) { .gallery-thumb__actions { opacity: 1; } }
.gallery-thumb__btn {
	display: grid; place-items: center;
	width: 1.55rem; height: 1.55rem;
	padding: 0;
	border: none; border-radius: 50%;
	background: rgba(0,0,0,0.6); color: #fff;
	font-size: 0.8rem;
	cursor: pointer;
	transition: background var(--timing-base) var(--ease-out);
}
.gallery-thumb__btn .icon { font-size: 0.9rem; }
.gallery-thumb__btn:hover { background: var(--accent); }
.gallery-thumb__btn--danger:hover { background: var(--clr-sell); }
/* the add-tile rail (and the at-cap upsell) span the full row beneath the 3-up thumbs
   so its in-flight progress cards have room instead of cramming one 1/3-width cell. */
.car-gallery__strip > .uploader-rail { grid-column: 1 / -1; width: auto; }
.car-gallery__strip .uploader--rail {
	aspect-ratio: auto;
	flex-direction: row;
	justify-content: center;
	padding: 0.6rem 1rem;
	gap: 0.5rem;
	margin: 0;
	font-size: 0.72rem;
}
.car-gallery__strip .uploader--rail .uploader__icon { font-size: 1.1rem; }
/* §86/§74 at-cap add-tile: a dropzone-shaped link to /billing that stands in for the
   uploader when the gallery is full. Accent-tinted so it reads as an upgrade CTA
   (not a disabled tile); the whole anchor is the target, so no text-decoration. */
.uploader--upsell { color: var(--accent); border-color: color-mix(in oklab, var(--accent) 55%, var(--border)); text-decoration: none; }
.uploader--upsell:hover { color: var(--accent); border-color: var(--accent); border-style: solid; background: var(--tint-sm); }
.uploader__upgrade { font-weight: 600; font-size: 0.68rem; }

@layer components {
	/* §92 Werksdatenblatt – a certificate-styled factory data sheet on the
	   "Editorial × Instrument" system (serif masthead, mono figures, a seal). */
	.panel--wdb { position: relative; overflow: hidden; }
	/* Fine engine-turned top rule – a light guilloché nod. */
	.panel--wdb::before {
		content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
		background: repeating-linear-gradient(90deg, var(--accent) 0 6px, transparent 6px 10px);
		opacity: 0.5;
	}
	.wdb-head {
		display: flex; justify-content: space-between; align-items: flex-start;
		gap: 1rem; padding-bottom: 1rem; margin-bottom: 1.25rem;
		border-bottom: 1px solid var(--border-subtle);
	}
	.wdb-eyebrow {
		display: block; font-family: var(--font-mono); font-size: 0.7rem;
		letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent);
	}
	.wdb-make {
		font-family: var(--font-serif); font-size: clamp(1.5rem, 4vw, 2.1rem);
		line-height: 1.1; margin: 0.15rem 0 0;
	}
	.wdb-model { margin: 0.2rem 0 0; color: var(--text-muted); }
	/* Seal – a stamped provenance medallion drawn as SVG (ring text + centre),
	   faintly rotated for the "single-ink stamp" finish; theme-aware via currentColor. */
	.wdb-seal { flex: none; width: 8rem; height: 8rem; color: var(--accent); transform: rotate(-4deg); }
	.wdb-seal__svg { width: 100%; height: 100%; overflow: visible; }
	.wdb-seal__ring { font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 1.4px; fill: currentColor; }
	.wdb-seal__mono { font-family: var(--font-serif); font-weight: 700; font-size: 19px; }
	.wdb-seal__code { font-family: var(--font-mono); font-weight: 700; font-size: 17px; letter-spacing: 0.3px; fill: currentColor; }
	.wdb-seal__ver { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px; fill: currentColor; }
	/* §107 Inc 8: the Energieetikette bars above the spec grid. The chart draws the
	   official green-to-red ramp itself (it is reproducing a federal artefact, so those
	   colours are fixed in both themes); everything here is chrome. */
	.energy-label { margin: 0 0 1.5rem; padding: 0 0 1.25rem; border-bottom: 1px solid var(--border-subtle); }
	.energy-label__chart { display: block; width: 100%; max-width: 26rem; height: 230px; } /* 7 rows + callouts */
	.energy-label__caption { margin: 0.5rem 0 0; max-width: 30rem; font-size: 0.78rem; line-height: 1.45; color: var(--text-muted); }
	.wdb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1.25rem 2rem; }
	.wdb-block__title {
		font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.12em;
		text-transform: uppercase; color: var(--text-muted); margin: 0 0 0.5rem;
		padding-bottom: 0.35rem; border-bottom: 1px solid var(--border-subtle);
	}
	.wdb-dl { margin: 0; }
	.wdb-item { display: flex; justify-content: space-between; gap: 1rem; padding: 0.2rem 0; align-items: baseline; }
	.wdb-item__label { color: var(--text-muted); }
	.wdb-item__value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
	.wdb-foot {
		display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; align-items: baseline;
		margin-top: 1.5rem; padding-top: 0.9rem; border-top: 1px solid var(--border-subtle);
		font-size: 0.78rem; color: var(--text-muted);
	}
	.wdb-years { font-family: var(--font-mono); color: var(--accent); }
	.wdb-rarity { font-family: var(--font-mono); color: var(--accent); }
	/* §93 rarity badge chips – the collectible narrative + the "rare in CH" mark. */
	.wdb-badge {
		display: inline-flex; align-items: center; font-family: var(--font-mono);
		font-size: 0.72rem; letter-spacing: 0.03em; padding: 0.08rem 0.5rem;
		border-radius: 999px; white-space: nowrap; border: 1px solid var(--accent);
		color: var(--accent);
	}
	.wdb-badge--collectible {
		font-weight: 600; background: color-mix(in srgb, var(--accent) 12%, transparent);
	}
	.wdb-limited { font-style: italic; }
	.wdb-source { margin-left: auto; opacity: 0.8; }
	.wdb-download {
		display: inline-flex; align-items: center; gap: 0.4rem; margin-top: 0.8rem;
		width: fit-content; padding: 0.35rem 0.75rem;
		font-family: var(--font-mono); font-size: 0.8rem; color: var(--accent);
		text-decoration: none; border: 1px solid var(--accent); border-radius: 999px;
	}
	.wdb-download:hover { background: var(--accent-soft); }
	.wdb-download__icon { --icon-size: 0.9rem; }
	/* §91: the original federal Typenschein – a subordinate, ghost variant of the
	   primary "download data sheet" pill, sitting just beneath it. */
	.wdb-download--original {
		margin-top: 0.4rem; border-color: var(--border);
		color: var(--text-muted); font-size: 0.75rem;
	}
	.wdb-download--original:hover { border-color: var(--accent); color: var(--accent); }

	/* ── §38 audit history (Verlauf) ───────────────────────────────────────
	   Per-car who-changed-what timeline: a tamper-evidence badge over a list of
	   events, each an entity/verb chip line with a field-level before→after diff. */
	.history-modal .form-modal-content { max-width: 42rem; }
	.history-badge { margin-bottom: 1rem; }
	.history-list {
		list-style: none; margin: 0; padding: 0;
		display: flex; flex-direction: column; gap: 0.6rem;
	}
	.history-item {
		padding: 0.6rem 0.75rem;
		border: 1px solid var(--border-subtle);
		border-radius: var(--radius-control);
		background: var(--surface-1);
	}
	.history-item__meta { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
	.history-item__spacer { flex: 1 1 auto; }
	.history-item__entity { font-size: 0.85rem; color: var(--text-2); }
	.history-item__target { font-size: 0.85rem; color: var(--text-2); font-weight: 600; }
	.history-item__count { font-size: 0.75rem; color: var(--text-3); }
	.history-item__time {
		font-size: 0.75rem; color: var(--text-3);
		font-variant-numeric: tabular-nums; white-space: nowrap;
	}
	.history-item__actor { margin-top: 0.15rem; font-size: 0.8rem; color: var(--text-3); }
	.history-chip {
		display: inline-block; padding: 1px 8px;
		border-radius: var(--radius-pill);
		font-size: 0.72rem; font-weight: 600; letter-spacing: 0.02em;
		background: var(--surface-3); color: var(--text-2);
		border: 1px solid var(--border); white-space: nowrap;
	}
	.history-chip[data-verb="create"], .history-chip[data-verb="grant"] {
		color: var(--clr-sell); border-color: color-mix(in oklab, var(--clr-sell) 40%, transparent);
	}
	.history-chip[data-verb="delete"], .history-chip[data-verb="revoke"], .history-chip[data-verb="dispose"] {
		color: var(--clr-repair); border-color: color-mix(in oklab, var(--clr-repair) 40%, transparent);
	}
	.history-diff {
		list-style: none; margin: 0.45rem 0 0; padding: 0.4rem 0 0;
		border-top: 1px dashed var(--border-subtle);
		display: flex; flex-direction: column; gap: 0.2rem;
	}
	.history-diff__row {
		display: grid; grid-template-columns: minmax(6rem, 10rem) 1fr auto 1fr;
		align-items: baseline; gap: 0.4rem; font-size: 0.8rem;
	}
	.history-diff__field { color: var(--text-3); }
	.history-diff__from { color: var(--text-3); text-decoration: line-through; font-family: var(--font-mono); word-break: break-word; }
	.history-diff__arrow { color: var(--text-4); }
	.history-diff__to { color: var(--text-1); font-family: var(--font-mono); word-break: break-word; }
	@media (max-width: 34rem) {
		.history-diff__row { grid-template-columns: 1fr; gap: 0.05rem; }
		.history-diff__arrow { display: none; }
	}

	/* §99: the §15 "was wurde gemacht?" catalog, collapsed. The summary reuses
	   .form-section-title verbatim (same micro-label rule as every other form
	   section head) and only adds the caret + ticked-count, so a collapsed block
	   is indistinguishable from a plain section header until you look for it. */
	.entry-tags__summary {
		display: flex; align-items: center; gap: 0.4rem;
		cursor: pointer; list-style: none;
		transition: color var(--timing-base) var(--ease-out);
	}
	.entry-tags__summary::-webkit-details-marker { display: none; }
	.entry-tags__summary:hover { color: var(--accent); }
	.entry-tags__summary::after {
		content: ""; margin-left: auto;
		width: 0; height: 0;
		border-top: 4px solid transparent;
		border-bottom: 4px solid transparent;
		border-left: 5px solid currentColor;
		transition: transform var(--timing-base) var(--ease-out);
	}
	.entry-tags[open] > .entry-tags__summary::after { transform: rotate(90deg); }
	/* ticked-count, written by Datastar; empty (and so invisible) at zero. */
	.entry-tags__count:not(:empty) {
		font-size: 0.7rem; font-weight: 700;
		padding: 1px 7px; border-radius: var(--radius-pill);
		background: var(--accent-soft); color: var(--accent);
	}
}

/* §106 C – the "why this number" disclosure under the Fixkosten table: the tax base,
   the schedule version that applied, the CHF breakdown, and the rule's own caveats.
   Reference material, so it reads quiet: same collapsed-disclosure shape as
   .bill-disclosure, but sized down to sit under a table rather than beside one. */
.tax-prov {
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-control);
	margin-top: 0.75rem;
}
.tax-prov__summary {
	cursor: pointer;
	padding: 0.5rem 0.8rem;
	font-size: 0.85rem;
	color: var(--text-3);
	list-style: none;
	display: flex;
	align-items: center;
}
.tax-prov__summary::-webkit-details-marker { display: none; }
.tax-prov__summary::after {
	content: "\25be"; /* ▾ */
	margin-left: auto;
	color: var(--text-4);
	transition: transform 0.15s ease;
}
.tax-prov[open] .tax-prov__summary::after { transform: rotate(180deg); }
.tax-prov__body {
	padding: 0 0.8rem 0.8rem;
	font-size: 0.85rem;
	color: var(--text-3);
}
.tax-prov__meta {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 0.2rem 0.9rem;
	margin: 0 0 0.6rem;
}
.tax-prov__meta dt { color: var(--text-4); }
.tax-prov__meta dd { margin: 0; color: var(--text-2); }
.tax-prov__table {
	width: 100%;
	border-collapse: collapse;
	margin-bottom: 0.6rem;
}
.tax-prov__table td {
	padding: 0.2rem 0;
	border-bottom: 1px solid var(--border-subtle);
}
.tax-prov__table tr:last-child td { border-bottom: none; }
.tax-prov__chf {
	text-align: right;
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	color: var(--text-2);
}
.tax-prov__notes {
	margin: 0;
	padding-left: 1.1rem;
	color: var(--text-4);
}
.tax-prov__notes li { margin: 0.15rem 0; }

/* §110: a standing advisory (a VVV Art. 13 rule the plate group does not satisfy).
   Warmer than .form-hint, quieter than an error – the app never blocks on these. */
.form-hint--warn {
	color: var(--clr-warning, var(--text-2));
	border-left: 2px solid var(--clr-warning, var(--border-subtle));
	padding-left: 0.6rem;
}

/* §108 Fahrzeug zum Verkauf – sell modal (disclosure console) + readiness meter. */
.sell-modal .form-modal-content { max-width: 34rem; }
.sell-group {
	border: 0;
	border-top: 1px solid var(--border-subtle);
	margin: 1.1rem 0 0;
	padding: 1.1rem 0 0;
}
.sell-group__legend {
	font-family: var(--font-mono);
	font-size: 0.72rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--text-4);
	padding: 0;
	margin-bottom: 0.6rem;
}
.sell-modal .check-row { display: flex; align-items: center; gap: 0.5rem; margin: 0.45rem 0; cursor: pointer; }
.sell-price-amount { margin-top: 0.7rem; }
.sell-amount-row { display: flex; gap: 0.5rem; }
.sell-currency { max-width: 5rem; text-transform: uppercase; }
.sell-indent { margin: 0.4rem 0 0; }
.sell-mt { margin-top: 0.8rem; }
.sell-subnote { margin: 0.25rem 0 0.4rem; font-size: 0.82rem; }
.listing-link { margin: 0.4rem 0 0.2rem; }
.listing-link__label {
	margin: 0 0 0.25rem;
	font-family: var(--font-mono);
	font-size: 0.72rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--text-4);
}
.listing-link__url { width: 100%; font-family: var(--font-mono); font-size: 0.85rem; }
.sell-ready {
	margin: 1.1rem 0 0;
	padding: 0.85rem 1rem;
	border-radius: var(--radius-card, 10px);
	background: var(--surface-sunken, var(--tint-sm));
	border: 1px solid var(--border-subtle);
}
.sell-ready__title {
	margin: 0 0 0.5rem;
	font-family: var(--font-mono);
	font-size: 0.72rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--text-4);
}
.sell-ready__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.sell-ready__item {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: baseline;
	gap: 0.35rem 0.5rem;
	font-size: 0.88rem;
	color: var(--text-3);
}
.sell-ready__item svg { width: 0.95em; height: 0.95em; align-self: center; color: var(--text-4); }
.sell-ready__item.is-ok { color: var(--text-1); }
.sell-ready__item.is-ok svg { color: var(--accent); }
.sell-ready__label { min-width: 0; }
.sell-ready__value { font-family: var(--font-mono); color: var(--text-2); }
.sell-ready__hint {
	grid-column: 2 / -1;
	font-size: 0.8rem;
	color: var(--text-4);
}
.listing-grant-result:empty { display: none; }
.listing-grant {
	margin-top: 0.6rem;
	padding: 0.75rem;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card, 10px);
	background: var(--surface-sunken, var(--tint-sm));
	display: grid;
	gap: 0.5rem;
}
.listing-grant .listing-link__url { width: 100%; }
