/* portal.officeplanner.pro — browser UI, plain CSS, no framework. Same design
   tokens AND same shell structure (sidebar + top bar) as
   admin.officeplanner.pro/public/app/style.css for a consistent brand (user request
   2026-09-06: "einheitlich zum Admin-Panel") - components this app doesn't
   use (tabs, breadcrumb, activation-row bars, expand-chevron) were left out
   rather than copied wholesale. */

:root {
	--bg: #f4f5f7;
	--surface: #ffffff;
	--border: #e4e6eb;
	--text: #1c2230;
	--text-muted: #6b7280;
	--primary: #2454ff;
	--primary-hover: #1a3fd6;
	--on-primary: #ffffff;		/* text on the primary fill - dark in the dark scheme, where the fill is light */
	--danger: #c53030;
	--danger-bg: #fbe7e7;
	--success: #166a35;
	--success-bg: #e6f6ec;
	--warn: #92650a;
	--warn-bg: #fdf1d8;
	--radius: 10px;
	--radius-lg: 18px;		/* login card / auth inputs - softer than the 10px used inside the app */
	--radius-md: 12px;
	--input-h: 3.4667rem;		/* touch-friendly auth fields, taller than the dense in-app forms */
	--field-icon: #9aa2b1;	/* leading/trailing glyphs inside an input - never the text colour, they must recede */
	--shadow: 0 1px 2px rgba(20, 24, 34, .06), 0 4px 16px rgba(20, 24, 34, .06);
	--dialog-backdrop: rgba(20, 24, 34, .48);
	--topbar-h: 4rem;
	--topbar-compact-padding: 1.0667rem;
	--topbar-compact-gap: .5333rem;
	--sidebar-bg: #182238;
	--sidebar-text: #dfe3ee;
	--sidebar-text-muted: #8891a8;
	--sidebar-text-strong: #ffffff;	/* the brand and the active entry */
	--logo-name: var(--text);	/* the name in the product logo (BRAND_LOGO); its tiles keep their colours */
	--sidebar-logo-width: 11rem;
	/* The block under the sidebar logo (client, 2026-11-05): which app, in the portal
	   also whose account - left-aligned with the navigation, icon on the nav's icon column. */
	--sidebar-context-padding: .9333rem 1.3333rem;		/* the label starts where the section headings do */
	--sidebar-context-reading-indent: 3px;		/* the width of a nav entry's marker: the icon stands on the nav icons' column */
	--sidebar-context-label-size: .72rem;
	--sidebar-context-gap: .4rem;
	--sidebar-context-reading-size: .92rem;
	--sidebar-context-icon-size: 1.05rem;
	--sidebar-context-icon-gap: .6667rem;
	/* The person icon before the customer number (client, 2026-11-05): a line icon in
	   the blue of the logo's tiles, lifted so it holds 4.8:1 on the dark sidebar
	   (the tiles' #2454ff reaches only 2.4:1 there), a little bolder than the
	   line icons of the content. The sidebar is dark in both schemes. */
	--sidebar-context-icon-color: #5b8cff;
	--sidebar-context-icon-stroke: 2.4;
	/* The customer number in its frame, the label before it (client, 2026-11-05). */
	--sidebar-context-value-padding: .0667rem .5333rem;
	--sidebar-context-value-border: 1px solid var(--sidebar-text-muted);
	--sidebar-context-value-radius: 6px;
	--auth-logo-width: 16rem;
	--sidebar-backdrop: rgba(20, 24, 34, .45);	/* behind the off-canvas sidebar on narrow screens */
	--sidebar-hover-bg: rgba(255, 255, 255, .07);
	--sidebar-border: rgba(255, 255, 255, .08);
	/* Deliberately darker/receding, NOT the hover/active highlight above -
	   a section label must never look like an interactive/active nav item. */
	--sidebar-section-bg: rgba(0, 0, 0, .18);
	/* Module symbols from the product page cards (UI-PATTERNS "Icons"): drawn as
	   line icons in the accent colour, the way the product page draws them. */
	--module-icon-size: 1.3333rem;
	--module-icon-stroke: 1.8;
	--module-icon-gap: .5333rem;
	/* Layout (2026-10-23): the content takes the room beside the sidebar up to
	   --content-max; forms keep a readable width; a compact table is as wide as
	   its content but not narrower than --table-compact-min. */
	--content-max: 96rem;
	--form-max: 42.6667rem;
	--table-compact-min: 32rem;
	--reading-font-size: .85rem;
	--reading-padding-block: .2667rem;
	--reading-padding-inline: .8rem;
	--reading-border: 1px solid var(--border);
	--table-column-gap: .8rem;
	--action-gap: .5333rem;
	--row-field-width: 24rem;	/* a select or input beside its button in a .row */
	--feature-icon-radius: 50%;
	--feature-icon-size: 3.2rem;
	--feature-icon-glyph-size: 1.6rem;
	--feature-icon-bg: #eef1ff;
	--feature-storage-icon-bg: #e9f6f0;
	--feature-storage-icon: #3bb86b;
	--feature-card-gap: 1.6rem;
	--feature-title-size: 1.3333rem;
	--feature-title-gap: .9333rem;
	--feature-section-gap: .9333rem;
	--feature-label-width: 17rem;
	--feature-label-bg: #f0f2f5;
	--feature-value-bg: #f8f9fb;
	--feature-cell-padding: .5333rem .9333rem;
	--feature-corner: 6px;
	--feature-rule: 1px solid var(--border);
	--feature-row-rule: 1px solid var(--surface);
	--feature-label-weight: 600;
	--feature-info-size: 1.0667rem;
	--feature-info-gap: .5333rem;
	--table-framed-cell-padding: .4rem .9333rem;
	--price-mobile-amount-width: 8rem;
	--table-framed-font-size: .9rem;
	--table-framed-rule: 1px solid #edf0f4;
	--module-cell-label-size: .78rem;
	--module-record-gap: .5333rem;
	--module-record-padding: .9333rem;
	--module-label-gap: .2667rem;
	--visually-hidden-size: 1px;
	--payment-date-width: 8rem;
	--payment-amount-width: 9rem;
	--payment-status-width: 10.5rem;
	--payment-columns: var(--payment-date-width) minmax(0, 1fr) var(--payment-amount-width) var(--payment-status-width);
	--payment-record-gap: 1.3333rem;
	--payment-record-padding: 1.0667rem;
	--payment-record-spacing: .6667rem;
	--payment-status-border-width: 4px;
	--payment-title-size: 1rem;
	--payment-amount-size: 1.1333rem;
	--payment-label-size: .78rem;
	--payment-status-icon-size: 1rem;
	--empty-state-padding: 2.1333rem;
	--empty-state-gap: .8rem;
	--table-emphasis-bg: #e8edff;
	/* Radio cards (choiceCardsHtml(), UI-PATTERNS "Forms"): a choice among a few offers with their prices -
	   base package, module add-on - as wide as a card needs, several in a row on wide screens. */
	--choice-card-min: 15rem;
	--choice-card-gap: .8rem;
	--choice-card-price-size: 1.0667rem;
	--choice-card-radio-offset: .2rem;
	--choice-card-disabled-opacity: .5;
	/* The bars of the card "AI usage" (aiMeterHtml(), UI-PATTERNS "Readings and status"): the monthly AI quota and the
	   purchased credits left, each 0 to 100 %; the width is data, set by sizeAiMeters() as --ai-meter-fill. */
	--ai-meter-height: .8rem;
	--ai-meter-radius: 6px;
	--ai-meter-track: var(--feature-label-bg);
	--ai-meter-gap: .4rem;
	/* A dialog with content of its own (openDialog()): wider than a question. */
	--dialog-wide-max: 46rem;
	--legal-card-max: 56rem;	/* a legal text and its consent page: room for the text, a readable line */
	/* The colour scheme switch at the end of the top bar (themeToggleHtml()). */
	--theme-toggle-size: 2.1333rem;
	--theme-toggle-icon-size: 1.2rem;
	--discount-indent: 1.6rem;	/* a discount row stands indented under its service */	/* column titles and total of the price overview - a blue tint, unlike the grey group titles */
	/* The info icon and its tooltip (infoIcon(), UI-PATTERNS "Help icons") - the same names and values as the admin panel. */
	--info: #ffc700;
	--info-ink: #4a3b00;
	--tooltip-bg: #1f2430;
	--tooltip-ink: #ffffff;
	--z-tooltip: 3000;
	--transition: 120ms ease;
	--intro-max: 75ch;	/* line length of a section introduction - readable, not across the whole card */
	/* Customer reports (UI-PATTERNS "Feedback"): a chosen image before sending, an image of a sent report. */
	--feedback-preview-size: 4.8rem;
	--feedback-image-height: 9rem;
}

/* Dark scheme (client, 2026-11-05): only colour tokens change, never a size -
   the values of the Windows app's dark theme, the same block as the admin
   panel. Set by theme.js on <html data-theme="dark">. Not pure black: a black
   ground under white text produces halation. */
:root[data-theme="dark"] {
	color-scheme: dark;
	--bg: #161920;
	--surface: #1e222b;
	--border: #2d323d;
	--text: #e4e7ec;
	--text-muted: #99a1af;
	--primary: #5b8cff;		/* lifted: the light scheme's blue has too little contrast here */
	--primary-hover: #7aa2ff;
	--on-primary: #0e1729;
	--danger: #e5645a;
	--danger-bg: #2c1d1d;
	--success: #3ec46d;
	--success-bg: #17291f;
	--warn: #e8b93a;
	--warn-bg: #2e2715;
	--field-icon: #6b7385;
	--shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 4px 16px rgba(0, 0, 0, .45);
	--dialog-backdrop: rgba(0, 0, 0, .6);
	--sidebar-bg: #11151d;
	--sidebar-backdrop: rgba(0, 0, 0, .55);
	--feature-icon-bg: #1c2740;
	--feature-storage-icon-bg: #17291f;
	--feature-storage-icon: #3ec46d;
	--feature-label-bg: #262b35;
	--feature-value-bg: #222731;
	--table-framed-rule: 1px solid #2a2f3a;
	--table-emphasis-bg: #1c2740;
	--info: #d8a800;
	--info-ink: #241c00;
	--tooltip-bg: #39414f;		/* lighter than the page, so it stands off it */
	--tooltip-ink: #f2f4f8;
}

* { box-sizing: border-box; }

html, body {
	margin: 0;
	background: var(--bg);
	color: var(--text);
	font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	font-size: 15px;
	line-height: 1.45;
}

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }

/* margin-bottom was 4px originally - too tight before whatever follows a
   heading (a button, a form). Fixed at the same value as admin.officeplanner.pro's for the
   same reason (2026-09-06), from the start here
   instead of waiting for the same complaint to repeat. */
h1, h2, h3 { margin: 0 0 .6667rem; font-weight: 650; }
h1 { font-size: 1.4rem; }
h2 { font-size: 1.15rem; }

p { margin: 0 0 .5333rem; }

/* --- App shell: full-height left sidebar + top bar + content column ---
   Identical structure to admin.officeplanner.pro/public/app/style.css - see its comment for
   the reasoning (Plesk-style: dark full-height sidebar for logo/nav, top
   bar only spans the remaining width for account-level controls). */

.shell { display: flex; min-height: 100vh; align-items: stretch; }
.content-column { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.main-area { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
	height: var(--topbar-h);
	position: sticky;
	top: 0;
	z-index: 50;
	display: flex;
	align-items: center;
	gap: 1.0667rem;
	padding: 0 1.6rem;
	background: var(--surface);
	border-bottom: 1px solid var(--border);
}
.topbar .hamburger { display: none; }
.topbar-brand-mobile { display: none; font-weight: 700; font-size: 1rem; }
.topbar-spacer { flex: 1; }
.topbar select {
	max-width: 9.3333rem;
	padding: .2667rem .5333rem;
	font-size: .82rem;
	border-color: transparent;
	background: none;
}
.topbar select:hover { border-color: var(--border); }
/* The colour scheme switch - the product page's toggle: a round button whose
   icon names the scheme a click switches to (UI-PATTERNS "Shell"). */
.theme-toggle {
	display: inline-flex; align-items: center; justify-content: center; flex: none;
	width: var(--theme-toggle-size); height: var(--theme-toggle-size);
	padding: 0; border: 1px solid var(--border); border-radius: 50%;
	background: none; color: var(--text); cursor: pointer;
}
.theme-toggle:hover, .theme-toggle:focus-visible { background: var(--bg); border-color: var(--primary); color: var(--primary); }
.theme-toggle svg { width: var(--theme-toggle-icon-size); height: var(--theme-toggle-icon-size); }

/* User menu: name click-target, dropdown holds actions (currently just
   Logout - a portal account has no "edit profile"/role, unlike admin.officeplanner.pro's). */
.user-menu { position: relative; }
.user-menu-trigger {
	display: flex;
	align-items: center;
	gap: .5333rem;
	border: none;
	background: none;
	padding: .4rem .5333rem;
	border-radius: 8px;
	cursor: pointer;
}
.user-menu-trigger:hover { background: var(--bg); border-color: transparent; }
.user-menu-trigger .who { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.25; }
.user-menu-trigger .name { font-size: .85rem; font-weight: 600; color: var(--text); }
.user-menu-trigger .chevron { font-size: .7rem; color: var(--text-muted); }
.user-menu-trigger .user-icon { font-size: 1.15rem; line-height: 1; }
.user-menu-dropdown .menu-icon { display: inline-block; width: 1.3em; }
.user-menu-dropdown {
	position: absolute;
	top: calc(100% + .4rem);
	right: 0;
	min-width: 10.6667rem;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: 8px;
	box-shadow: var(--shadow);
	padding: .4rem;
	z-index: 60;
}
.user-menu-dropdown[hidden] { display: none; }
.user-menu-dropdown button {
	display: block;
	width: 100%;
	text-align: left;
	border: none;
	background: none;
	padding: .5333rem .6667rem;
	border-radius: 6px;
	font-size: .88rem;
}
.user-menu-dropdown button:hover { background: var(--bg); border-color: transparent; }

.sidebar {
	flex: 0 0 15.3333rem;
	width: 15.3333rem;
	background: var(--sidebar-bg);
	color: var(--sidebar-text);
	display: flex;
	flex-direction: column;
	position: sticky;
	top: 0;
	height: 100vh;
	overflow-y: auto;
}
.sidebar .brand {
	padding: 1.3333rem 1.3333rem 1.0667rem;
	font-weight: 700;
	font-size: 1.05rem;
	color: var(--sidebar-text-strong);
	border-bottom: 1px solid var(--sidebar-border);
}
/* Under the logo: the app's name as a small label and - portal - the
   customer number as a reading (GENERAL_RULES 6.1: no frame, no hover, no
   hand cursor, so it never looks like a button or a menu entry). */
.sidebar-context {
	display: flex; flex-direction: column; gap: var(--sidebar-context-gap);
	padding: var(--sidebar-context-padding);
	border-bottom: 1px solid var(--sidebar-border);
}
.sidebar-context-label {
	font-size: var(--sidebar-context-label-size); font-weight: 700;
	letter-spacing: .04em; text-transform: uppercase;
	color: var(--sidebar-text-muted);
}
.sidebar-context-reading {
	display: flex; align-items: center; gap: var(--sidebar-context-icon-gap);
	padding-left: var(--sidebar-context-reading-indent);
	font-size: var(--sidebar-context-reading-size); font-weight: 500;
	color: var(--sidebar-text);
}
.sidebar-context-value {
	padding: var(--sidebar-context-value-padding);
	border: var(--sidebar-context-value-border); border-radius: var(--sidebar-context-value-radius);
	background: var(--sidebar-section-bg); color: var(--sidebar-text-strong);
}
.sidebar-context-icon { display: inline-flex; flex: none; color: var(--sidebar-context-icon-color); }
.sidebar-context-icon svg { width: var(--sidebar-context-icon-size); height: var(--sidebar-context-icon-size); stroke-width: var(--sidebar-context-icon-stroke); }
.sidebar nav { flex: 1; display: flex; flex-direction: column; gap: .1333rem; padding: 1.0667rem 0; }
.sidebar nav a {
	display: flex;
	align-items: center;
	gap: .6667rem;
	padding: .6667rem 1.3333rem;
	border-left: 3px solid transparent;
	color: var(--sidebar-text);
	font-size: .92rem;
	font-weight: 500;
}
.sidebar nav a .nav-icon { font-size: 1.05rem; line-height: 1; width: 1.3em; text-align: center; flex: none; }
.nav-section {
	margin-top: .8rem;
	padding: .5333rem 1.3333rem;
	font-size: .72rem;
	font-weight: 700;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--sidebar-text-muted);
	background: var(--sidebar-section-bg);
}
.nav-section:first-child { margin-top: 0; }
.sidebar nav a:hover { background: var(--sidebar-hover-bg); text-decoration: none; }
.sidebar nav a.active { background: var(--sidebar-hover-bg); border-left-color: var(--primary); color: var(--sidebar-text-strong); font-weight: 600; }

.sidebar-backdrop { display: none; }

/* --- Layout --- */

main.wrap { max-width: var(--content-max); margin: 0 auto; padding: 1.6rem; width: 100%; box-sizing: border-box; flex: 1; }
.center { display: flex; align-items: center; justify-content: center; min-height: 80vh; padding: 1.6rem; }
footer.foot { text-align: center; padding: 1.6rem; color: var(--text-muted); font-size: .8rem; }


.card {
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow);
	padding: 1.6rem;
	margin-bottom: 1.3333rem;
}
.card + .card { margin-top: 1.3333rem; }

/* --- Public auth screens (login / password forgotten / new password) ------
   Redesigned 2026-09-07 to the client's mockup: one centred card with the
   brand line, a rule, a short intro, icon-led fields, a show-password eye and
   a full-width primary action. Same markup and class names in admin.officeplanner.pro and
   portal.officeplanner.pro so both masks stay recognisably one product. Every value here is a
   token or a class - nothing inline in app.js (CLAUDE.md, section "Design tokens"). */

.auth-card {
	width: 100%;
	max-width: 30.6667rem;
	padding: 2.1333rem;
	border-radius: var(--radius-lg);
}

/* Language picker sits in the card's top-right corner - the same place it
   occupies in the top bar once you are logged in, so it does not move. */
.auth-lang { display: flex; justify-content: flex-end; margin-bottom: .2667rem; }
.auth-lang select {
	max-width: 10rem;
	padding: .2667rem .5333rem;
	font-size: .82rem;
	border-color: transparent;
	background: none;
}
.auth-lang select:hover { border-color: var(--border); }

/* The product logo on the login card, above the subtitle. */
.auth-logo { margin: 0 auto; max-width: var(--auth-logo-width); }
.logo-primary { fill: var(--logo-name); }
.brand-logo, .auth-logo svg { display: block; }
.brand-logo svg, .auth-logo svg { display: block; width: 100%; height: auto; }
/* The sidebar is dark in both schemes, so the name there is always light. */
/* The logo alone and centred in its own band (client, 2026-11-05): its
   built-in margin is the same on both sides, so it lines up with nothing
   it would visibly miss. */
.sidebar .brand-logo { --logo-name: var(--sidebar-text-strong); max-width: var(--sidebar-logo-width); margin-inline: auto; }
.auth-brand { display: flex; align-items: center; justify-content: center; gap: .8rem; }
.auth-brand svg { width: 2.1333rem; height: 2.1333rem; color: var(--primary); flex: none; }
.auth-brand h1 { margin: 0; font-size: 1.45rem; letter-spacing: -.01em; }
.auth-sub { margin: .5333rem 0 0; text-align: center; color: var(--text-muted); }
.auth-rule { width: 60%; margin: 1.3333rem auto; border: 0; border-top: 1px solid var(--border); }
.auth-intro { margin: 0 0 1.4667rem; text-align: center; color: var(--text-muted); line-height: 1.5; }

/* Input with a leading icon and (optionally) a trailing button inside it.
   The icon is absolutely positioned so the input keeps its own full width -
   a flex row would make the input narrower than every other field. */
.input-icon { position: relative; display: flex; align-items: center; }
.input-icon input {
	width: 100%;
	height: var(--input-h);
	padding-left: 2.9333rem;
	padding-right: 2.9333rem;
	border-radius: var(--radius-md);
}
.input-icon svg { width: 1.2rem; height: 1.2rem; }
.input-icon__lead {
	position: absolute; left: .9333rem;
	display: flex; color: var(--field-icon);
	pointer-events: none;	/* clicking the icon must focus the field, not swallow the click */
}
.input-icon__toggle {
	position: absolute; right: .5333rem;
	display: flex; align-items: center;
	padding: .5333rem; width: auto;
	border: none; background: none; color: var(--field-icon);
	border-radius: 8px;
}
.input-icon__toggle:hover { color: var(--text); background: var(--bg); border-color: transparent; }
/* Inside a normal form: the field of the form, only the eye added. */
.input-icon--compact input { height: auto; padding: .5333rem 2.4rem .5333rem .8rem; border-radius: 6px; }
.input-icon--compact .input-icon__toggle { right: .2667rem; padding: .2667rem; }
.input-icon--compact svg { width: 1.1rem; height: 1.1rem; }

.field-aside { display: flex; justify-content: flex-end; margin-top: .5333rem; }
.field-aside a { font-size: .88rem; font-weight: 600; }

.btn-arrow {
	display: inline-flex; align-items: center; justify-content: center; gap: .6667rem;
	width: 100%;	/* the one full-width button: the auth screens (UI-PATTERNS "Buttons") */
	height: var(--input-h);
	border-radius: var(--radius-md);
	font-size: 1rem; font-weight: 600;
}
.btn-arrow svg { width: 1.2rem; height: 1.2rem; }

/* "oder" rule: the line is drawn by the pseudo-elements, so the label stays
   centred whatever its translation is. */
.auth-or {
	display: flex; align-items: center; gap: .8rem;
	margin: 1.4667rem 0 1.0667rem;
	color: var(--text-muted); font-size: .9rem;
}
.auth-or::before, .auth-or::after { content: ""; flex: 1; border-top: 1px solid var(--border); }

.auth-foot {
	display: flex; align-items: center; justify-content: center; gap: .5333rem;
	margin: 0; text-align: center; color: var(--text-muted);
}
.auth-foot svg { width: 1.2rem; height: 1.2rem; color: var(--field-icon); flex: none; }

/* --- Password rules checklist (2026-09-07, client spec) -------------------
   Sits under a "new password" field and ticks off while typing. Muted until a
   rule is met, then the accent colour - the unmet state must not read as an
   error, nothing is wrong yet while someone is still typing. */

.pw-rules {
	margin-top: -.2667rem;
	padding: .8rem .9333rem;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	font-size: .85rem;
}
.pw-rules__title { margin: 0 0 .5333rem; color: var(--text-muted); font-weight: 600; }
.pw-rules ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
.pw-rule { display: flex; align-items: center; gap: .5333rem; color: var(--text-muted); }
.pw-rule__mark { display: flex; }
.pw-rule svg { width: 1rem; height: 1rem; }
.pw-rule--ok { color: var(--success); }

textarea { min-height: 6.4rem; resize: vertical; font-family: inherit; }

@media (max-width: 30rem) {
	.auth-card { padding: 1.6rem 1.3333rem; }
	.auth-brand h1 { font-size: 1.2rem; }
	.auth-brand svg { width: 1.7333rem; height: 1.7333rem; }
}

/* --- Layout utilities (CLAUDE.md, section "Design tokens": spacing/width values live here as
   utility classes, never as inline style="" in app.js). --- */

.mt-0 { margin-top: 0; }
.mt-8 { margin-top: .5333rem; }
.mt-10 { margin-top: .6667rem; }
.mt-12 { margin-top: .8rem; }
.mt-14 { margin-top: .9333rem; }
.mt-16 { margin-top: 1.0667rem; }
.mb-16 { margin-bottom: 1.0667rem; }
.max-w-560 { max-width: 37.3333rem; }
.align-end { align-items: end; }
.form-error.warn { background: var(--warn-bg); color: var(--warn); }

.module-name { display: inline-flex; align-items: center; gap: var(--module-icon-gap); }
.module-icon { display: inline-flex; flex: none; width: var(--module-icon-size); height: var(--module-icon-size); color: var(--primary); }
.module-icon svg {
	width: 100%;
	height: 100%;
	fill: none;
	stroke: currentColor;
	stroke-width: var(--module-icon-stroke);
	stroke-linecap: round;
	stroke-linejoin: round;
}

.muted { color: var(--text-muted); }
.empty { color: var(--text-muted); font-style: italic; padding: .5333rem 0; }
.section-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: .8rem; gap: .8rem; flex-wrap: wrap; }

form.stacked { display: flex; flex-direction: column; gap: .9333rem; }
.field { display: flex; flex-direction: column; gap: .2667rem; min-width: 0; }
/* A checkbox with its label on one line - same block and name as the admin panel. */
.field.inline { flex-direction: row; align-items: center; gap: .5333rem; }
.field.inline input[type="checkbox"] { width: auto; }
.field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9333rem; }
/* Controls in one line, each its own width - same block and name as the admin panel.
   A field in it has a readable width, its button stays as wide as its label. */
.row { display: flex; gap: .8rem; align-items: center; flex-wrap: wrap; }
.row > .field { flex: 0 1 var(--row-field-width); max-width: 100%; }	/* a readable width - never across the whole card */
.row.align-end { align-items: end; }	/* a field with its label above: the button lines up with the input */
.text-center { text-align: center; }

/* Title row of a group inside a table (price overview: Package, Storage, Modules;
   workstations and devices) - one table, so the columns of all groups line up. */
.table-group td { background: var(--bg); color: var(--primary); font-weight: 700; font-size: .78rem; }	/* the height of the column titles (th) */
.table-group-icon { margin-right: var(--module-icon-gap); }
.table--framed thead th, .price-total td { background: var(--table-emphasis-bg); }
.price-total td { font-weight: 700; }
/* A discount of a service, below it like on an invoice. */
.price-discount td:first-child { padding-left: var(--discount-indent); }
/* A negative amount - a discount, a deduction - in red, the same in admin and portal. */
.amount-negative { color: var(--danger); }
label { font-size: .85rem; font-weight: 600; color: var(--text-muted); }

input, select, textarea {
	font: inherit;
	padding: .5333rem .8rem;
	border: 1px solid var(--border);
	border-radius: 6px;
	background: var(--surface);
	color: var(--text);
	width: 100%;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--primary); outline-offset: -1px; }

/* Explanatory note under something. Two different contexts need opposite
   margins (learned from admin.officeplanner.pro/public/app/style.css's 2026-09-06 fix, built
   in correctly here from the start instead of repeating the same mistake):
   a hint sitting INSIDE a .field, right after its input, should hug that
   input; everywhere else it is a standalone paragraph and needs normal
   breathing room instead. */
.hint { font-size: .8rem; color: var(--text-muted); margin-top: .4rem; }
/* A hint inside a .field only needs that field's own 4px gap. The -8px this
   used to carry overshot: a flex gap is not a margin and cannot be cancelled by
   one, so the net offset was MINUS 4px and the hint ran into the input's bottom
   border. Found in admin.officeplanner.pro via a screenshot 2026-09-07, the same line was here. */
.field > .hint { margin-top: 0; }

button, .btn {
	font: inherit;
	cursor: pointer;
	border: 1px solid var(--border);
	background: var(--surface);
	color: var(--text);
	padding: .5333rem .9333rem;
	border-radius: 6px;
}
button:hover, .btn:hover { border-color: var(--primary); }
button.primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
button.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
/* Destructive actions ("terminate this module") carried class="danger" from the
   start, but the rule only existed in admin.officeplanner.pro's stylesheet - so the button that
   cancels a module looked exactly like every other one here (found 2026-09-07).
   Same values as admin.officeplanner.pro/public/app/style.css, maintained per app (CLAUDE.md, section "Design tokens"). */
button.danger { color: var(--danger); border-color: var(--danger-bg); }
button.danger:hover { border-color: var(--danger); }
button.link { border: none; background: none; color: var(--primary); padding: .1333rem .2667rem; }
button.link:hover { text-decoration: underline; }
button:disabled { opacity: .5; cursor: default; }
button.small, .btn.small { padding: .2667rem .6667rem; font-size: .85rem; width: auto; }

/* margin-top so an error/success banner never sticks directly to whatever
   came before it (e.g. a button right above it) - same root-cause fix as
   admin.officeplanner.pro's .hint (2026-09-06). Harmless while the
   container is still empty (no error yet). */
.form-error {
	background: var(--danger-bg); color: var(--danger);
	padding: .5333rem .8rem; border-radius: 6px; font-size: .9rem;
	margin-top: .8rem;
}
.form-success {
	background: var(--success-bg); color: var(--success);
	padding: .5333rem .8rem; border-radius: 6px; font-size: .9rem;
	margin-top: .8rem;
}

/* Confirmation for an action that repaints the page (booking a module,
   releasing a device) - an inline banner would be wiped by that repaint in the
   same tick. Sits on <body>, outside the repainted area, and fades out by
   itself. Own copy, same values as admin.officeplanner.pro's (CLAUDE.md, section "Design tokens"). */
.toast {
	position: fixed;
	right: 1.6rem;
	bottom: 1.6rem;
	z-index: 70;
	max-width: 24rem;
	padding: .8rem 1.0667rem;
	border-radius: var(--radius);
	border: 1px solid var(--success);
	background: var(--success-bg);
	color: var(--success);
	box-shadow: var(--shadow);
	font-size: .9rem;
	font-weight: 600;
	opacity: 0;
	transform: translateY(.5333rem);
	transition: opacity .18s ease, transform .18s ease;
}
.toast.show { opacity: 1; transform: none; }

/* The app's own yes/no question (askConfirmation() in app.js) instead of the
   browser's confirm(). Own copy, same values as admin.officeplanner.pro's
   (CLAUDE.md, section "Design tokens"). */
.confirmation-dialog {
	width: min(92vw, 32rem);
	max-width: 32rem;
	padding: 0;
	border: 0;
	border-radius: var(--radius);
	background: var(--surface);
	color: var(--text);
	box-shadow: var(--shadow);
}
.confirmation-dialog::backdrop { background: var(--dialog-backdrop); }
.confirmation-dialog--wide { width: min(92vw, var(--dialog-wide-max)); max-width: var(--dialog-wide-max); }
.confirmation-dialog-panel { padding: 1.6rem; }
.confirmation-dialog-panel p { color: var(--text-muted); margin-bottom: 1.3333rem; }
.confirmation-dialog-panel .field.inline { margin-bottom: 1.3333rem; }
.confirmation-dialog-actions { display: flex; justify-content: flex-end; gap: .8rem; flex-wrap: wrap; }
/* askLeave(): the changes listed, "Discard changes" apart on the left. */
.confirmation-dialog-actions .apart { margin-right: auto; }
.leave-changes { margin: 0 0 1.3333rem; padding-left: 1.2rem; color: var(--text-muted); }
.leave-changes li + li { margin-top: .2667rem; }

.badge {
	display: inline-block; font-size: .78rem; font-weight: 600;
	padding: .1333rem .6667rem; border-radius: 6px; border: 1px solid var(--border); white-space: nowrap;
}
.badge.ok, .badge.active, .badge.paid { background: var(--success-bg); color: var(--success); }
.badge.fail, .badge.deactivated { background: var(--danger-bg); color: var(--danger); }
.badge.warn, .badge.terminated, .badge.open, .badge.overdue { background: var(--warn-bg); color: var(--warn); }
.badge.neutral { background: var(--bg); color: var(--text-muted); }
/* A mark inside a badge ("Done" with its check mark), as high as the text. */
.badge svg { width: .9em; height: .9em; margin-right: .2667rem; vertical-align: -.1em; }

/* Info icon and its one shared tooltip (infoIcon(), sectionIntro(); UI-PATTERNS
   "Help icons") - copied from the admin panel under the same names and values. */
.info-icon {
	display: inline-flex; align-items: center; justify-content: center;
	width: 1rem; height: 1rem; margin-left: .2667rem;
	border-radius: 50%;
	background: var(--info); color: var(--info-ink);
	font-family: Georgia, "Times New Roman", serif;
	font-size: .75rem; font-weight: 700; font-style: normal;
	line-height: 1; cursor: help; vertical-align: middle;
}
.info-icon:hover, .info-icon:focus-visible { background: var(--border); color: var(--text); }
.info-tip {
	position: fixed; z-index: var(--z-tooltip);
	pointer-events: none;
	max-width: 24rem;
	padding: .5333rem .8rem;
	border-radius: var(--radius-md);
	background: var(--tooltip-bg); color: var(--tooltip-ink);
	font-size: .8rem; font-weight: 400;
	line-height: 1.45; text-align: left; white-space: pre-line;
	box-shadow: var(--shadow);
	opacity: 0; visibility: hidden;
	transition: opacity var(--transition);
}
.info-tip.is-open { opacity: 1; visibility: visible; }
.section-intro { color: var(--text-muted); margin: 0 0 .9333rem; max-width: var(--intro-max); }

.activation-key {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 1.1rem;
	font-weight: 700;
	letter-spacing: .03em;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: .5333rem .9333rem;
	display: inline-block;
	min-width: 20ch;
	text-align: center;
	cursor: pointer;
	transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.activation-key:hover { border-color: var(--primary); }
.activation-key:focus-visible { outline: .15rem solid var(--primary); outline-offset: .15rem; }
.activation-key.copied { background: var(--success); border-color: var(--success); color: var(--surface); }
.clipboard-helper { position: fixed; inset-inline-start: -100vw; }

/* QR code above, key text below, both centered (user feedback 2026-09-06:
   was left-aligned with the key text above the QR code). Same as
   admin.officeplanner.pro/public/app/style.css. */
.license-key-block { display: flex; flex-direction: column; align-items: center; gap: .8rem; margin-top: .8rem; }

.detail-list { display: flex; flex-direction: column; }
.row-item { display: grid; grid-template-columns: 10.6667rem 1fr; gap: 1.0667rem; padding: .6667rem 0; border-bottom: 1px solid var(--border); }
.row-item:last-child { border-bottom: none; }
/* A labelled value to read inside a form, without input or action styling. */
.reading-box {
	display: inline-block;
	font-size: var(--reading-font-size);
	color: var(--text);
	background: var(--bg);
	border: var(--reading-border);
	border-radius: var(--radius);
	padding: var(--reading-padding-block) var(--reading-padding-inline);
}

.dt { font-size: .82rem; color: var(--text-muted); font-weight: 600; }
.dd { font-size: .92rem; color: var(--text); word-break: break-word; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: .5333rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
th { font-size: .78rem; text-transform: uppercase; letter-spacing: .02em; color: var(--text-muted); font-weight: 600; }
/* Tables (2026-10-23): a list fills its card; column titles, amounts and
   actions never wrap - a wide table scrolls in its .table-scroll instead. An
   action cell stays a table cell (".row" on a td made it a flex box, which
   wrapped its buttons); its buttons stand side by side. A table with few
   columns is .table--compact: as wide as its content, so label and amount
   do not drift apart. */
th, td.nowrap, td.amount, td.row, td.actions { white-space: nowrap; }
td.row, td.actions { display: table-cell; }
td.row > * + *, td.actions > * + * { margin-left: var(--action-gap); }
th.amount, td.amount { text-align: right; font-variant-numeric: tabular-nums; }
table.table--compact { width: auto; min-width: var(--table-compact-min); }
/* Icon-led settings cards share one content edge and full-width readings. */
.feature-card { display: grid; grid-template-columns: var(--feature-icon-size) minmax(0, 1fr); gap: var(--feature-card-gap); }
.feature-card-icon { width: var(--feature-icon-size); height: var(--feature-icon-size); display: flex; align-items: center; justify-content: center; border-radius: var(--feature-icon-radius); color: var(--primary); background: var(--feature-icon-bg); }
.feature-card-icon svg { width: var(--feature-icon-glyph-size); height: var(--feature-icon-glyph-size); }
.feature-card-icon--storage { color: var(--feature-storage-icon); background: var(--feature-storage-icon-bg); }
.feature-card-content { min-width: 0; }
.feature-card-content > h2 { display: flex; align-items: center; flex-wrap: wrap; gap: var(--feature-info-gap); font-size: var(--feature-title-size); margin-bottom: var(--feature-title-gap); }
.detail-list--filled { border-radius: var(--feature-corner); overflow: hidden; }
.detail-list--filled .row-item { grid-template-columns: var(--feature-label-width) minmax(0, 1fr); gap: 0; padding: 0; border-bottom: var(--feature-row-rule); }
.detail-list--filled .row-item:last-child { border-bottom: none; }
.detail-list--filled .dt, .detail-list--filled .dd { padding: var(--feature-cell-padding); }
.detail-list--filled .dt { background: var(--feature-label-bg); }
.detail-list--filled .dd { background: var(--feature-value-bg); }
.change-form { border-top: var(--feature-rule); margin-top: var(--feature-section-gap); padding-top: var(--feature-section-gap); }
.change-form label { color: var(--text); font-weight: var(--feature-label-weight); }
.change-form h3 { margin: 0 0 .8rem; font-size: 1rem; }
.feature-card-action { margin-left: auto; }
/* Payment method (UI-PATTERNS "Payment method"): the choice between the own
   SEPA form and Stripe's element is a button group with the chosen one marked
   (GENERAL_RULES 6.3), the mandate text a quiet reading box, the element's
   mount keeps its height while Stripe draws into it. */
.choice-group { display: flex; flex-wrap: wrap; gap: var(--action-gap); margin-bottom: var(--feature-section-gap); }
.choice-group button { width: auto; }
.choice-group button.active { color: var(--primary); border-color: var(--primary); background: var(--feature-icon-bg); }
.mandate-text { border: var(--reading-border); border-radius: var(--radius); background: var(--feature-value-bg); padding: var(--feature-cell-padding); font-size: .88rem; line-height: 1.5; }
.mandate-text p { margin: 0; }
.mandate-text .mandate-text-title { margin-bottom: .4rem; font-weight: 600; }
.payment-element-mount { min-height: 8rem; }
/* The tab row of a page - the same block and values as the admin panel (GENERAL_RULES 6.3). */
.tabs { display: flex; gap: .2667rem; border-bottom: 1px solid var(--border); margin-bottom: 1.3333rem; }
.tabs button {
	border: none;
	border-bottom: 2px solid transparent;
	border-radius: 0;
	background: none;
	padding: .6667rem .2667rem;
	margin-right: 1.3333rem;
	font-weight: 600;
	color: var(--text-muted);
}
.tabs button:hover { border-color: var(--border); color: var(--text); }
.tabs button.active { color: var(--primary); border-color: var(--primary); }
.section-form .field { max-width: var(--row-field-width); }
.section-form .hint.mt-0 { margin-top: 0; }
.section-form [data-form-message]:empty { display: none; }
.pw-row { display: flex; align-items: center; gap: .5333rem; }
.pw-row .input-icon { flex: 1 1 auto; min-width: 0; }
.generated-password { display: flex; align-items: center; gap: .8rem; margin-top: .5333rem; }
.generated-password[hidden] { display: none; }
.generated-password code { padding: .4rem .6667rem; border: 1px solid var(--border); border-radius: var(--feature-corner); background: var(--bg); font-size: .95rem; letter-spacing: .04em; }
.info-note { display: flex; align-items: flex-start; gap: var(--feature-info-gap); }
.info-note svg { width: var(--feature-info-size); height: var(--feature-info-size); flex-shrink: 0; }
.price-summary { width: 100%; }
.table-frame { border: var(--feature-rule); border-radius: var(--feature-corner); }
.price-table { min-width: var(--table-compact-min); }
.table--framed { font-size: var(--table-framed-font-size); }
.table--framed th, .table--framed td { padding: var(--table-framed-cell-padding); border-bottom: var(--table-framed-rule); }
.table--framed td.actions { text-align: right; }
.table-cell-label { display: none; }
/* Status containers, shared by payment records and future invoice records. */
.payment-list { display: flex; flex-direction: column; gap: var(--payment-record-spacing); }
.payment-list-heading, .payment-record { display: grid; grid-template-columns: var(--payment-columns); gap: var(--payment-record-gap); align-items: center; }
.payment-list-heading { padding: var(--payment-record-spacing) var(--payment-record-padding); border-left: var(--payment-status-border-width) solid transparent; font-size: var(--payment-label-size); color: var(--text-muted); }
.payment-list-heading > :nth-child(3), .payment-list-heading > :last-child { text-align: right; }
.payment-record { padding: var(--payment-record-padding); border: var(--feature-rule); border-left: var(--payment-status-border-width) solid var(--danger); border-radius: var(--feature-corner); background: var(--surface); }
.payment-record--paid { border-left-color: var(--success); }
.payment-record-title { min-width: 0; overflow-wrap: anywhere; }
.payment-record-title h3 { margin: 0; font-size: var(--payment-title-size); }
.payment-record-date { font-size: var(--table-framed-font-size); font-variant-numeric: tabular-nums; }
.payment-record-amount { text-align: right; font-size: var(--payment-amount-size); font-weight: var(--feature-label-weight); font-variant-numeric: tabular-nums; }
.payment-record-state { text-align: right; }
.payment-status { display: inline-flex; align-items: center; gap: var(--module-label-gap); padding: var(--reading-padding-block) var(--reading-padding-inline); border-radius: var(--feature-corner); color: var(--danger); background: var(--danger-bg); font-size: var(--payment-label-size); font-weight: var(--feature-label-weight); }
.payment-status svg { width: var(--payment-status-icon-size); height: var(--payment-status-icon-size); flex-shrink: 0; }
.payment-record--paid .payment-status { color: var(--success); background: var(--success-bg); }
.record-label { display: none; }
.empty-state { display: flex; flex-direction: column; align-items: center; gap: var(--empty-state-gap); padding: var(--empty-state-padding); border: var(--feature-rule); border-radius: var(--feature-corner); background: var(--feature-value-bg); text-align: center; }
.empty-state-icon { display: flex; color: var(--text-muted); }
.empty-state-icon svg { width: var(--feature-icon-glyph-size); height: var(--feature-icon-glyph-size); }
.empty-state h3, .empty-state .hint { margin: 0; }
@media (max-width: 75rem) {
	.payment-list-heading { display: none; }
	.payment-record { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--payment-record-spacing); }
	.payment-record-date { grid-column: 1; grid-row: 1; }
	.payment-record-amount { grid-column: 2; grid-row: 1; }
	.payment-record-title { grid-column: 1 / -1; grid-row: 2; }
	.payment-record-state { grid-column: 1 / -1; grid-row: 3; }
	.record-label { display: block; margin-bottom: var(--module-label-gap); font-size: var(--payment-label-size); color: var(--text-muted); font-weight: var(--feature-label-weight); }
}
.table-group-label { display: inline-flex; align-items: center; gap: var(--module-icon-gap); }
.table-group-label svg { width: var(--feature-info-size); height: var(--feature-info-size); }
.quota-table .table-group td { padding: var(--table-framed-cell-padding); }
.quota-table .identifier-cell { font-variant-numeric: tabular-nums; }

.module-table th:first-child, .module-table td:first-child { width: 1%; white-space: nowrap; }
.module-discounts { overflow-wrap: anywhere; }
.module-discount + .module-discount { margin-top: var(--module-label-gap); }
@media (max-width: 75rem) {
	.table--records, .table--records tbody { display: block; }
	.table--records thead { position: absolute; width: var(--visually-hidden-size); height: var(--visually-hidden-size); clip-path: inset(50%); overflow: hidden; }
	.table--records tbody tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--module-record-gap); padding: var(--module-record-padding); border-bottom: var(--table-framed-rule); }
	.table--records tbody tr:last-child { border-bottom: none; }
	.table--records tbody td { display: block; width: auto; min-width: 0; padding: 0; border: none; white-space: normal; }
	.table--records td:first-child { grid-column: 1 / -1; width: auto; white-space: normal; font-weight: var(--feature-label-weight); }
	.module-table td:nth-child(2) { grid-column: 1; grid-row: 2; }
	.module-table td:nth-child(5) { grid-column: 2; grid-row: 2; text-align: right; }
	.module-table td.amount { grid-column: 1 / -1; grid-row: 3; text-align: left; }
	.module-table td.module-discounts { grid-column: 1 / -1; grid-row: 4; }
	.module-table td.actions { grid-column: 1 / -1; grid-row: 5; }
	.table--records tbody tr[hidden] { display: none; }	/* the closed details of a report: the grid above must not show them */
	.table--records .table-cell-label { display: block; margin-bottom: var(--module-label-gap); font-size: var(--module-cell-label-size); color: var(--text-muted); font-weight: var(--feature-label-weight); }
	.module-table .module-name { align-items: flex-start; }
	.module-table .badge { white-space: normal; }
	.quota-table td:nth-child(2) { grid-column: 1; grid-row: 2; }
	.quota-table td:nth-child(3) { grid-column: 2; grid-row: 2; text-align: right; }
	.quota-table td.identifier-cell { grid-column: 1 / -1; grid-row: 3; overflow-wrap: anywhere; }
	.quota-table td.actions { grid-column: 1 / -1; grid-row: 4; }
	.quota-table .table-group { display: block; padding: 0; }
	.quota-table .table-group td { font-weight: var(--feature-label-weight); }
	.quota-table td.empty { grid-column: 1 / -1; }

}
.price-table .price-discount td:first-child { padding-left: var(--discount-indent); }
.price-summary > .hint { margin-top: var(--feature-info-gap); }
@media (max-width: 56.25rem) {
	.detail-list--filled .row-item { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 48rem) {
	.price-table { min-width: 0; table-layout: fixed; }
	.price-table th { white-space: normal; }
	.price-table th.amount { width: var(--price-mobile-amount-width); }
	.feature-card { display: block; }
	.feature-card-icon { float: left; margin-right: var(--feature-info-gap); }
	.feature-card-content > h2 { min-height: var(--feature-icon-size); display: flex; align-items: center; }
}
/* A column only as wide as its content (status, actions): the free width goes
   to the descriptive columns, actions stand at the right edge. */
th.shrink, td.shrink, td.row, td.actions { width: 1%; white-space: nowrap; }
/* Separate horizontal rules by column; the first column takes unused space. */
table.table--actions { border-collapse: separate; border-spacing: var(--table-column-gap) 0; }
.table--actions td.actions { text-align: right; }
.table--actions th:first-child, .table--actions td:first-child { padding-left: 0; }
.table--actions th:last-child, .table--actions td.actions { padding-right: 0; }
.form-content { width: 100%; max-width: var(--form-max); }

/* Customer reports (renderFeedbackPage(), UI-PATTERNS "Feedback"). A field
   shown only for a bug report is hidden as a whole; .field sets display. */
.field[hidden], .field-row[hidden] { display: none; }
.feedback-prompts { margin: .2667rem 0 0; padding-left: 1.2rem; }
.feedback-previews { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5333rem; }
.feedback-previews:empty { display: none; }
.feedback-preview { display: flex; align-items: center; gap: .8rem; padding: .5333rem; border: var(--feature-rule); border-radius: var(--feature-corner); background: var(--feature-value-bg); }
.feedback-preview img { flex: none; width: var(--feedback-preview-size); height: var(--feedback-preview-size); object-fit: cover; border: 1px solid var(--border); border-radius: var(--feature-corner); }
.feedback-preview-text { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: .2667rem; overflow-wrap: anywhere; }
/* The report's excerpt is the button that opens its details - by mouse and by keyboard. */
.feedback-toggle { padding: 0; text-align: left; }
.feedback-toggle-mark { display: inline-block; width: 1.2rem; color: var(--text-muted); }
.feedback-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.feedback-images { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: .8rem; }
.feedback-image { margin: 0; }
.feedback-image img { display: block; height: var(--feedback-image-height); max-width: 100%; border: 1px solid var(--border); border-radius: var(--radius); object-fit: contain; }
/* The count of a list and its pages, below the list. */
.list-pager { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .5333rem; margin-top: .8rem; color: var(--text-muted); font-size: .9rem; }

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

/* Wide tables scroll inside their own box instead of forcing the page wide -
   same reasoning/pattern as admin.officeplanner.pro's (important on narrow screens). */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* The legal texts (renderLegalPage(), renderLegalConsentLink(), renderLegalTextsPage()): the text in the
   dialect of renderMarkdown(), and the comparison of two versions - what went struck through on red,
   what came on green (legalChangesHtml(), the admin panel's building block of the same name). */
.auth-card.legal-card { max-width: var(--legal-card-max); }
.legal-body h2 { margin-top: 1.6rem; font-size: 1.05rem; }
.legal-body h3, .legal-body h4 { margin-top: 1.0667rem; }
.legal-body p { margin-bottom: .8rem; }
.legal-body ul, .legal-body ol { margin: 0 0 .8rem; padding-left: 1.4rem; }
.legal-body li { margin-bottom: .2667rem; }
.legal-body code { padding: 0 .2667rem; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); font-size: .9em; }
.legal-body .legal-note { padding: .5333rem .8rem; border-left: 3px solid var(--warn); border-radius: 0 var(--radius) var(--radius) 0; background: var(--bg); }
.legal-body .table-scroll { margin-bottom: .8rem; }
.legal-table { width: auto; min-width: var(--table-compact-min); }
.legal-table td { white-space: normal; vertical-align: top; }
.legal-changes { display: flex; flex-direction: column; gap: .8rem; margin-bottom: 1.0667rem; }
.legal-change { border-left: 3px solid var(--border); padding-left: .8rem; }
.legal-change-removed, .legal-change-added { padding: .4rem .6667rem; border-radius: var(--radius); margin-top: .2667rem; }
.legal-change-removed { background: var(--danger-bg); text-decoration: line-through; }
.legal-change-added { background: var(--success-bg); }
.legal-change .legal-body p:last-child, .legal-change-removed p:last-child, .legal-change-added p:last-child { margin-bottom: 0; }

.module-picker { display: flex; flex-direction: column; gap: .5333rem; }
.module-picker label { display: flex; align-items: center; gap: .5333rem; font-weight: 500; color: var(--text); }
.module-picker input[type="checkbox"] { width: auto; }

.hamburger {
	border: none;
	background: none;
	font-size: 1.4rem;
	line-height: 1;
	padding: .1333rem .4rem;
	color: var(--text);
}
.hamburger:hover { border-color: transparent; }

/* --- Responsive: sidebar becomes an off-canvas drawer below 60rem ---
   Same breakpoint/behavior as admin.officeplanner.pro/public/app/style.css. */

@media (max-width: 56.25rem) {
	.topbar .hamburger { display: inline-flex; align-items: center; }
	.topbar-brand-mobile { display: block; }

	.sidebar {
		position: fixed;
		top: var(--topbar-h);
		left: 0;
		width: 15.3333rem;
		height: calc(100vh - var(--topbar-h));
		transform: translateX(-100%);
		transition: transform .2s ease;
		box-shadow: var(--shadow);
		z-index: 40;
	}
	.sidebar.open { transform: translateX(0); }

	.sidebar-backdrop {
		display: block;
		position: fixed;
		top: var(--topbar-h);
		left: 0;
		right: 0;
		bottom: 0;
		background: var(--sidebar-backdrop);
		opacity: 0;
		pointer-events: none;
		transition: opacity .2s ease;
		z-index: 30;
	}
	.sidebar-backdrop.open { opacity: 1; pointer-events: auto; }

	main.wrap { padding: 1.0667rem; }
	.field-row { grid-template-columns: 1fr; }
	.toast { right: 1.0667rem; left: 1.0667rem; bottom: 1.0667rem; max-width: none; }
	.row-item { grid-template-columns: 1fr; gap: .1333rem; padding: .5333rem 0; }
	form.stacked { max-width: none; }
}

/* Keep account and language controls usable on narrow screens. */
@media (max-width: 48rem) {
	.topbar { gap: var(--topbar-compact-gap); padding-inline: var(--topbar-compact-padding); }
	.topbar-brand-mobile, .user-menu-trigger .who { display: none; }
	.topbar select { flex-shrink: 0; }
}
/* Radio cards (UI-PATTERNS "Forms", choiceCardsHtml()): every offer a card with its full price; the chosen
   one carries the accent like the chosen button of a .choice-group. A card is a label, so a click anywhere chooses it. */
.choice-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--choice-card-min), 1fr)); gap: var(--choice-card-gap); }
.choice-card { display: flex; align-items: flex-start; gap: var(--module-icon-gap); padding: var(--feature-cell-padding); border: var(--reading-border); border-radius: var(--radius); background: var(--surface); color: var(--text); font-size: var(--table-framed-font-size); font-weight: 400; cursor: pointer; }
.choice-card:hover { border-color: var(--primary); }
.choice-card:has(input:checked) { border-color: var(--primary); background: var(--feature-icon-bg); }
.choice-card:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 1px; }
.choice-card:has(input:disabled) { cursor: default; opacity: var(--choice-card-disabled-opacity); }
.choice-card input[type="radio"] { width: auto; margin-top: var(--choice-card-radio-offset); }
.choice-card-body { display: flex; flex-direction: column; gap: var(--module-label-gap); min-width: 0; }
.choice-card-title { font-weight: var(--feature-label-weight); }
.choice-card-price { font-weight: 700; font-size: var(--choice-card-price-size); }
/* The AI volume left (aiMeterHtml()). */
.ai-meter { position: relative; display: flex; height: var(--ai-meter-height); margin-top: var(--ai-meter-gap); border-radius: var(--ai-meter-radius); background: var(--ai-meter-track); overflow: hidden; }
.ai-meter-fill { width: var(--ai-meter-fill, 0%); background: var(--primary); }
.ai-meter--low .ai-meter-fill { background: var(--warn); }
.ai-meter--empty .ai-meter-fill { background: var(--danger); }
/* A panel of the choice that is not chosen stays hidden although the form is a flex box. */
[data-choice-panel][hidden] { display: none; }
