/**
 * Real Estate Pro — Shared Component Library
 *
 * Base styles for the primitives every product plugin builds on:
 * buttons, inputs, cards, tables, modals, tabs, alerts, badges, tooltips,
 * dropdowns, progress, pagination, empty/loading/error states, and step
 * indicators. Requires tokens.css to be loaded first.
 *
 * Naming: BEM-ish, `.rep-{component}` / `.rep-{component}__{part}` /
 * `.rep-{component}--{variant}`, matching the convention
 * docs/DATA-PRO-AUDIT.md found already working well in Data Pro's CSS.
 * State toggles use `is-*` classes / `[data-*]` attributes, not extra
 * modifier classes, so behavior hooks stay separate from visual variants.
 */

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

.rep-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--rep-space-xs);
	height: var(--rep-control-height);
	padding: 0 var(--rep-space-md);
	border: 1px solid var(--rep-border);
	border-radius: calc(var(--rep-radius-md) - 4px);
	background: var(--rep-surface);
	color: var(--rep-text);
	font: var(--rep-weight-semibold) var(--rep-control-size) / 1 var(--rep-font);
	cursor: pointer;
	text-decoration: none;
	transition: background var(--rep-transition-fast), border-color var(--rep-transition-fast), color var(--rep-transition-fast), transform var(--rep-transition-fast);
}

.rep-btn:hover {
	border-color: var(--rep-primary-light);
	color: var(--rep-text);
}

.rep-btn:focus-visible {
	outline: 2px solid var(--rep-primary);
	outline-offset: 1px;
}

.rep-btn:disabled,
.rep-btn[aria-disabled="true"] {
	opacity: 0.5;
	cursor: not-allowed;
}

.rep-btn--primary {
	background: var(--rep-primary);
	border-color: var(--rep-primary);
	color: var(--rep-on-primary);
	box-shadow: var(--rep-shadow-sm);
}
/*
 * :hover/:focus-visible/:active re-pin `color` explicitly rather than
 * leaving it to inherit from .rep-btn--primary above — a .rep-btn is
 * often an <a> (text-decoration: none, cursor: pointer above), and
 * without this, wp-admin's own core `a:hover`/`a:focus` color rules
 * (higher specificity than a class selector alone once :hover/:focus
 * apply, since neither state here previously set `color` itself) won by
 * default, tinting "Open"-style primary CTAs' text with wp-admin's link
 * blue instead of --rep-on-primary. A theme that sets its own `a:hover`
 * color on the front end could do the same. Found live in wp-admin's
 * dashboard product-card "Open" buttons.
 */
.rep-btn--primary:hover {
	background: var(--rep-primary-dark);
	border-color: var(--rep-primary-dark);
	color: var(--rep-on-primary);
	transform: translateY(-1px);
	box-shadow: var(--rep-shadow-md);
}
.rep-btn--primary:focus-visible { color: var(--rep-on-primary); }
.rep-btn--primary:active { color: var(--rep-on-primary); transform: translateY(0); box-shadow: var(--rep-shadow-sm); }

.rep-btn--secondary {
	background: var(--rep-secondary);
	border-color: var(--rep-secondary);
	color: var(--rep-on-primary);
}
.rep-btn--secondary:hover,
.rep-btn--secondary:focus-visible,
.rep-btn--secondary:active {
	color: var(--rep-on-primary);
}

.rep-btn--outline {
	background: transparent;
	border-color: var(--rep-primary);
	color: var(--rep-primary);
}
.rep-btn--outline:hover,
.rep-btn--outline:focus-visible,
.rep-btn--outline:active {
	background: var(--rep-primary-wash);
	color: var(--rep-primary);
}

.rep-btn--ghost {
	background: transparent;
	border-color: transparent;
	color: var(--rep-primary);
}
.rep-btn--ghost:hover,
.rep-btn--ghost:focus-visible,
.rep-btn--ghost:active {
	background: var(--rep-primary-wash);
	color: var(--rep-primary);
}

.rep-btn--danger { background: var(--rep-danger); border-color: var(--rep-danger); color: #fff; }
.rep-btn--danger:hover, .rep-btn--danger:focus-visible, .rep-btn--danger:active { color: #fff; }
.rep-btn--success { background: var(--rep-success); border-color: var(--rep-success); color: #fff; }
.rep-btn--success:hover, .rep-btn--success:focus-visible, .rep-btn--success:active { color: #fff; }

.rep-btn--sm { height: calc(var(--rep-control-height) - 0.5rem); padding: 0 var(--rep-space-sm); font-size: var(--rep-text-xs); }

/* .rep-btn's own `display: inline-flex` above is an author rule and beats
   the browser's default `[hidden] { display: none }` regardless of
   specificity (author styles always win over UA styles) — the same
   gotcha already documented below on .rep-modal__overlay and
   .rep-skeleton. Toggling the `hidden` attribute from JS is the natural
   way to show/hide a button built on this primitive — Forms Pro's
   multi-step wizard hides/shows its Prev/Next/Submit nav buttons exactly
   this way (see forms.js's initStepForm()) — so make that actually work
   rather than requiring every consumer to know the trap. Found live:
   without this, a `hidden` .rep-form__submit/.rep-form__next stayed
   visibly rendered on every step, not just the intended one.
*/
.rep-btn[hidden] { display: none; }

/* ---------- Inputs ---------- */

.rep-input,
.rep-select,
.rep-textarea {
	width: 100%;
	height: var(--rep-control-height);
	padding: 0 var(--rep-space-sm);
	border: 1px solid var(--rep-border);
	border-radius: calc(var(--rep-radius-md) - 4px);
	background: var(--rep-surface);
	color: var(--rep-text);
	font: var(--rep-weight-normal) var(--rep-control-size) / 1 var(--rep-font);
	transition: border-color var(--rep-transition-fast);
}

.rep-textarea { height: auto; min-height: 6rem; padding: var(--rep-space-sm); resize: vertical; }

.rep-input:focus-visible,
.rep-select:focus-visible,
.rep-textarea:focus-visible {
	outline: 2px solid var(--rep-primary);
	outline-offset: 1px;
	border-color: var(--rep-primary);
}

.rep-input.has-error,
.rep-select.has-error,
.rep-textarea.has-error {
	border-color: var(--rep-danger);
}

.rep-field__error {
	display: block;
	margin-top: var(--rep-space-xs);
	color: var(--rep-danger);
	font-size: var(--rep-text-xs);
}

.rep-checkbox,
.rep-radio {
	accent-color: var(--rep-primary);
	width: 1.1em;
	height: 1.1em;
}

.rep-toggle {
	position: relative;
	display: inline-block;
	width: 2.4rem;
	height: 1.4rem;
}
.rep-toggle input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.rep-toggle__track {
	position: absolute;
	inset: 0;
	background: var(--rep-border);
	border-radius: var(--rep-radius-pill);
	transition: background var(--rep-transition-fast);
}
.rep-toggle input:checked + .rep-toggle__track { background: var(--rep-primary); }
.rep-toggle__thumb {
	position: absolute;
	top: 2px;
	left: 2px;
	width: 1.2rem;
	height: 1.2rem;
	border-radius: 50%;
	background: #fff;
	transition: transform var(--rep-transition-fast);
}
.rep-toggle input:checked ~ .rep-toggle__thumb { transform: translateX(1rem); }

/* ---------- Card ---------- */

.rep-card {
	/* Falls back to the same fixed values as before whenever these three
	   template-resolved tokens aren't present for some reason — but
	   Design\Resolver::tokens() always sets them, so in practice every
	   selected template's surface treatment (flat/soft-gradient/glass/
	   bordered/dark-gradient) and shadow depth show up here, on far and
	   away the most-used card primitive in the whole suite. Previously
	   this only ever read the fixed, template-independent --rep-shadow-md/
	   --rep-surface tokens, so surface style and shadow depth were the
	   two template axes that never visibly changed anywhere — this is
	   what "picking a template doesn't change anything" actually was. */
	background: var(--rep-card-bg, var(--rep-surface));
	color: var(--rep-card-fg, var(--rep-text));
	border: var(--rep-card-border-w, 1px) solid var(--rep-card-border-color, var(--rep-border));
	border-radius: var(--rep-radius-md);
	/* --rep-glow defaults to `none` (see tokens.css) so this is a no-op
	   comma-separated shadow on every site that hasn't turned Glow on in
	   Front End Design → Effects — box-shadow accepts multiple values,
	   each of which may itself already be a multi-value shadow. */
	box-shadow: var(--rep-card-shadow, var(--rep-shadow-md)), var(--rep-glow, none);
	outline: var(--rep-outline-width, 0px) solid var(--rep-outline-color, transparent);
	outline-offset: 2px;
	backdrop-filter: var(--rep-card-backdrop, none);
	padding: var(--rep-card-padding, var(--rep-space-lg));
	opacity: var(--rep-card-opacity, 1);
	transition: box-shadow var(--rep-transition-normal), transform var(--rep-transition-normal), border-color var(--rep-transition-normal), background var(--rep-transition-normal), color var(--rep-transition-normal), opacity var(--rep-transition-normal);
}

.rep-card--danger { border-color: var(--rep-danger); background: var(--rep-danger-wash); }

/* Opt-in — most cards hold static content and shouldn't visually react to
   a passing cursor; use this on cards that are themselves a clickable
   target (a template/plan/option picker) so the lift reads as "this is
   interactive," not decoration for its own sake. */
.rep-card--interactive {
	cursor: pointer;
}
.rep-card--interactive:hover {
	box-shadow: var(--rep-shadow-lg);
	border-color: var(--rep-primary-light);
	transform: translateY(-2px);
}

/* ---------- Table ---------- */

.rep-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--rep-control-size);
	font-variant-numeric: tabular-nums;
}
.rep-table th,
.rep-table td {
	padding: var(--rep-space-sm) var(--rep-space-md);
	border-bottom: 1px solid var(--rep-border);
	text-align: left;
}
.rep-table thead th {
	position: sticky;
	top: 0;
	background: var(--rep-surface-alt);
	font-weight: var(--rep-weight-semibold);
}
.rep-table th[aria-sort] { cursor: pointer; }

/* ---------- Modal ---------- */

.rep-modal__overlay {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.5);
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 100000;
	opacity: 0;
	/* A closed modal still exists in the DOM with `display: flex` (its own
	   class rule beats the browser's default `[hidden] { display: none }`,
	   since author rules always win over UA rules regardless of matching
	   specificity) -- without this, the invisible, `position: fixed; inset: 0`
	   overlay silently blocks every click anywhere on the page for as long
	   as a modal exists in the DOM but hasn't been opened yet. Found live,
	   Phase D: any page with `[rep_listings]` on it had every other
	   interactive element unclickable. */
	pointer-events: none;
	transition: opacity var(--rep-transition-normal);
}
.rep-modal__overlay.is-open {
	opacity: 1;
	pointer-events: auto;
}

.rep-modal {
	background: var(--rep-card-bg, var(--rep-surface));
	color: var(--rep-card-fg, var(--rep-text));
	border-radius: var(--rep-radius-lg);
	box-shadow: var(--rep-card-shadow, var(--rep-shadow-lg));
	max-width: 640px;
	width: calc(100% - var(--rep-space-lg) * 2);
	max-height: calc(100vh - var(--rep-space-xl) * 2);
	overflow-y: auto;
	transform: scale(0.97);
	transition: transform var(--rep-transition-normal);
}
.rep-modal__overlay.is-open .rep-modal { transform: scale(1); }

.rep-modal__close {
	position: absolute;
	top: var(--rep-space-sm);
	right: var(--rep-space-sm);
	border-radius: 50%;
}

@media (prefers-reduced-motion: reduce) {
	.rep-modal__overlay,
	.rep-modal { transition: none; }
}

/* ---------- Tabs ---------- */

/*
 * A product with more tabs than fit a row (Data Pro/Tools Pro/Marketing
 * Pro's own tab bars run past a dozen entries) used to just overflow the
 * row silently — flex items squeezed to unreadable widths on a normal
 * viewport, or a raw horizontal page overflow on a narrow one. Two
 * independent mitigations, matched to viewport width:
 *  1. Below the stacking breakpoint (mobile-width wp-admin, collapsed
 *     sidebar or not), the row wraps onto multiple lines instead of
 *     scrolling — Shell::tabs() has already moved the long tail of a
 *     crowded tab bar under one "More" entry (see its own docblock), so
 *     what's left to wrap is short.
 *  2. Above it, the row scrolls horizontally rather than wrapping, so a
 *     handful of extra tabs on a merely-narrow-but-not-mobile window
 *     don't reflow the page's vertical rhythm.
 * `overflow-x: auto` alone would also force `overflow-y` to `auto` (the
 * CSS spec ties the two once either leaves `visible`), which would clip
 * the "More" group's own dropdown panel (position: absolute, below) the
 * instant it opens past the row's height — a real bug found live on
 * every product whose tab count actually folds (Data Pro among them):
 * the panel toggled open (native <details>, always worked) but rendered
 * invisible, reading as "the More menu doesn't work" from a click that
 * visibly did nothing. `.rep-tabs--folded` (set by Shell::tabs() only
 * when it actually rendered a "More" group) turns the scroll back off
 * for exactly that case — Shell::tabs() already caps what a folded bar
 * shows inline at a small fixed count regardless of the real tab total,
 * so it never needed this scroll to fit a row in the first place; a flat
 * (unfolded) bar, which never renders this panel, keeps it.
 */
.rep-tabs {
	display: flex;
	align-items: flex-end;
	gap: var(--rep-space-xs);
	border-bottom: 1px solid var(--rep-border);
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: thin;
}
.rep-tabs--folded {
	overflow-x: visible;
}
.rep-tab {
	flex: none;
	padding: var(--rep-space-sm) var(--rep-space-md);
	border: 0;
	background: transparent;
	color: var(--rep-muted);
	font: var(--rep-weight-semibold) var(--rep-control-size) / 1 var(--rep-font);
	white-space: nowrap;
	cursor: pointer;
	border-bottom: 2px solid transparent;
	transition: color var(--rep-transition-fast), border-color var(--rep-transition-fast);
}
.rep-tab[aria-selected="true"] { color: var(--rep-primary); border-bottom-color: var(--rep-primary); }
.rep-tab:focus-visible { outline: 2px solid var(--rep-primary); outline-offset: -2px; }

/*
 * The "More" overflow group Shell::tabs() renders once a product's tab
 * list runs past its inline budget — a native <details>/<summary> so the
 * extra tabs stay real, crawlable, keyboard-operable links (tab/enter/
 * space all work with zero JS) rather than a script-dependent dropdown.
 */
.rep-tabs__more {
	position: relative;
	flex: none;
}
.rep-tabs__more-toggle {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	list-style: none;
}
.rep-tabs__more-toggle::-webkit-details-marker { display: none; }
.rep-tabs__more-toggle::after {
	content: "\25BE";
	font-size: 0.7em;
	transition: transform var(--rep-transition-fast);
}
.rep-tabs__more[open] > .rep-tabs__more-toggle::after { transform: rotate(180deg); }
.rep-tabs__more-toggle.is-active { color: var(--rep-primary); border-bottom-color: var(--rep-primary); }

.rep-tabs__more-panel {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 10;
	display: flex;
	flex-direction: column;
	min-width: 12rem;
	margin-top: var(--rep-space-xs);
	padding: var(--rep-space-xs);
	background: var(--rep-surface);
	border: 1px solid var(--rep-border);
	border-radius: var(--rep-radius-md);
	box-shadow: var(--rep-shadow-md);
}
.rep-tabs__more-panel .rep-tab {
	border-bottom: 0;
	border-radius: calc(var(--rep-radius-md) - 4px);
	text-align: left;
}
.rep-tabs__more-panel .rep-tab[aria-selected="true"] { background: var(--rep-primary-wash); }

@media (max-width: 600px) {
	.rep-tabs {
		flex-wrap: wrap;
		overflow-x: visible;
	}
	.rep-tabs__more-panel {
		position: static;
		margin-top: var(--rep-space-xs);
		box-shadow: none;
		border-style: dashed;
	}
}

/* ---------- Alerts / Notices ---------- */

.rep-alert {
	display: flex;
	align-items: flex-start;
	gap: var(--rep-space-sm);
	padding: var(--rep-space-sm) var(--rep-space-md);
	border-radius: var(--rep-radius-md);
	font-size: var(--rep-control-size);
}
.rep-alert--info { background: var(--rep-info-wash); color: var(--rep-info); }
.rep-alert--success { background: var(--rep-success-wash); color: var(--rep-success); }
.rep-alert--warning { background: var(--rep-warning-wash); color: var(--rep-warning); }
.rep-alert--danger { background: var(--rep-danger-wash); color: var(--rep-danger); }

/* Licensing\UpsellNotice — the one shared "this requires Pro" callout,
   consumed across admin views and public "locked" templates alike. */
.rep-upsell {
	flex-wrap: wrap;
	justify-content: space-between;
	color: var(--rep-text);
}
.rep-upsell__body { flex: 1 1 240px; }
.rep-upsell__heading { display: block; margin-bottom: var(--rep-space-xs); }
.rep-upsell__text { margin: 0; }
.rep-upsell__actions {
	display: flex;
	align-items: center;
	gap: var(--rep-space-xs);
	flex-shrink: 0;
}

/* ---------- Badges ---------- */

.rep-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--rep-space-xs);
	padding: 0.15rem var(--rep-space-sm);
	border-radius: var(--rep-radius-pill);
	font-size: var(--rep-text-xs);
	font-weight: var(--rep-weight-semibold);
	letter-spacing: var(--rep-tracking-wide);
	text-transform: uppercase;
	line-height: 1;
}
.rep-badge--neutral { background: var(--rep-surface-alt); color: var(--rep-muted); }
.rep-badge--primary { background: var(--rep-primary-wash); color: var(--rep-primary-dark); }
.rep-badge--success { background: var(--rep-success-wash); color: var(--rep-success); }
.rep-badge--warning { background: var(--rep-warning-wash); color: var(--rep-warning); }
.rep-badge--danger { background: var(--rep-danger-wash); color: var(--rep-danger); }

/* ---------- Tooltip ---------- */

.rep-tooltip {
	position: absolute;
	max-width: 260px;
	padding: var(--rep-space-sm);
	background: var(--rep-text);
	color: #fff;
	border-radius: var(--rep-radius-sm);
	box-shadow: var(--rep-shadow-lg);
	font-size: var(--rep-text-xs);
	z-index: 100001;
}

/* ---------- Dropdown ---------- */

.rep-dropdown__panel {
	position: absolute;
	background: var(--rep-surface);
	border: 1px solid var(--rep-border);
	border-radius: var(--rep-radius-md);
	box-shadow: var(--rep-shadow-lg);
	padding: var(--rep-space-sm);
	z-index: 1000;
}

/* ---------- Progress ---------- */

.rep-progress {
	position: relative;
	height: 6px;
	border-radius: var(--rep-radius-pill);
	background: var(--rep-surface-alt);
	overflow: hidden;
}
.rep-progress__fill {
	position: absolute;
	inset: 0;
	width: 40%;
	background: var(--rep-primary);
	border-radius: inherit;
	animation: rep-progress-indeterminate 1.1s ease-in-out infinite;
}
.rep-progress__fill[data-value] {
	animation: none;
	width: 100%;
	transform: scaleX(var(--rep-progress-ratio, 0));
	transform-origin: left;
	transition: transform var(--rep-transition-normal);
}

@keyframes rep-progress-indeterminate {
	0% { left: -40%; }
	100% { left: 100%; }
}
@media (prefers-reduced-motion: reduce) {
	.rep-progress__fill { animation: none; }
}

/* ---------- Pagination ---------- */

.rep-pagination {
	display: flex;
	gap: var(--rep-space-xs);
	align-items: center;
}
.rep-pagination__btn {
	composes: rep-btn;
}
.rep-pagination [aria-current="page"] {
	background: var(--rep-primary);
	color: var(--rep-on-primary);
	border-color: var(--rep-primary);
}

/* ---------- Empty / loading / error states ---------- */

.rep-empty,
.rep-error {
	text-align: center;
	padding: var(--rep-space-xl);
	color: var(--rep-muted);
}
.rep-error { color: var(--rep-danger); }

.rep-loading {
	opacity: 0.5;
	pointer-events: none;
	transition: opacity var(--rep-transition-normal);
}

/* Skeleton placeholder — prefer this over a spinner sitting in the middle
   of content that's about to exist; it holds the shape of what's coming
   so layout doesn't jump when real content lands. Sizeable via width/
   height on the element itself; .rep-skeleton--text defaults a text-line
   height so a paragraph of them reads as a paragraph, not a stack of bars. */
.rep-skeleton {
	display: block;
	border-radius: var(--rep-radius-sm);
	background: linear-gradient(
		90deg,
		var(--rep-surface-alt) 25%,
		color-mix(in srgb, var(--rep-surface-alt) 50%, var(--rep-surface)) 50%,
		var(--rep-surface-alt) 75%
	);
	background-size: 200% 100%;
	animation: rep-skeleton-shimmer 1.4s ease-in-out infinite;
}
.rep-skeleton--text { height: 0.85em; border-radius: var(--rep-radius-sm); }
.rep-skeleton--title { height: 1.4em; width: 60%; }
/* .rep-skeleton's own `display: block` is an author rule and beats the
   browser's default `[hidden] { display: none }` regardless of specificity
   (author styles always win over UA styles) — the same gotcha already
   documented on .rep-modal__overlay above. Toggling the `hidden` attribute
   from JS is the natural way to show/hide this primitive, so make that
   actually work rather than requiring every consumer to know the trap. */
.rep-skeleton[hidden] { display: none; }

@keyframes rep-skeleton-shimmer {
	0% { background-position: 200% 0; }
	100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
	.rep-skeleton { animation: none; background: var(--rep-surface-alt); }
}

/* Tabular figures outside a <table> — KPI cards, stat grids, price/percent
   callouts. Keeps digits aligned column-to-column the same way .rep-table
   already does. */
.rep-nums {
	font-variant-numeric: tabular-nums;
}

/* Inline AJAX-form error text — pairs with WP core's own .spinner (toggle
   its .is-active class rather than duplicating a spinner here) next to a
   submit button converted from admin_post to wp_ajax. */
.rep-ajax-status {
	color: var(--rep-danger);
	margin-left: var(--rep-space-sm);
}

/* ---------- Step indicator (Forms Pro multi-step) ---------- */

.rep-steps {
	display: flex;
	gap: var(--rep-space-sm);
	list-style: none;
	margin: 0 0 var(--rep-space-lg);
	padding: 0;
}
.rep-steps__item {
	display: flex;
	align-items: center;
	gap: var(--rep-space-xs);
	color: var(--rep-muted);
	font-size: var(--rep-text-xs);
}
.rep-steps__index {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.6rem;
	height: 1.6rem;
	border-radius: 50%;
	background: var(--rep-surface-alt);
	font-weight: var(--rep-weight-bold);
}
.rep-steps__item.is-active .rep-steps__index { background: var(--rep-primary); color: var(--rep-on-primary); }
.rep-steps__item.is-complete .rep-steps__index { background: var(--rep-success); color: #fff; }

/* ---------- Stat grid / empty state ---------- */
/* Shared by the Dashboard's product-card grid and every product's own
   Overview tab (docs/ADMIN-UX-ARCHITECTURE.md) — a responsive card grid
   plus a centered "nothing here yet" state, both product-agnostic. */

.rep-stat-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: var(--rep-space-lg);
}

.rep-empty-state {
	text-align: center;
	color: var(--rep-muted);
	padding: var(--rep-space-2xl);
}
.rep-empty-state .rep-btn {
	margin-top: var(--rep-space-md);
}

/* ---------- Screen-reader-only utility ---------- */

.rep-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* ---------- Optional per-heading-level color/weight override ----------
   See Settings\Design::default_headings() / Resolver::apply_heading_
   overrides() — only emitted onto :root when the admin actually sets one
   via the Customize panel's "Headings" section, so this is a complete
   no-op (falls through to `inherit`, i.e. whatever Classic's own markup
   already set) on every site that hasn't touched it. Bare tag selectors
   are safe here specifically because the fallback is `inherit`, not a
   fixed color/weight — unlike the non-Classic systems' own typography.css
   heading rules (which DO set a real default and are therefore scoped to
   each system's own page wrapper, see Core 2.21.0's changelog for the bug
   that taught us why). */

h1 {
	color: var(--rep-h1-color, inherit);
	font-weight: var(--rep-h1-weight, inherit);
}
h2 {
	color: var(--rep-h2-color, inherit);
	font-weight: var(--rep-h2-weight, inherit);
}
h3 {
	color: var(--rep-h3-color, inherit);
	font-weight: var(--rep-h3-weight, inherit);
}

/* ==========================================================================
   Page scaffolding (Design\Components::page_wrap()/page_header()/
   stat_strip()/card_grid()) — reusable page-level primitives any product
   screen can call instead of writing its own wrapper/header/grid markup.
   ========================================================================== */

.rep-page {
	max-width: 1120px;
	margin: 0 auto;
}

.rep-page-header {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--rep-space-md);
	margin-bottom: var(--rep-space-lg);
}
.rep-page-header__title h1 {
	margin: 0;
}
.rep-page-header__actions {
	display: flex;
	gap: var(--rep-space-sm);
	flex-shrink: 0;
}

.rep-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: var(--rep-space-lg);
}
.rep-card__title {
	margin: 0 0 var(--rep-space-sm);
}
.rep-card__footer {
	margin-top: var(--rep-space-md);
	padding-top: var(--rep-space-md);
	border-top: 1px solid var(--rep-border);
}

.rep-stat-strip {
	display: flex;
	flex-wrap: wrap;
	border: 1px solid var(--rep-border);
	border-radius: var(--rep-radius-md);
	overflow: hidden;
}
.rep-stat {
	flex: 1 1 160px;
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: var(--rep-space-md) var(--rep-space-lg);
	border-right: 1px solid var(--rep-border);
}
.rep-stat:last-child {
	border-right: 0;
}
.rep-stat__value {
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--rep-text-xl);
	font-weight: var(--rep-weight-bold);
	color: var(--rep-text);
}
.rep-stat__trend {
	margin-left: 6px;
	font-size: var(--rep-text-xs);
	font-weight: var(--rep-weight-semibold);
}
.rep-stat__trend--up {
	color: var(--rep-rise);
}
.rep-stat__trend--down {
	color: var(--rep-fall);
}
.rep-eyebrow {
	font-size: var(--rep-text-xs);
	text-transform: uppercase;
	letter-spacing: var(--rep-tracking-wide);
	color: var(--rep-muted);
}

.rep-table__num {
	text-align: right;
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Gauge / meter / KPI / HUD — the suite's one reusable instrument-panel
   grammar (Design\Components::gauge()/meter_bar()/kpi_card()/chart_card()/
   hud_dashboard_grid()). Every number here is a position on a min..max
   range with a directional judgment, so it's rendered as a dial or a bar,
   never a bare figure in a spreadsheet cell. Used at hero scale for a
   Market Snapshot/Report headline stat, at inline scale wherever another
   product (a calculator, a lead score) has a real range to show. See
   docs/REAL-ESTATE-PRO-DESIGN-SYSTEM.md "Signal" for the full rationale.
   ========================================================================== */

/* ---------- Gauge ---------- */

.rep-gauge {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 100%;
	max-width: 260px;
	margin: 0 auto;
}
.rep-gauge__svg {
	width: 100%;
	height: auto;
	overflow: visible;
}
.rep-gauge__track {
	fill: none;
	stroke: var(--rep-surface-alt);
	stroke-width: 14;
	stroke-linecap: round;
}
.rep-gauge__fill {
	fill: none;
	stroke-width: 14;
	stroke-linecap: round;
	transition: stroke-dashoffset var(--rep-transition-slow);
}
.rep-gauge__needle {
	transform-origin: 100px 100px;
	transition: transform var(--rep-transition-slow);
}
.rep-gauge__needle line {
	stroke: var(--rep-text);
	stroke-width: 3;
	stroke-linecap: round;
}
.rep-gauge__needle circle {
	fill: var(--rep-text);
}
.rep-gauge__readout {
	margin-top: calc(var(--rep-space-xl) * -1);
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 2px;
}
.rep-gauge__value {
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--rep-text-2xl);
	font-weight: var(--rep-weight-bold);
	color: var(--rep-text);
}
.rep-gauge__label {
	font-size: var(--rep-text-xs);
	color: var(--rep-muted);
	text-transform: uppercase;
	letter-spacing: var(--rep-tracking-wide);
}
.rep-gauge--sm {
	max-width: 120px;
}
.rep-gauge--sm .rep-gauge__readout {
	margin-top: calc(var(--rep-space-md) * -1);
}
.rep-gauge--sm .rep-gauge__value {
	font-size: var(--rep-text-md);
}
.rep-gauge--sm .rep-gauge__track,
.rep-gauge--sm .rep-gauge__fill {
	stroke-width: 10;
}
@media (prefers-reduced-motion: reduce) {
	.rep-gauge__fill,
	.rep-gauge__needle {
		transition: none;
	}
}
.rep-hud__gauge-caption {
	margin: var(--rep-space-sm) 0 0;
	text-align: center;
	color: var(--rep-muted);
	font-size: var(--rep-text-xs);
}
.rep-hud__meters {
	margin-top: var(--rep-space-lg);
}

/* ---------- Spectrum meter (three named zones, e.g. Seller's / Balanced /
   Buyer's Market) — reads left-to-right instead of gauge()'s dial, for a
   value whose meaning comes from which zone it falls in. ---------- */

.rep-market-meter-card {
	width: 100%;
}
.rep-spectrum-meter {
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-md);
	width: 100%;
	max-width: 720px;
	margin: 0 auto;
}
.rep-spectrum-meter__readout {
	display: flex;
	align-items: baseline;
	justify-content: center;
	gap: var(--rep-space-sm);
}
.rep-spectrum-meter__value {
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--rep-text-2xl);
	font-weight: var(--rep-weight-bold);
	color: var(--rep-text);
}
.rep-spectrum-meter__label {
	font-size: var(--rep-text-xs);
	color: var(--rep-muted);
	text-transform: uppercase;
	letter-spacing: var(--rep-tracking-wide);
}
.rep-spectrum-meter__track {
	position: relative;
	height: 10px;
	border-radius: var(--rep-radius-pill);
	background: linear-gradient(90deg, var(--rep-rise) 0%, var(--rep-surface-alt) 50%, var(--rep-accent) 100%);
}
.rep-spectrum-meter__marker {
	position: absolute;
	top: 50%;
	left: 0;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: var(--rep-surface);
	border: 3px solid var(--rep-text);
	box-shadow: var(--rep-shadow-md);
	transform: translate(-50%, -50%);
	transition: left var(--rep-transition-slow);
}
.rep-spectrum-meter__zones {
	display: flex;
	justify-content: space-between;
	font-size: var(--rep-text-xs);
	color: var(--rep-muted);
}
.rep-spectrum-meter__zone--mid {
	flex: 1;
	text-align: center;
}
.rep-spectrum-meter__zone--right {
	text-align: right;
}
.rep-spectrum-meter__zone.is-active {
	color: var(--rep-text);
	font-weight: var(--rep-weight-semibold);
}
@media (prefers-reduced-motion: reduce) {
	.rep-spectrum-meter__marker {
		transition: none;
	}
}

/* ---------- Meter bar (secondary range metric) ---------- */

.rep-meter-bar {
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-xs);
	padding: var(--rep-space-sm) 0;
}
.rep-meter-bar + .rep-meter-bar {
	border-top: 1px solid var(--rep-border);
}
.rep-meter-bar__head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--rep-space-sm);
	font-size: var(--rep-text-sm);
}
.rep-meter-bar__label {
	color: var(--rep-muted);
}
.rep-meter-bar__value {
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
	font-weight: var(--rep-weight-semibold);
	color: var(--rep-text);
}
.rep-meter-bar__track {
	position: relative;
	height: 8px;
	border-radius: var(--rep-radius-pill);
	background: var(--rep-surface-alt);
	overflow: hidden;
}
.rep-meter-bar__fill {
	position: absolute;
	inset: 0;
	width: 0;
	border-radius: inherit;
	background: var(--rep-primary);
	transition: width var(--rep-transition-slow);
}
.rep-meter-bar__fill--rise {
	background: var(--rep-rise);
}
.rep-meter-bar__fill--fall {
	background: var(--rep-fall);
}
@media (prefers-reduced-motion: reduce) {
	.rep-meter-bar__fill {
		transition: none;
	}
}

/* ---------- KPI card (composes with .rep-card) ---------- */

.rep-kpi-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-sm);
	min-width: 0;
	overflow: hidden;
}
/* A quiet top accent tied to trend direction — the one bit of color a
   resting tile carries, so a row of many tiles still reads at a glance
   without every value needing its own colored box. */
.rep-kpi-card::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	background: var(--rep-border);
}
.rep-kpi-card--rise::before {
	background: var(--rep-rise);
}
.rep-kpi-card--fall::before {
	background: var(--rep-fall);
}
.rep-kpi-card__label {
	font-size: var(--rep-text-xs);
	text-transform: uppercase;
	letter-spacing: var(--rep-tracking-wide);
	color: var(--rep-muted);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.rep-kpi-card__value {
	font-family: var(--rep-font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--rep-text-2xl);
	font-weight: var(--rep-weight-bold);
	line-height: 1.1;
	color: var(--rep-text);
}
.rep-kpi-card__delta {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	width: fit-content;
	padding: 2px var(--rep-space-sm);
	border-radius: var(--rep-radius-pill);
	font-size: var(--rep-text-xs);
	font-weight: var(--rep-weight-semibold);
}
.rep-kpi-card__delta--rise {
	color: var(--rep-rise);
	background: var(--rep-rise-wash);
}
.rep-kpi-card__delta--fall {
	color: var(--rep-fall);
	background: var(--rep-fall-wash);
}
.rep-kpi-card__delta--flat {
	color: var(--rep-muted);
	background: var(--rep-surface-alt);
}
.rep-kpi-row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--rep-space-md);
	min-width: 0;
	width: 100%;
}

/* ---------- Chart card (composes with .rep-card) ---------- */

.rep-chart-card__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--rep-space-md);
	margin-bottom: var(--rep-space-md);
}
.rep-chart-card__title {
	font-size: var(--rep-text-md);
	font-weight: var(--rep-weight-semibold);
	margin: 0;
}
.rep-chart-card__actions {
	display: flex;
	align-items: center;
	gap: var(--rep-space-xs);
	flex-shrink: 0;
}
.rep-chart-card__body {
	position: relative;
	min-width: 0;
}

/* ---------- HUD dashboard grid (instrument-bay layout) ---------- */

.rep-hud {
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-lg);
}
.rep-hud__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--rep-space-sm) var(--rep-space-md);
	padding-bottom: var(--rep-space-md);
	border-bottom: 1px solid var(--rep-border);
	font-size: var(--rep-meta-size);
	color: var(--rep-muted);
	text-transform: uppercase;
	letter-spacing: var(--rep-tracking-wide);
}
.rep-hud__meta strong {
	color: var(--rep-text);
	text-transform: none;
	letter-spacing: normal;
}
.rep-hud__stage {
	display: grid;
	grid-template-columns: minmax(240px, 320px) 1fr;
	gap: var(--rep-space-lg);
	align-items: start;
}
.rep-hud__rail {
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-lg);
	min-width: 0;
}
.rep-hud__main {
	display: flex;
	flex-direction: column;
	gap: var(--rep-space-lg);
	min-width: 0;
}
.rep-hud__actions {
	position: sticky;
	bottom: var(--rep-space-md);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--rep-space-md);
	padding: var(--rep-space-md) var(--rep-space-lg);
	background: var(--rep-primary);
	color: var(--rep-on-primary);
	border-radius: var(--rep-radius-md);
	box-shadow: var(--rep-shadow-lg);
}
.rep-hud__actions .rep-btn--primary {
	background: var(--rep-on-primary);
	border-color: var(--rep-on-primary);
	color: var(--rep-primary);
}
.rep-hud__actions .rep-btn--primary:hover {
	background: var(--rep-primary-wash);
	border-color: var(--rep-primary-wash);
	color: var(--rep-primary);
}

@media (max-width: 782px) {
	.rep-hud__stage {
		grid-template-columns: 1fr;
	}
	.rep-hud__actions {
		position: static;
	}
}

@media print {
	.rep-hud__actions {
		display: none;
	}
}

/* ---------- Animated backgrounds (Front End Design → Effects, opt-in) ----------
   Gated entirely by a body class Design\Output stamps from
   Settings\Design's custom.animated_background — every site that hasn't
   turned this on renders neither rule at all. */

body.rep-bg-drift {
	position: relative;
}
body.rep-bg-drift::before {
	content: "";
	position: fixed;
	inset: -20%;
	z-index: -1;
	pointer-events: none;
	background:
		radial-gradient(circle at 20% 20%, color-mix(in srgb, var(--rep-primary) 12%, transparent), transparent 60%),
		radial-gradient(circle at 80% 80%, color-mix(in srgb, var(--rep-accent) 10%, transparent), transparent 60%);
	animation: rep-bg-drift 24s ease-in-out infinite alternate;
}
@keyframes rep-bg-drift {
	0% {
		transform: translate(0, 0) scale(1);
	}
	100% {
		transform: translate(-3%, 2%) scale(1.06);
	}
}

body.rep-bg-scanline {
	position: relative;
}
body.rep-bg-scanline::before {
	content: "";
	position: fixed;
	left: 0;
	right: 0;
	height: 2px;
	top: 0;
	z-index: 9999;
	pointer-events: none;
	opacity: 0.5;
	background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--rep-primary) 60%, transparent), transparent);
	animation: rep-bg-scanline 6s linear infinite;
}
@keyframes rep-bg-scanline {
	0% {
		top: 0;
	}
	100% {
		top: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	body.rep-bg-drift::before,
	body.rep-bg-scanline::before {
		animation: none;
		display: none;
	}
}
