/*
 * core/tabs — `Side tabs`, the FAQ browser from the design.
 *
 * The design puts a 340px directory of industries down the left of a 1340px row
 * and the questions for the chosen one on the right: each tab is a 24px icon, a
 * label, and — on the tab you are on — a count of what is inside it. On a phone
 * the same directory is a row of chips you swipe through above the answers.
 *
 * Core's Tabs block gives none of that room to work in. `core/tab-list` renders
 * one bare `<button>` per tab and nothing else: the label is a rich-text
 * attribute *sourced from the buttons themselves*, so there is no inner block to
 * put an icon in and no attribute to hang a badge off. The icon and the count are
 * therefore drawn on the button's own `::before` and `::after`, from two custom
 * properties per tab that `includes/blocks/tabs-side-tabs.php` writes onto the
 * `.wp-block-tabs` wrapper on the front end and
 * `src/editor/filters/side-tabs.js` writes onto the same element in the canvas.
 * The three files have to agree on the property names and on the class below.
 *
 * That is also why this file carries a block of `nth-child` rules: the properties
 * arrive on the *wrapper*, indexed, and the mapping from index to button is the
 * only thing CSS can do about it. It is capped — see the comment there.
 *
 * **What the icon and the count each are, in accessibility terms, is deliberate.**
 * The icon is decorative: it repeats the label beside it, so a `mask-image` is the
 * honest representation — invisible to a screen reader, recoloured by
 * `currentColor` with the rest of the button. The count is information, so it is
 * `content` on a pseudo-element, which *is* in the accessibility tree and is
 * announced after the label ("Marine, 7 questions"). The cost of that is real and
 * worth knowing: generated content cannot be selected, and a browser's page
 * translation will not touch it. The alternative was inserting a `<span>` into
 * core's saved markup, which the HTML API cannot do and a regex should not.
 */

/*
 * The row.
 *
 * A grid rather than the flow layout core gives the block, because the two child
 * blocks are a fixed sidebar and everything else — which is a grid's one job.
 * `core/tabs` sets `layout.allowEditing: false`, so there is no layout control
 * for this to fight with.
 *
 * 21.25rem is the design's 340px. `minmax(0, 1fr)` and not `1fr`, because a `1fr`
 * track has a `min-width: auto` floor: one long unbreakable word in an answer
 * would push the track wider than the grid and the whole section would overflow
 * the page rather than wrap.
 *
 * The gap is `min(17%, 14.1875rem)` and both halves are the design's. 227px is
 * what `justify-between` leaves between the two columns at 1340px, and 227/1340 is
 * 16.94% — so the percentage *is* the design's proportion, held at every width,
 * and the `rem` is the same distance as a ceiling for anything wider. A single
 * `clamp()` against the viewport would have been the usual form and is wrong here:
 * this block sits on the layout width, which is `min(100vw - gutters, 83.75rem)`,
 * so past 1440px the viewport keeps growing and the column does not.
 *
 * (A percentage is safe in this one property. It is not safe in a custom property
 * shared across property families — `%` resolves against different boxes in
 * `margin`, `padding` and `scroll-padding` — which is the mistake
 * `term-carousel` was written around.)
 */
.wp-block-tabs.is-style-side-tabs {
	align-items: start;
	column-gap: min(17%, 14.1875rem);
	display: grid;
	grid-template-columns: 21.25rem minmax(0, 1fr);
}

/*
 * **A known gap this style opens, and it cannot be closed from CSS.**
 *
 * Core's Interactivity store handles `ArrowLeft`, `ArrowRight`, `Home` and `End`
 * on the tablist and nothing else, because core's Tabs block is a horizontal strip
 * and those are the keys the ARIA tabs pattern asks for there. Turning the strip
 * into a column does not change the store — it is registered with `lock: true`, so
 * it cannot be extended — so **`ArrowUp` and `ArrowDown` do nothing on the desktop
 * layout**, where they are the keys a keyboard reader will reach for. Left and
 * Right still move between tabs, and `Tab` still reaches the list, so the block is
 * fully operable; the arrows just do not match the axis they are drawn on.
 *
 * `aria-orientation="vertical"` is deliberately *not* set either. It would be a
 * promise of Up/Down that nothing keeps, and it would be wrong at half the widths
 * anyway — below 72rem this list is a horizontal row, and `aria-orientation` is a
 * static attribute with no media-query equivalent.
 *
 * Closing it means shipping JavaScript: a script module registering a store of its
 * own, with `data-wp-interactive` and `data-wp-on--keydown` added to the tab list by
 * the render filter, mapping Up/Down onto the same focus move. That is a front-end
 * script layer this theme does not have yet — `includes/styles/blocks/` has no JS
 * story at all — so it is left as a decision rather than invented here.
 *
 * The directory: a column, not core's wrapping row.
 *
 * Core's `core/tab-list` declares a flex layout with `flexWrap: wrap` and no way
 * to change either — `allowOrientation` and `allowWrap` are both off in its
 * `supports.layout`. So the orientation is the style's to state, at 0-3-0 against
 * the `.wp-container-core-tab-list-is-layout-*` class core generates at 0-1-0.
 */
.wp-block-tabs.is-style-side-tabs > .wp-block-tab-list {
	flex-direction: column;
	flex-wrap: nowrap;
}

/*
 * A tab.
 *
 * Core's own button CSS is entirely inside `:where()`, which is 0-0-0, so none of
 * it has to be outranked — but it does have to be *replaced*, because what it sets
 * is `display: block` and `width: max-content`, and this is a full-width flex row.
 *
 * The three flex items are the icon (`::before`), the label — an anonymous flex
 * item, because on the front end the label is a bare text node inside the button
 * and in the editor it is core's `RichText` span — and the badge (`::after`). The
 * badge is pushed to the far edge with `margin-inline-start: auto` rather than with
 * `justify-content: space-between`, which would also open a gap between the icon
 * and the label.
 *
 * Typography is the design's SH5: Nure Display, 20px, weight 600, +5% tracking.
 * `font-variation-settings` is stated because the Display cut is an `opsz` value
 * on the same variable font as the Text cut, not a second family — see
 * `assets/css/global/fonts.css`.
 *
 * The inset is `md` (16px) on all four sides, and it is deliberately the same on
 * the tab you are on and the ones you are not. The design draws the selected tab
 * with 16px of padding inside its filled card and the rest with 16px top and
 * bottom only, which leaves their icons 16px to the left of the selected one's —
 * a hairline misalignment in Figma that would be a visible ragged edge in a
 * browser, and a smaller hit area on five of the six tabs.
 */
.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button {
	align-items: center;
	border-radius: var(--wp--preset--border-radius--md);
	color: var(--wp--preset--color--neutral-500);
	display: flex;
	font-family: var(--wp--preset--font-family--body-display);
	font-size: var(--wp--preset--font-size--sh-5);
	font-variation-settings: var(--wp--custom--optical-size--display);
	font-weight: 600;
	gap: var(--wp--preset--spacing--md);
	inline-size: 100%;
	letter-spacing: 0.05em;
	line-height: 1.2;
	padding: var(--wp--preset--spacing--md);
	text-align: start;
}

/*
 * The tab you are on.
 *
 * **`neutral-500` for the rest, where the design has 30% opacity, and that is the
 * one place this file does not reproduce the design.** #1C1C1C at 30% over white
 * is #C8C8C8, which is 1.8:1 against it — a tab label nobody with less than
 * excellent vision can read, and these are controls. `neutral-500` is 4.51:1, the
 * lightest step on the theme's scale that clears AA for 20px text, and it keeps
 * the thing the design is actually doing: a wide gap in weight between the tab you
 * are on and the ones you are not.
 */
.wp-block-tabs.is-style-side-tabs
	.wp-block-tab-list
	button[aria-selected="true"] {
	background-color: var(--wp--preset--color--neutral-50);
	color: var(--wp--preset--color--neutral-900);
}

/*
 * The same look for the first tab, until the block hydrates.
 *
 * Core binds `aria-selected` with the Interactivity API and writes no value into
 * the saved markup, so between first paint and the view module running, *no* tab
 * is selected and the directory has no highlight at all. Every panel is visible in
 * that window too, which is core's no-JavaScript fallback and is the reason it does
 * not simply render the attribute — so the fix is not to add one server-side, it is
 * to say in CSS what the first paint should look like when script is on its way.
 *
 * `:not(:has(button[aria-selected]))` is that condition exactly, and it stops
 * matching the moment the runtime binds the attribute on all of them. In the editor
 * it never matches, because core's `edit` renders `aria-selected` on every button.
 *
 * Inside `@media (scripting: enabled)` for the same reason `accordion.css` gates
 * its collapse: with no script the panels stay open and the tabs are inert, and
 * highlighting one of them would be a lie about what the reader is looking at.
 */
@media (scripting: enabled) {
	.wp-block-tabs.is-style-side-tabs
		.wp-block-tab-list:not(:has(button[aria-selected]))
		button:first-child {
		background-color: var(--wp--preset--color--neutral-50);
		color: var(--wp--preset--color--neutral-900);
	}
}

/*
 * The icon.
 *
 * `background-color` painted through a `mask-image` rather than the SVG itself, so
 * the glyph takes `currentColor` and dims and brightens with the label it belongs
 * to. The icons in `icons/` are stroked in `currentColor`, but a `url()` in
 * `mask-image` is an independent document with no colour to inherit — the mask
 * reads the alpha channel, which a stroke of any colour fills, so the SVG's own
 * colours are simply irrelevant here.
 *
 * **The fallback is a transparent gradient, not `none`.** An unset
 * `--kg-tab-icon` makes `mask-image` invalid at computed-value time, which resolves
 * to `none`, which means *no mask* — and an unmasked box is a solid 24px square of
 * `currentColor`. A mask that is transparent everywhere hides the box instead, and
 * keeps its 24px, so a tab without an icon leaves the slot and the labels down the
 * column stay aligned. That is the intended behaviour for this style rather than a
 * consolation: it is built around a directory where every entry has a glyph.
 *
 * Two of core's declarations have to be undone here, and it is not obvious why:
 * core draws the selected tab's underline on this *same* pseudo-element
 * (`button[aria-selected=true]:before`, with `position: absolute` and
 * `border-bottom: 2px solid`). This style is a filled card, not an underline, so
 * the border goes and the box comes back into flow. `flex: 0 0 1.5rem` pins the
 * main size from `flex-basis` so core's `width: 100%` on that rule cannot matter
 * whichever way the physical/logical cascade falls.
 */
.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button::before {
	background-color: currentcolor;
	block-size: 1.5rem;
	border-block-end: 0;
	content: "";
	flex: 0 0 1.5rem;
	inline-size: 1.5rem;
	mask-image: var(--kg-tab-icon, linear-gradient(#0000, #0000));
	mask-position: center;
	mask-repeat: no-repeat;
	mask-size: contain;
	position: static;
}

/*
 * The count.
 *
 * `content: none` in the base rule is what keeps the badge off the tabs that are
 * not selected — a pseudo-element with `content: none` is not generated at all, so
 * there is no empty pill to hide and nothing to reserve space for. The selected
 * rule then substitutes the property, and its own `none` fallback covers the tab
 * that has nothing to count: a panel with no accordion items gets no badge rather
 * than an empty one, because `includes/blocks/tabs-side-tabs.php` writes no
 * property for it.
 *
 * `sm` (8px) where the design draws a 6px radius. Two pixels on a 6px corner, in
 * exchange for a badge that keeps following the theme's radius scale.
 *
 * **`text-box` is what makes the tab the right height**, which is not obvious for a
 * badge. The design trims this label to its cap height, so the pill is 8 + 8.6 + 8
 * ≈ 25px and the tab around it is 16 + 25 + 16 ≈ 57px — the same height as a tab
 * with no badge, where the 24px icon is the tallest thing in the row. Untrimmed the
 * label keeps its 1.5 line box, the pill grows to 34px, and the selected tab stands
 * 10px taller than every other one.
 */
.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button::after {
	background-color: var(--wp--preset--color--brand-dark-green);
	border-radius: var(--wp--preset--border-radius--sm);
	color: var(--wp--preset--color--white);
	content: none;
	/*
	 * A block and not a flex box, which `text-box` below depends on: a flex
	 * container's text lives in an anonymous item, and the trim has no line box
	 * of its own to work on there. There is nothing to lay out inside a badge
	 * anyway — it is one run of generated text.
	 */
	display: block;
	flex: none;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--sh-4);
	font-variation-settings: var(--wp--custom--optical-size--text);
	font-weight: 600;
	letter-spacing: 0;
	line-height: 1.5;
	margin-inline-start: auto;
	padding: var(--wp--preset--spacing--xs);
	text-box: trim-both cap alphabetic;
	white-space: nowrap;
}

.wp-block-tabs.is-style-side-tabs
	.wp-block-tab-list
	button[aria-selected="true"]::after {
	content: var(--kg-tab-count, none);
}

@media (scripting: enabled) {
	.wp-block-tabs.is-style-side-tabs
		.wp-block-tab-list:not(:has(button[aria-selected]))
		button:first-child::after {
		content: var(--kg-tab-count, none);
	}
}

/*
 * Hover and focus.
 *
 * The design draws neither, and a directory of six controls needs both. Hover
 * brings an unselected tab up to the selected tab's colour — the cheapest possible
 * "this is a control" and no layout movement. `@media (hover: hover)` so a touch
 * device does not leave the last tapped tab looking hovered.
 *
 * The focus ring is the theme's — 2px solid `neutral-900` — turned inwards, for the
 * reason `accordion.css` sets out at length: outward it would have to contrast with
 * whatever section the block is placed on and would spill into the neighbouring
 * tab, since the column has no gap between rows. `-2px` with the card's own radius
 * keeps it concentric with the corner it sits in.
 */
@media (hover: hover) {
	.wp-block-tabs.is-style-side-tabs
		.wp-block-tab-list
		button:not([aria-selected="true"]):hover {
		color: var(--wp--preset--color--neutral-900);
	}
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:focus-visible {
	outline: 2px solid var(--wp--preset--color--neutral-900);
	outline-offset: -2px;
}

@media (prefers-reduced-motion: no-preference) {
	.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button {
		transition:
			background-color 0.2s var(--wp--custom--transition-spring-smooth),
			color 0.2s var(--wp--custom--transition-spring-smooth);
	}
}

/*
 * A swipeable row of chips, below the tablet breakpoint.
 *
 * `width <= 72rem` is `settings.viewport.tablet` in theme.json, the same threshold
 * `media-text.css` stacks at, so a page built from these patterns changes shape
 * once rather than three times on the way down. It is a literal because a media
 * query cannot read a custom property: it has to be changed here **and** in
 * theme.json together.
 *
 * The nav stops being a column and becomes a scroller. `scroll-snap-type: x
 * proximity` rather than `mandatory`, so a half-swipe that the reader meant to
 * leave half-way is left alone, and a chip wider than the viewport can still be
 * scrolled past.
 *
 * **The scrollbar is hidden, and the keyboard is the reason that is defensible.**
 * A row of chips that runs off the edge is its own affordance on touch, where the
 * scrollbar is an overlay that is not painted until you move anyway. What would
 * make hiding it wrong is if scrolling were the only way to reach the tabs off
 * screen — and it is not: core's Interactivity store handles Arrow/Home/End on the
 * tablist and moves focus between tabs, and focusing a chip scrolls it into view.
 */
@media (width <= 72rem) {
	.wp-block-tabs.is-style-side-tabs {
		grid-template-columns: minmax(0, 1fr);

		/*
		 * `3-xl` (32→64px) rather than the `xl` this started as. The row is a
		 * *navigation bar* once it is horizontal, and at 16–32px it sat close
		 * enough to the first Q&A label to read as part of it — the chips and the
		 * answers looked like one stack rather than a control above its content.
		 * It has to beat the `xxl` (48px) gap *between* Q&A groups inside the
		 * panel, or the nav is more tightly bound to the first group than the
		 * groups are to each other.
		 */
		row-gap: var(--wp--preset--spacing--3-xl);
	}

	.wp-block-tabs.is-style-side-tabs > .wp-block-tab-list {
		/*
		 * How far the row reaches past its column on each side.
		 *
		 * **Derived from core's wide-size property, not from `100%`, and that is a
		 * bug fix rather than a preference.** A percentage resolves against a
		 * different box depending on the property it lands in: in `margin` and
		 * `padding` it is the containing block's inline size, but in
		 * `scroll-padding` it is the **scrollport** — which here is the bled row
		 * itself. One `(100vw - 100%) / 2` fed to all three would therefore
		 * compute to the gutter twice and to *zero* once, and the first chip would
		 * snap flush to the window instead of to its column. This expression has
		 * no percentage in it, so all three agree. `term-carousel` lost time to
		 * exactly this; the theme skill has it as a silent failure.
		 *
		 * `max(0px, …)` keeps it sane if the block is ever placed somewhere wider
		 * than the wide size.
		 */
		--kg-side-tabs-bleed: max(
			0px,
			calc((100vw - var(--wp--style--global--wide-size)) / 2)
		);

		flex-direction: row;
		flex-wrap: nowrap;

		/*
		 * The row runs off the edge of the screen rather than stopping at the
		 * column, and that is what stops a chip being **chopped in half in the
		 * middle of the page**: at the column's edge a cut looks like a rendering
		 * fault, at the window's edge it reads as "there is more, swipe". The
		 * negative margins take the scrollport out to the viewport on both sides
		 * and the padding puts the chips back inside the column on both, so the
		 * first chip still starts in line with the text below it and scrolling to
		 * the end brings the last chip to rest on the column's right edge rather
		 * than against the side of the window.
		 *
		 * `scroll-padding-inline-start` repeats the start padding because snapping
		 * measures against the scrollport and not the padding box — without it
		 * every snap lands one gutter to the left of where the chips sit.
		 *
		 * Nothing needs `overflow: clip` on an ancestor for this: `reset.css`
		 * already sets `overflow-x: clip` on the document, so the bleed cannot
		 * raise a horizontal scrollbar on the page.
		 */
		margin-inline: calc(-1 * var(--kg-side-tabs-bleed));
		padding-inline: var(--kg-side-tabs-bleed);
		scroll-padding-inline-start: var(--kg-side-tabs-bleed);

		overflow-x: auto;
		overscroll-behavior-inline: contain;
		scroll-snap-type: x proximity;

		/*
		 * A swipe and the arrow keys are the controls; the design draws no bar,
		 * and on touch the platform's own scrollbar is an overlay that is not
		 * painted until the row moves anyway. What would make hiding it wrong is
		 * if scrolling were the only way to reach a chip off screen — it is not:
		 * core's Interactivity store moves focus with Left/Right/Home/End and
		 * focusing a chip scrolls it into view.
		 */
		scrollbar-width: none;
	}

	.wp-block-tabs.is-style-side-tabs > .wp-block-tab-list::-webkit-scrollbar {
		display: none;
	}

	.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button {
		flex: none;
		inline-size: auto;
		scroll-snap-align: start;
		white-space: nowrap;
	}

	/*
	 * On a chip the badge sits next to the label. `auto` would push it to the
	 * chip's own right edge, which is where it already is.
	 */
	.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button::after {
		margin-inline-start: 0;
	}
}

/*
 * Index → button.
 *
 * The icon and the count arrive as `--kg-tab-icon-N` / `--kg-tab-count-N` on the
 * `.wp-block-tabs` wrapper, because that is the one element both halves of this
 * feature can reach: PHP has the whole block tree there, and the editor's
 * `editor.BlockListBlock` filter can only decorate a block's own wrapper. Handing
 * each button its pair is therefore a mapping CSS has to spell out, one rule per
 * position.
 *
 * **Twelve is the cap, and past it a tab keeps its label and loses its icon and
 * count.** Nothing breaks — the `mask-image` and `content` fallbacks above are
 * exactly this case — but nothing appears either, and the PHP stops writing
 * properties at the same number so the two do not disagree. Twelve is well past
 * the point where a 340px directory has stopped being readable; raising it means
 * adding rules here and raising `MAX_TABS` in
 * `includes/blocks/tabs-side-tabs.php`.
 *
 * `sibling-index()` would collapse the whole block into one rule and is too new to
 * rely on.
 */
.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(1) {
	--kg-tab-count: var(--kg-tab-count-1);
	--kg-tab-icon: var(--kg-tab-icon-1);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(2) {
	--kg-tab-count: var(--kg-tab-count-2);
	--kg-tab-icon: var(--kg-tab-icon-2);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(3) {
	--kg-tab-count: var(--kg-tab-count-3);
	--kg-tab-icon: var(--kg-tab-icon-3);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(4) {
	--kg-tab-count: var(--kg-tab-count-4);
	--kg-tab-icon: var(--kg-tab-icon-4);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(5) {
	--kg-tab-count: var(--kg-tab-count-5);
	--kg-tab-icon: var(--kg-tab-icon-5);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(6) {
	--kg-tab-count: var(--kg-tab-count-6);
	--kg-tab-icon: var(--kg-tab-icon-6);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(7) {
	--kg-tab-count: var(--kg-tab-count-7);
	--kg-tab-icon: var(--kg-tab-icon-7);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(8) {
	--kg-tab-count: var(--kg-tab-count-8);
	--kg-tab-icon: var(--kg-tab-icon-8);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(9) {
	--kg-tab-count: var(--kg-tab-count-9);
	--kg-tab-icon: var(--kg-tab-icon-9);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(10) {
	--kg-tab-count: var(--kg-tab-count-10);
	--kg-tab-icon: var(--kg-tab-icon-10);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(11) {
	--kg-tab-count: var(--kg-tab-count-11);
	--kg-tab-icon: var(--kg-tab-icon-11);
}

.wp-block-tabs.is-style-side-tabs .wp-block-tab-list button:nth-child(12) {
	--kg-tab-count: var(--kg-tab-count-12);
	--kg-tab-icon: var(--kg-tab-icon-12);
}
