/**
 * Shared layout primitives for pattern templates.
 *
 * frow / fcol / fwrap are the suite's existing flex shorthands (see power_core.css and the
 * accelerate-builder project stylesheets, where they are scoped to a host class). Templates get
 * them unscoped here so every generated pattern reaches for the same three classes instead of
 * re-declaring display:flex in every template.css.
 *
 * TWO STEPS OF PRIORITY
 * ---------------------
 * Step 1 is the plain rule. Step 2 repeats it behind `:root:not(#_)`, the specificity
 * escalation already used in the suite's acc_blocks stylesheet: it matches the same elements but
 * carries two id-worth of specificity, so a theme rule like `.entry-content div { display:block }`
 * cannot quietly flatten a pattern's layout. Neither step uses !important, so a template.css rule
 * scoped to its own {{scope}} can still override deliberately.
 *
 * This file is the one exception to "the template stylesheet is the only styling authority". It
 * supplies layout primitives only - no color, no spacing beyond the flex gap, no typography - so a
 * template still owns everything about how a pattern looks.
 *
 * CURSOR PFLEX-001 - Shared flex primitives for every generated pattern.
 *
 * @package Accelerate
 * @since 1.0.0
 */

/* Step 1: the primitives. */

.frow,
.fcol,
.fwrap {
	display: flex;
	gap: 10px;
}

.frow {
	flex-flow: row nowrap;
	align-items: center;
}

.fcol {
	flex-flow: column nowrap;
}

.fwrap {
	flex-flow: row wrap;
}

/* Modifiers, so a template rarely needs its own flex declarations at all. */

.frow.ftop,
.fwrap.ftop {
	align-items: flex-start;
}

.frow.fbottom,
.fwrap.fbottom {
	align-items: flex-end;
}

.frow.fstretch,
.fwrap.fstretch {
	align-items: stretch;
}

.fcol.fcenter {
	align-items: center;
}

.frow.fcenter,
.fwrap.fcenter {
	justify-content: center;
}

.frow.fbetween,
.fwrap.fbetween {
	justify-content: space-between;
}

.fgrow {
	flex: 1 1 auto;
	min-width: 0;
}

/* The floor is what makes a half a half only while a half is still readable. Without it a 50% column
   holds its share all the way down and a 400px card ends up with two 150px columns setting a heading
   seven characters to the line. min() keeps the floor from ever exceeding the container, so the
   wrapped item still fits, and growing from that basis means the item that has a row to itself takes
   the whole of it rather than sitting two thirds wide with dead space beside it. */

.fhalf {
	width: calc(50% - var(--accpt-flex-gap, 10px) / 2);
	flex: 1 1 calc(50% - var(--accpt-flex-gap, 10px) / 2);
	min-width: min(100%, 16em);
}

.ffull {
	width: 100%;
	flex-basis: 100%;
}

/**
 * List marker.
 *
 * A collection's own bullet, drawn as an icon before each item. Color and size come from the
 * declaration as custom properties; the template decides everything about the row it sits in.
 */

.accpt-marker {
	flex: 0 0 auto;
	color: var(--accpt-marker-color, currentColor);
	font-size: var(--accpt-marker-size, 1em);
	line-height: 1;
}

/**
 * Form.
 *
 * One rule, and it is not decoration. The trap field must be invisible to people and present to
 * bots, so it cannot be left to a template stylesheet that might not load, might be overridden, or
 * might simply forget - and a visible trap field means real submissions get rejected.
 *
 * `position: absolute` with `left: -9999px` rather than `display: none`: a field that is display:none
 * is one many bots know to skip, which defeats the point of it.
 */

/* The image frame.
 *
 * CURSOR PIMG-001 - A window of a fixed shape with the picture blown up behind it. The
 * wrapper owns the ratio; the image owns how much of itself shows through, as a width and an offset
 * the renderer works out from the buyer's crop. Both default to "the whole picture", so a frame with
 * no crop is simply the picture at the frame's shape.
 *
 * display: block on the span because a frame is a box, and an inline wrapper would sit on the text
 * baseline with a gap underneath it.
 */

/*
 * A checklist row that has been ticked.
 *
 * CURSOR PCHK-001 - The marker is whatever glyph the designer chose, in whichever font, so the
 * tick is not a second glyph swapped in: it is a filled inner square drawn on the marker's own box,
 * which reads as checked in any icon set. The words are struck and dimmed; a template may redraw
 * either with a rule of its own.
 */

.accpt-checklist__done > [data-accpt-node] {
	text-decoration: line-through;
	opacity: 0.55;
}

[data-accpt-behavior="checklist"] .accpt-marker[role="checkbox"] {
	position: relative;
	cursor: pointer;
}

.accpt-checklist__done .accpt-marker::after {
	content: "";
	position: absolute;
	inset: 26%;
	background-color: currentColor;
	border-radius: 15%;
}

.accpt-frame {
	display: block;
	position: relative;
	overflow: hidden;
	aspect-ratio: var(--accpt-frame-ratio, auto);
}

/* Written as a descendant so it outranks the `height: auto` every image in the suite otherwise gets:
   inside a frame the picture is sized by the window, not by its own proportions. */

.accpt-frame .accpt-frame__img {
	position: absolute;
	left: var(--accpt-img-x, 0);
	top: var(--accpt-img-y, 0);
	width: var(--accpt-img-w, 100%);
	height: var(--accpt-img-h, 100%);
	max-width: none;
	object-fit: cover;
}

.accpt-frame--circle {
	border-radius: 50%;
}

/* Dashicons fixes its box at 20px while several of its glyphs advance 26px, so the glyph draws
   outside the box it was given and anything laid out from that box - a flex gap, a text run beside
   it - is measured against the wrong width. Letting the box follow the glyph costs nothing for the
   icons that already fit. Scoped to nodes the renderer drew, so a theme's own dashicons are left
   exactly as the theme wants them. */

[data-accpt-node].dashicons,
[data-accpt-node].bi,
[data-accpt-node].fa-solid,
[data-accpt-node].fa-regular,
[data-accpt-node].fa-brands {
	width: auto;
	height: auto;
}

/* A text input's default width is its `size` attribute, roughly 20 characters, and it does not
   shrink with its container - so a form that fits at 800px hangs out of the card at 400px. The
   template still decides how a field looks; this only stops it being wider than the space it has. */

.accpt-form__field input,
.accpt-form__field select,
.accpt-form__field textarea {
	max-width: 100%;
	box-sizing: border-box;
}

.accpt-form__trap {
	position: absolute !important;
	left: -9999px !important;
	top: auto !important;
	width: 1px !important;
	height: 1px !important;
	overflow: hidden !important;
}

/**
 * The effects floor - the buyer's switches.
 *
 * CURSOR PFX-001 - One class per library effect, `accpt-fx-<id>`, written by the renderer
 * only when the buyer's switch is on. Everything here is zero-specificity so a template can redraw
 * any of it, and everything answers to the palette: an effect that named a color of its own would
 * be the one thing on the page that ignored the buyer's palette. Knobs are custom properties a
 * sheet may set on the target; none of them is a buyer option.
 *
 * Slots, so two effects never fight over one pseudo-element: ::before is the border family
 * (gradient, foil, brackets); ::after is the overlay family (sheen, grain); the ground family
 * (mesh, hatch) paints the element's own background-image. The validator refuses two of one
 * family on one target.
 */

/* ---- stagger the parts ---- */

:where(.accpt-fx-stagger__part) {
	--accpt-motion-delay: calc(var(--accpt-i, 0) * var(--accpt-fx-stagger-step, 80ms));
}

/* ---- sheen sweep: a highlight crosses the surface once, on first sight ----
   CURSOR PFX-010 - A keyframed pass that ends hidden: the overlay is off-canvas at rest and
   invisible when done, so nothing of it lingers over the ground or the content. The one pseudo
   it uses is its own - the grounds paint the element's background instead. */

@keyframes accpt-fx-sheen {
	from { background-position: 0% 0; opacity: 1; }
	92%  { background-position: 100% 0; opacity: 1; }
	to   { background-position: 100% 0; opacity: 0; }
}

/* The highlight travels as a background-position across a triple-width gradient, never as a
   transform, so the overlay stays inside its box and the element needs no overflow clipping - a
   clip here would also cut off anything another effect draws outside the box, crop marks and
   photo corners among them. */

:where(.accpt-fx-sheen) {
	position: relative;
	isolation: isolate;
}

:where(.accpt-fx-sheen)::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	border-radius: inherit;
	background-image: linear-gradient(
		115deg,
		transparent 42%,
		color-mix(in oklab, white var(--accpt-fx-sheen-strength, 62%), transparent) 50%,
		transparent 58%
	);
	background-size: 300% 100%;
	background-repeat: no-repeat;
	background-position: 0% 0;
	opacity: 0;
}

:where(.accpt-fx-sheen[data-accpt-inview])::after {
	animation: accpt-fx-sheen var(--accpt-fx-sheen-dur, 1.9s) ease both;
	animation-delay: var(--accpt-motion-delay, 0s);
}

/* ---- card lift on hover ---- */

:where(.accpt-fx-lift) {
	/* A hover edge: the probe runs at rest and cannot see the shadow coming, so the lift keeps
	   its own mat. Zero-specificity, as the probe's is. */
	padding: var(--accpt-mat, var(--acc-space-3, 1rem));
	transition-property: translate, box-shadow;
	transition-duration: 0.25s;
	transition-timing-function: var(--acc-ease-out, ease);
}

:where(.accpt-fx-lift:hover) {
	translate: 0 var(--accpt-fx-lift-rise, -4px);
	box-shadow: var(--acc-elev-3);
}

/* ---- leans to the pointer: spends the pointer reporter's --px / --py ----
   CURSOR PFX-006 - The perspective follows the element's size (--ew / --eh, from the same
   reporter), so a button and a band lean by the same apparent amount: a fixed 900px perspective
   was a shrug on the button and a lurch on the band. Smaller things also get a little more angle,
   since a small surface has less depth to show the lean with. */

:where(.accpt-fx-lean) {
	--accpt-fx-lean-size: max(var(--ew, 600), var(--eh, 600));
	--accpt-fx-lean-persp: clamp(240px, calc(var(--accpt-fx-lean-size) * 2.2px), 1400px);
	--accpt-fx-lean-boost: clamp(1, calc(420 / var(--accpt-fx-lean-size)), 1.8);
	transform:
		perspective(var(--accpt-fx-lean-persp))
		rotateX(calc(clamp(-0.5, var(--py, 0), 0.5) * var(--accpt-fx-lean-tilt, -10deg) * var(--accpt-fx-lean-boost)))
		rotateY(calc(clamp(-0.5, var(--px, 0), 0.5) * var(--accpt-fx-lean-tilt, -10deg) * -1 * var(--accpt-fx-lean-boost)));
	transition: transform 0.15s ease-out;
	transform-style: preserve-3d;
}

/* The glare checkbox: a soft light that follows the pointer across the leaning surface, spending
   the reporter's --mx / --my and fading with --prox. */

:where(.accpt-fx-lean--glare) {
	position: relative;
	overflow: clip;
}

:where(.accpt-fx-lean--glare)::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	border-radius: inherit;
	background: radial-gradient(
		circle at var(--mx, 50%) var(--my, 50%),
		color-mix(in oklab, white var(--accpt-fx-glare-strength, 28%), transparent) 0,
		transparent 55%
	);
	opacity: var(--prox, 0);
	transition: opacity 0.2s ease-out;
}

/* The shadow switch: the pointer is the light, so the shadow falls away from it - offset by the
   reporter's -px / -py, sized to the element, darkening as the pointer nears and gone when it has
   left. The color is the suite's shadow role, so a tinted shadow stays a declared opt-in. */

:where(.accpt-fx-lean--shadow) {
	--accpt-fx-lean-reach: clamp(6px, calc(var(--accpt-fx-lean-size, 300) * 0.06px), 28px);
	box-shadow:
		calc(clamp(-0.5, var(--px, 0), 0.5) * var(--accpt-fx-lean-reach) * -2)
		calc(clamp(-0.5, var(--py, 0), 0.5) * var(--accpt-fx-lean-reach) * -2)
		calc(var(--accpt-fx-lean-reach) * 1.6)
		calc(var(--accpt-fx-lean-reach) * -0.4)
		color-mix(in oklab, var(--acc-shadow-color, #000) calc(var(--prox, 0) * var(--accpt-fx-shadow-strength, 28%)), transparent);
	transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
}

/* ---- underline wipe on links ---- */

:where(.accpt-fx-underline) {
	text-decoration: none;
	background-image: linear-gradient(currentColor, currentColor);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% var(--accpt-fx-underline-w, 1px);
	transition: background-size 0.3s var(--acc-ease-out, ease);
}

:where(.accpt-fx-underline:hover, .accpt-fx-underline:focus-visible) {
	background-size: 100% var(--accpt-fx-underline-w, 1px);
}

/* ---- foil in the headings ----
   The specimen's own gold, not the palette: foil is a material, and a metal that took the brand's
   hue read as a tint rather than a shine. One pass of the highlight across the glyphs on first
   sight, then the ink fades back up through the gold - the true color arrives rather than
   replacing the metal on the last frame. Raised one id: a design paints its headings through a
   {{scope}} selector, and at zero specificity the clip was lost and nothing happened. */

@keyframes accpt-fx-foil {
	from { background-position: 0% 0; -webkit-text-fill-color: transparent; }
	58%  { background-position: 100% 0; -webkit-text-fill-color: transparent; }
	to   { background-position: 100% 0; -webkit-text-fill-color: currentColor; }
}

:root:not(#_) .accpt-fx-foil {
	background-image: linear-gradient(100deg, #7d5a12, #ffeaa8 26%, #a67c1f 42%, #fff6d6 58%, #7d5a12);
	background-size: 220% 100%;
	background-repeat: no-repeat;
	background-position: 100% 0;
	-webkit-background-clip: text;
	background-clip: text;
}

:root:not(#_) .accpt-fx-foil[data-accpt-inview] {
	animation: accpt-fx-foil var(--accpt-fx-foil-dur, 1.05s) ease-out both;
	animation-delay: var(--accpt-motion-delay, 0s);
}

/* ---- picture zooms in its frame ---- */

:where(.accpt-fx-zoom) {
	overflow: clip;
}

:where(.accpt-fx-zoom) :where(img),
:where(img.accpt-fx-zoom) {
	transition: scale 0.6s var(--acc-ease-out, ease);
}

:where(.accpt-fx-zoom:hover) :where(img),
:where(img.accpt-fx-zoom:hover) {
	scale: var(--accpt-fx-zoom-scale, 1.06);
}

/* ---- the border family, in ::before ----
   The mat is not drawn here any more: the page's mat probe sees a painted pseudo-element as an
   edge and pads the target itself, so the ring and the brackets clear the content without a rule
   of their own that could disagree with it. */

:where(.accpt-fx-gradient-border) {
	position: relative;
}

:where(.accpt-fx-brackets) {
	position: relative;
}

/* The designer's rounded corners: the house radius, which the ring inherits. */

:where(.accpt-fx-gradient-border--rounded) {
	border-radius: var(--acc-radius, 0.75rem);
}

:where(.accpt-fx-gradient-border)::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	padding: var(--accpt-fx-border-w, 1.5px);
	pointer-events: none;
	background: linear-gradient(var(--accpt-fx-border-angle, 135deg), var(--acc-accent), var(--acc-interactive));
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
}

/* The buyer's foil switch: the specimen's machined-metal ring, a conic gradient turning once inside
   the border box on first sight and then stopping. Turning it for ever meant regenerating a conic
   gradient every frame for as long as the page was open; the sweep costs nothing once it has
   finished, and Replay re-runs it like any other one-shot. --accpt-angle is the suite's registered
   angle, which is what lets the turn interpolate at all. */

@keyframes accpt-fx-border-foil {
	to { --accpt-angle: 360deg; }
}

:where(.accpt-fx-gradient-border--foil)::before {
	padding: var(--accpt-fx-border-w, 3px);
	background: conic-gradient(
		from var(--accpt-angle, 0deg),
		color-mix(in oklab, var(--acc-accent) 45%, black),
		#ffeaa8 16%,
		var(--acc-accent) 34%,
		#fff6d6 54%,
		var(--acc-accent) 76%,
		color-mix(in oklab, var(--acc-accent) 45%, black)
	);
}

:where(.accpt-fx-gradient-border--foil[data-accpt-inview])::before {
	animation: accpt-fx-border-foil var(--accpt-fx-foil-dur, 3.6s) linear both;
	animation-delay: var(--accpt-motion-delay, 0s);
}

/* Corner brackets, three styles on one pseudo-element - the buyer's Bracket style select.
   border  - the default: an L of hairlines at each corner, tight to the box
   photo   - photo-album pockets: tinted triangles with a darker diagonal edge, overhanging the box
             by two pixels so they read as holding the object
   crop    - printer's crop marks: short hairlines just outside each corner, the way a proof is marked
   Size, color and overhang are the sheet's knobs. */

:where(.accpt-fx-brackets)::before {
	content: "";
	position: absolute;
	inset: var(--accpt-fx-bracket-inset, 0px);
	pointer-events: none;
	--accpt-fx-l: var(--accpt-fx-bracket-len, 1.25rem);
	--accpt-fx-b: var(--accpt-fx-bracket-w, 2px);
	--accpt-fx-c: var(--accpt-fx-bracket-color, var(--acc-accent, currentColor));
	background:
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top left / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top left / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top right / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top right / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom left / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom left / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom right / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom right / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat;
}

:where(.accpt-fx-brackets--photo)::before {
	inset: calc(var(--accpt-fx-bracket-inset, 0px) - var(--accpt-fx-bracket-hold, 2px));
	--accpt-fx-l: var(--accpt-fx-bracket-len, 1.6rem);
	--accpt-fx-c: var(--accpt-fx-bracket-color, color-mix(in oklab, var(--acc-accent, currentColor) 28%, var(--acc-surface, white)));
	--accpt-fx-e: var(--accpt-fx-bracket-edge, color-mix(in oklab, var(--acc-accent, currentColor) 55%, var(--acc-surface, white)));
	background:
		linear-gradient(135deg, var(--accpt-fx-c) 0 calc(50% - 1px), var(--accpt-fx-e) calc(50% - 1px) 50%, transparent 50%) top left / var(--accpt-fx-l) var(--accpt-fx-l) no-repeat,
		linear-gradient(225deg, var(--accpt-fx-c) 0 calc(50% - 1px), var(--accpt-fx-e) calc(50% - 1px) 50%, transparent 50%) top right / var(--accpt-fx-l) var(--accpt-fx-l) no-repeat,
		linear-gradient(45deg, var(--accpt-fx-c) 0 calc(50% - 1px), var(--accpt-fx-e) calc(50% - 1px) 50%, transparent 50%) bottom left / var(--accpt-fx-l) var(--accpt-fx-l) no-repeat,
		linear-gradient(315deg, var(--accpt-fx-c) 0 calc(50% - 1px), var(--accpt-fx-e) calc(50% - 1px) 50%, transparent 50%) bottom right / var(--accpt-fx-l) var(--accpt-fx-l) no-repeat;
}

/* Crop marks sit outside the box with a gap: the layer is grown by mark length plus gap, and each
   mark runs along an outer edge, stopping short of the corner by the gap. */

:where(.accpt-fx-brackets--crop)::before {
	--accpt-fx-l: var(--accpt-fx-bracket-len, 0.9rem);
	--accpt-fx-b: var(--accpt-fx-bracket-w, 1px);
	--accpt-fx-gap: var(--accpt-fx-bracket-gap, 0.35rem);
	--accpt-fx-off: calc(var(--accpt-fx-l) + var(--accpt-fx-gap));
	inset: calc(var(--accpt-fx-bracket-inset, 0px) - var(--accpt-fx-off));
	--accpt-fx-c: var(--accpt-fx-bracket-color, color-mix(in oklab, var(--acc-text, currentColor) 60%, transparent));
	background:
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) left var(--accpt-fx-off) top 0 / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) left 0 top var(--accpt-fx-off) / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) right var(--accpt-fx-off) top 0 / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) right 0 top var(--accpt-fx-off) / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) left var(--accpt-fx-off) bottom 0 / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) left 0 bottom var(--accpt-fx-off) / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) right var(--accpt-fx-off) bottom 0 / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) right 0 bottom var(--accpt-fx-off) / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat;
}

/* Viewfinder: the camera reticle - hairline Ls pulled out from the corners by a gap, with a dot at
   each true corner of the box. */

:where(.accpt-fx-brackets--viewfinder)::before {
	--accpt-fx-l: var(--accpt-fx-bracket-len, 1rem);
	--accpt-fx-b: var(--accpt-fx-bracket-w, 1.5px);
	--accpt-fx-gap: var(--accpt-fx-bracket-gap, 0.4rem);
	inset: calc(var(--accpt-fx-bracket-inset, 0px) - var(--accpt-fx-gap));
	background:
		radial-gradient(circle, var(--accpt-fx-c) 0 var(--accpt-fx-b), transparent calc(var(--accpt-fx-b) + 0.5px)) left calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) top calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) / calc(var(--accpt-fx-b) * 2) calc(var(--accpt-fx-b) * 2) no-repeat,
		radial-gradient(circle, var(--accpt-fx-c) 0 var(--accpt-fx-b), transparent calc(var(--accpt-fx-b) + 0.5px)) right calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) top calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) / calc(var(--accpt-fx-b) * 2) calc(var(--accpt-fx-b) * 2) no-repeat,
		radial-gradient(circle, var(--accpt-fx-c) 0 var(--accpt-fx-b), transparent calc(var(--accpt-fx-b) + 0.5px)) left calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) bottom calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) / calc(var(--accpt-fx-b) * 2) calc(var(--accpt-fx-b) * 2) no-repeat,
		radial-gradient(circle, var(--accpt-fx-c) 0 var(--accpt-fx-b), transparent calc(var(--accpt-fx-b) + 0.5px)) right calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) bottom calc(var(--accpt-fx-gap) - var(--accpt-fx-b)) / calc(var(--accpt-fx-b) * 2) calc(var(--accpt-fx-b) * 2) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top left / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top left / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top right / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) top right / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom left / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom left / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom right / var(--accpt-fx-l) var(--accpt-fx-b) no-repeat,
		linear-gradient(var(--accpt-fx-c), var(--accpt-fx-c)) bottom right / var(--accpt-fx-b) var(--accpt-fx-l) no-repeat;
}

/* Rivets: a filled disc inset from each corner, lit from the upper left. The plate-and-screws look. */

:where(.accpt-fx-brackets--rivets)::before {
	--accpt-fx-r: var(--accpt-fx-bracket-len, 0.28rem);
	--accpt-fx-in: var(--accpt-fx-bracket-gap, 0.45rem);
	--accpt-fx-c: var(--accpt-fx-bracket-color, color-mix(in oklab, var(--acc-text, currentColor) 45%, var(--acc-surface, white)));
	--accpt-fx-s: calc(var(--accpt-fx-r) * 2 + 1px);
	background:
		radial-gradient(circle at 38% 34%, color-mix(in oklab, var(--accpt-fx-c) 55%, white) 0 30%, var(--accpt-fx-c) 31% var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) left var(--accpt-fx-in) top var(--accpt-fx-in) / var(--accpt-fx-s) var(--accpt-fx-s) no-repeat,
		radial-gradient(circle at 38% 34%, color-mix(in oklab, var(--accpt-fx-c) 55%, white) 0 30%, var(--accpt-fx-c) 31% var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) right var(--accpt-fx-in) top var(--accpt-fx-in) / var(--accpt-fx-s) var(--accpt-fx-s) no-repeat,
		radial-gradient(circle at 38% 34%, color-mix(in oklab, var(--accpt-fx-c) 55%, white) 0 30%, var(--accpt-fx-c) 31% var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) left var(--accpt-fx-in) bottom var(--accpt-fx-in) / var(--accpt-fx-s) var(--accpt-fx-s) no-repeat,
		radial-gradient(circle at 38% 34%, color-mix(in oklab, var(--accpt-fx-c) 55%, white) 0 30%, var(--accpt-fx-c) 31% var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) right var(--accpt-fx-in) bottom var(--accpt-fx-in) / var(--accpt-fx-s) var(--accpt-fx-s) no-repeat;
}

/* Ticket notch: a quarter-circle bitten out of each corner in the surface color - the punched
   ticket, the coupon. Reads only where the target paints its own ground. */

:where(.accpt-fx-brackets--notch)::before {
	--accpt-fx-r: var(--accpt-fx-bracket-len, 0.85rem);
	--accpt-fx-g: var(--accpt-fx-bracket-color, var(--acc-surface, white));
	background:
		radial-gradient(circle at 0 0, var(--accpt-fx-g) var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) top left / var(--accpt-fx-r) var(--accpt-fx-r) no-repeat,
		radial-gradient(circle at 100% 0, var(--accpt-fx-g) var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) top right / var(--accpt-fx-r) var(--accpt-fx-r) no-repeat,
		radial-gradient(circle at 0 100%, var(--accpt-fx-g) var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) bottom left / var(--accpt-fx-r) var(--accpt-fx-r) no-repeat,
		radial-gradient(circle at 100% 100%, var(--accpt-fx-g) var(--accpt-fx-r), transparent calc(var(--accpt-fx-r) + 0.5px)) bottom right / var(--accpt-fx-r) var(--accpt-fx-r) no-repeat;
}

/* Ornament: a fleur-de-lis at each corner - a V leaving the corner straight along both edges, the vertex on the corner itself and the arms on
   the edges, each bowing slightly outward past its edge from the middle, and a small leaf on the diagonal, its point toward the corner and a hair
   clear of the petals, its body opening inward. The one style that is a drawing rather than a gradient: an SVG mask, drawn for the
   bottom-left and mirrored into the other three, filled with the bracket color so it still answers
   to the palette. */

:where(.accpt-fx-brackets--ornament)::before {
	--accpt-fx-l: var(--accpt-fx-bracket-len, 2.4rem);
	--accpt-fx-c: var(--accpt-fx-bracket-color, var(--acc-accent, currentColor));
	/* A twelfth of the drawing lies outside the box, so the arms can bow past the edge. */
	inset: calc(var(--accpt-fx-bracket-inset, 0px) - var(--accpt-fx-l) / 12);
	background: var(--accpt-fx-c);
	-webkit-mask-image:
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(48 0) scale(-1 1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(0 48) scale(1 -1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(48 48) scale(-1 -1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>");
	mask-image:
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(48 0) scale(-1 1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(0 48) scale(1 -1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>"),
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><g transform='translate(48 48) scale(-1 -1)'><path d='M4 44 L4 32 Q4 24 1 18' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M4 44 L16 44 Q24 44 30 47' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/><path d='M8 40 C10 34 14 30 19.5 28.5 C19 34.5 15.5 38.5 8 40 Z' fill='black'/></g></svg>");
	-webkit-mask-size: var(--accpt-fx-l) var(--accpt-fx-l);
	mask-size: var(--accpt-fx-l) var(--accpt-fx-l);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: bottom left, bottom right, top left, top right;
	mask-position: bottom left, bottom right, top left, top right;
}

/* ---- grain over the ground ----
   The specimen's grain: a grid of one-pixel dots, not a noise texture - noise at low alpha read as
   a flat tint. Painted as the element's own background-image like the other grounds, above its
   color and below its content, so it never has to share a pseudo-element with a sweep. */

:root:not(#_) .accpt-fx-grain {
	background-image: radial-gradient(color-mix(in oklab, var(--acc-text, #000) calc(16% * var(--accpt-fx-grain-strength, 0.5) * 2), transparent) 1px, transparent 1px);
	background-size: 3px 3px;
}

/* ---- the ground family: the element's own background-image ----

   CURSOR PFX-003 - Raised one id, for the same reason the reveal states are: a design
   that paints its surface with the `background` shorthand resets background-image to none, and
   at zero specificity the ground silently never appeared. One id outranks that; a {{scope}} rule
   carries two and can still redraw it. */

:root:not(#_) .accpt-fx-mesh {
	background-image:
		radial-gradient(42% 42% at 14% 18%, color-mix(in oklab, var(--acc-accent) 30%, transparent), transparent 70%),
		radial-gradient(46% 46% at 86% 14%, color-mix(in oklab, var(--acc-interactive) 26%, transparent), transparent 70%),
		radial-gradient(52% 52% at 62% 92%, color-mix(in oklab, var(--acc-accent) 20%, transparent), transparent 70%);
}

/* Hairlines, not a texture: one pixel, and light enough to read as paper rather than a pattern. */

:root:not(#_) .accpt-fx-hatch {
	background-image: repeating-linear-gradient(
		var(--accpt-fx-hatch-angle, 45deg),
		color-mix(in oklab, currentColor var(--accpt-fx-hatch-strength, 7%), transparent) 0 1px,
		transparent 1px var(--accpt-fx-hatch-gap, 10px)
	);
}

/**
 * Accordion.
 *
 * Mechanics only, and only the two a template cannot reasonably be asked to remember: a hidden
 * panel must actually stay hidden even when a flex rule would otherwise show it, and a marker that
 * is declared as rotating must rotate. Everything else about how an accordion looks - the header,
 * the divider, the animation - stays with the template.
 */

[data-accpt-accordion-panel][hidden] {
	display: none;
}

/* `display` on a flex or grid child beats the hidden attribute's own UA rule, which is how a closed
   panel ends up visible in a template that lays its items out with flex. Raised the same way the
   flex primitives are, so a template rule can still override deliberately. */

:root:not(#_) [data-accpt-accordion-panel][hidden] {
	display: none;
}

[data-accpt-behavior-rotate="true"] [data-accpt-accordion-marker] {
	transition: transform 0.2s ease;
}

[data-accpt-behavior-rotate="true"] [data-state="open"] [data-accpt-accordion-marker] {
	transform: rotate(180deg);
}

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

	[data-accpt-behavior-rotate="true"] [data-accpt-accordion-marker] {
		transition: none;
	}
}

/**
 * Captioned image.
 *
 * The mechanics only: a figure with no default margin, and the five anchor positions the caption may
 * take. Everything visible about a caption - type, color, the scrim behind an overlaid one - stays
 * with the template, which is why the only color here is the one that makes overlaid text legible
 * before a template has said anything at all.
 */

/* An image node is emitted with the width and height of the registered size it was drawn for, which
   is what stops the layout jumping while it loads - and what makes it overflow a card narrower than
   that size. The cap costs nothing at full width and is the difference between a 300px image sitting
   inside a 289px card and hanging out of it. Specificity is deliberately low: a template that wants a
   fixed height for a crop still wins. */

[data-accpt-node] img,
img[data-accpt-node],
.accpt-figure img {
	max-width: 100%;
	height: auto;
}

.accpt-figure {
	display: flex;
	flex-direction: column;
	margin: 0;
	position: relative;
}

.accpt-figure__caption {
	font-size: 0.85em;
	line-height: 1.35;
}

/* The three overlay positions sit on the image rather than beside it, so the figure stops being a
   column and becomes the positioning context. */

.accpt-figure--top .accpt-figure__caption,
.accpt-figure--middle .accpt-figure__caption,
.accpt-figure--bottom .accpt-figure__caption {
	position: absolute;
	left: 0;
	right: 0;
	padding: 0.4em 0.6em;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
}

.accpt-figure--top .accpt-figure__caption {
	top: 0;
}

.accpt-figure--middle .accpt-figure__caption {
	top: 50%;
	transform: translateY(-50%);
}

.accpt-figure--bottom .accpt-figure__caption {
	bottom: 0;
}

/**
 * Rating node.
 *
 * The mechanics of a rating are not a design decision: a half glyph is half a glyph wide, a pie
 * fills clockwise, an empty step is the empty color. Those live here so every template that drops
 * a rating in gets a working one without restating the geometry. What a template still owns is
 * everything visible about it - the size, the two palette roles, the gap - all of which arrive as
 * custom properties the renderer writes from the designer's and buyer's choices.
 */

.accpt-rating {
	--accpt-rating-size: 1.25rem;
	--accpt-rating-gap: 0.15em;
	--accpt-rating-thickness: 0.35em;
	--accpt-rating-full: currentColor;
	--accpt-rating-empty: rgba(128, 128, 128, 0.35);
	display: inline-flex;
	flex-flow: row wrap;
	align-items: baseline;
	gap: 0.35em;
}

.accpt-rating--num-above,
.accpt-rating--num-below {
	flex-flow: column nowrap;
	align-items: flex-start;
}

.accpt-rating__readout {
	display: inline-flex;
	align-items: baseline;
	gap: 0.1em;
}

.accpt-rating--num-over {
	position: relative;
}

/* The whole readout is centered over the chart, not each half of it separately: positioning the
   number and the `/5` independently stacked them on the same spot. */

.accpt-rating--num-over .accpt-rating__readout {
	position: absolute;
	inset: 0;
	justify-content: center;
	/* Centered, not baseline-aligned: over a dial there is no shared baseline to sit on, and baseline
	   left the readout riding high in the ring. */
	align-items: center;
	pointer-events: none;
}

.accpt-rating__num {
	font-size: var(--accpt-rating-num-size);
	font-weight: var(--accpt-rating-num-weight);
	line-height: 1;
}

/* The out-of value follows the number rather than the star size, so changing one keeps the pair in
   proportion. The ratio reproduces the old 0.65-of-star-size exactly at the default. */

.accpt-rating__max {
	font-size: calc(var(--accpt-rating-num-size) * 0.684);
	opacity: 0.7;
	line-height: 1;
}

.accpt-rating__chart {
	display: inline-flex;
	flex-flow: row nowrap;
	align-items: center;
	gap: var(--accpt-rating-gap);
	line-height: 1;
}

/* Glyph charts. The icon font sets the shape; the state sets which color it takes. */

.accpt-rating__icon {
	font-size: var(--accpt-rating-size);
	line-height: 1;
	color: var(--accpt-rating-empty);
}

.accpt-rating__icon.is-full,
.accpt-rating__icon.is-half {
	color: var(--accpt-rating-full);
}

/* Empty-step styles. Each draws the set's own full glyph and changes how it is painted, so a family
   that ships no outline still gets a usable empty state. */

.accpt-rating--empty-faded .accpt-rating__icon.is-empty {
	color: var(--accpt-rating-full);
	opacity: var(--accpt-rating-fade, 0.25);
}

/* Space is kept, not reclaimed: five steps with two filled says "two out of five", where two lone
   glyphs say only "two". */

.accpt-rating--empty-hidden .accpt-rating__icon.is-empty {
	visibility: hidden;
}

/* Hollowing a solid glyph: paint the fill transparent and stroke the letterform. Gated behind
   @supports because without the stroke the transparent fill would render nothing at all - the
   fallback is the plain empty color, which is merely plainer, not broken. */

@supports (-webkit-text-stroke: 1px currentColor) {

	.accpt-rating--empty-outline .accpt-rating__icon.is-empty {
		color: transparent;
		-webkit-text-stroke: var(--accpt-rating-stroke, 0.045em) var(--accpt-rating-empty);
	}
}

/* Partial steps: the outer glyph is the empty color, the nested copy is the full color clipped to
   --accpt-rating-clip. A set with no half glyph clips to 50%; the single-glyph chart clips to the
   exact ratio, so 3.7/5 is 74% of one star. */

.accpt-rating__icon.is-clipped,
.accpt-rating__icon--single {
	position: relative;
	color: var(--accpt-rating-empty);
}

.accpt-rating__icon-fill {
	position: absolute;
	inset: 0;
	color: var(--accpt-rating-full);
	clip-path: inset(0 calc(100% - var(--accpt-rating-clip, 0%)) 0 0);
}

/* Geometric charts, which need no icon font at all. */

.accpt-rating--bar .accpt-rating__chart,
.accpt-rating--vbar .accpt-rating__chart {
	background: var(--accpt-rating-empty);
	overflow: hidden;
	border-radius: calc(var(--accpt-rating-thickness) / 2);
}

.accpt-rating--bar .accpt-rating__chart {
	width: calc(var(--accpt-rating-size) * 6);
	height: var(--accpt-rating-thickness);
}

.accpt-rating--vbar .accpt-rating__chart {
	width: var(--accpt-rating-thickness);
	height: calc(var(--accpt-rating-size) * 3);
	align-items: flex-end;
}

.accpt-rating--bar .accpt-rating__fill {
	display: block;
	width: var(--accpt-rating-pct, 0%);
	height: 100%;
	background: var(--accpt-rating-full);
}

.accpt-rating--vbar .accpt-rating__fill {
	display: block;
	width: 100%;
	height: var(--accpt-rating-pct, 0%);
	background: var(--accpt-rating-full);
}

.accpt-rating--circle .accpt-rating__chart {
	width: calc(var(--accpt-rating-size) * 2.4);
	height: calc(var(--accpt-rating-size) * 2.4);
	border-radius: 50%;
	background: conic-gradient(var(--accpt-rating-full) var(--accpt-rating-pct, 0%), var(--accpt-rating-empty) 0);
}

.accpt-rating--circle .accpt-rating__fill {
	display: block;
	width: calc(100% - var(--accpt-rating-thickness) * 2);
	height: calc(100% - var(--accpt-rating-thickness) * 2);
	margin: auto;
	border-radius: 50%;
	background: var(--acc-surface, #fff);
}

/* Signal bars: each step is taller than the last, so the shape reads as a level even in mono. */

.accpt-rating--bars .accpt-rating__chart {
	height: calc(var(--accpt-rating-size) * 1.6);
	align-items: flex-end;
}

.accpt-rating--bars .accpt-rating__step {
	display: block;
	width: var(--accpt-rating-thickness);
	height: var(--accpt-rating-step, 100%);
	background: var(--accpt-rating-empty);
	border-radius: calc(var(--accpt-rating-thickness) / 4);
}

.accpt-rating--bars .accpt-rating__step.is-full,
.accpt-rating--bars .accpt-rating__step.is-half {
	background: var(--accpt-rating-full);
}

.accpt-rating--bars .accpt-rating__step.is-half {
	opacity: 0.55;
}

/* The chart carries no meaning to a screen reader, so the sentence beside it does. Declared here
   because a template cannot be relied on to ship the theme's own hidden-text class. */

.accpt-rating__sr {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Step 2: same rules, raised above theme resets without !important. */

:root:not(#_) .frow,
:root:not(#_) .fcol,
:root:not(#_) .fwrap {
	display: flex;
}

:root:not(#_) .frow {
	flex-flow: row nowrap;
}

:root:not(#_) .fcol {
	flex-flow: column nowrap;
}

:root:not(#_) .fwrap {
	flex-flow: row wrap;
}

:root:not(#_) .fgrow {
	flex: 1 1 auto;
}

:root:not(#_) .ffull {
	width: 100%;
	flex-basis: 100%;
}

/*
 * Links that own what they say.
 *
 * CURSOR PLINK-001 - Two treatments, and which one is the designer's choice. `link` is text
 * that happens to go somewhere; `button` is a control, and gets a shape here so that a template
 * saying `variant: button` and nothing else still looks like a button.
 *
 * CURSOR PLINK-004 - Written in :where(), so all of it has zero specificity. This is a
 * floor under 28 links that were styled by their templates long before the module existed: any rule
 * with a class in it beats every line below, including the flex primitives on the same element and
 * every `{{scope}} .thing` a designer has already written. A floor that outranks the design is not a
 * floor, it is a restyle.
 */

:where(.accpt-btn) {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
}

:where(.accpt-btn__icon) {
	flex: 0 0 auto;
	line-height: 1;
}

/* The words wrap, the icon does not. */

:where(.accpt-btn__text) {
	min-width: 0;
}

/* CURSOR PLINK-005 - A button's whole shape, radius and weight included. It is in
   :where(), so a template that has drawn its own control beats every line of it - but a template
   that says only `variant: button` gets something that looks like one rather than a colored
   rectangle. Four of the converted templates never stated a radius or a weight and take these:
   that is the floor doing its job, not overruling a decision. */

:where(.accpt-btn--button) {
	padding: 0.6em 1.1em;
	border-radius: 0.35em;
	background-color: var(--acc-interactive, #1e40af);
	font-weight: 600;
	text-decoration: none;
	/* CURSOR PBTN-001 - As wide as its words. A button inside a column is a flex item, and a
	   flex item's cross size is stretch unless it has a width of its own - so every button in every
	   fcol arrived as a full-width bar, which is the wrong resting shape for nearly all of them. A
	   fit-content width is not a stretch and needs no align-self, so it holds in rows as well as
	   columns. Still :where(), so a design that wants the bar states a width and wins. */
	width: fit-content;
	max-width: 100%;
}

/* CURSOR PLINK-006 / PWAVE-028 - The button label, at a weight that actually lands.
 *
 * PLINK-006 described this fault correctly and then did not fix it, which is worth keeping as the
 * warning it turned out to be. A theme coloring its links with a bare `a` scores 0,0,1; the floor
 * was answering from inside `:where()`, which scores 0,0,0 - so the ground came from the floor and
 * the words came from the theme, and the note recording the fix was written against a rule that had
 * exactly the same weight as the one it replaced. The whole of the change was moving the text out
 * of a zero-specificity wrapper, and that never happened.
 *
 * It measured as a near-black button carrying dark purple words: 1.48 against a required 4.5, on
 * 121 nodes, the single largest contrast fault in the catalog and present on the default palette.
 *
 * `.accpt-root` as an ancestor is the smallest weight that settles it. 0,2,0 outranks any bare
 * element selector a theme can write, and still loses to a template rule, which carries the two ids
 * of {{scope}} - so a designer who states a label color still wins, which is the way round it
 * should be.
 *
 * Every state is named, not just the resting one, or a theme's own `a:hover` takes the words back
 * the moment the pointer arrives - the same fault through the other door.
 */

.accpt-root .accpt-btn--button,
.accpt-root .accpt-btn--button:hover,
.accpt-root .accpt-btn--button:focus-visible,
.accpt-root .accpt-btn--button:active {
	color: var(--acc-on-interactive, #ffffff);
}

/* CURSOR PWAVE-025 - Button states, as a tint over whatever color the button actually is.
 *
 * Two things were wrong and only one of them was obvious. The rule hovered to --acc-accent while
 * the button rests on --acc-interactive, so any palette giving those roles the same value - the
 * common case - repainted the button the exact color it already was, and the button read as dead.
 *
 * The second is why naming a color cannot be the fix. A template paints its own CTA through
 * `{{scope}} .thing`, which carries two ids and beats anything the floor can write; and even
 * winning that fight would be wrong, because the floor cannot know which color the template chose
 * and would swap the button to an unrelated hue on hover.
 *
 * An inset tint has no color of its own. It lightens or darkens what is already there, whatever
 * that is and whoever painted it, so it needs no specificity fight at all - nothing else in the
 * sheet sets box-shadow on a button. A template that wants a different hover states one, and its
 * own rule wins, which is the way round it should be.
 */

:where(.accpt-btn--button) {
	transition: box-shadow 0.18s ease;
}

:where(.accpt-btn--button):hover,
:where(.accpt-btn--button):focus-visible {
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.15);
}

:where(.accpt-btn--button):active {
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.13);
}

/* The link variant has the same fight to win and lost it the same way. Fixing only the one that was
   measured would leave the identical bug behind under a different class name, which is how PLINK-006
   came to be written twice. */

.accpt-root .accpt-btn--link,
.accpt-root .accpt-btn--link:hover,
.accpt-root .accpt-btn--link:focus-visible,
.accpt-root .accpt-btn--link:active {
	color: var(--acc-interactive, inherit);
}

/*
 * Price module floor.
 *
 * CURSOR PPRICE-001 - Price module.
 *
 * Zero specificity throughout, the same as the link floor, so a template sheet always wins without
 * having to out-specify anything. What is here is only what a price cannot be read without: the four
 * spans on one line, the symbol and period not competing with the amount for size, and the old price
 * struck through. Everything else - scale, color, weight, where the symbol sits - is the design's,
 * and a design that says nothing still gets something legible.
 */
:where(.accpt-price) {
	display: inline-flex;
	align-items: baseline;
	gap: 0.1em;
}

:where(.accpt-price__currency),
:where(.accpt-price__period) {
	font-size: 0.65em;
}

:where(.accpt-price__was) {
	font-size: 0.7em;
	text-decoration: line-through;
	opacity: 0.7;
}

/*
 * Stat module floor.
 *
 * CURSOR PSTAT-001 - Stat module.
 *
 * The figure has to read as the figure and the label as the label, and that is the whole of it. No
 * color on the movement: which way is good depends on what is being counted - a fall in complaints
 * is a rise - so the direction is exposed as a class and a design decides what it means.
 */
:where(.accpt-stat) {
	display: flex;
	flex-direction: column;
	gap: 0.15em;
}

:where(.accpt-stat__figure) {
	font-size: 2em;
	line-height: 1.1;
}

:where(.accpt-stat__label),
:where(.accpt-stat__movement) {
	font-size: 0.8em;
}

/*
 * Table module floor.
 *
 * CURSOR PTABLE-001 - Table module.
 *
 * Collapsed borders and left-aligned cells, because a table that arrives with browser defaults
 * arrives with a 2px outset ridge from 1997. Nothing else: rules, padding, stripes and how it
 * behaves when it runs out of room are the design's, and every design wants them different.
 */
:where(.accpt-table) {
	width: 100%;
	border-collapse: collapse;
}

:where(.accpt-table__head),
:where(.accpt-table__cell) {
	text-align: left;
	vertical-align: top;
}

:where(.accpt-table__caption) {
	text-align: left;
}

/**
 * Suite floor - kit 1.
 *
 * CURSOR TCHEST-1 - Catalog-wide floor rules from the specimen exploration. Everything
 * here is either zero-specificity (:where(), so any template rule beats it) or deliberately raised
 * one id, and each raised rule says why. `.accpt-root` is stamped by root_attributes() on every
 * pattern's block wrapper - the scope class beside it is per-template, so without it the floor has
 * nothing stable to select.
 */

/* Headings even their lines out instead of stranding the last word on its own line; body copy
   avoids the same orphan. Zero specificity, so a template that declares its own text-wrap wins. */

:where(.accpt-root) :where(h1, h2, h3, h4, h5, h6) {
	text-wrap: balance;
}

:where(.accpt-root) :where(p, li, dd, figcaption, blockquote) {
	text-wrap: pretty;
}

/* Numerals that line up in columns - only where digits sit against other digits, because
   proportional figures remain the right answer in running text. */

:where(.accpt-table__head),
:where(.accpt-table__cell),
:where(.accpt-stat__figure) {
	font-variant-numeric: tabular-nums;
}

/* Color-inherit defense. A pattern lands inside a stylesheet nobody wrote for it, and a live
   theme was found styling headings by element name - an element selector beats a color inherited
   from the template's own band, so white-on-green headings shipped in the theme's navy at 1.6:1,
   on the published site only. Raised one id so a theme's element and class rules lose; a template
   rule carries two ids and still wins. Links are left out: a theme's link color is the theme's
   to keep until a template says otherwise. */

:root:not(#_) .accpt-root :where(h1, h2, h3, h4, h5, h6, p, li, td, th, blockquote, cite, figcaption) {
	color: inherit;
}

/* The seam rule: the space between two stacked patterns belongs to one of them, not both. The
   lower block gives up the flow margin the theme puts between blocks, so two full-bleed bands
   meet with no sliver of page ground between them, and an unpainted pair is spaced by its own
   padding alone. Raised one id to beat the theme's flow-layout margin; a template that sets its
   own margin outranks it. The other half of the measured doubling - two paddings meeting at a
   join - waits on the kit-2 spacing token, because a floor must not strip padding a template
   chose. */

:root:not(#_) .accpt-root + .accpt-root {
	margin-block-start: 0;
}

/**
 * The token layer - kit 2, the derivation engine.
 *
 * CURSOR TCHEST-2 - Values derived from the palette roles, so nothing is picked twice:
 * a site with a different accent gets a correct hover, active, soft wash, focus ring, tint ramp
 * and elevation for free. Everything is declared on :where(.accpt-root) at zero specificity and
 * custom properties inherit, so any template redeclaration - on the scope or on a node - wins.
 * That is the owner's fork-2 call made real: derived is the default, the designer overrides.
 *
 * Owner's calls, 2026-09-01: state colors default-with-override (fork 2); tinted shadows are a
 * declared opt-in, never automatic (fork 3) - one line, `--acc-shadow-color: var(--acc-accent)`,
 * opts a design in; elevation is the five-step scale, level 0 a border, the old three-step habit
 * mapping onto steps 1-3 (fork 4).
 *
 * Color derivations extend the palette's own --acc- vocabulary because that is what a designer
 * already types. Nothing here is buyer-facing, ever.
 */

:where(.accpt-root) {
	/* State colors, mixed - the fallback grammar every current browser knows. */
	--acc-accent-hover: color-mix(in oklab, var(--acc-accent) 85%, white);
	--acc-accent-active: color-mix(in oklab, var(--acc-accent) 88%, black);
	--acc-accent-soft: color-mix(in oklab, var(--acc-accent) 12%, var(--acc-surface));
	--acc-accent-ring: color-mix(in oklab, var(--acc-accent) 55%, transparent);
	--acc-interactive-hover: color-mix(in oklab, var(--acc-interactive) 85%, white);
	--acc-interactive-active: color-mix(in oklab, var(--acc-interactive) 88%, black);
	--acc-interactive-soft: color-mix(in oklab, var(--acc-interactive) 12%, var(--acc-surface));
	--acc-interactive-ring: color-mix(in oklab, var(--acc-interactive) 55%, transparent);

	/* INK. The color that reads ON a role, named after the ground rather than after itself.
	 *
	 * This exists because choosing a text color against a ground is the one decision that cannot be
	 * made safely in advance. The palette used to declare an ink beside each ground, once, for the
	 * ground it had in mind; the buyer then changed the ground and the ink stayed where it was, so
	 * white sat on a pale accent and the words disappeared. Measured across the catalog, that pairing
	 * was the largest remaining source of unreadable text.
	 *
	 * A designer writing `color: var(--acc-on-accent)` cannot get this wrong, because the ink is
	 * derived from the ground rather than declared beside it. Name the ground, get the ink.
	 *
	 * A palette declares every one of these on the block itself, computed for the ground it actually
	 * built, and an inline declaration beats anything here. What follows is the answer for a block
	 * carrying no palette at all: the page's own text color, which is dull but never invalid. The
	 * @supports block below improves on it wherever the browser can do the arithmetic. */
	--acc-on-surface: var(--acc-text);
	--acc-on-surface-elevated: var(--acc-text);
	--acc-on-accent: var(--acc-text);
	--acc-on-interactive: var(--acc-text);
	--acc-on-medium: var(--acc-text);
	--acc-on-border: var(--acc-text);

	/* The tint ramp: the accent walked into the surface, so the steps belong to each other and to
	   the palette. Chroma tapers naturally as the mix thins. */
	--acc-accent-tint-1: color-mix(in oklab, var(--acc-accent) 8%, var(--acc-surface));
	--acc-accent-tint-2: color-mix(in oklab, var(--acc-accent) 16%, var(--acc-surface));
	--acc-accent-tint-3: color-mix(in oklab, var(--acc-accent) 28%, var(--acc-surface));
	--acc-accent-tint-4: color-mix(in oklab, var(--acc-accent) 45%, var(--acc-surface));
	--acc-accent-tint-5: color-mix(in oklab, var(--acc-accent) 65%, var(--acc-surface));

	/* A hairline that reads on light and dark palettes alike. */
	--acc-hairline: color-mix(in oklab, var(--acc-border) 60%, transparent);

	/* Elevation: five steps, one light source. Level 0 is a border, because a design that uses
	   shadow for everything has no way to say "at rest". The light top edge is part of every
	   raised level; on a dark ground a design raises its alpha, because depth there comes from a
	   light top edge rather than a darker bottom - black shadows vanish on black. The shadow
	   color is one token: leaving it black is the default, pointing it at a role is the tinted
	   opt-in. */
	--acc-shadow-color: #000;
	--acc-elev-edge: inset 0 1px 0 rgba(255, 255, 255, 0.05);
	--acc-elev-0: 0 0 0 1px var(--acc-hairline);
	--acc-elev-1: var(--acc-elev-edge),
		0 1px 2px color-mix(in oklab, var(--acc-shadow-color) 6%, transparent),
		0 1px 3px color-mix(in oklab, var(--acc-shadow-color) 10%, transparent);
	--acc-elev-2: var(--acc-elev-edge),
		0 4px 6px color-mix(in oklab, var(--acc-shadow-color) 5%, transparent),
		0 10px 15px color-mix(in oklab, var(--acc-shadow-color) 10%, transparent);
	--acc-elev-3: var(--acc-elev-edge),
		0 10px 20px color-mix(in oklab, var(--acc-shadow-color) 6%, transparent),
		0 20px 40px color-mix(in oklab, var(--acc-shadow-color) 12%, transparent);
	--acc-elev-4: var(--acc-elev-edge),
		0 18px 36px color-mix(in oklab, var(--acc-shadow-color) 9%, transparent),
		0 36px 70px color-mix(in oklab, var(--acc-shadow-color) 16%, transparent);

	/* The spacing scale: gaps proportional to relationship, so proximity carries the grouping.
	   Spend a step, never a bare length - and the join between two sections spends step 5 once,
	   which is the other half of the seam rule. */
	--acc-space-1: 0.25rem;
	--acc-space-2: 0.5rem;
	--acc-space-3: 1rem;
	--acc-space-4: 1.5rem;
	--acc-space-5: 2.5rem;
	--acc-space-6: 4rem;

	/* Type: the measure that survives a font-size change, and the tracking pair - display type
	   tightens, small-caps labels open up. The radius is the outer one; an inner radius is never
	   its own decision: inner = outer minus the padding between them. */
	--acc-measure: 65ch;
	--acc-track-display: -0.02em;
	--acc-track-caps: 0.08em;
	--acc-radius: 0.75rem;

	/* Named easings - kit 6. The house curves, tuned once for the whole suite. Spend them as
	   LONGHANDS (transition-timing-function / animation-timing-function): a later shorthand
	   silently resets a timing function, which is the trap that put the rule in the vocabulary.
	   The two linear() curves fall back to their cubic neighbors where unsupported. */
	--acc-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
	--acc-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
	--acc-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
	--acc-ease-snap: cubic-bezier(0.5, 1.5, 0.6, 1);
}

@supports (transition-timing-function: linear(0, 1)) {

	:where(.accpt-root) {
		--acc-ease-spring: linear(
			0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017, 1.077 20.4%,
			1.121, 1.149 24.3%, 1.159, 1.163 27%, 1.154, 1.129 32.8%, 1.051 39.6%, 1.017 43.1%,
			0.991, 0.977 51%, 0.974 53.8%, 0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1);
		--acc-ease-snap: linear(0, 0.63 12%, 0.99 24%, 1.06 36%, 1.01 54%, 0.998 72%, 1);
	}
}

/* Where relative color syntax is understood, the states derive from the role's own lightness
   instead of mixing toward white or black - distinct on any palette, including one whose accent
   is already pale, which is where the mixes above drift. Same names, so a designer override still
   beats both. */

/* Ink, computed. `l` is the ground's own lightness, so `(0.62 - l) * 1000` is a large positive
 * number on a dark ground and a large negative one on a light ground; clamping it to the readable
 * ends of the scale turns that into near-white ink or near-black ink with nothing in between. There
 * is no branching in CSS, and this is the arithmetic that stands in for it.
 *
 * 0.62 is the perceptual midpoint in oklch, not the sRGB one - the point where a ground stops being
 * able to carry dark words and starts being able to carry light ones. Chroma is dropped to zero so
 * the ink is neutral whatever the ground's hue, which is the safe choice: a tinted ink on a
 * saturated ground loses contrast in exactly the case that needs it most.
 *
 * Gated on the precise syntax rather than on relative color in general, because a browser that
 * parses `calc(l + 0.1)` may still refuse a clamp around it - and a rule that fails to parse takes
 * the whole declaration with it, leaving the ground with no ink at all. */

@supports (color: oklch(from red clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h)) {

	:where(.accpt-root) {
		--acc-on-surface: oklch(from var(--acc-surface) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
		--acc-on-surface-elevated: oklch(from var(--acc-surface-elevated) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
		--acc-on-accent: oklch(from var(--acc-accent) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
		--acc-on-interactive: oklch(from var(--acc-interactive) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
		--acc-on-medium: oklch(from var(--acc-medium) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
		--acc-on-border: oklch(from var(--acc-border) clamp(0.15, calc((0.62 - l) * 1000), 0.97) 0 h);
	}
}

@supports (color: oklch(from red calc(l + 0.1) c h)) {

	:where(.accpt-root) {
		--acc-accent-hover: oklch(from var(--acc-accent) calc(l + 0.06) c h);
		--acc-accent-active: oklch(from var(--acc-accent) calc(l - 0.05) c h);
		--acc-accent-ring: oklch(from var(--acc-accent) l calc(c * 0.6) h / 0.55);
		--acc-accent-complement: oklch(from var(--acc-accent) l c calc(h + 180));
		--acc-interactive-hover: oklch(from var(--acc-interactive) calc(l + 0.06) c h);
		--acc-interactive-active: oklch(from var(--acc-interactive) calc(l - 0.05) c h);
		--acc-interactive-ring: oklch(from var(--acc-interactive) l calc(c * 0.6) h / 0.55);
	}
}

/**
 * The focus ring - the derivation engine's first real job.
 *
 * CURSOR PWAVE-018 - Every interactive thing the renderer emits gets a visible focus
 * ring, drawn in a color DERIVED from the interactive role rather than picked. Before this the
 * only outline in the suite was on form controls: links, buttons, tabs and accordion triggers
 * signalled focus by changing color, which is a weak indicator on its own and is nothing at all
 * where a host theme has cleared the browser's own outline - which plenty of themes do.
 *
 * Raised one id so a theme's `*:focus { outline: none }` cannot take it away, while a template
 * rule scoped to {{scope}} still carries two and can draw its own focus treatment deliberately.
 * `:focus-visible` rather than `:focus`, so a mouse click on a button does not ring it.
 */

:root:not(#_) .accpt-root :is(a[href], button, summary, [tabindex], [role="button"], [role="tab"]):focus-visible {
	outline: 2px solid var(--acc-interactive-ring, var(--acc-interactive, currentColor));
	outline-offset: 2px;
}

/**
 * The design's surface.
 *
 * CURSOR PPAL-004 - The palette's ground is painted on the dom root, the element the template
 * shapes, and nowhere else. It used to be painted on the host's wrapper, outside the design, which
 * put a square ground behind every rounded card - visible the moment a dark palette met a light
 * page. Zero specificity: a template that paints its own ground, with any selector at all, wins.
 */

:where(.accpt-surface) {
	background: var(--acc-surface);
	color: var(--acc-text);
}

/**
 * The mat.
 *
 * CURSOR PMAT-001 - An edge needs a mat, and which roots have an edge is decided on the page
 * by the mat probe (the patterns plugin prints it after each block): a ground unlike the one behind
 * it, a border, a shadow, a painted pseudo-element. The probe adds accpt-mat where the root has an
 * edge and less than the house inset of padding; this pads it, at zero specificity, so a template
 * that pads its own root keeps its number. --accpt-mat-min is the threshold the probe reads, in px.
 */

:where(.accpt-mat) {
	padding: var(--accpt-mat, var(--acc-space-3, 1rem));
}

/* The probe's other verdict: the floor's ground is close enough to the page's not to be worth a
   box, so it is not painted. The design's own ground, where it has one, is never touched. */

:where(.accpt-surface--blend) {
	background: transparent;
}

/**
 * Registered properties - kit 4.
 *
 * CURSOR TCHEST-4 - Central @property registrations, made once for the whole suite. An
 * unregistered custom property is a string and cannot animate; registering the three types the
 * catalog's techniques spend - an angle for conic borders, a percentage for rings and ramps, an
 * integer for counters - makes those transitions real everywhere. The renderer's own index facts
 * (--accpt-i / --accpt-n) stay unregistered on purpose: they are inputs to calc(), never animated
 * themselves. Templates use these; they never re-register them.
 */

@property --accpt-angle {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0deg;
}

@property --accpt-pct {
	syntax: "<percentage>";
	inherits: false;
	initial-value: 0%;
}

@property --accpt-int {
	syntax: "<integer>";
	inherits: false;
	initial-value: 0;
}

/**
 * Open and close, honestly - kit 5.
 *
 * CURSOR TCHEST-5 - The state floor for the shipped behaviors. A closed panel is hidden
 * with the `hidden` attribute, which is a display flip - and a display flip cannot animate without
 * the two pieces here: `interpolate-size` lets height travel to and from `auto`, and the discrete
 * `display` transition holds the panel visible while it collapses. All of it is zero-specificity,
 * so a template that draws its own open/close animation replaces it wholesale, and all of it hangs
 * off `data-accpt-ready`, which the runtime stamps only after the initial state has landed - a
 * page must not open by animating every closed panel shut. Browsers without interpolate-size snap
 * exactly as they did before this existed. Durations and easing read from --accpt-open-dur and
 * --accpt-open-ease so the motion vocabulary can reach them later; the reduced-motion block below
 * collapses the lot.
 */

:where([data-accpt-ready] [data-accpt-accordion-panel]) {
	interpolate-size: allow-keywords;
	overflow: clip;
	transition:
		height var(--accpt-open-dur, 0.25s) var(--accpt-open-ease, ease),
		padding-block var(--accpt-open-dur, 0.25s) var(--accpt-open-ease, ease),
		opacity var(--accpt-open-dur, 0.25s) var(--accpt-open-ease, ease),
		display var(--accpt-open-dur, 0.25s) allow-discrete;
}

:where([data-accpt-ready] [data-accpt-accordion-panel][hidden]) {
	height: 0;
	padding-block: 0;
	opacity: 0;
}

/* The entry half: when `hidden` comes off, the panel starts collapsed and travels open. */

@starting-style {

	:where([data-accpt-ready] [data-accpt-accordion-panel]:not([hidden])) {
		height: 0;
		padding-block: 0;
		opacity: 0;
	}
}

/* Tabs cross in rather than collapse: the leaving panel goes instantly - two visible panels would
   shove the layout - and the arriving one fades up from nothing. */

:where([data-accpt-ready] [data-accpt-tabs-panel]) {
	transition: opacity var(--accpt-open-dur, 0.25s) var(--accpt-open-ease, ease);
}

@starting-style {

	:where([data-accpt-ready] [data-accpt-tabs-panel]:not([hidden])) {
		opacity: 0;
	}
}

/**
 * The reveal floor - kit 6.
 *
 * CURSOR TCHEST-6 - The motion verbs. The renderer writes data-accpt-motion and the knob
 * properties from the node's declaration; the runtime arms the node (data-accpt-motion-armed) and
 * stamps data-accpt-inview when it enters the viewport, once. Everything here is the journey
 * between those two attributes. Zero specificity throughout, so a template can redraw any verb -
 * and the starting states hang off the ARMED attribute, never the verb alone, so a page whose
 * script fails shows everything, still, in place.
 *
 * Knobs, all overridable per node or per template rule: --accpt-motion-dur, --accpt-motion-delay,
 * --accpt-motion-dist, --accpt-motion-ease, and --accpt-motion-stagger for the split verbs. A
 * stagger across a collection is one template rule:
 * `--accpt-motion-delay: calc(var(--accpt-i) * 80ms)`.
 */

:where([data-accpt-motion-armed]) {
	transition-property: opacity, transform, clip-path;
	transition-duration: var(--accpt-motion-dur, 0.6s);
	transition-timing-function: var(--accpt-motion-ease, var(--acc-ease-out, ease));
	transition-delay: var(--accpt-motion-delay, 0s);
}

/* CURSOR PWAVE-011 - The STARTING states are raised one id, and the reason is a fault
   found by measuring rather than reading: a design that sets a static `opacity` on the node it
   also moves - a muted list of points at .92 - beat a zero-specificity `opacity: 0` and the
   entrance silently never happened. Nothing looked broken; the gesture simply was not there.

   `:root:not(#_)` carries one id, so these now outrank an ordinary class rule while a template
   rule scoped to {{scope}} still carries two and can redraw any verb deliberately. The transition
   above stays at zero specificity, because retiming is exactly what a template should be able to
   do without a fight. */

:root:not(#_) [data-accpt-motion="fade"][data-accpt-motion-armed]:not([data-accpt-inview]) {
	opacity: 0;
}

:root:not(#_) [data-accpt-motion="rise"][data-accpt-motion-armed]:not([data-accpt-inview]) {
	opacity: 0;
	transform: translateY(var(--accpt-motion-dist, 1.5rem));
}

:root:not(#_) [data-accpt-motion="zoom"][data-accpt-motion-armed]:not([data-accpt-inview]) {
	opacity: 0;
	transform: scale(0.94);
}

/* A wipe needs the same shape at both ends - inset() to none is not interpolable - so the resting
   state is a clip that clips nothing. */

:where([data-accpt-motion="wipe"][data-accpt-motion-armed]) {
	clip-path: inset(0 0 0 0);
}

:root:not(#_) [data-accpt-motion="wipe"][data-accpt-motion-armed]:not([data-accpt-inview]) {
	clip-path: inset(0 100% 0 0);
}

/* The split verbs move their units, never the node itself - hiding the parent would hide the
   stagger. Units ride the same knobs, plus a per-unit delay from the index the runtime wrote. */

:where([data-accpt-motion-armed]) .accpt-motion__unit {
	display: inline-block;
	transition-property: opacity, transform;
	transition-duration: var(--accpt-motion-dur, 0.6s);
	transition-timing-function: var(--accpt-motion-ease, var(--acc-ease-out, ease));
	transition-delay: calc(var(--accpt-motion-delay, 0s) + var(--accpt-i, 0) * var(--accpt-motion-stagger, 40ms));
}

:root:not(#_) [data-accpt-motion-armed]:not([data-accpt-inview]) .accpt-motion__unit {
	opacity: 0;
	transform: translateY(var(--accpt-motion-dist, 0.4em));
}

/**
 * Module extensions - kit 8.
 *
 * CURSOR TCHEST-8 - Charts sweep, figures count, forms have manners. Everything visible
 * stays the template's; what lives here is the mechanics no design should restate.
 */

/* The rating properties, registered so a chart can SWEEP: an unregistered custom property is a
   string and snaps. `inherits: true` deliberately - these are written on the rating root and read
   by the chart below it, which is inheritance; registering them any other way would break every
   rating already shipped. */

@property --accpt-rating-pct {
	syntax: "<percentage>";
	inherits: true;
	initial-value: 0%;
}

@property --accpt-rating-clip {
	syntax: "<percentage>";
	inherits: true;
	initial-value: 0%;
}

/* A rating with declared motion sweeps its chart as it reveals: while armed and unseen the fill
   is held at zero - !important because the real value sits in a style attribute, and this is the
   one way a stylesheet outranks it - and first sight releases it to travel to the buyer's value.
   Bars widen, dials sweep, star fills pour in, all from the same pair of properties. */

:where(.accpt-rating[data-accpt-motion-armed]),
:where(.accpt-rating[data-accpt-motion-armed]) :where(.accpt-rating__icon, .accpt-rating__icon-fill, .accpt-rating__fill, .accpt-rating__chart) {
	transition-property: opacity, transform, --accpt-rating-pct, --accpt-rating-clip;
	transition-duration: var(--accpt-motion-dur, 0.9s);
	transition-timing-function: var(--accpt-motion-ease, var(--acc-ease-out, ease));
	transition-delay: var(--accpt-motion-delay, 0s);
}

:where(.accpt-rating[data-accpt-motion-armed]:not([data-accpt-inview])),
:where(.accpt-rating[data-accpt-motion-armed]:not([data-accpt-inview])) :where(.accpt-rating__icon, .accpt-rating__icon-fill, .accpt-rating__fill, .accpt-rating__chart) {
	--accpt-rating-pct: 0% !important;
	--accpt-rating-clip: 0% !important;
}

/* The odometer: each digit is a clipped column the runtime rolls to its value. Geometry only -
   the type is the figure's own. */

.accpt-odometer {
	display: inline-flex;
	line-height: 1;
}

.accpt-odometer__col {
	display: inline-block;
	height: 1em;
	overflow: hidden;
}

.accpt-odometer__roll {
	display: inline-block;
	line-height: 1;
	transition: transform 1.1s var(--acc-ease-out, ease);
	transition-delay: calc(var(--accpt-i, 0) * 90ms);
}

.accpt-odometer--rolled .accpt-odometer__roll {
	transform: translateY(calc(var(--accpt-odo-steps, 0) * -1em));
}

/* A field that looks designed, before any design has said a word: sunk into the surface, capped
   with a hairline, and a focus ring that is actually visible. All zero-specificity - the first
   template rule wins. `:user-invalid` waits for the person to have been in the field, because a
   form that scolds before anyone has typed is worse than no styling at all. */

:where(.accpt-form__control) {
	border: 1px solid var(--acc-hairline, rgba(128, 128, 128, 0.35));
	border-radius: calc(var(--acc-radius, 0.75rem) * 0.5);
	padding: 0.55em 0.75em;
	background-color: var(--acc-surface, #fff);
	color: inherit;
	box-shadow: inset 0 1px 3px color-mix(in oklab, var(--acc-shadow-color, #000) 8%, transparent);
}

:where(.accpt-form__control:focus-visible) {
	outline: 2px solid var(--acc-interactive-ring, var(--acc-interactive, #1e40af));
	outline-offset: 2px;
}

:where(.accpt-form__control:user-invalid) {
	border-color: color-mix(in oklab, #b32d2e 70%, var(--acc-border, #b32d2e));
	box-shadow: inset 0 1px 3px color-mix(in oklab, #b32d2e 18%, transparent);
}

/* The moment between the click and the page leaving: the runtime stamps the form working and
   disables the button; this is only the face of that. */

:where(.accpt-form[data-state="working"] .accpt-form__submit) {
	opacity: 0.65;
	cursor: progress;
}

/**
 * The ribbon package - kit 9.
 *
 * CURSOR TCHEST-9 - The mechanics of three strip presentations. Everything hangs off
 * data-accpt-ribbon-armed, which only the running runtime writes: without it the strip is exactly
 * the row of items the template drew. What the items look like stays the template's; what is here
 * is only what makes each presentation work at all.
 */

/* Marquee. The track is twice one cycle and travels exactly one; translate3d, not translate,
   because a 2d translate of an odd-width track ticks at the seam. Duration arrives derived from
   the cycle width. The strip pauses under the pointer, because a logo someone is trying to read
   should hold still for them. */

:where([data-accpt-ribbon-armed="marquee"]) {
	overflow: hidden;
}

:where([data-accpt-ribbon-armed="marquee"]) :where(.accpt-ribbon__track) {
	display: flex;
	width: max-content;
	will-change: transform;
	animation: accpt-ribbon-scroll var(--accpt-ribbon-dur, 40s) linear infinite;
}

:where([data-accpt-ribbon-armed="marquee"]:hover) :where(.accpt-ribbon__track) {
	animation-play-state: paused;
}

:where(.accpt-ribbon__cycle) {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
}

@keyframes accpt-ribbon-scroll {

	to {
		transform: translate3d(-50%, 0, 0);
	}
}

/* Cross-fade cycle: the items stack in one grid cell and show in turn. Grid rather than absolute
   positioning, so the strip is as tall as its tallest item and never collapses. */

:where([data-accpt-ribbon-armed="cycle"]) {
	display: grid;
}

:where([data-accpt-ribbon-armed="cycle"]) > :where(*) {
	grid-area: 1 / 1;
	opacity: 0;
	transition: opacity 0.6s var(--acc-ease-out, ease);
}

:where([data-accpt-ribbon-armed="cycle"]) > :where([data-state="current"]) {
	opacity: 1;
}

/* Scroller: a real scroll-snap row. The runtime only advances it; these are the rails. */

:where([data-accpt-ribbon-armed="scroller"]) {
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
}

:where([data-accpt-ribbon-armed="scroller"]) > :where(*) {
	scroll-snap-align: start;
	flex-shrink: 0;
}

/**
 * Filter - kit 10.
 *
 * CURSOR TCHEST-10 - Mechanics only. The buttons are generated by the runtime from the
 * groups the buyer actually typed; everything about how they look beyond "in a row" is the
 * template's, styled through .accpt-filter__btn and its aria-pressed state.
 */

:where([data-accpt-filter-menu]) {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5em;
}

/* Same fault and same fix as the accordion: `display` on a flex or grid child beats the hidden
   attribute's own UA rule, and a filtered-out card that stays visible makes the filter a lie. */

:root:not(#_) [data-accpt-filter-list] > [hidden] {
	display: none;
}

/**
 * Lightbox - Wave A's module unlock.
 *
 * CURSOR PWAVE-007 - Runtime-owned overlay UI, not a floor under templates: the overlay
 * is the runtime's own markup, so it is styled at normal specificity and looks the same over any
 * design. `position: fixed` is legal here precisely because template CSS can never say it - the
 * validator's ban is on sheets a package ships, and this file is the suite's own.
 */

[data-accpt-lightbox-item] {
	cursor: zoom-in;
}

.accpt-lightbox {
	position: fixed;
	inset: 0;
	z-index: 99999;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 3rem 4.5rem;
	background: rgba(10, 10, 12, 0.9);
}

:root:not(#_) .accpt-lightbox[hidden] {
	display: none;
}

.accpt-lightbox__figure {
	margin: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	max-width: 100%;
	max-height: 100%;
}

.accpt-lightbox__img {
	max-width: min(92vw, 87.5rem);
	max-height: 82vh;
	width: auto;
	height: auto;
	border-radius: 0.25rem;
	box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
}

.accpt-lightbox__cap {
	color: rgba(255, 255, 255, 0.85);
	font-size: 0.9rem;
	text-align: center;
	text-wrap: balance;
}

.accpt-lightbox__btn {
	position: absolute;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	border: 0;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.12);
	color: #fff;
	font-size: 1.6rem;
	line-height: 1;
	cursor: pointer;
}

.accpt-lightbox__btn:hover,
.accpt-lightbox__btn:focus-visible {
	background: rgba(255, 255, 255, 0.28);
}

/* CURSOR PWAVE-018 - The overlay is the runtime's own UI and sits on its own dark
   backdrop, outside any pattern - so it takes a light ring rather than the palette's interactive
   one, which has no contrast to rely on here. */

.accpt-lightbox__btn:focus-visible {
	outline: 2px solid rgba(255, 255, 255, 0.9);
	outline-offset: 2px;
}

.accpt-lightbox__btn--close {
	top: 1rem;
	right: 1rem;
}

.accpt-lightbox__btn--prev {
	left: 1rem;
	top: 50%;
	transform: translateY(-50%);
}

.accpt-lightbox__btn--next {
	right: 1rem;
	top: 50%;
	transform: translateY(-50%);
}

/* One picture is not a gallery: the arrows stand down. */

.accpt-lightbox[data-accpt-single="true"] .accpt-lightbox__btn--prev,
.accpt-lightbox[data-accpt-single="true"] .accpt-lightbox__btn--next {
	display: none;
}

@media (max-width: 40rem) {

	.accpt-lightbox {
		padding: 3rem 1rem;
	}
}

/* Central reduced-motion handling, so no template ever writes its own @media block for it.
   Animation and transition collapse to a single frame - end states still land, nothing is left
   hidden - and smooth scrolling stands down. !important is deliberate, the same as the form trap:
   this is the one preference a design is never entitled to override. */

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

	.accpt-root,
	.accpt-root * {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		/* Delays too, or a staggered reveal still makes a reader wait for content to appear. */
		transition-delay: 0s !important;
		animation-delay: 0s !important;
		scroll-behavior: auto !important;
	}
}
