/*!
 * WEBE Cookie Banner — front-end styles
 * @author    Florian Hüing
 * @copyright 2026 webe Media — Florian Hüing. All rights reserved.
 */

/*
 * Page-covering backdrop shown together with the initial consent banner, so
 * the banner reads as a true modal popup (WCAG 1.4.10-friendly: dims but
 * never traps scroll) rather than a bar the visitor can ignore. Kept as a
 * separate element (not merged into .webe-cc) so the preferences panel's
 * own backdrop can layer on top without doubling up the banner markup.
 *
 * Frosted-glass look (light blur, not a dark dim): the site behind stays
 * bright and legible — just softened — until the visitor decides, rather
 * than the page going dark. Falls back to a plain light tint on browsers
 * without backdrop-filter support (still communicates "site is behind a
 * layer" without the blur).
*/
/*
 * Modal scroll lock: toggled on <html> by setScrollLock() in banner.js
 * whenever the backdrop is visible (first prompt, or reopened via the
 * trigger/"Manage preferences"). The backdrop element already blocks clicks
 * on the page behind it (a full-viewport element above the page's own
 * content in the stacking order), but nothing previously stopped the page
 * from scrolling underneath a still-open dialog. Locking <html> itself
 * (not just <body>) is the version that holds reliably on iOS Safari too.
 */
html.webe-cc-scroll-lock,
html.webe-cc-scroll-lock body {
	overflow: hidden !important;
}

.webe-cc__backdrop {
	position: fixed;
	inset: 0;
	z-index: 999998;
	background: color-mix(in srgb, var(--webe-cc-backdrop-color, #ffffff) 55%, transparent);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
	opacity: 1;
	transition: opacity 200ms ease;
}

.webe-cc__backdrop[hidden] {
	display: block;
	opacity: 0;
	pointer-events: none;
}

.webe-cc {
	position: fixed;
	left: 50%;
	z-index: 999999;
	box-sizing: border-box;
	width: calc(100% - 2rem);
	max-width: var(--webe-cc-width, 620px);
	padding: var(--webe-cc-padding, 1.25rem);
	/*
	 * !important on the CI-defining properties in this file (background,
	 * color, border, border-radius) is deliberate: this banner renders
	 * inside arbitrary client sites, and popular theme/page-builder resets
	 * (e.g. Hello Elementor's reset.css targets bare `button`/[type=button]
	 * selectors) tie or beat our class-selector specificity, silently
	 * discarding the client's configured CI colors — confirmed live on a
	 * client site where reset.css's `button:hover` rule painted every
	 * button pink regardless of the accent color set in Settings. Without
	 * !important here, "CI configurable per client" silently breaks on any
	 * theme with its own button reset.
	 */
	border-radius: var(--webe-cc-card-radius, 16px) !important;
	background: var(--webe-cc-bg, #1c1c1e) !important;
	color: var(--webe-cc-text, #f5f5f7) !important;
	font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	/* When --webe-cc-font is not set, inherit the host page's font (the
	 * var() default). The plugin overrides only when the admin opts in. */
	font-family: var(--webe-cc-font, inherit);
	display: flex;
	flex-wrap: wrap;
	/*
	 * row-gap must stay 0. The action zone and the footer below it are one
	 * continuous tinted band (see .webe-cc > .webe-cc__actions); any row
	 * gap between them lets the card's own background show through as a
	 * stripe splitting that band in two. Vertical rhythm is handled by the
	 * elements' own padding/margins instead — .webe-cc__title's
	 * margin-bottom under the logo, the action zone's own padding-top.
	 */
	column-gap: 1rem;
	row-gap: 0;
	align-items: center;
	justify-content: space-between;
	box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
	opacity: 1;
	transition: transform 200ms ease, opacity 200ms ease;
}

.webe-cc[hidden] {
	display: flex;
	pointer-events: none;
	opacity: 0;
}

.webe-cc--bottom {
	bottom: 1.25rem;
	transform: translateX(-50%) translateY(0);
	transform-origin: bottom;
}

.webe-cc--bottom[hidden] {
	transform: translateX(-50%) translateY(20px);
}

.webe-cc--top {
	top: 1.25rem;
	transform: translateX(-50%) translateY(0);
	transform-origin: top;
}

.webe-cc--top[hidden] {
	transform: translateX(-50%) translateY(-20px);
}

/*
 * The logo always gets the full top row of its own. It used to be a
 * flex sibling of the body copy with a 320px flex-basis, so on anything
 * wider than a phone it sat *beside* the paragraph, vertically centred —
 * reading as a bullet next to the text rather than as the brand mark of
 * the dialog.
 */
.webe-cc__title {
	flex: 1 1 100%;
	display: flex;
	align-items: center;
	/* The container's row-gap is 0 (see .webe-cc), so the space between the
	 * logo and the copy below it lives here. */
	margin-bottom: 0.85rem;
}

/*
 * With no logo configured this element holds only the visually-hidden
 * heading, so it would contribute an empty row plus the container's
 * row-gap above the copy. Hiding it is safe for the dialog's accessible
 * name: it is the direct target of aria-labelledby, and the accessible
 * name computation explicitly uses a directly-referenced element even
 * when that element is hidden.
 */
.webe-cc:not(:has(.webe-cc__logo)) .webe-cc__title {
	display: none;
}

/*
 * The body copy sits in its own framed well rather than floating directly on
 * the card. With the logo above it and the tinted action zone below, the card
 * otherwise read as one undivided block of text; the frame gives the copy a
 * defined container and makes the three zones legible as structure.
 *
 * Tint and border are derived from the configured card background with
 * color-mix, so this stays proportionate on a dark CI instead of assuming a
 * white card. min() on the radius keeps the inner corner tighter than the
 * card's own — an inner box repeating a 20px (or pill) outer radius looks
 * like a mistake.
 */
.webe-cc__body {
	flex: 1 1 100%;
	min-width: 0;
	box-sizing: border-box;
	padding: 0.95rem 1.1rem;
	border: 1px solid color-mix(in srgb, var(--webe-cc-bg, #ffffff) 88%, black);
	border-radius: min(var(--webe-cc-card-radius, 20px), 14px);
	background: color-mix(in srgb, var(--webe-cc-bg, #ffffff) 97%, black);
}

/*
 * Browsers without color-mix() get a neutral translucent overlay instead:
 * it darkens a light card and lightens nothing, but it never renders as an
 * invisible or clashing block the way a hard-coded gray would on a dark CI.
 */
@supports not (background: color-mix(in srgb, white 90%, black)) {
	.webe-cc__body {
		border-color: rgba(128, 128, 128, 0.28);
		background: rgba(128, 128, 128, 0.07);
	}
}

.webe-cc__logo {
	display: block;
	max-height: var(--webe-cc-logo-height, 28px);
	/* height:auto + max-width:100% keeps SVG logos honest: an SVG that
	 * ships with only a viewBox and no intrinsic width/height has its
	 * width derived from the aspect ratio instead of falling back to the
	 * 300×150 default replaced-element size, and a wide logo can never
	 * push past the card edge. */
	height: auto;
	width: auto;
	max-width: 100%;
}

.webe-cc__actions {
	/*
	 * flex: 1 1 100% (rather than the old 0 0 auto) makes this container
	 * claim the banner's full width once it wraps onto its own row below
	 * the body text in the OUTER .webe-cc flex-wrap layout, and min-width:
	 * 0 lets it actually shrink to that width instead of overflowing the
	 * card (confirmed on a 375px viewport: "Alle akzeptieren" used to run
	 * off-screen because the rigid 0 0 auto container sized itself to its
	 * natural content width — three buttons side by side — before its own
	 * internal layout ever got a chance to adapt).
	 */
	flex: 1 1 100%;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

/*
 * Two-tone card: the main banner's action row (and the footer right below
 * it, which continues the same zone — see .webe-cc__footer) bleeds to the
 * card's own edges (negative margin matching --webe-cc-padding, then
 * re-applies that padding inside) and gets a subtly darker tint of the card
 * background — a separate visual "zone" from the body/logo area above,
 * rather than one flat slab of color. Reads as white-card-with-light-gray-
 * footer by default, and stays proportionate whether the admin's card
 * background is light or dark since it's a relative mix, not a fixed gray.
 *
 * Scoped to `.webe-cc > .webe-cc__actions` — a *direct child* of the main
 * banner card — rather than plain `.webe-cc__actions`, which also matches
 * the preferences panel's action row. The panel card has asymmetric
 * padding (extra padding-right reserved for the close button — see
 * .webe-cc__panel-card), so a *symmetric* negative margin calculated from
 * the same --webe-cc-padding var doesn't reach the panel's actual right
 * edge: confirmed live, a ~20px gap of bare white card showing on the
 * right where the tint should have reached. The panel's own actions stay
 * plain (no bleed, no tint) instead of trying to special-case that offset.
 *
 * No bottom rounding/margin here: when the footer is present (almost
 * always — the language switcher alone guarantees it) it continues this
 * same background flush underneath, so only the footer needs the bottom
 * corners; when the footer really is empty, .webe-cc__actions:last-child
 * below picks up the rounding instead.
 */
/*
 * The action row keeps the card's own background — only the footer strip at
 * the very bottom is tinted. The tint used to start here, which made the
 * buttons sit on a gray slab that read as a separate toolbar; the decision
 * itself belongs on the card, and the gray is reserved for the utility row
 * (legal links, language) below it.
 */
.webe-cc > .webe-cc__actions {
	margin: 0;
	padding: 1rem 0 0.5rem;
}

/*
 * Only relevant when no footer renders (admin cleared both legal URLs AND
 * the language switcher is somehow absent): the action row then becomes the
 * last element and has to close off the card itself.
 */
.webe-cc > .webe-cc__actions:last-child {
	margin: 0 calc(var(--webe-cc-padding, 1.25rem) * -1) calc(var(--webe-cc-padding, 1.25rem) * -1);
	padding: 1rem var(--webe-cc-padding, 1.25rem) var(--webe-cc-padding, 1.25rem);
	border-radius: 0 0 var(--webe-cc-card-radius, 16px) var(--webe-cc-card-radius, 16px);
}

/* Mobile: buttons full-width stacked, each an equally-weighted tap target
 * rather than differently-sized inline buttons — applies to both the main
 * banner's and the preferences panel's action rows. */
.webe-cc__actions .webe-cc__btn {
	width: 100%;
	text-align: center;
}

/*
 * From ~tablet width up there's room to be less linear: "Manage
 * preferences" (secondary, lower-frequency action) sits on its own row,
 * with Reject/Accept — the two decisive actions — side by side below it.
 * Grid with named areas (rather than relying on DOM order + flex `order`)
 * places each button correctly regardless of their source order, which
 * stays reject → manage → accept for a sensible keyboard tab sequence.
 * Scoped to the main banner only — see the two-tone comment above for why
 * the panel's own action row (a different button set) is styled
 * separately, just below.
 */
@media (min-width: 640px) {
	.webe-cc > .webe-cc__actions {
		display: grid;
		grid-template-columns: 1fr 1fr;
		grid-template-areas: "manage manage" "reject accept";
		gap: 0.5rem;
	}

	.webe-cc__actions .webe-cc__btn {
		width: auto;
	}

	/*
	 * Same rhythm as the banner's action row above: buttons always fill the
	 * row they sit in — two per row at 50% each, a lone one at full width.
	 * They used to be content-width and left-aligned (flex: 0 1 auto), which
	 * left a ragged gap on the right of every row.
	 *
	 * Auto-placement handles the first two (necessary-only, select-all);
	 * only "save" is pinned, spanning both columns on its own row, so this
	 * keeps working if the shortcut buttons are ever reordered.
	 */
	.webe-cc__panel-card .webe-cc__actions {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 0.5rem;
	}

	.webe-cc__panel-card .webe-cc__actions [data-webe-action="save-preferences"] {
		grid-column: 1 / -1;
	}

	/*
	 * Scoped to the banner's own action row with `>`. Unscoped, these also
	 * matched the preferences panel: its "Select all" button deliberately
	 * reuses data-webe-action="accept-all", so it inherited `grid-area:
	 * accept` — a name that does not exist in the panel's grid — and got
	 * pushed into an implicit row of its own instead of sitting beside
	 * "Necessary only". Measured: 34% / 28% / 69% wide across three rows
	 * rather than 50/50 + full width.
	 */
	.webe-cc > .webe-cc__actions [data-webe-action="manage"] {
		grid-area: manage;
	}

	.webe-cc > .webe-cc__actions [data-webe-action="reject-all"] {
		grid-area: reject;
	}

	.webe-cc > .webe-cc__actions [data-webe-action="accept-all"] {
		grid-area: accept;
	}
}

.webe-cc__btn {
	appearance: none;
	border: 1px solid transparent !important;
	border-radius: var(--webe-cc-radius, 999px) !important;
	/* !important for the same reason as the colors below: a host theme's
	 * button rules match at the same specificity and win on source order.
	 * Measured on a client site, every button in this plugin was silently
	 * rendering with the theme's 8px/16px padding instead of ours. */
	padding: 0.6em 1.3em !important;
	font: inherit;
	font-weight: 600;
	cursor: pointer;
	/* !important: see the note on .webe-cc above — host button resets
	 * (incl. their :hover/:focus variants) otherwise win on tied
	 * specificity and override the configured CI colors, including on
	 * hover, not just at rest. */
	background: transparent !important;
	color: inherit !important;
}

.webe-cc__btn--accept {
	background: var(--webe-cc-accent, #0a84ff) !important;
	color: #fff !important;
}

.webe-cc__btn--reject {
	border-color: currentColor !important;
}

.webe-cc__btn--accept:hover,
.webe-cc__btn--accept:focus-visible {
	background: var(--webe-cc-accent, #0a84ff) !important;
	color: #fff !important;
}

.webe-cc__btn--reject:hover,
.webe-cc__btn--reject:focus-visible,
.webe-cc__btn:not(.webe-cc__btn--accept):hover,
.webe-cc__btn:not(.webe-cc__btn--accept):focus-visible {
	background: transparent !important;
	color: inherit !important;
	border-color: currentColor !important;
}

.webe-cc__btn:focus-visible {
	outline: 2px solid var(--webe-cc-accent, #0a84ff);
	outline-offset: 2px;
}

/*
 * Footer: privacy-policy/imprint links (only rendered by PHP when the admin
 * set a URL — see WEBE_Banner_Renderer::footer_markup()) plus the
 * visitor-facing language switcher. Sits inside the two-tone action zone so
 * it reads as one continuous "utility" area under the main choice.
 */
.webe-cc__footer {
	flex: 1 1 100%;
	/*
	 * One row: legal links left, language picker right. This only fits
	 * because the picker collapsed from five buttons into a single select —
	 * it wraps to a second line on narrow screens rather than squeezing.
	 */
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.35rem 1rem;
	/* The card's only tinted zone: a utility strip along the bottom edge.
	 * It bleeds to the card's edges (negative margin matching the padding,
	 * then puts that padding back inside) and rounds the card's bottom
	 * corners, since it is normally the last element — the footer is only
	 * absent if the admin cleared both legal URLs, and even then the
	 * language switcher keeps it present in practice.
	 *
	 * margin-top adds the breathing room the action row's old bottom
	 * padding used to provide now that the two no longer form one band. */
	margin: 0.9rem calc(var(--webe-cc-padding, 1.25rem) * -1) calc(var(--webe-cc-padding, 1.25rem) * -1);
	padding: 0.7rem var(--webe-cc-padding, 1.25rem) calc(var(--webe-cc-padding, 1.25rem) * 0.8);
	background: color-mix(in srgb, var(--webe-cc-bg, #1c1c1e) 92%, black);
	border-top: 1px solid color-mix(in srgb, var(--webe-cc-text, #1c1c1e) 12%, transparent);
	border-radius: 0 0 var(--webe-cc-card-radius, 16px) var(--webe-cc-card-radius, 16px);
	font-size: 0.78rem;
}

.webe-cc__footer-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0 0.75rem;
}

.webe-cc__footer-link {
	color: inherit !important;
	opacity: 0.8;
	text-decoration: underline;
	text-underline-offset: 2px;
	text-decoration-thickness: 1px;
}

/* Hairline divider between the legal links, so they read as one group
 * without needing a wide gap to separate them. */
.webe-cc__footer-link + .webe-cc__footer-link {
	position: relative;
}

.webe-cc__footer-link + .webe-cc__footer-link::before {
	content: "";
	position: absolute;
	left: -0.4rem;
	top: 0.15em;
	bottom: 0.15em;
	width: 1px;
	background: currentColor;
	opacity: 0.3;
}

.webe-cc__footer-link:hover,
.webe-cc__footer-link:focus-visible {
	opacity: 1;
}

/*
 * Language switcher: deliberately the lightest thing in the card. It's a
 * correction for the minority of visitors whose auto-detected locale was
 * wrong, not an action competing with Accept/Reject — so it's a single
 * small control, not a row of five.
 */
.webe-cc__lang-switch {
	position: relative;
	display: inline-flex;
}

/*
 * The trigger is a quiet pill until touched: it must read as a utility
 * control next to the legal links, not as a fourth thing to click
 * alongside Accept/Reject.
 */
.webe-cc__lang-trigger {
	appearance: none;
	/* !important on the whole box for the same reason as .webe-cc__btn:
	 * host theme button resets match [type="button"] at our specificity
	 * and win on source order, which previously killed `display` (and with
	 * it `gap`) outright. */
	display: inline-flex !important;
	align-items: center !important;
	gap: 0.35rem !important;
	width: auto !important;
	margin: 0 !important;
	padding: 0.3rem 0.5rem !important;
	border: 1px solid rgba(0, 0, 0, 0.14) !important;
	border-radius: 7px !important;
	background: transparent !important;
	color: inherit !important;
	font: inherit;
	font-size: 0.72rem;
	line-height: 1.4;
	cursor: pointer;
	opacity: 0.75;
	transition: opacity 120ms ease, background-color 120ms ease, border-color 120ms ease;
}

.webe-cc__lang-trigger:hover,
.webe-cc__lang-trigger:focus-visible,
.webe-cc__lang-trigger[aria-expanded="true"] {
	opacity: 1;
	background: rgba(0, 0, 0, 0.04) !important;
	border-color: rgba(0, 0, 0, 0.22) !important;
}

.webe-cc__lang-icon {
	width: 13px;
	height: 13px;
	flex: none;
}

.webe-cc__lang-caret {
	width: 11px;
	height: 11px;
	flex: none;
	opacity: 0.7;
	transition: transform 140ms ease;
}

.webe-cc__lang-trigger[aria-expanded="true"] .webe-cc__lang-caret {
	transform: rotate(180deg);
}

/*
 * Opens UPWARD. The switcher sits in the footer, i.e. on the bottom edge
 * of the card, so a downward list would be clipped by the card or run off
 * the bottom of the viewport. Right-aligned to match the trigger, which
 * is itself right-aligned in the footer row.
 */
.webe-cc__lang-list {
	position: absolute;
	bottom: calc(100% + 0.4rem);
	right: 0;
	z-index: 10;
	min-width: max(100%, 9.5rem);
	max-height: 13rem;
	overflow-y: auto;
	margin: 0 !important;
	padding: 0.3rem !important;
	list-style: none !important;
	background: #fbfbfc !important;
	border: 1px solid rgba(0, 0, 0, 0.08) !important;
	border-radius: 10px !important;
	box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16) !important;
	text-align: left;
}

.webe-cc__lang-list[hidden] {
	display: none;
}

.webe-cc__lang-option {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.25rem;
	margin: 0 !important;
	padding: 0.42rem 0.6rem !important;
	border-radius: 6px;
	list-style: none !important;
	color: #1c1c1e;
	font-size: 0.78rem;
	line-height: 1.4;
	cursor: pointer;
	/* No outline on the option itself: focus moves with .is-active, which
	 * is what the trigger's aria-activedescendant points at. */
	outline: none;
}

.webe-cc__lang-option::before,
.webe-cc__lang-option::marker {
	content: none;
}

.webe-cc__lang-option:hover,
.webe-cc__lang-option.is-active {
	background: rgba(0, 0, 0, 0.055);
}

.webe-cc__lang-check {
	width: 13px;
	height: 13px;
	flex: none;
	color: var(--webe-cc-accent, #0a84ff);
	/* Reserved, not removed: hiding it with display:none would let the
	 * label shift sideways as the selection moves between rows. */
	visibility: hidden;
}

.webe-cc__lang-option[aria-selected="true"] .webe-cc__lang-check {
	visibility: visible;
}

/*
 * Plain-language cookie explainer in the preferences panel: a disclosure
 * above the decisive buttons, collapsed by default so it informs the
 * visitors who want it without pushing the actual choice below the fold
 * for everyone else.
 */
/*
 * Shares the button shape with .webe-cc__btn — same radius, same padding box,
 * same full-width footprint — so it reads as a control rather than as a stray
 * link between the category rows. It stays outline-only (never filled): it is
 * not a consent action and must not compete with Save/Necessary-only.
 */
.webe-cc__info-toggle {
	appearance: none;
	/*
	 * !important on the layout here, not just the colors: this is a
	 * <button>, and a host theme's button reset (Hello Elementor's, for
	 * one) matches `[type="button"]` at the same specificity as our class
	 * and wins on source order, previously resetting display back to
	 * inline-block and dropping the padding with it.
	 */
	display: flex !important;
	width: 100% !important;
	box-sizing: border-box !important;
	align-items: center !important;
	justify-content: center !important;
	margin: 1.25rem 0 0 !important;
	padding: 0.6em 1.3em !important;
	border: 1px solid currentColor !important;
	border-radius: var(--webe-cc-radius, 999px) !important;
	background: transparent !important;
	color: var(--webe-cc-accent, #0a84ff) !important;
	font: inherit;
	font-size: 0.85rem;
	font-weight: 600;
	line-height: 1.35;
	cursor: pointer;
	text-align: center;
	transition: background-color 120ms ease;
}

.webe-cc__info-toggle:hover,
.webe-cc__info-toggle:focus-visible {
	background: color-mix(in srgb, var(--webe-cc-accent, #0a84ff) 8%, transparent) !important;
}

/*
 * Without this the browser's own focus ring applies — a hard black rectangle
 * that ignores the client's CI and clashes with the button's accent border.
 * Same accent ring the .webe-cc__btn controls use, so keyboard focus looks
 * the same everywhere. The ring is replaced, never removed: dropping it would
 * leave keyboard users with no visible focus at all (WCAG 2.4.7).
 */
.webe-cc__info-toggle:focus-visible {
	outline: 2px solid var(--webe-cc-accent, #0a84ff);
	outline-offset: 2px;
}

.webe-cc__info-caret {
	width: 13px;
	height: 13px;
	flex: none;
	margin-left: 0.45rem;
	transition: transform 140ms ease;
}

.webe-cc__info-toggle[aria-expanded="true"] .webe-cc__info-caret {
	transform: rotate(180deg);
}

.webe-cc__info {
	margin: 0.75rem 0 0;
	padding: 0.9rem 1rem;
	border-radius: 10px;
	background: rgba(0, 0, 0, 0.04);
	font-size: 0.82rem;
	line-height: 1.55;
}

.webe-cc__info[hidden] {
	display: none;
}

.webe-cc__info p {
	margin: 0 0 0.7rem;
}

.webe-cc__info p:last-child {
	margin-bottom: 0;
}

/*
 * The panel's own action row is a plain block inside the card (the
 * two-tone bleed belongs to the main banner only — see
 * .webe-cc > .webe-cc__actions), so it needs its own separation from the
 * last category row above it. Without this the buttons sat flush against
 * the Marketing description.
 */
/*
 * No rule between the buttons: the explainer toggle and the three choice
 * buttons are one group of controls, and a hairline across the middle of it
 * read as a section break that isn't there. Separation is spacing only.
 */
.webe-cc__panel-card .webe-cc__actions {
	margin-top: 0.75rem;
	padding-top: 0;
}

.webe-cc__panel-card .webe-cc__btn {
	width: auto;
}

.webe-cc__panel {
	position: fixed;
	inset: 0;
	z-index: 1000000;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(0, 0, 0, 0.4);
}

.webe-cc__panel[hidden] {
	display: none;
}

/*
 * The card is a frame, not a scroll container. It used to scroll as a
 * whole, so on a short viewport the heading scrolled away and the
 * Save/Necessary-only buttons sat somewhere below the fold — the visitor
 * had to scroll to the very bottom to find out there was a decision to
 * make. Now the heading and the action row are fixed and only
 * .webe-cc__panel-body between them scrolls.
 */
.webe-cc__panel-card {
	/* Explicit rather than relying on a host theme's global border-box
	 * reset, so --webe-cc-width means the same outer width here as it does
	 * on the banner card. */
	box-sizing: border-box;
	background: #fff !important;
	color: #1c1c1e !important;
	border-radius: var(--webe-cc-card-radius, 16px) !important;
	padding: var(--webe-cc-padding, 1.75rem);
	/*
	 * Same cap as the banner card so both read as one dialog frame at one
	 * width, rather than the panel snapping to a narrower column when it
	 * opens.
	 */
	max-width: var(--webe-cc-width, 620px);
	width: calc(100% - 2rem);
	max-height: calc(100vh - 4rem);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	position: relative;
	box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.webe-cc__panel-body {
	/* min-height:0 is what actually lets a flex child shrink below its
	 * content size and scroll; without it the body just grows and pushes
	 * the action row out of the card. */
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	/* Nothing inside is meant to exceed this box horizontally, so a second,
	 * horizontal scrollbar would only ever be the symptom of a layout bug —
	 * hidden rather than auto, since there would be nothing to scroll to.
	 * (An earlier revision did overhang here, and this clipped it square on
	 * one side; the rows now stay within the column — see
	 * .webe-cc__category-row.) */
	overflow-x: hidden;
	overscroll-behavior: contain;
	/*
	 * The scroll gutter belongs in the card's padding band, not in the text
	 * column: with the track inside the content box the copy ended 46px from
	 * the card edge against 24px on the other three sides (measured).
	 *
	 * Bleeding the container right by exactly the scrollbar's own width puts
	 * the track in the padding band and leaves the content box ending on the
	 * card's own inset, so the copy lines up with the header above and the
	 * action row below.
	 *
	 * That width cannot be expressed in CSS: it is platform-dependent and is
	 * 0 where the OS draws overlay scrollbars — which is why the earlier
	 * fixed-value arithmetic here was wrong in one state or the other, and
	 * why scrollbar-gutter alone does not rescue it (the spec reserves
	 * nothing when scrollbars are overlays). banner.js measures it once with
	 * a throwaway probe and publishes it as --webe-cc-scroll-track.
	 *
	 * The 0px default is deliberate: with no JS, or before the measurement
	 * lands, no bleed is exactly right for an overlay scrollbar and merely
	 * a little tight for a classic one.
	 *
	 * scrollbar-gutter: stable then keeps that reservation constant whether
	 * or not the content currently overflows, so the copy does not shift
	 * sideways as categories are expanded.
	 */
	scrollbar-gutter: stable;
	margin-right: calc(-1 * var(--webe-cc-scroll-track, 0px));
	scrollbar-width: thin;
	scrollbar-color: rgba(0, 0, 0, 0.25) transparent;
}

.webe-cc__panel-body::-webkit-scrollbar {
	width: 10px;
}

.webe-cc__panel-body::-webkit-scrollbar-track {
	background: transparent;
}

.webe-cc__panel-body::-webkit-scrollbar-thumb {
	background: rgba(0, 0, 0, 0.22);
	border-radius: 999px;
}

.webe-cc__panel-body::-webkit-scrollbar-thumb:hover {
	background: rgba(0, 0, 0, 0.35);
}

/*
 * Header band: title left, close right, separated from the scroll area by a
 * hairline. Gives the card three readable zones (header / content / actions)
 * instead of one undifferentiated column, and lets the card keep an even
 * padding on all four sides.
 */
.webe-cc__panel-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-bottom: 1.1rem;
	padding-bottom: 0.9rem;
	border-bottom: 1px solid #ecedf0;
}

.webe-cc__panel-title {
	margin: 0;
	font-size: 1.2rem;
	font-weight: 700;
	color: inherit;
}

/*
 * No sideways bleed. The hover tint used to reach 12px from the card edge
 * while the copy, the switches, the buttons and the header all sat on the
 * card's own 24px column — so the category block was visibly the only thing
 * running wider than everything else. It now shares that column.
 */
/*
 * Each row IS the tinted card: its box spans exactly the card's own column,
 * the same width as the buttons below, and the cushion around the copy is
 * its padding rather than an overhang.
 *
 * Earlier revisions painted the tint with an overhanging ::before so the copy
 * could stay flush with the header. That made the tint wider than every other
 * element in the card, and — because the overhang crossed the scroll area's
 * overflow-x boundary — it was clipped square on one side. Indenting the copy
 * instead keeps one column for the tint, the separators, the explainer box
 * and the buttons alike.
 */
.webe-cc__category-row {
	margin: 0;
	padding: 0.9rem 0.7rem;
	border-radius: 10px;
	transition: background-color 150ms ease;
}

.webe-cc__category-row:hover {
	background: rgba(0, 0, 0, 0.03);
}

.webe-cc__category-row:not(:last-child) {
	border-bottom: 1px solid #ecedf0;
}

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

.webe-cc__category > span {
	font-weight: 600;
}

.webe-cc__category-desc {
	margin: 0.35rem 0 0;
	padding: 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: #6b6f76;
}

/*
 * Toggle switch, built entirely on the native checkbox (no extra markup):
 * appearance: none clears the OS checkbox box so the element becomes a bare
 * rounded track, and ::before draws the thumb positioned with plain
 * top/left + a transform on :checked. Keeps all native checkbox behavior
 * (keyboard, screen readers announce it via the existing role="switch" +
 * aria-checked on the input) — this is styling only, no interaction change.
 */
.webe-cc__category input[type="checkbox"] {
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	flex: none;
	width: 2.75rem;
	height: 1.5rem;
	margin: 0;
	border-radius: 999px;
	background: #d8dadf;
	cursor: pointer;
	transition: background-color 150ms ease;
}

.webe-cc__category input[type="checkbox"]::before {
	content: "";
	position: absolute;
	top: 2px;
	left: 2px;
	width: 1.25rem;
	height: 1.25rem;
	border-radius: 50%;
	background: #fff;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
	transition: transform 150ms ease;
}

.webe-cc__category input[type="checkbox"]:checked {
	background: var(--webe-cc-accent, #0a84ff);
}

.webe-cc__category input[type="checkbox"]:checked::before {
	transform: translateX(1.25rem);
}

.webe-cc__category input[type="checkbox"]:disabled {
	opacity: 0.65;
	cursor: not-allowed;
}

.webe-cc__category input[type="checkbox"]:focus-visible {
	outline: 2px solid var(--webe-cc-accent, #0a84ff);
	outline-offset: 2px;
}

/*
 * A flex item in the header now, not absolutely positioned. Its old
 * containing block was .webe-cc__panel (position: fixed; inset: 0), so it
 * pinned itself to the VIEWPORT corner rather than the card's — measured
 * sitting 29px outside the card edge on a narrow viewport.
 */
.webe-cc__panel-close {
	flex: none;
	display: flex !important;
	align-items: center;
	justify-content: center;
	/* 38px rather than 30: this is the only way out of a modal dialog for a
	 * visitor who does not want to decide right now, and a 30px glyph was a
	 * small target on a phone. Comfortably above the 24px minimum target size
	 * WCAG 2.2 asks for, without competing with the action buttons. */
	width: 38px !important;
	height: 38px !important;
	margin: -0.35rem -0.5rem -0.35rem 0 !important;
	background: transparent !important;
	border: none !important;
	font-size: 1.7rem;
	line-height: 1;
	cursor: pointer;
	padding: 0 !important;
	color: #1c1c1e !important;
	opacity: 0.55;
	transition: opacity 120ms ease, background-color 120ms ease;
	border-radius: 7px !important;
}

.webe-cc__panel-close:hover,
.webe-cc__panel-close:focus-visible {
	opacity: 1;
}

.webe-cc__panel-close:focus-visible {
	outline: 2px solid var(--webe-cc-accent, #0a84ff);
	outline-offset: 2px;
}

.webe-cc__panel-close:hover {
	background: rgba(0, 0, 0, 0.05) !important;
}

/*
 * Reopen trigger: an icon-only floating button. It used to carry its label
 * next to the glyph, which made a permanently-pinned element as wide as
 * whatever the admin typed ("Cookie-Einstellungen" is 20 characters) sit
 * over the client's own content on every page. The label lives on as the
 * button's aria-label and title instead.
 */
.webe-cc__trigger {
	position: fixed;
	z-index: 999998;
	/* !important on the box: a host theme's button padding/display rules
	 * otherwise win on source order — measured on a client site this
	 * rendered as a 54px-wide block instead of a centred 44px square. */
	display: flex !important;
	align-items: center;
	justify-content: center;
	box-sizing: border-box !important;
	width: 44px !important;
	height: 44px !important;
	padding: 0 !important;
	border: none !important;
	/* Always a circle, deliberately NOT following the button/popup radius
	 * setting. This is a small persistent element floating over the
	 * client's own page rather than part of the dialog, and at 44px a
	 * square or barely-rounded tile reads as a stray box someone forgot to
	 * style — the round shape is what makes it legible as a utility
	 * control at that size. */
	border-radius: 50% !important;
	background: var(--webe-cc-accent, #0a84ff) !important;
	color: #fff !important;
	cursor: pointer;
	opacity: 0.8;
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
	transition: opacity 200ms ease, transform 200ms ease;
}

.webe-cc__trigger:hover,
.webe-cc__trigger:focus-visible {
	opacity: 1;
	transform: scale(1.06);
}

.webe-cc__trigger:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 2px;
}

.webe-cc__trigger[hidden] {
	display: none;
}

.webe-cc__trigger--bottom-right {
	right: 1rem;
	bottom: 1rem;
}

.webe-cc__trigger--bottom-left {
	left: 1rem;
	bottom: 1rem;
}

.webe-cc__trigger-icon {
	width: 22px;
	height: 22px;
	display: block;
	/* The chips are holes punched through the glyph (fill-rule: evenodd in
	 * WEBE_Banner_Renderer::trigger_icon()), so they simply show the
	 * button's own accent background — nothing to recolor per client. */
	fill: currentColor;
	pointer-events: none;
}

/*
 * Visually hidden utility: content is accessible to screen readers but
 * invisible on screen. Used for the dialog title and the aria-live region.
 */
.webe-cc__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;
}

/*
 * Respect the user's motion preference.
 * Disables ALL transitions and animations on banner elements so the UI
 * never animates for users who experience motion sickness or vestibular
 * disorders (WCAG 2.1 SC 2.3.3).
 */
@media (prefers-reduced-motion: reduce) {
	.webe-cc,
	.webe-cc__trigger {
		animation: none;
		transition: none;
	}
}

/*
 * Embed guard: wraps a gated <iframe> (YouTube, Google Maps, etc.) with a
 * responsive placeholder and a blurred consent overlay. The iframe itself
 * stays in normal document flow (width/height attributes untouched) but is
 * pinned to fill the wrapper via inset:0 while its src is neutered to
 * about:blank by WEBE_Embed_Guard; the wrapper's own height is driven by
 * the padding-top percentage trick using the provider's real aspect ratio
 * (--webe-cc-embed-ratio, set inline per-embed) so the layout doesn't jump
 * once content loads.
 */
.webe-cc-embed {
	position: relative;
	width: 100%;
	margin: 0 auto;
	overflow: hidden;
	border-radius: min(var(--webe-cc-card-radius, 16px), 24px);
	background: #1c1c1e;
}

.webe-cc-embed::before {
	content: "";
	display: block;
	padding-top: var(--webe-cc-embed-ratio, 56.25%);
}

.webe-cc-embed iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

/*
 * Decorative, purely local "blur" background — never the real provider's
 * thumbnail (fetching that pre-consent would itself be third-party
 * tracking). A few softly blurred color blobs in the site's own accent
 * color communicate "content is hidden" without loading anything external.
 *
 * CSS `filter` blurs an element's ENTIRE rendered output, including its
 * descendants — there is no way to "un-blur" a nested child. So the blur
 * lives on its own sibling layer (.webe-cc-embed__bg) instead of on the
 * overlay itself; the card sits next to it, never inside it, and stays
 * fully sharp and legible.
 */
.webe-cc-embed__overlay {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1rem;
	text-align: center;
}

.webe-cc-embed__bg {
	position: absolute;
	inset: 0;
	background:
		linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.35)),
		radial-gradient(circle at 20% 30%, color-mix(in srgb, var(--webe-cc-accent, #0a84ff) 55%, transparent), transparent 60%),
		radial-gradient(circle at 80% 70%, color-mix(in srgb, var(--webe-cc-accent, #0a84ff) 35%, transparent), transparent 55%),
		#e5e5ea;
	filter: blur(18px) saturate(130%);
}

.webe-cc-embed__card {
	position: relative;
	z-index: 1;
	max-width: 22rem;
	color: #fff;
	font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-family: var(--webe-cc-font, inherit);
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

.webe-cc-embed__provider {
	margin: 0 0 0.35em;
	font-weight: 700;
}

.webe-cc-embed__text {
	margin: 0 0 1em;
	font-size: 0.875rem;
	opacity: 0.95;
}

.webe-cc-embed__btn {
	text-shadow: none;
}

/* Once WEBE_Embed_Guard's front-end JS activates the iframe, hide the
 * overlay so the real (now-consented) content is fully visible. */
.webe-cc-embed--unlocked .webe-cc-embed__overlay {
	display: none;
}
