/**
 * Consent Manager — banner styles.
 * Mobile-first, no layout shift, does not cover the whole viewport.
 * Colours come from CSS custom properties injected from plugin settings:
 *   --cm-primary          primary button / accent
 *   --cm-text             banner text
 *   --cm-bg               banner background
 *   --cm-btn-radius       consent button corner radius
 *   --cm-btn-pad-y/-pad-x consent button padding
 *   --cm-btn-font-family  consent button font stack (omitted = inherit)
 *   --cm-btn-font-size    consent button font size
 *   --cm-btn-font-weight  consent button font weight
 * The --cm-btn-* vars deliberately do NOT reach the reopen pill: its pill shape
 * is its identity, not a button the site is matching.
 * Fallbacks below keep it sane if the vars are ever missing.
 */

.cm-banner {
	position: fixed;
	left: 1rem;
	right: 1rem;
	bottom: 1rem;
	z-index: 999999;
	max-width: 32rem;
	margin-inline: auto;
	padding: 1rem 1.25rem;
	background: var(--cm-bg, #ffffff);
	color: var(--cm-text, #1a1a1a);
	border-radius: 12px;
	box-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
	font-size: 0.9rem;
	line-height: 1.45;
}

.cm-banner[hidden] { display: none; }

.cm-banner__text { margin: 0 0 0.85rem; }

.cm-banner__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

/* Button shape/typography come from settings so the consent buttons can be made
   to match the buttons on the host site (docs/decisions/button-styling.md). The
   fallbacks are the plugin's own defaults, so the stylesheet still stands alone
   if the vars are missing. `font: inherit` stays first — it resets the UA's
   button font; the longhands after it apply the admin's overrides.

   SINGLE-CLASS SPECIFICITY IS DELIBERATE. A theme that styles bare `button`
   outranks these rules (or ties and wins on load order, as `[type="button"]`
   in hello-elementor's reset.css does), and the consent buttons then inherit
   the site's button look — the right default for a plugin dropped into someone
   else's design. The "Theme buttons" setting restates these declarations at
   doubled-class specificity to win instead; that block lives in
   Renderer::override_style(), so any change here may need mirroring there. */
.cm-btn {
	flex: 1 1 auto;
	min-width: 6.5rem;
	padding: var(--cm-btn-pad-y, 0.6rem) var(--cm-btn-pad-x, 0.9rem);
	border: 1px solid transparent;
	border-radius: var(--cm-btn-radius, 8px);
	font: inherit;
	font-family: var(--cm-btn-font-family, inherit);
	font-size: var(--cm-btn-font-size, inherit);
	font-weight: var(--cm-btn-font-weight, 600);
	cursor: pointer;
}

/* Equal prominence: "Accept all" AND "Reject all" both use --primary, so neither
   choice is visually privileged (ROADMAP "no dark patterns" hard rule). */
.cm-btn--primary { background: var(--cm-primary, #1a56db); color: #fff; }
.cm-btn--primary:hover { filter: brightness(0.92); }

/* Secondary weight is reserved for "Preferences", which opens a panel rather than
   recording a consent choice — it is not one of the accept/reject decision buttons. */
.cm-btn--secondary {
	background: transparent;
	color: var(--cm-text, #1a1a1a);
	border-color: color-mix(in srgb, var(--cm-text, #1a1a1a) 25%, transparent);
}
.cm-btn--secondary:hover { background: color-mix(in srgb, var(--cm-text, #1a1a1a) 8%, transparent); }

/* Visible keyboard focus. :focus-visible only shows the ring for keyboard/AT users,
   not on mouse click, and is drawn with an offset outline so it reads against any
   admin-chosen button colour. Applies to buttons, category checkboxes and the pill. */
.cm-btn:focus-visible,
.cm-prefs__row input[type="checkbox"]:focus-visible,
.cm-reopen:focus-visible,
.cm-embed__load:focus-visible {
	outline: 3px solid var(--cm-primary, #1a56db);
	outline-offset: 2px;
	/* Second ring in the background colour guarantees contrast when the outline
	   colour is close to the element/background behind it. */
	box-shadow: 0 0 0 5px var(--cm-bg, #fff);
}

/* Body variants (full vs. notice-only). Only one is ever visible; banner.js
   decides which. The [hidden] rule mirrors the banner-level one so a UA
   stylesheet quirk can never show both. */
.cm-banner__body[hidden] { display: none; }

/* CPRA links row: the statutory "Do Not Sell or Share" link (in its
   data-cm-slot="do-not-sell" slot) + the optional "Notice at Collection"
   link. Plain, visible text links — statutory links must not be styled into
   invisibility. The slot collapses entirely while empty. */
.cm-banner__dns-slot:empty { display: none; }

.cm-banner__links {
	margin: 0.65rem 0 0;
	font-size: 0.8rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 1rem;
}
.cm-banner__links a,
.cm-do-not-sell,
.cm-notice-at-collection {
	color: var(--cm-text, #1a1a1a);
	text-decoration: underline;
	text-underline-offset: 2px;
}
.cm-banner__links a:hover { opacity: 0.8; }
.cm-banner__links a:focus-visible {
	outline: 3px solid var(--cm-primary, #1a56db);
	outline-offset: 2px;
}

/* Focused CPRA opt-out surface (opened by the Do Not Sell link). */
.cm-dns {
	margin-top: 0.9rem;
	padding-top: 0.9rem;
	border-top: 1px solid color-mix(in srgb, var(--cm-text, #1a1a1a) 15%, transparent);
}
.cm-dns[hidden] { display: none; }
.cm-dns__text { margin: 0 0 0.85rem; }
/* Exactly one copy variant (carried vs fresh) is visible; banner.js picks. */
.cm-dns__text[hidden] { display: none; }

/* Auto footer links block (dns_footer_auto). Deliberately minimal and
   theme-styleable: inherits colors, small text, centered. Themes override
   via .cm-footer-links / its child anchor classes. */
.cm-footer-links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem 1.5rem;
	padding: 1rem;
	font-size: 0.8rem;
}
.cm-footer-links a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
}
.cm-footer-links a:focus-visible {
	outline: 3px solid var(--cm-primary, #1a56db);
	outline-offset: 2px;
}

/* GPC acknowledgment notes: muted, smaller, on their own line — used by the
   DNS surface ("already opted out via your browser's privacy signal") and by
   the preferences rows' suppression note (docs/decisions/gpc.md). */
.cm-dns__gpc-note,
.cm-prefs__gpc-note {
	display: block;
	margin: 0 0 0.65rem;
	font-size: 0.78rem;
	opacity: 0.75;
}
.cm-prefs__gpc-note { margin: 0.1rem 0 0; flex-basis: 100%; }

.cm-prefs {
	margin-top: 0.9rem;
	padding-top: 0.9rem;
	border-top: 1px solid color-mix(in srgb, var(--cm-text, #1a1a1a) 15%, transparent);
}
.cm-prefs[hidden] { display: none; }

.cm-prefs__row {
	display: flex;
	flex-wrap: wrap; /* lets the injected GPC note wrap onto its own line */
	align-items: center;
	gap: 0.5rem;
	padding: 0.35rem 0;
}

/* The banner is focused programmatically on open (banner.js focusDialog) so
   assistive tech announces the dialog and its text. It carries tabindex="-1",
   so it is never reached by Tab and a ring on it would only ever be a ring
   nobody navigated to — on a whole panel that reads as a rendering bug, not as
   a focus indicator. Suppressed here and ONLY here: every control inside keeps
   its :focus-visible ring, which is what a keyboard user actually follows. */
.cm-banner:focus { outline: none; }

/* Optional persistent re-open pill (off by default; enabled in settings). */
.cm-reopen {
	position: fixed;
	bottom: 1rem;
	left: 1rem;
	z-index: 999998;
	padding: 0.5rem 0.85rem;
	background: var(--cm-text, #1a1a1a);
	color: var(--cm-bg, #fff);
	border: none;
	border-radius: 999px;
	font-size: 0.8rem;
	cursor: pointer;
	opacity: 0.85;
}
.cm-reopen--right { left: auto; right: 1rem; }
.cm-reopen:hover { opacity: 1; }
.cm-reopen[hidden] { display: none; }

/* Consent-gated embeds */
.cm-embed {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 12rem;
	background: #0f172a;
	border-radius: 8px;
}
/* The facade's "Load content" control is a consent button too, so it follows the
   same settings-driven shape/typography as .cm-btn (its own padding fallback is
   slightly roomier, which is what it had before the vars existed). */
.cm-embed__load {
	padding: var(--cm-btn-pad-y, 0.7rem) var(--cm-btn-pad-x, 1.1rem);
	background: var(--cm-primary, #1a56db);
	color: #fff;
	border: none;
	border-radius: var(--cm-btn-radius, 8px);
	font-family: var(--cm-btn-font-family, inherit);
	font-size: var(--cm-btn-font-size, inherit);
	font-weight: var(--cm-btn-font-weight, 600);
	cursor: pointer;
}
.cm-embed iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: 8px; }

/* Swept facade — the one the engine builds at runtime around an iframe the
   server gate never saw (a JS-injected player: Elementor's video widget, a
   slider, a lazy-loader). Unlike a server-rendered facade, the ORIGINAL iframe
   is still inside it, disarmed: the host page's CSS and scripts are bound to
   that element, so the sweep wraps it rather than replacing it.

   Two consequences to style. A src-less iframe still paints — a blank box under
   the Load button — so hide it until it is re-armed. And once it is, the
   wrapper has done its job: `display: contents` takes it out of the layout
   entirely, handing the iframe back to whatever box its own page built for it,
   instead of leaving a stray dark 12rem panel around a playing video. */
.cm-embed--swept > iframe:not([src]) { display: none; }
.cm-embed--swept[data-cm-loaded] { display: contents; }

/* Fill the box the player reserved, the same problem the .wp-has-aspect-ratio
   rule below solves — but here the wrapper belongs to whatever built the
   player, so the shape is read off the iframe instead of a known class.

   Two techniques in the wild. A parent with a definite height (aspect-ratio,
   or a fixed one): `height: 100%` fills it, and harmlessly computes to auto
   against an auto-height parent, leaving min-height in charge. Or the older
   padding-spacer trick, where the iframe is absolutely positioned inside a
   relative parent: the sweep sees that on the frame itself and marks the
   wrapper, which then takes the position the iframe held. Without this the
   facade sits in flow at 12rem inside a taller reserved box, and the player's
   own background shows as a band above or below it. */
.cm-embed--swept { height: 100%; }
.cm-embed--swept[data-cm-fill] {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	min-height: 0;
}

/* Aspect-ratio embeds (WP's responsive-embed wrapper).
   WordPress reserves the player's box with a padding-top spacer on
   .wp-block-embed__wrapper::before, then absolutely positions the IFRAME to
   fill it — a pair of rules written when the iframe was the wrapper's only
   child. The facade breaks that pair: it puts a static div where the iframe
   was, so nothing fills the reserved box. Gated, the facade stacks BELOW the
   spacer (an empty player-sized gap above the Load button); loaded, the iframe
   matches WP's rule again but resolves 100%/100% against the WRAPPER — now
   spacer plus facade tall — and comes out too tall, at the wrong ratio.

   So the facade takes the place WP's CSS expects the iframe to take: fill the
   reserved box exactly. The hydrated iframe then sizes against the facade
   instead of the wrapper and gets the author's real aspect ratio back.
   Scoped to .wp-has-aspect-ratio, so ratio-less embeds (blockquote/rich
   providers) and facades outside a WP embed wrapper keep their own flow. */
.wp-embed-responsive .wp-has-aspect-ratio .wp-block-embed__wrapper > .cm-embed {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	min-height: 0;
}

/* Hard-blocked embed: an inert policy placeholder — no Load button exists
   because no interaction can (or may) load the provider. */
.cm-embed--blocked { min-height: 8rem; }
.cm-embed__blocked-note {
	margin: 0;
	padding: 1rem 1.5rem;
	color: #e2e8f0;
	font-size: 0.85rem;
	text-align: center;
	opacity: 0.85;
}

/* Respect prefers-reduced-motion: neutralise any transition/animation on our UI for
   users who ask for reduced motion (vestibular safety + WCAG 2.3.3). The banner ships
   with no motion today; this is a defensive guard so any future transition/animation
   added to these elements is automatically disabled for those users. Colour/opacity
   hover states remain (they are instantaneous, not motion). */
@media (prefers-reduced-motion: reduce) {
	.cm-banner,
	.cm-banner *,
	.cm-reopen,
	.cm-embed,
	.cm-embed * {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* Desktop anchoring — position modifiers set the horizontal edge. */
@media (min-width: 640px) {
	.cm-banner { margin-inline: 0; }
	.cm-banner--left  { left: 1.5rem; right: auto; }
	.cm-banner--right { left: auto;  right: 1.5rem; }
	.cm-banner--center { left: 0; right: 0; margin-inline: auto; }
	.cm-banner__actions { flex-wrap: nowrap; }
	.cm-btn { flex: 0 0 auto; }
}
