/**
 * AOL List: shared front end and editor styles for the parent block.
 *
 * Specificity
 * -----------
 * Almost every theme, and the block editor's own reset, carries something like
 * `.entry-content ul { padding: 0; list-style: none; }` for navigation menus.
 * A single class selector loses to that, which is how a list ends up with no
 * bullets or numbers. Structural rules are therefore written with two classes
 * (`.aol-list.aol-list--list`), which beats a class-plus-element theme reset
 * without resorting to !important.
 *
 * Working with the theme
 * ----------------------
 * Rules here fall into two tiers.
 *
 * Functional rules keep normal specificity. Without them the block does not
 * work: an outside marker with no indent to sit in, a details element still
 * showing its native triangle, a grid that will not lay out. These are the
 * minimum needed for the block to render as a list or an accordion at all.
 *
 * Cosmetic rules are wrapped in :where(), which gives them zero specificity.
 * Spacing, weights, colours, hover states and margin resets can therefore be
 * overridden by a single plain class in the theme stylesheet, with no
 * !important and no specificity arithmetic.
 *
 * On top of that, every value is a custom property, so a theme can restyle
 * the whole block by declaring the variables listed below on any ancestor,
 * and the marker itself can be handed back to the theme entirely by choosing
 * "Inherit from theme" in the block settings.
 *
 * Scoping
 * -------
 * Every selector, custom property and counter name in this file begins with
 * `aol-list` or `--aol-list`, so nothing here can be matched or overwritten by
 * a generic rule from a theme or another plugin, and nothing here can leak out
 * and restyle somebody else's markup.
 *
 * @package AOL_List
 */

/*
 * Defaults. Each falls back to the theme's own global style value first, so
 * an untouched block already follows the site's rhythm and palette.
 */
:where( .aol-list ) {
	--aol-list-gap: var( --wp--style--block-gap, 0.75rem );
	--aol-list-columns: 1;
	--aol-list-marker-color: currentColor;
	--aol-list-divider-color: rgba( 0, 0, 0, 0.12 );
	--aol-list-divider-opacity: 0.15;
	--aol-list-marker-space: 1.5em;

	margin-block: 0;
}

.aol-list {
	box-sizing: border-box;
}

/* --------------------------------------------------------------------
 * Spacing presets
 * ------------------------------------------------------------------ */

:where( .aol-list.aol-list--gap-none ) {
	--aol-list-gap: 0rem;
}

:where( .aol-list.aol-list--gap-small ) {
	--aol-list-gap: 0.5rem;
}

/* Medium follows the theme's own block spacing. */
:where( .aol-list.aol-list--gap-medium ) {
	--aol-list-gap: var( --wp--style--block-gap, 0.75rem );
}

:where( .aol-list.aol-list--gap-large ) {
	--aol-list-gap: 1.25rem;
}

:where( .aol-list.aol-list--gap-xlarge ) {
	--aol-list-gap: 2rem;
}

/* --------------------------------------------------------------------
 * Structural defaults for list mode
 *
 * These restore what a theme reset usually removes: the indent that gives an
 * outside marker somewhere to sit, and list-item display on the children.
 * ------------------------------------------------------------------ */

/*
 * Functional. A theme reset that zeroes list padding leaves an outside marker
 * with nowhere to render, which is why this has to out-specify it. The
 * :not() opts the block out entirely when the author chose to inherit the
 * theme's own list styling.
 */
.aol-list.aol-list--list:not( .aol-list--marker-theme ) {
	padding-inline-start: var( --aol-list-marker-space );
	list-style-position: outside;
}

.aol-list.aol-list--list > .aol-list-item {
	display: list-item;
}

.aol-list.aol-list--no-marker,
.aol-list.aol-list--painted {
	padding-inline-start: 0;
	list-style-type: none;
}

.aol-list.aol-list--list > .aol-list-item::marker {
	color: var( --aol-list-marker-color, currentColor );
}

.aol-list.aol-list--no-marker > .aol-list-item::marker {
	content: "";
}

/* Vertical rhythm between items. Cosmetic, so the theme can take it over. */
:where( .aol-list > .aol-list-item + .aol-list-item ) {
	margin-block-start: var( --aol-list-gap );
}

/* --------------------------------------------------------------------
 * Native marker styles
 * ------------------------------------------------------------------ */

.aol-list.aol-list--marker-disc {
	list-style-type: disc;
}

.aol-list.aol-list--marker-circle {
	list-style-type: circle;
}

.aol-list.aol-list--marker-square {
	list-style-type: square;
}

.aol-list.aol-list--marker-decimal {
	list-style-type: decimal;
}

.aol-list.aol-list--marker-decimal-leading-zero {
	list-style-type: decimal-leading-zero;
}

.aol-list.aol-list--marker-lower-alpha {
	list-style-type: lower-alpha;
}

.aol-list.aol-list--marker-upper-alpha {
	list-style-type: upper-alpha;
}

.aol-list.aol-list--marker-lower-roman {
	list-style-type: lower-roman;
}

.aol-list.aol-list--marker-upper-roman {
	list-style-type: upper-roman;
}

/* --------------------------------------------------------------------
 * Ordered lists: size the number to the item, not the list
 *
 * The native ::marker inherits the list item's own font, so a plain "1."
 * (or "a." / "I.") looks small and light beside a large item heading. Draw
 * the number on the first block inside the item instead, where it picks up
 * that block's type styles (a heading, or a paragraph if there is none).
 *
 * counter( list-item, ... ) is used rather than a bespoke counter, so the
 * native <ol start> and reversed attributes still drive the value. Setting
 * list-style: none on the item hides the native marker but leaves it a
 * display: list-item box, so that counter keeps incrementing.
 *
 * Covers every native ordered style (decimal, alpha, roman). Painted
 * markers, multi-column lists and "Inherit from theme" keep their own
 * rendering. One content rule per style, because a var() inside counter()
 * is invalid at computed-value time where the style is unsupported and
 * would drop the whole declaration.
 *
 * The paired ::before selectors cover both DOM shapes: the saved markup
 * nests .aol-list-item__content directly in the <li>, the editor wraps it
 * in .aol-list-item__panel first.
 * ------------------------------------------------------------------ */

.aol-list.aol-list--list.aol-list--ordered:not( .aol-list--painted ):not( .aol-list--marker-theme ) {
	padding-inline-start: 0;
}

.aol-list.aol-list--ordered:not( .aol-list--painted ):not( .aol-list--marker-theme ) > .aol-list-item {
	list-style: none;
}

.aol-list.aol-list--ordered:not( .aol-list--painted ):not( .aol-list--marker-theme ) > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--ordered:not( .aol-list--painted ):not( .aol-list--marker-theme ) > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	color: var( --aol-list-marker-color, currentColor );
	font-variant-numeric: tabular-nums;
}

.aol-list.aol-list--marker-decimal > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-decimal > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, decimal ) ". ";
}

.aol-list.aol-list--marker-decimal-leading-zero > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-decimal-leading-zero > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, decimal-leading-zero ) ". ";
}

.aol-list.aol-list--marker-lower-alpha > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-lower-alpha > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, lower-alpha ) ". ";
}

.aol-list.aol-list--marker-upper-alpha > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-upper-alpha > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, upper-alpha ) ". ";
}

.aol-list.aol-list--marker-lower-roman > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-lower-roman > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, lower-roman ) ". ";
}

.aol-list.aol-list--marker-upper-roman > .aol-list-item > .aol-list-item__content > :first-child::before,
.aol-list.aol-list--marker-upper-roman > .aol-list-item > .aol-list-item__panel > .aol-list-item__content > :first-child::before {
	content: counter( list-item, upper-roman ) ". ";
}

/* --------------------------------------------------------------------
 * Painted markers
 *
 * Used for check marks, arrows and custom characters, and for every marker in
 * multi column mode, where a grid item's outside ::marker has nowhere to sit.
 * ------------------------------------------------------------------ */

.aol-list.aol-list--painted > .aol-list-item {
	position: relative;
	padding-inline-start: var( --aol-list-marker-space );
}

.aol-list.aol-list--painted > .aol-list-item::before {
	content: var( --aol-list-marker, "\2022" );
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 0;
	inline-size: calc( var( --aol-list-marker-space ) - 0.4em );
	color: var( --aol-list-marker-color, currentColor );
	font-variant-numeric: tabular-nums;
	line-height: inherit;
	text-align: start;

	/* The marker is decoration: it should not be selectable. */
	-webkit-user-select: none;
	user-select: none;
}

.aol-list.aol-list--paint-disc > .aol-list-item::before {
	content: "\2022";
}

.aol-list.aol-list--paint-circle > .aol-list-item::before {
	content: "\25E6";
}

.aol-list.aol-list--paint-square > .aol-list-item::before {
	content: "\25AA";
}

.aol-list.aol-list--paint-check > .aol-list-item::before {
	content: "\2713";
}

.aol-list.aol-list--paint-arrow > .aol-list-item::before {
	content: "\2192";
}

/* The custom character arrives as an inline custom property. */
.aol-list.aol-list--paint-custom > .aol-list-item::before {
	content: var( --aol-list-marker, "\2022" );
}

/* An item can override just its own marker. */
.aol-list.aol-list--painted > .aol-list-item.aol-list-item--own-marker::before {
	content: var( --aol-list-marker );
}

/* Progressive enhancement: engines that allow content on ::marker get the per
   item override even when the list uses native markers. */
@supports selector( ::marker ) {
	.aol-list.aol-list--list > .aol-list-item.aol-list-item--own-marker::marker {
		content: var( --aol-list-marker ) " ";
	}
}

/* --------------------------------------------------------------------
 * Counters for painted ordered lists
 *
 * The counter is always reset on the container, so a nested list starts from
 * its own first number instead of continuing the outer one. The seed is only
 * overridden inline when the author changes the starting number.
 * ------------------------------------------------------------------ */

.aol-list.aol-list--counter {
	counter-reset: aol-counter 0;
}

.aol-list.aol-list--counter > .aol-list-item {
	counter-increment: aol-counter 1;
}

.aol-list.aol-list--count-down > .aol-list-item {
	counter-increment: aol-counter -1;
}

/*
 * One rule per counter style, rather than a var() inside counter(). A custom
 * property there parses fine but is invalid at computed value time in engines
 * that do not support it, which would discard the whole content declaration
 * and leave the item with no number at all.
 */
.aol-list.aol-list--counter-decimal > .aol-list-item::before {
	content: counter( aol-counter, decimal ) ".";
}

.aol-list.aol-list--counter-decimal-leading-zero > .aol-list-item::before {
	content: counter( aol-counter, decimal-leading-zero ) ".";
}

.aol-list.aol-list--counter-lower-alpha > .aol-list-item::before {
	content: counter( aol-counter, lower-alpha ) ".";
}

.aol-list.aol-list--counter-upper-alpha > .aol-list-item::before {
	content: counter( aol-counter, upper-alpha ) ".";
}

.aol-list.aol-list--counter-lower-roman > .aol-list-item::before {
	content: counter( aol-counter, lower-roman ) ".";
}

.aol-list.aol-list--counter-upper-roman > .aol-list-item::before {
	content: counter( aol-counter, upper-roman ) ".";
}

/* --------------------------------------------------------------------
 * Accordion container
 * ------------------------------------------------------------------ */

.aol-list.aol-list--accordion {
	padding-inline-start: 0;
	list-style: none;
}

/* --------------------------------------------------------------------
 * Icon position
 *
 * The child mirrors the parent's setting onto its own class, but a child that
 * has not been re-saved since the parent changed could disagree. The parent is
 * the source of truth, so these two rules let it win in both directions.
 * ------------------------------------------------------------------ */

.aol-list.aol-list--icon-left .aol-list-item__summary {
	flex-direction: row-reverse;
	justify-content: flex-end;
}

.aol-list.aol-list--accordion:not( .aol-list--icon-left ) .aol-list-item__summary--icon-left {
	flex-direction: row;
	justify-content: flex-start;
}

/*
 * Styling hooks with no default rules, emitted so a theme can target them:
 * .aol-list--ordered, .aol-list--unordered and .aol-list-item__title-text.
 */

/* --------------------------------------------------------------------
 * Expand and collapse all
 *
 * Rendered with the hidden attribute and revealed by the view script, because
 * it cannot do anything without JavaScript. The [hidden] rule is required:
 * a display value would otherwise override the attribute.
 * ------------------------------------------------------------------ */

.aol-list__controls {
	display: flex;
}

:where( .aol-list__controls ) {
	justify-content: flex-end;
	margin-block-end: var( --aol-list-gap );
}

.aol-list__controls[ hidden ] {
	display: none;
}

/* Functional: stop a theme's generic button styling turning this into a
   full width block button. */
.aol-list__toggle-all {
	appearance: none;
	background: none;
	border: 0;
	cursor: pointer;
}

/* Cosmetic. */
:where( .aol-list__toggle-all ) {
	padding: 0.25em 0;
	color: inherit;
	font: inherit;
	font-size: 0.875em;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

:where( .aol-list__toggle-all:hover ) {
	opacity: 0.75;
}

.aol-list__toggle-all:focus-visible {
	outline: 2px solid var( --aol-list-marker-color, currentColor );
	outline-offset: 2px;
	border-radius: 2px;
}

.aol-list__toggle-all[ aria-expanded="true" ] .aol-list__toggle-label--expand,
.aol-list__toggle-all[ aria-expanded="false" ] .aol-list__toggle-label--collapse {
	display: none;
}

/* --------------------------------------------------------------------
 * Multi column layout
 * ------------------------------------------------------------------ */

.aol-list.aol-list--cols-2 {
	--aol-list-columns: 2;
}

.aol-list.aol-list--cols-3 {
	--aol-list-columns: 3;
}

.aol-list.aol-list--cols-4 {
	--aol-list-columns: 4;
}

.aol-list.aol-list--cols-2,
.aol-list.aol-list--cols-3,
.aol-list.aol-list--cols-4 {
	display: grid;
	grid-template-columns: repeat( var( --aol-list-columns, 1 ), minmax( 0, 1fr ) );
	gap: var( --aol-list-gap );
}

.aol-list.aol-list--cols-2 > .aol-list-item,
.aol-list.aol-list--cols-3 > .aol-list-item,
.aol-list.aol-list--cols-4 > .aol-list-item {
	display: list-item;
	margin-block-start: 0;
}

/* The controls span the full width rather than becoming a grid cell. */
.aol-list > .aol-list__controls {
	grid-column: 1 / -1;
}

@media ( max-width: 781px ) {
	.aol-list.aol-list--cols-3,
	.aol-list.aol-list--cols-4 {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}
}

@media ( max-width: 600px ) {
	.aol-list.aol-list--cols-2,
	.aol-list.aol-list--cols-3,
	.aol-list.aol-list--cols-4 {
		grid-template-columns: minmax( 0, 1fr );
	}
}

/* --------------------------------------------------------------------
 * Dividers
 * ------------------------------------------------------------------ */

:where( .aol-list.aol-list--dividers > .aol-list-item + .aol-list-item ) {
	border-block-start: 1px solid var( --aol-list-divider-color );
	padding-block-start: var( --aol-list-gap );
}

/*
 * Where color-mix is available the divider is derived from the inherited text
 * colour, so it suits whatever palette the theme sets, in light and dark
 * alike. Elsewhere the neutral default above stands.
 */
@supports ( color: color-mix( in srgb, red, blue ) ) {
	:where( .aol-list.aol-list--dividers > .aol-list-item + .aol-list-item ) {
		border-block-start-color: color-mix(
			in srgb,
			currentColor calc( var( --aol-list-divider-opacity, 0.15 ) * 100% ),
			transparent
		);
	}
}

.aol-list.aol-list--cols-2.aol-list--dividers > .aol-list-item + .aol-list-item,
.aol-list.aol-list--cols-3.aol-list--dividers > .aol-list-item + .aol-list-item,
.aol-list.aol-list--cols-4.aol-list--dividers > .aol-list-item + .aol-list-item {
	border-block-start: 0;
	padding-block-start: 0;
}

/* --------------------------------------------------------------------
 * Print
 * ------------------------------------------------------------------ */

@media print {
	.aol-list.aol-list--cols-2,
	.aol-list.aol-list--cols-3,
	.aol-list.aol-list--cols-4 {
		display: block;
	}

	.aol-list > .aol-list-item {
		break-inside: avoid;
	}

	.aol-list__controls {
		display: none;
	}
}
