/*
 * Square Buttons — shared base.
 *
 * Carries the container, the cqi calibration and the generic slots. Every
 * template's own look lives in assets/square/group-<group>.css, scoped under its
 * own .mf-sq--<slug> modifier. See docs/core/square-buttons.md.
 *
 * CALIBRATION: 1cqi = 3px at the 300px cap, i.e. every value taken from the
 * design prototype (docs/quadrat-buttons.html, drawn at exactly 300px) is that
 * px value divided by 3. A 21px title is 7cqi. Verified pixel-identical against
 * the prototype at the cap — see docs/PLAN-square-buttons.md M0.5. Keep using
 * cqi for anything that must scale with the tile; px is only correct for
 * hairlines that should stay 1px at any size.
 */

/*
 * The WRAPPER is the query container, never .mf-sq itself: a container query
 * cannot style its own container, and the tile's own padding is expressed in cqi
 * too.
 *
 * `width` is deliberately a definite length rather than 100%. `container-type:
 * inline-size` implies `contain: layout inline-size`, so the container's inline
 * size must not depend on its contents — with `width: 100%` the wrapper collapses
 * to its shrink-to-fit parent (a flex item, a float, a grid auto column). The
 * definite width plus max-width:100% is what makes it "fluid, capped at 300px".
 */
.mf-sq-wrap {

	/* Font stacks, replicated from src/embed/style.scss :root — a page with only
	   a square button does not load the row engine's stylesheet, so inheriting
	   them is not an option. Scoped to our own root rather than :root so nothing
	   leaks into the theme. Self-hosted / system stacks only, never a webfont:
	   the design prototype's Fraunces maps to --mf-serif and its JetBrains Mono
	   to --mf-mono, which names the real font for anyone who has it installed. */
	--mf-font: system-ui, -apple-system, "Segoe UI", roboto, helvetica, arial, sans-serif;
	--mf-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", menlo, consolas, monospace;
	--mf-serif: georgia, "Times New Roman", times, serif;

	/* The prototype's playful variants use Fredoka, which is not shipped. This is
	   the closest self-hosted-free equivalent: Apple platforms resolve ui-rounded
	   to SF Rounded and look as intended, everywhere else it degrades to the
	   default sans. A deliberate trade — see docs/core/square-buttons.md. */
	--mf-sq-round: ui-rounded, "SF Pro Rounded", "Hiragino Maru Gothic ProN", var(--mf-font);

	container-type: inline-size;
	width: var(--mf-sq-size, 300px);
	max-width: 100%;
}

/*
 * SPECIFICITY — the one thing to understand before editing any square CSS.
 *
 * The base is deliberately split in two, and the split is load-bearing:
 *
 * 1. `.mf-sq-wrap .mf-sq` (0-2-0) carries ONLY the inherited properties that an
 *    outside rule attacks. The tile is an <a> inside post content and a sibling
 *    plugin ships `.entry-content a { color: inherit }` site-wide — 0-1-1, which
 *    beats a plain `.mf-sq--<slug>` rule. A dark template's light text lost to the
 *    theme's paragraph colour, silently: measured rgb(26,26,26) on sq-slate where
 *    #dfe3e8 was declared. Templates set --mf-sq-ink rather than `color`.
 *
 * 2. `.mf-sq` (0-1-0) carries the layout. It has to stay at 0-1-0 so a template
 *    can override it: this sheet loads first, so an equally specific rule in a
 *    group sheet wins on source order. When the layout lived in the 0-2-0 rule
 *    instead, *every* per-template `padding`, `border-radius`, `justify-content`
 *    and `transition` was silently ignored — found by measuring a template whose
 *    zones came out 260px tall inside a 300px tile.
 *
 * Adding a declaration here means asking which of the two it belongs in. If a
 * template may override it, it belongs in the second rule.
 */
.mf-sq-wrap .mf-sq {
	color: var(--mf-sq-ink, #111);
	font-family: var(--mf-sq-face, var(--mf-font));
}

.mf-sq {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	box-sizing: border-box;
	width: 100%;
	aspect-ratio: 1 / 1;
	padding: 6.667cqi;
	overflow: hidden;
	border-radius: 4.667cqi;
	text-decoration: none;

	/*
	 * THE ACCENT, AND THE ACCENT AS TEXT.
	 *
	 * `--mf-sq-c` is the chosen colour or the engine default (#1d4f99, the
	 * prototype's blue, which clears AA on white where its magenta does not).
	 * Structure — borders, rails, rings, backgrounds — uses it raw.
	 *
	 * Text cannot. Measured: an accent of #1d4f99 on the navy tile gives 2.08:1, and
	 * #000000 on any dark ground gives 1:1. No mix ratio fixes that, because the
	 * problem is lightness rather than proportion. So the two derived colours take
	 * the accent's hue and chroma and fix its *lightness* to suit the ground: `-lit`
	 * for dark tiles, `-deep` for light ones. Verified over six accents (including
	 * pure black and pure white) on four grounds — 24 of 24 clear AA, worst 6.18:1.
	 *
	 * The chain sits HERE and not on the wrapper: a template overrides `--mf-sq-c` on
	 * the tile to give itself a different default (the navy tile's brass, the
	 * heartbeat's pink), and a custom property only sees that override when both are
	 * declared on the same element.
	 *
	 * The values below are plain colours, and the relative-colour versions come in
	 * the @supports block: a var() whose value the browser cannot parse computes to
	 * `unset` rather than falling back to an earlier declaration — the usual custom
	 * property trap. Without relative colour syntax a template loses the tint and
	 * keeps its legibility.
	 */
	--mf-sq-c: var(--mf-accent, #1d4f99);
	--mf-sq-accent-lit: #fff;
	--mf-sq-accent-deep: #14181f;
	transition:
		transform 0.25s ease,
		box-shadow 0.25s ease,
		background 0.25s ease,
		border-color 0.25s ease,
		color 0.25s ease;
}

@supports (color: oklch(from red 0.5 c h)) {

	.mf-sq {
		--mf-sq-accent-lit: oklch(from var(--mf-sq-c) 0.82 c h);
		--mf-sq-accent-deep: oklch(from var(--mf-sq-c) 0.45 c h);
	}
}

/* Keyboard focus must stay visible inside a tile that hides its overflow. */
.mf-sq:focus-visible {
	outline: 2px solid currentcolor;
	outline-offset: -3px;
}

/*
 * The three text slots. z-index keeps them above whatever decoration a template
 * paints behind them (a gradient, an image, a pseudo-element).
 */
.mf-sq__k {
	position: relative;
	z-index: 3;
	display: block;
	font-size: 3.167cqi;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.mf-sq__t {
	position: relative;
	z-index: 3;
	display: block;
	margin: 2.333cqi 0 3.667cqi;
	font-size: 7cqi;
	font-weight: 700;
	line-height: 1.13;
	letter-spacing: -0.022em;
}

.mf-sq__c {
	position: relative;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 2.333cqi;
	font-size: 4cqi;
	font-weight: 700;

	/* So a template that recolours its action line on hover fades rather than
	   snaps. The tile's own transition does not cover this element. */
	transition: color 0.22s ease;
}

.mf-sq__c i {
	font-style: normal;
	transition: transform 0.22s ease;
}

/*
 * THE ACTION LINE'S COLOUR, AND WHY IT IS A PAIR OF VARIABLES.
 *
 * Templates want the action line muted at rest and stronger under the pointer, and
 * they do not agree on what "stronger" is: the accent lightened (slate, obsidian),
 * the accent deepened (annual report), or the plain ink (diplomatic, monolith). So
 * the base owns the MECHANICS and each template names its two colours — one register
 * row plus a CSS block stays the price of a new template.
 *
 * Both rules sit above any `.mf-sq--<slug> .mf-sq__c` (0-2-0), and that is the point
 * of the pair rather than an accident:
 *
 *   - a template MUST use the variables. Writing `color` on its own action line does
 *     nothing — and does nothing *visibly, at rest, on first look*.
 *   - leaving the rest rule at 0-1-0 instead fails far worse. The hover rule would
 *     still win, so a template setting `color` for rest would keep its rest colour and
 *     have only its hover quietly replaced by the fallback. A bug you can see solely
 *     with a pointer on the tile is the exact class of bug this feature has already
 *     produced four times.
 *
 * `inherit` as the last fallback is the honest no-op: an unstyled action line inherits
 * from the tile, or from a zone that painted its own ground. That is what lets the two
 * templates whose action line sits inside a solid accent bar say nothing at all here.
 *
 * Declare the variables on the tile. A two-zone template that needs its halves to
 * differ declares them on `.mf-sq__zone--<n>` instead, which inherits the same way.
 */
.mf-sq-wrap .mf-sq .mf-sq__c {
	color: var(--mf-sq-cta, inherit);
}

/*
 * Keyed to the LINK, not the tile: a single-zone template *is* the anchor, a two-zone
 * one has an anchor per zone. Hanging this on `.mf-sq:hover` would recolour both
 * halves of a duo when the pointer is on one of them. That was not hypothetical — the
 * icon nudge below used to do it, measured as a 4px shift in the right-hand zone while
 * the pointer sat in the left one.
 *
 * `:focus-visible` rides along so the emphasis is not pointer-only.
 */
.mf-sq-wrap .mf-sq:not(.mf-sq--duo):hover .mf-sq__c,
.mf-sq-wrap .mf-sq:not(.mf-sq--duo):focus-visible .mf-sq__c,
.mf-sq-wrap .mf-sq__zone:hover .mf-sq__c,
.mf-sq-wrap .mf-sq__zone:focus-visible .mf-sq__c {
	color: var(--mf-sq-cta-hover, var(--mf-sq-cta, inherit));
}

.mf-sq:not(.mf-sq--duo):hover .mf-sq__c i,
.mf-sq:not(.mf-sq--duo):focus-visible .mf-sq__c i,
.mf-sq__zone:hover .mf-sq__c i,
.mf-sq__zone:focus-visible .mf-sq__c i {
	transform: translateX(1.333cqi);
}

/*
 * THE ADVERTISING LABEL.
 *
 * Absolute, so it disturbs neither the tile's flex column nor a two-zone tile's grid:
 * it is the tile's first child, and in a grid a first child in flow would take the
 * first declared cell and displace zone 1.
 *
 * It carries its own backing rather than using --mf-sq-ink, because the tile's ink is
 * only guaranteed against the tile's own ground — over a photograph the top of the
 * image is whatever the photo happens to be there, and the veil templates ramp their
 * scrim towards the BOTTOM, where the text is. So the pair is fixed: white on a dark
 * wash. Worst case is the wash over pure white, which composites to rgb(84,84,84) and
 * gives 7.6:1 — above AA for text this size with room to spare, and it can only
 * improve on a darker tile.
 *
 * z-index clears the masthead (5), the highest any template's own layer reaches. A
 * disclosure that something else can cover is not a disclosure.
 */
.mf-sq__ad {
	position: absolute;
	top: 0;
	left: 0;
	z-index: 6;
	padding: 1.333cqi 2.333cqi;
	border-radius: 0 0 1.667cqi 0;
	background: rgb(17 17 17 / 72%);
	color: #fff;
	font-size: 3cqi;
	font-weight: 700;
	letter-spacing: 0.12em;
	line-height: 1.2;
	text-transform: uppercase;

	/* The label sits inside the link on a one-target tile; it must not become a
	   separate hit target or swallow part of the tile's own. */
	pointer-events: none;
}

/*
 * The generic decoration slot. A template positions and paints it; the base only
 * guarantees it sits above the background and never captures a click that belongs
 * to the link. This one element is what lets ~24 of the prototype's variants
 * share a single skeleton — their .aur, .chase, .spray, .bm, .glass, .chip and
 * .qm are all this slot, styled differently.
 */
.mf-sq__dec {
	position: absolute;
	z-index: 2;
	pointer-events: none;
}

/*
 * Two decorations carry data rather than pure decoration, so they are not
 * absolutely positioned by default: a template places them itself.
 */
.mf-sq__dec--text {
	position: static;
	z-index: 3;
}

.mf-sq__dec--fill {
	display: flex;
	gap: 1.667cqi;
}

.mf-sq__dec--fill i {
	flex: 1;
	height: 1.667cqi;
	border-radius: 1.333cqi;
	background: currentcolor;
	opacity: 0.16;
}

.mf-sq__dec--fill i.is-on {
	background: var(--mf-sq-c);
	opacity: 1;
}

/*
 * The body wrapper, used only by the `dec-body` shape: the decoration sits beside
 * the text block instead of behind it. It must not become a flex item that eats
 * the remaining height, or the text stops sitting at the bottom of the tile.
 */
.mf-sq__body {
	position: relative;
	z-index: 3;
	display: block;
}

/*
 * THE NOTE — a paragraph in the tile's empty area, and the one thing here that
 * appears and disappears with the button's size.
 *
 * Hidden by default and shown only at the full 300px width. `min-width: 300px` is
 * the right form: `max-width: 300px` is inclusive, so it would hide the note at
 * exactly the cap — the one size where it is meant to show.
 *
 * This is where the container the cqi typography already needed pays off a second
 * time. Note that it queries the container from a *descendant*, which is allowed;
 * a container cannot query itself (see .mf-sq-wrap above).
 *
 * The text block is bottom-aligned, so a note grows the block upward and fills the
 * empty area from below rather than pushing anything off the tile. Clamped at three
 * lines so a long one cannot push the kicker out of view.
 */
.mf-sq__note {
	display: none;
}

@container (min-width: 300px) {

	/*
	 * The clamp needs `display: -webkit-box`, and the note is a flex item of the
	 * tile, so flex blockification makes its *computed* display read `flow-root`
	 * instead. The clamp still applies — verified by measuring scrollHeight 75
	 * against clientHeight 57 on a note whose text needs five lines. Do not "fix"
	 * the computed value; the standard `line-clamp` is declared alongside so this
	 * stops depending on the legacy box model as browsers adopt it.
	 */
	.mf-sq__note {
		position: relative;
		z-index: 3;
		display: -webkit-box;
		margin: 0 0 3.333cqi;
		overflow: hidden;
		font-size: 4.333cqi;
		font-weight: 400;
		line-height: 1.45;
		line-clamp: 3;
		-webkit-line-clamp: 3;
		-webkit-box-orient: vertical;
	}
}

/* Motion that runs without being asked for is opt-in. */
@media ( prefers-reduced-motion: reduce ) {

	.mf-sq,
	.mf-sq__c,
	.mf-sq__c i {
		transition: none;
	}
}

/* ==========================================================================
 * TWO-ZONE MECHANICS.
 *
 * These live in the base rather than in group-duo.css because a template's group
 * decides which sheet loads, and the image duo templates belong to the `image`
 * group — they would get the zone markup with none of the rules that make it a
 * layout. Engine mechanics belong here; per-template looks stay in their group.
 * ========================================================================== */

/*
 * The tile is a <div> here, not an <a>: it contains two anchors. It is also a grid
 * rather than the base sheet's flex column.
 *
 * SPECIFICITY: the base lays a tile out at `.mf-sq-wrap .mf-sq` (0-2-0), so a
 * plain `.mf-sq--duo-…` rule (0-1-0) loses and the grid silently never applies —
 * measured once as zones of 260×112 inside a 300×300 tile, which looks plausible
 * enough to miss. Hence the marker class and the matching specificity; this sheet
 * loads after the base, so equal specificity resolves this way.
 */
.mf-sq--duo {
	display: grid;

	/*
	 * `justify-content` is reset because the layout rule above sets `flex-end` for
	 * its flex column — which in a grid aligns the *tracks* instead, so a template
	 * that declares only rows got an auto-width implicit column pushed to the right:
	 * measured 258.5px (the text's max-content) inside a 300px tile. With stretch
	 * restored, an auto track fills the container again.
	 *
	 * Tracks are deliberately NOT declared here: each duo template owns its own, and
	 * nothing shared competes with them.
	 */
	justify-content: stretch;
	align-content: stretch;
	padding: 0;
}

/*
 * A zone is a link that lays its own text out. Padding lives here rather than on
 * the tile, so each zone's clickable area reaches the tile's edge — a 300px tile
 * split in two gives small targets, and losing 20px of each to the parent's
 * padding would make them smaller still.
 */
.mf-sq__zone {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;

	/* Grid items refuse to shrink below min-content without this, so one long
	   word would push a zone past the tile's edge. */
	min-width: 0;
	padding: 6cqi;
	overflow: hidden;
	color: inherit;
	text-decoration: none;
	transition:
		background 0.22s ease,
		filter 0.22s ease,
		color 0.22s ease;
}

.mf-sq__zone:focus-visible {
	outline: 2px solid currentcolor;
	outline-offset: -3px;
}

/* The zones are smaller than a whole tile, so their kicker is a touch tighter. */
.mf-sq__zone .mf-sq__k {
	font-size: 3cqi;
	letter-spacing: 0.13em;
}

/*
 * THE FALLBACK. One target missing means one link filling the tile — the renderer
 * emits a single zone and adds this class. 0-2-0 so it beats the per-template
 * grid rules above without !important.
 */
.mf-sq-wrap .mf-sq--solo {
	grid-template-rows: 1fr;
	grid-template-columns: 1fr;
}

.mf-sq-wrap .mf-sq--solo .mf-sq__zone {
	grid-area: 1 / 1;
	clip-path: none;
}

@media (prefers-reduced-motion: reduce) {

	.mf-sq__zone {
		transition: none;
	}
}
