/* Brand-themeable base styles.
 *
 * Every colour, font and shape below resolves through the three tiers defined
 * in theme.css: a component token first, then the role it belongs to, then the
 * primitive behind that. Tokens are written onto :root by page-content.ts and
 * an absent token is never emitted, so the chain's tail is what an unthemed
 * brand sees — and the tails here are the same values the old hardcoded
 * fallbacks used, so nothing moves for a brand that has not opted in.
 *
 * Two rules for anything added here:
 *
 *   1. No hardcoded colours. If a value is not a var() chain, a brand cannot
 *      change it, and the point of this sheet is that they can.
 *   2. No !important. This sheet loads after Bootstrap now, so specificity is
 *      enough; !important only makes a brand's custom_css escalate to match.
 *      Two exceptions survive and are marked where they appear: redefining a
 *      Bootstrap utility that is itself !important, and beating an inline
 *      style. Neither is a fight load order can settle.
 */

body {
	background-color: var(--bg-page-background, var(--bg-canvas));
	color: var(--bg-page-text, var(--bg-ink));
	font-family: var(--bg-page-font-family, var(--bg-font-body));
}

/* Headings follow the heading font, which defaults to the body font — so a
 * brand that sets only --bg-font-body still gets a consistent page, and one
 * that pairs two faces gets the pairing. */
h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: var(--bg-heading-font-family, var(--bg-font-heading));
}

.header {
	background-color: var(--bg-header-background, var(--bg-surface));
	color: var(--bg-header-text, inherit);
}

.footer {
	background-color: var(--bg-footer-background, var(--bg-surface));
	color: var(--bg-footer-text, inherit);
}

.brand {
	background-color: var(--bg-header-background, var(--bg-surface));
	align-items: center;
	justify-content: center;
}

/* identity.logo_url renders a real <img> here. Legacy brands leave this empty
 * and paint a logo via background-image on .brand instead. */
.brand > .logo:empty {
	display: none;
}

/* The logo is sized by HEIGHT, not by its own width.
 *
 * An SVG exported with only a viewBox has an aspect ratio but no intrinsic
 * size. The header is a flex row and .logo takes its width from its content,
 * so an image with no intrinsic width inside a content-sized box is circular:
 * both resolve to zero and the logo renders 0x0 — present, loaded, invisible.
 * Raster logos never hit it, which is why it went unnoticed; brand logos
 * scraped from a brand's own site are very often exactly this kind of SVG.
 *
 * A definite height breaks the circularity: the ratio then yields a width.
 * It also gives every brand's logo the same height, which is what a header
 * wants. The cost is that a logo shorter than this is scaled up.
 *
 * identity.logo_max_height is written inline by App.vue as BOTH height and
 * max-height, so a brand that has set one keeps it and this is only the
 * default for the brands — most of them — that have not. */
.brand > .logo img {
	display: block;
	height: var(--bg-logo-height, 64px);
	width: auto;
	max-width: 100%;
	object-fit: contain;
}

.info_icon {
	color: var(--bg-icon-color, var(--bg-accent));
	margin-right: var(--bg-icon-gap, 5px);
}

.brand > .name {
	font-size: 2em;
	font-family: var(--bg-heading-font-family, var(--bg-font-heading));
}

/* Links follow the accent, whose own default is Bootstrap's blue — so an
 * unthemed page keeps Bootstrap's link colour while a brand that sets one
 * colour gets links in it. */
a {
	color: var(--bg-link-color, var(--bg-accent));
}

a:hover {
	color: var(--bg-link-hover-color, var(--bg-accent-hover));
}

/* .cleaned uses all:unset and must keep doing so. */
a.cleaned {
	color: inherit;
}

/* Small print: --bg-page-muted is documented as "secondary text - hints,
 * small print, disabled labels", which is exactly this. Asking for page-text
 * made the footnote compete with the heading on a real theme. */
.footnote {
	color: var(--bg-page-muted, var(--bg-ink-muted));
}

/* How wide the page may get. Was hardcoded in App.vue, where a brand could not
 * reach it; a brand whose own site runs narrow or full-bleed sets this. */
main > .container {
	max-width: var(--bg-page-max-width, 1024px);
	width: auto;
}

/* -------------------------------------------------------------------- *
 * Surfaces.
 *
 * Four different rules used to paint a card, each setting background, radius
 * and padding separately: .center_page, form.default, .content-card and
 * div.form.big. They are one thing and are defined once here; the individual
 * rules below and in forms.css now only add what is genuinely different about
 * each (width, layout, text alignment).
 * -------------------------------------------------------------------- */
.content-card,
div.form,
form.default,
div.form.big {
	background-color: var(--bg-surface-background, var(--bg-surface));
	color: var(--bg-surface-text, inherit);
	border-radius: var(--bg-surface-radius, var(--bg-radius));
	padding: var(--bg-surface-padding, var(--bg-space));
}

/* .center_page is a padded block, not a card: it has never painted a
 * background, and pages combine it with .form when they want one. */
.center_page {
	padding: var(--bg-surface-padding, var(--bg-space));
	border-radius: var(--bg-surface-radius, var(--bg-radius));
}

/* Bootstrap's .shadow utility, pointed at the theme's shadow. One of the two
 * places !important survives: Bootstrap declares the utility itself with
 * !important, so matching it is the only way to redefine it — this is not a
 * specificity fight we can win on load order. */
.shadow {
	box-shadow: var(--bg-surface-shadow, var(--bg-shadow)) !important;
}

@media (max-width: 500px) {
	.center_page {
		padding: 2px;
	}
}
/* The other surviving !important. On a phone a heading that arrived with an
 * inline background — authored HTML, or a legacy brand's markup — paints a
 * band across the card, and an inline style outranks any rule we could write
 * without it. */
@media (max-width: 768px) {
	div.form div h1 {
		background-color: transparent !important;
	}
}

/* Copy left, offer image right, above the rating. Roughly 60/40: the copy
 * carries a lead line, a headline and an instruction, so it needs the wider
 * column; the image only has to be recognisable. space-around previously left
 * a gap in the middle and let the two drift apart. */
div.description {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 1.5rem;
	text-align: left;
}

div.content {
	flex: 1 1 60%;
	min-width: 0;
	color: var(--bg-surface-content-text, inherit);
}

div.description > .giftcard {
	flex: 0 1 40%;
	display: flex;
	justify-content: center;
}

div.description > .giftcard img {
	width: 100%;
	max-width: 260px;
	height: auto;
}

/* A brand writes its offer headline as a heading inside a richtext slot. The
 * sanitizer strips style attributes, so inline colour is not available to them
 * and must not be — the heading takes the theme's heading colour instead. */
div.content h1,
div.content h2,
div.content h3,
div.content h4 {
	color: var(--bg-surface-heading, var(--bg-ink));
}

div.content > *:last-child {
	margin-bottom: 0;
}

@media (max-width: 500px) {
	div.description {
		flex-direction: column-reverse;
	}
	div.content {
		margin-bottom: 1rem;
		margin-top: 1rem;
	}
}

/* A single panel holding copy, offer image and rating. Wider than
 * form.default's 580px because it carries two columns. */
.content-card {
	max-width: var(--bg-card-max-width, 720px);
	margin-left: auto;
	margin-right: auto;
	text-align: left;
}

/* Inside the panel the rating is just a row, not a card of its own. */
.content-card div.form.big {
	max-width: none;
	padding: 0;
	margin-top: 1.5rem;
	background-color: transparent;
}

/* Two columns need more room than the 500px the rest of the page stacks at. */
@media (max-width: 768px) {
	div.description {
		flex-direction: column-reverse;
	}
	div.description > .giftcard {
		flex-basis: auto;
	}
}

/* The rating screens (StarsForm, NPSForm) put their widget in a bare
 * .form.big instead of sharing the .center_page.form card every other page
 * uses. Against the old near-white page background its white background read
 * as nothing; against a themed page it became a full-width white stripe.
 * It takes the shared surface treatment above; only its width is its own.
 */
div.form.big {
	max-width: var(--bg-form-max-width, 580px);
	margin-left: auto;
	margin-right: auto;
}

/* -------------------------------------------------------------------- *
 * Authored content.
 *
 * .authored wraps HTML the brand wrote itself, and .page-title / .page-desc /
 * .main-body are the thank-you and retry pages. All four were class hooks with
 * no rule behind them anywhere in the app — authored copy inherited whatever
 * happened to fall through, which on a themed page was frequently the wrong
 * thing. They are styled from tokens here, and named in the theme contract, so
 * a brand can target them from custom_css without guessing.
 * -------------------------------------------------------------------- */
.authored {
	color: var(--bg-surface-text, inherit);
	font-family: var(--bg-page-font-family, var(--bg-font-body));
}

.authored h1,
.authored h2,
.authored h3,
.authored h4,
.page-title {
	color: var(--bg-surface-heading, var(--bg-ink));
	font-family: var(--bg-heading-font-family, var(--bg-font-heading));
}

.authored a {
	color: var(--bg-link-color, var(--bg-accent));
}

.authored > *:last-child {
	margin-bottom: 0;
}

.page-desc {
	color: var(--bg-surface-text, inherit);
}

.main-body {
	color: var(--bg-page-text, var(--bg-ink));
}

/* Bootstrap button theming.
 *
 * Bootstrap 5.3 drives .btn entirely from --bs-btn-* custom properties, so the
 * brand tokens are mapped onto those rather than overriding declarations.
 * Setting --bs-primary at :root does NOT do this — that variable is published
 * for reuse and the components compile their colours from Sass, so the
 * per-component map below is the supported runtime route.
 *
 * The three resting tokens mean:
 *
 *   --bg-primary-background  the FILL. Solid button at rest; outline button on
 *                            hover. An outline button has no resting fill, so
 *                            that is hardcoded transparent and a brand cannot
 *                            flatten the distinction between the two variants.
 *   --bg-primary-text        the label ON a fill, so it must contrast with the
 *                            fill. Solid at rest; outline on hover.
 *   --bg-primary-border      the ACCENT LINE: the outline button's border, and
 *                            also its resting label, which sits on the page
 *                            rather than on a fill and so follows the line.
 *
 * Each now falls through to the accent role rather than to a blue hex, so a
 * brand that sets --bg-brand gets all three states without naming them.
 */
.btn-outline-primary {
	/* Resting label follows the accent line, not the on-fill text token. */
	--bs-btn-color: var(--bg-primary-border, var(--bg-primary-background, var(--bg-accent)));
	--bs-btn-bg: transparent;
	--bs-btn-border-color: var(
		--bg-primary-border,
		var(--bg-primary-background, var(--bg-accent))
	);
	--bs-btn-border-radius: var(--bg-primary-radius, var(--bg-radius-control));

	/* On hover it gains a fill, so the label becomes the on-fill token. */
	--bs-btn-hover-color: var(--bg-primary-text, var(--bg-on-accent));
	--bs-btn-hover-bg: var(--bg-primary-background, var(--bg-accent));
	--bs-btn-hover-border-color: var(
		--bg-primary-hover-border,
		var(--bg-primary-background, var(--bg-accent))
	);

	--bs-btn-active-color: var(--bg-primary-active-text, var(--bg-on-accent));
	--bs-btn-active-bg: var(--bg-primary-active-background, var(--bg-accent-active));
	--bs-btn-active-border-color: var(--bg-primary-active-border, var(--bg-accent-active));
	--bs-btn-active-shadow: var(--bg-primary-active-shadow, none);

	/* Still an outline when disabled: no fill.
	 *
	 * The label tries --bg-primary-disabled-text FIRST, then falls back to the
	 * border token. Label-follows-line is the right default here and mirrors
	 * the resting state, where --bg-primary-border is deliberately both the
	 * border and the label. But a token named "-text" that could never colour
	 * any text was a control that did not do what its name said: a brand
	 * setting it to grey got grey on the filled button and the border colour
	 * here. Falling through keeps the convention when the token is unset and
	 * honours it when it is set. */
	--bs-btn-disabled-color: var(
		--bg-primary-disabled-text,
		var(--bg-primary-disabled-border, var(--bg-accent))
	);
	--bs-btn-disabled-bg: transparent;
	--bs-btn-disabled-border-color: var(--bg-primary-disabled-border, var(--bg-accent));

	/* Bootstrap wants a bare "r, g, b" triplet here, not a shadow, so this one
	 * cannot derive from the accent and keeps a literal default. */
	--bs-btn-focus-shadow-rgb: var(--bg-primary-focus-shadow, 13, 110, 253);
}

.btn-primary,
.form-buttons .btn-primary {
	--bs-btn-color: var(--bg-primary-text, var(--bg-on-accent));
	--bs-btn-bg: var(--bg-primary-background, var(--bg-accent));
	--bs-btn-border-color: var(
		--bg-primary-border,
		var(--bg-primary-background, var(--bg-accent))
	);
	--bs-btn-border-radius: var(--bg-primary-radius, var(--bg-radius-control));

	--bs-btn-hover-color: var(--bg-primary-hover-text, var(--bg-on-accent));
	--bs-btn-hover-bg: var(--bg-primary-hover-background, var(--bg-accent-hover));
	--bs-btn-hover-border-color: var(
		--bg-primary-hover-border,
		var(--bg-primary-hover-background, var(--bg-accent-hover))
	);

	--bs-btn-active-color: var(--bg-primary-active-text, var(--bg-on-accent));
	--bs-btn-active-bg: var(--bg-primary-active-background, var(--bg-accent-active));
	--bs-btn-active-border-color: var(
		--bg-primary-active-border,
		var(--bg-primary-active-background, var(--bg-accent-active))
	);
	--bs-btn-active-shadow: var(--bg-primary-active-shadow, none);

	--bs-btn-disabled-color: var(--bg-primary-disabled-text, var(--bg-on-accent));
	--bs-btn-disabled-bg: var(--bg-primary-disabled-background, var(--bg-accent));
	--bs-btn-disabled-border-color: var(--bg-primary-disabled-border, var(--bg-accent));

	--bs-btn-focus-shadow-rgb: var(--bg-primary-focus-shadow, 49, 132, 253);
}

/* The quieter button. Previously unthemed, so a brand with a themed primary
 * got a Bootstrap-grey Cancel next to it. */
.btn-secondary {
	--bs-btn-color: var(--bg-secondary-text, var(--bg-ink));
	--bs-btn-bg: var(--bg-secondary-background, transparent);
	--bs-btn-border-color: var(--bg-secondary-border, var(--bg-line));
	--bs-btn-border-radius: var(--bg-primary-radius, var(--bg-radius-control));

	--bs-btn-hover-color: var(--bg-secondary-hover-text, var(--bg-ink));
	--bs-btn-hover-bg: var(--bg-secondary-hover-background, var(--bg-accent-subtle));
	--bs-btn-hover-border-color: var(--bg-secondary-border, var(--bg-line));

	--bs-btn-active-color: var(--bg-secondary-hover-text, var(--bg-ink));
	--bs-btn-active-bg: var(--bg-secondary-hover-background, var(--bg-accent-subtle));
	--bs-btn-active-border-color: var(--bg-secondary-border, var(--bg-line));
}
