/* =========================================================================
   Titus Blocks — framework defaults layer
   -------------------------------------------------------------------------
   Makes the blocks framework-AGNOSTIC. Enqueued on the front end and in the
   editor by titus-blocks.php.

   HOW IT WORKS
   Every rule here is written at ZERO specificity — token defaults live in
   `:where(:root)`, component styles in `:where(.titusb-…)`. Any real CSS
   framework defines the same tokens/classes with a normal selector
   (`:root {…}`, `.btn--primary {…}`), whose specificity (0,1,0) automatically
   beats everything here (0,0,0), regardless of load order. So:

     • On an ACSS site   → ACSS's own tokens/classes win; this file is inert.
     • On a Core site     → the fallback chains below resolve to Core's tokens
                            (e.g. --space-xxl → Core's --space-2xl).
     • On a bare site     → the literal defaults at the end of each chain apply,
                            so the blocks still look right with no framework.

   ADDING ANOTHER FRAMEWORK
   Extend the fallback chain for any renamed token, e.g. to also support a
   framework that calls it --spacing-xxl:
       --space-xxl: var(--space-2xl, var(--spacing-xxl, 4rem));
   Everything is centralised here, so the block code never needs to change.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Design-token defaults
   Framework token names the blocks reference. The var() chain reads the
   next-known framework's equivalent, ending in a standalone literal.
   ------------------------------------------------------------------------- */
:where(:root) {

	/* Spacing scale (Container padding + gaps, Feature Row gaps).
	   xs–xl share names across ACSS & Core; only xxl differs (Core = 2xl). */
	--space-xs:  0.5rem;
	--space-s:   1rem;
	--space-m:   1.5rem;
	--space-l:   2rem;
	--space-xl:  3rem;
	--space-xxl: var(--space-2xl, 4rem);

	/* Section vertical-rhythm scale. ACSS ships --section-space-*; Core has no
	   equivalent, so fall back to (bumped) fluid spacing, then a literal. */
	--section-space-xs:  var(--space-m,   2rem);
	--section-space-s:   var(--space-l,   3rem);
	--section-space-m:   var(--space-xl,  4rem);
	--section-space-l:   var(--space-2xl, 6rem);
	--section-space-xl:  var(--space-3xl, 8rem);
	--section-space-xxl: var(--space-4xl, 10rem);

	/* Widths / gutters (Container + Feature Row). Same names in both. */
	--content-width:      1140px;
	--content-width-safe: 1000px;
	--gutter:             2rem;
	--container-gap:      1.5rem;

	/* Grid track templates (Container grid emits `var(--grid-N)`, N = 1–12).
	   ACSS ships --grid-N; Core uses .columns-N utilities instead. */
	--grid-1:  repeat(1,  minmax(0, 1fr));
	--grid-2:  repeat(2,  minmax(0, 1fr));
	--grid-3:  repeat(3,  minmax(0, 1fr));
	--grid-4:  repeat(4,  minmax(0, 1fr));
	--grid-5:  repeat(5,  minmax(0, 1fr));
	--grid-6:  repeat(6,  minmax(0, 1fr));
	--grid-7:  repeat(7,  minmax(0, 1fr));
	--grid-8:  repeat(8,  minmax(0, 1fr));
	--grid-9:  repeat(9,  minmax(0, 1fr));
	--grid-10: repeat(10, minmax(0, 1fr));
	--grid-11: repeat(11, minmax(0, 1fr));
	--grid-12: repeat(12, minmax(0, 1fr));

	/* Ratio (asymmetric) grids — two tracks in the given proportion. Matches
	   ACSS's --grid-x-y variables; Core has none, so these defaults cover Core
	   and bare sites (ACSS overrides with its identical values). */
	--grid-1-2: minmax(0, 1fr) minmax(0, 2fr);
	--grid-1-3: minmax(0, 1fr) minmax(0, 3fr);
	--grid-2-1: minmax(0, 2fr) minmax(0, 1fr);
	--grid-2-3: minmax(0, 2fr) minmax(0, 3fr);
	--grid-3-1: minmax(0, 3fr) minmax(0, 1fr);
	--grid-3-2: minmax(0, 3fr) minmax(0, 2fr);

	/* Content-grid breakout widths — extra track width beyond the content column
	   on EACH side, for the feature / feature-max breakouts. Matches ACSS/Core;
	   the content-grid rules below also carry these as inline fallbacks. */
	--feature-width:     50px;
	--feature-max-width: 100px;

	/* Radius (Container / Image radius options). xs–xl share names; the rest
	   differ: Core has --radius-full only, and no circle/50 tokens.
	   --radius-50 and --radius-circle mirror ACSS's own values exactly, so the
	   two shape options behave identically on every framework:
	     50%  follows the box, so it only reads as a circle when the box is
	          square — on a rectangle the corners come out oval;
	     50vw is far larger than any corner can be, so the browser clamps every
	          corner to half the box's shorter side — perfectly round corners
	          whatever the shape (a pill on a rectangle, a circle on a square). */
	--radius-xs:     0.125rem;
	--radius-s:      0.25rem;
	--radius-m:      0.375rem;
	--radius-l:      0.5rem;
	--radius-xl:     1rem;
	--radius-xxl:    var(--radius-full, 1.5rem);
	--radius-50:     50%;   /* "Full (50%)" option */
	--radius-circle: 50vw;  /* "Circle" option */

	/* Box-shadow scale (Container "Shadow" option). ACSS and Core Framework ship
	   the SAME three names — --box-shadow-m / -l / -xl — and no others, which is
	   why the block offers exactly those three steps and no s/xs.

	   These literals are only reached on a standalone (no-framework) site: both
	   frameworks define the same names at normal :root specificity, which beats
	   this :where(:root) block, so their own shadows win automatically. The
	   values mirror ACSS's shape but use plain rgba() rather than its
	   --black-trans-* tokens, which don't exist without ACSS. */
	--box-shadow-m:  0 0 40px rgba(0, 0, 0, 0.2);
	--box-shadow-l:  0 0 60px rgba(0, 0, 0, 0.2);
	--box-shadow-xl: 0 0 80px rgba(0, 0, 0, 0.3);

	/* Colour name aliases.
	   We deliberately DON'T define the brand colours (--primary, --secondary,
	   --tertiary, --accent, --base) here — those belong to the framework. Leaving
	   them undefined lets Core Framework (or ACSS) own them completely, so they
	   stay fully editable in the framework's own colour system.
	   We only alias the few names that differ between frameworks: Core ships
	   --light / --dark, not ACSS's --text-light / --text-dark / --black /
	   --neutral. These resolve to the framework's --light/--dark (still editable
	   there); the literal is only the no-framework fallback.
	   --text-light = light text for dark backgrounds, and vice-versa. */
	--neutral:    var(--dark, #000000);   /* Core neutral dark */
	/*--black:      var(--dark, #101114);*/
	--text-light: var(--light, #ffffff);
	--text-dark:  var(--dark, #101114);
}

/* -------------------------------------------------------------------------
   2. `.is-bg` background-image helper (Section)
   ACSS turns a direct-child <img>/<div>.is-bg into a full-cover background
   layer. Core has no equivalent. Scoped to Section so it never touches other
   `.is-bg` uses on an ACSS site (where ACSS's own rule wins anyway).
   ------------------------------------------------------------------------- */
:where(.titusb-section .is-bg) {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: var(--bg-object-position, center);
	z-index: -2;
	pointer-events: none;
}

/* Image block background mode (`.titusb-image.is-bg`). A real framework (ACSS /
   Core) supplies the generic `.is-bg` behaviour — including giving the parent
   its positioning context and reading the --bg-* custom properties — and wins
   at normal specificity. These zero-specificity fallbacks reproduce just enough
   of that for a standalone (no-framework) site: the parent that directly holds
   the figure gets a positioning context, the figure becomes a cover layer, and
   the image fills it. All honour the same --bg-* API as the frameworks. */
:where(:has(> .titusb-image.is-bg)) {
	position: relative;
	isolation: isolate;
}
:where(.titusb-image.is-bg) {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: var(--bg-object-fit, cover);
	object-position: var(--bg-object-position, center);
	z-index: -2;
	pointer-events: none;
}
:where(.titusb-image.is-bg > img) {
	object-fit: var(--bg-object-fit, cover);
	object-position: var(--bg-object-position, center);
}

/* -------------------------------------------------------------------------
   3. Button system (Button block)
   The block outputs `.titusb-button .btn--{variant}` (+ optional size /
   `.btn--outline`) and overrides colours via inline --btn-* custom
   properties. ACSS / Core Framework supply the real `.btn--*` styling; a
   standalone (no-framework) site has none, so we provide a fallback here —
   scoped to `.titusb-button` so we never restyle other buttons.

   This whole section lives in the `titusb-buttons` cascade layer, which is
   deliberately the LOWEST-priority layer on the page. That is what makes the
   fallback a true fallback: a framework's declarations (whether unlayered, as
   in the block editor, or in their own layer, as ACSS's front-end
   `@layer acss-layer-anchors`) outrank anything in a layer that was registered
   first, so the framework wins every --btn-* token it sets — on the front end
   and in the editor alike. Specificity can't do this alone: ACSS's front-end
   rules are layered, and *any* unlayered rule (which is what `:where()` here
   used to be) beats a layered one regardless of specificity — which is exactly
   how the fallback was overriding ACSS's button text colour. The fallback only
   fills tokens the framework leaves unset. Inline --btn-* overrides from
   render.php are inline styles, so they still beat everything here.

   Because the framework always wins its own colours, the fallback contrast
   (text) colour is simply white for every variant — it is only ever seen on a
   no-framework site, where a solid coloured fill wants light text. --btn-color
   has no hardcoded fallback: it resolves to each variant's palette token.
   ------------------------------------------------------------------------- */
@layer titusb-buttons {
	:where(.titusb-button) {
		/* Structure (overridden per size). */
		--btn-font-size:      var(--text-m, 1rem);
		--btn-padding-block:  var(--space-xs, 0.75rem);
		--btn-padding-inline: var(--space-m, 1.5rem);
		--btn-radius:         var(--radius-m, 0.375rem);

		/* Colours. Variants set --btn-color; --btn-contrast is the text colour
		   and defaults to white (--text-light alias, else a literal). */
		--btn-color:         var(--primary);
		--btn-color-hover:   var(--btn-color);
		--btn-contrast:      var(--text-light, #ffffff);
		--btn-background:        var(--btn-color);
		--btn-background-hover:   var(--btn-color-hover);
		--btn-text-color:        var(--btn-contrast);
		--btn-text-color-hover:  var(--btn-contrast);
		--btn-border-color:       var(--btn-color);
		--btn-border-color-hover: var(--btn-color-hover);

		padding: var(--btn-padding-block) var(--btn-padding-inline);
		font-size: var(--btn-font-size);
		line-height: 1.15;
		text-align: center;
		text-decoration: none;
		cursor: pointer;
		border: 2px solid var(--btn-border-color);
		border-radius: var(--btn-radius);
		background-color: var(--btn-background);
		color: var(--btn-text-color);
		transition:
			background-color 0.15s ease,
			color 0.15s ease,
			border-color 0.15s ease;
	}

	:where(.titusb-button):hover,
	:where(.titusb-button):focus-visible {
		background-color: var(--btn-background-hover);
		color: var(--btn-text-color-hover);
		border-color: var(--btn-border-color-hover);
	}

	/* Colour variants — each points at the matching palette token defined in
	   section 1 (which already resolves to the framework's value or a literal).
	   Text stays white for all (see section note); a framework overrides both. */
	:where(.titusb-button.btn--primary)   { --btn-color: var(--primary); }
	:where(.titusb-button.btn--secondary) { --btn-color: var(--secondary); }
	:where(.titusb-button.btn--tertiary)  { --btn-color: var(--tertiary); }
	:where(.titusb-button.btn--accent)    { --btn-color: var(--accent); }
	:where(.titusb-button.btn--base)      { --btn-color: var(--base); }
	:where(.titusb-button.btn--neutral)   { --btn-color: var(--neutral); }

	/* Sizes — Default (no size class) uses the base ~medium size above. */
	:where(.titusb-button.btn--xs)  { --btn-font-size: var(--text-xs,  0.8rem);  --btn-padding-block: var(--space-2xs, 0.4rem); --btn-padding-inline: var(--space-s, 1rem); }
	:where(.titusb-button.btn--s)   { --btn-font-size: var(--text-s,   0.9rem);  --btn-padding-block: var(--space-2xs, 0.5rem); --btn-padding-inline: var(--space-s, 1rem); }
	:where(.titusb-button.btn--m)   { --btn-font-size: var(--text-m,   1rem);    --btn-padding-block: var(--space-xs,  0.75rem); --btn-padding-inline: var(--space-m, 1.5rem); }
	:where(.titusb-button.btn--l)   { --btn-font-size: var(--text-l,   1.25rem); --btn-padding-block: var(--space-s,   1rem);   --btn-padding-inline: var(--space-l, 2rem); }
	:where(.titusb-button.btn--xl)  { --btn-font-size: var(--text-xl,  1.5rem);  --btn-padding-block: var(--space-s,   1rem);   --btn-padding-inline: var(--space-l, 2rem); }
	:where(.titusb-button.btn--xxl) { --btn-font-size: var(--text-2xl, 1.85rem); --btn-padding-block: var(--space-m,   1.5rem); --btn-padding-inline: var(--space-xl, 3rem); }

	/* Outline — transparent fill, coloured text + border; fills on hover. Placed
	   after the variants so it layers on top of the variant's --btn-color. */
	:where(.titusb-button.btn--outline) {
		--btn-background:       transparent;
		--btn-text-color:       var(--btn-color);
		--btn-background-hover: var(--btn-color);
		--btn-text-color-hover: var(--btn-contrast);
	}
}

/* -------------------------------------------------------------------------
   4. Content grid (Section "Content grid layout" + Container placement)
   The framework-native breakout grid: a centred content column with feature /
   full-bleed tracks either side. Both ACSS and Core ship this identically, so
   this block is only reached on a standalone (no-framework) site; there it is
   token-driven (reads --content-width / --gutter / --feature-*). Written at
   zero specificity so a framework's own .content-grid always wins. `!important`
   on display is kept (as the frameworks do) so the grid beats the section's
   flex base regardless of load order.
   ------------------------------------------------------------------------- */
:where(.content-grid) {
	--full: minmax(var(--gutter), 1fr);
	padding-inline: 0;
	column-gap: 0 !important;
	display: grid !important;
	grid-template-columns:
		[full-start] var(--full)
		[feature-max-start] minmax(0, var(--feature-max-width, 100px))
		[feature-start] minmax(0, var(--feature-width, 50px))
		[content-start] min(var(--content-width), 100% - var(--gutter) * 2) [content-end]
		minmax(0, var(--feature-width, 50px)) [feature-end]
		minmax(0, var(--feature-max-width, 100px)) [feature-max-end]
		var(--full) [full-end];
}

/* Direct children default to the content column and fill it. */
:where(.content-grid) > :where( :not( .content--feature, .content--feature-max, .content--full, .content--full-safe ) ) {
	grid-column: content;
	width: 100%;
}

/* ...but a background layer spans every track. Both ACSS and Core ship this
   exemption verbatim (`.content-grid > :is(*,img,figure,picture).is-bg
   { grid-column: full }`); without it the default-child rule above drops the
   cover layer into the content column, and because that layer is absolutely
   positioned the column becomes its containing block — so `inset: 0` stops at
   the content width and the "background" only covers the middle of the section.
   Normal specificity (0,2,0), as the frameworks use, to beat the rule above. */
.content-grid > .is-bg {
	grid-column: full;
}

/* Breakout placements — each occupies a wider named track. */
:where(.content--feature)     { grid-column: feature; }
:where(.content--feature-max) { grid-column: feature-max; }
:where(.content--full)        { grid-column: full; }
:where(.content--full-safe)   { grid-column: full; padding-inline: var(--gutter); }

/* A breakout item fills its track regardless of its own width rules. */
:where( .content--feature, .content--feature-max, .content--full, .content--full-safe ) {
	width: 100% !important;
	max-width: 100%;
}

/* Asymmetric spans — aligned to the content column on one side, bled to the full
   edge on the other (the "content + full-bleed" split, e.g. copy beside an image
   that runs off the browser edge). No framework ships these, so they are defined
   here for ACSS / Core / standalone alike — and at normal specificity (not
   :where) with a child combinator so they beat the grid's default rule that
   would otherwise place an unclassed child back in the content column. */
.content-grid > .content--content-full { grid-column: content-start / full-end; }
.content-grid > .content--full-content { grid-column: full-start / content-end; }
:where( .content--content-full, .content--full-content ) {
	width: 100%;
	max-width: 100%;
}

/* A bleed-stacked child fills its grid track. Grid auto/stretch is not enough:
   when the child's only content is out of flow (e.g. an `.is-bg` background
   image) it reports zero content width and collapses to 0 in a fractional
   track. 100% resolves against the track and fills it. This base rule covers
   splits with no per-breakpoint overrides; when a container has responsive
   settings the scoped stylesheet emits the same 100% (and 100vw when stacked),
   see gridGutterCSS() / $gutter_css. */
:where( .content--content-full, .content--full-content ) > .titusb-container--bleed-stacked {
	width: 100%;
}
