/* 2026-10-13: role surfaces supersede the historic mint mappings discussed below.
 * White helpers, paper gifts, dark closing actions; mint only for signed Diana quotes.
 */
/*
 * The FAQ page.
 *
 * The fourth per-page stylesheet, enqueued only where it is used (plan section
 * 1.1, engineering standards section 7). It loads after components.css and may
 * build on both it and tokens.css; like the other three it declares no colour of
 * its own.
 *
 * ONE WIDTH FOR THE WHOLE PAGE. The mockup caps every band at 880 px rather than
 * the site's 1100 px grid, so .duk-band overrides .container's max-width once and
 * every section on the page uses it. That is a second WIDTH, not a second grid:
 * 880 is one of the narrow reading widths the measurer knows (canon.mjs
 * NARROW_MAX_WIDTHS), and because every band shares it their edges line up
 * exactly as invariant I11.1 requires. The header and the footer keep 1100.
 *
 * MOBILE FIRST WITH NO BREAKPOINT OF OUR OWN. The layout is one column of cards
 * at every width; the only things that change are clamped type and clamped
 * padding, which the mockup already expresses as clamps. A media query here
 * would move a boundary the design does not have.
 *
 * WHAT WAS SNAPPED TO THE CANON, each written down rather than quietly rounded:
 *
 *   THREE TOUCH TARGETS. Measured in the mockup at 390 px: the search field is
 *   38 px tall, its clear button 36x36, and a category pill 42 px. All three are
 *   under the 44 px floor invariant I8.2 fixes, so all three get a min-height
 *   here. Measured cost: the search pill grows from 52 px to 58 and each
 *   category pill from 42 to 44. The alternative is a phone-first page whose own
 *   phone controls miss. Filed as a finding against the mockup rather than fixed
 *   silently.
 *
 *   RADII. Three bands only - 12-16 for icon boxes, 20-28 for cards, 999 for
 *   pills - enforced as qa-tokens T4. This mockup stays inside them everywhere;
 *   the one place it did not was the quiz bar, whose radius WPS-019 corrected
 *   on the way in rather than transferring as drawn (see components.css, "The
 *   quiz band" - its rules live there rather than here because the same bar
 *   is drawn a second time on Kainos.dc.html).
 *
 *   SHADOWS. The mockup casts `0 2px 8px rgba(23,28,33,0.05)` under the answer
 *   cards and the search pill. The palette has --shadow-soft at the same
 *   geometry and a slightly firmer alpha (0.08) and --shadow-hairline at the
 *   same alpha and a softer blur (10px). --shadow-soft is the one taken: the
 *   offset and the blur are what an eye reads as a lift, and three hundredths of
 *   alpha under a white card on the page's near-white canvas is not visible.
 *
 *   THREE COLOURS THE MOCKUP INVENTS. Its call-to-action lead is painted in a
 *   dark green that is in neither the design system nor the palette - a second
 *   value for a role --color-mint-ink already names - and its two hover washes,
 *   under an answer row and under the search clear button, are unnamed in the
 *   same way. All three take the palette member nearest their role
 *   (--color-mint-ink, --color-bg, --color-fill), which is exactly how finding
 *   AS-97 settled the same question for the front page's lighter mint: the theme
 *   uses what the palette has and whether the system should grow a token stays
 *   Andrius's decision. Both greens clear the contrast floor on mint, so nothing
 *   is traded here but a shade. The values themselves are in the audit register
 *   under AS-116 rather than repeated here, because a hex spelled out in a
 *   comment is still a colour that left tokens.css (qa-grep G4).
 *
 * WHAT THE STYLESHEET DELIBERATELY DOES NOT DO. It never hides an answer with
 * `display: none`. A collapsed answer is closed with grid-template-rows plus
 * `visibility`, which is what takes it out of the accessibility tree - the half
 * of finding AS-57 that a height alone does not fix, and the reason a screen
 * reader on the old screen read all eighteen answers in a row.
 */

/* ---------------------------------------------------------------------------
 * The shared band
 */

.duk-band {
	max-width: 880px;
}

/* ---------------------------------------------------------------------------
 * Hero
 *
 * The gap is the mockup's 14 px. The spacing scale steps 12 -> 16 around it and
 * neither reads correctly here: 12 pulls the lead into the heading, 16 pushes
 * the search box away from the sentence that explains it.
 */

.duk-hero {
	display: flex;
	flex-direction: column;
	padding-block: clamp( 28px, 5vw, 60px ) clamp( 20px, 3vw, 32px );
	gap: 14px;
}

.duk-hero__eyebrow {
	margin: 0;
}

/*
 * Smaller than the shared h1 - clamp( 36px, 5.4vw, 56px ) - because this page's
 * heading sits above a search box rather than carrying the first screen on its
 * own, and the mockup sizes it for that. The type scale is unchanged; only this
 * heading's clamp is.
 */
.duk-hero__title {
	margin: 0;
	font-size: clamp( 32px, 5vw, 50px );
}

.duk-hero__lead {
	max-width: 620px;
	margin: 0;
	color: var( --text-body );
	font-size: clamp( 16px, 2vw, 19px );
	line-height: var( --lh-body );
}

/* ---------------------------------------------------------------------------
 * Search
 *
 * Printed hidden and revealed by main.js: the filter is client-side, so a field
 * that appeared without scripting would take a query and do nothing with it.
 */

.duk-search {
	display: flex;
	align-items: center;
	margin-top: clamp( 10px, 1.5vw, 18px );
	padding: 6px 8px 6px 20px;
	background: var( --surface-card );
	border: 1px solid var( --border-control );
	border-radius: var( --radius-pill );
	box-shadow: var( --shadow-soft );
	gap: var( --space-3 );
}

/* The display above would otherwise beat the hidden attribute's own display:
 * none, and a visitor with no scripting would be handed a search box that
 * cannot search. The theme hits this trap wherever a flex element is printed
 * hidden - the photo viewer and the courses toggle carry the same two lines. */
.duk-search[hidden] {
	display: none;
}

/* Scripted: keep the field's space from the first paint (see sypsena_mark_scripted_document). */
.sypsena-js .duk-search[hidden] {
	display: flex;
	visibility: hidden;
}

.duk-search__icon {
	flex: 0 0 auto;
	color: var( --text-meta );
	font-size: 24px;
}

/*
 * min-height rather than more padding: the field is a flex child, so a height
 * floor is the one declaration that cannot be undone by the row growing or
 * shrinking around it. 38 px in the mockup, 44 here (invariant I8.2).
 */
.duk-search__field {
	flex: 1;
	min-width: 0;
	min-height: 44px;
	padding: 0;
	background: transparent;
	border: 0;
	color: var( --text-heading );
	font-family: inherit;
	font-size: clamp( 15px, 1.8vw, 16px );
}

.duk-search__field:focus {
	outline: none;
}

/* The ring belongs on the whole pill: the field has no border of its own, so a
 * ring drawn around it would appear inside a control the eye reads as one. */
.duk-search:focus-within {
	outline: 3px solid var( --focus-ring );
	outline-offset: 2px;
}

/* Browsers paint a placeholder in their own grey. --text-meta measures 5.65:1
 * on white; the default does not clear the floor everywhere. */
.duk-search__field::placeholder {
	color: var( --text-meta );
	opacity: 1;
}

/* The engine's own clear affordance would sit beside ours. */
.duk-search__field::-webkit-search-cancel-button {
	appearance: none;
}

.duk-search__clear {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	background: var( --tint-mist );
	border: 0;
	border-radius: 50%;
	color: var( --text-body );
	cursor: pointer;
	transition: background var( --dur ) var( --ease );
}

/* Same trap: without this the clear button stands in the field before anything
 * has been typed. */
.duk-search__clear[hidden] {
	display: none;
}

.duk-search__clear:hover {
	background: var( --color-fill );
}

.duk-search__clear .material-symbols-outlined {
	font-size: 20px;
}

.duk-search__result {
	margin: 12px 0 0;
	padding-left: 6px;
	color: var( --text-meta );
	font-size: var( --fs-caption );
}

/* ---------------------------------------------------------------------------
 * Category pills
 *
 * Plain anchors to the groups below, so they work with no scripting at all.
 * min-height for the same reason as the search field: 42 px in the mockup.
 */

.duk-nav {
	display: flex;
	flex-wrap: wrap;
	margin-top: clamp( 14px, 2vw, 20px );
	gap: 10px;
}

/* Same trap once more: the pills are hidden while a search is running, because
 * some of the groups they jump to are not on the page then. */
.duk-nav[hidden] {
	display: none;
}

.duk-nav__pill {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 9px 16px;
	background: var( --surface-card );
	border: 1px solid var( --border-hairline );
	border-radius: var( --radius-pill );
	color: var( --text-body );
	font-size: var( --fs-caption );
	font-weight: var( --fw-bold );
	text-decoration: none;
	gap: 7px;
	transition:
		border-color var( --dur ) var( --ease ),
		color var( --dur ) var( --ease );
}

.duk-nav__pill:hover {
	border-color: var( --color-accent );
	color: var( --text-link );
}

.duk-nav__pill .material-symbols-outlined {
	color: var( --text-link );
	font-size: 18px;
}

/* ---------------------------------------------------------------------------
 * Nothing found
 */

.duk-empty {
	margin-bottom: clamp( 28px, 4vw, 44px );
	padding-block: clamp( 8px, 1.5vw, 16px ) 0;
}

.duk-empty__card {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: clamp( 28px, 4vw, 44px );
	background: var( --surface-card );
	border: 1px solid var( --border-hairline );
	border-radius: var( --radius-lg );
	gap: var( --space-3 );
	text-align: center;
}

.duk-empty__icon {
	color: var( --tint-icon-muted );
	font-size: 44px;
}

.duk-empty__title {
	margin: 0;
	color: var( --text-heading );
	font-size: 19px;
	font-weight: var( --fw-black );
}

.duk-empty__text {
	max-width: 460px;
	margin: 0;
	color: var( --text-meta );
	font-size: var( --fs-sm );
	line-height: var( --lh-body );
}

.duk-empty__cta {
	margin-top: 6px;
}

.duk-empty__cta .material-symbols-outlined {
	font-size: 18px;
}

/* ---------------------------------------------------------------------------
 * A category and its questions
 */

.duk-groups {
	padding-top: clamp( 12px, 2vw, 20px );
}

.duk-group {
	padding-block: 0 clamp( 28px, 4vw, 44px );
	/* The category pills jump here, and the header is sticky. */
	scroll-margin-top: 92px;
}

.duk-group__head {
	display: flex;
	align-items: center;
	margin-bottom: clamp( 14px, 2vw, 20px );
	gap: 14px;
}

.duk-group__icon {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	margin: 0;
	background: var( --tint-ice );
	border-radius: 50%;
	color: var( --color-accent-text );
}

.duk-group__icon .material-symbols-outlined {
	font-size: 24px;
}

/*
 * Smaller than the shared h2 - clamp( 26px, 3.6vw, 38px ) - for the reason the
 * mockup gives it: this heading names a group inside the page rather than
 * opening a section of its own, and it sits in a row beside a 46 px icon.
 */
.duk-group__title {
	margin: 0;
	font-size: clamp( 22px, 3vw, 30px );
	letter-spacing: -0.01em;
}

/* line-height: normal because this is a badge, not a paragraph. Left to inherit
 * --lh-body it measures 30.8 px against the mockup's 26 - the same difference
 * WPS-022 found under its step labels, and a one-line badge is the case where
 * the body's leading has nothing to lead. */
.duk-group__count {
	flex: 0 0 auto;
	margin: 0 0 0 auto;
	padding: 5px 12px;
	background: var( --tint-panel );
	border-radius: var( --radius-pill );
	color: var( --text-meta );
	font-size: var( --fs-meta );
	font-weight: var( --fw-bold );
	line-height: normal;
}

.duk-group__items {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

/* ---------------------------------------------------------------------------
 * One question
 *
 * overflow: hidden so the answer cannot paint outside the card's rounded
 * corners while it is animating open.
 */

.duk-item {
	overflow: hidden;
	background: var( --surface-card );
	border-radius: var( --radius-md );
	box-shadow: var( --shadow-soft );
	/*
	 * main.js scrolls the whole card into view when a link names one of its
	 * answers (/duk/#duk-answer-s4 from the articles, WPS-056). base.css
	 * already keeps scroll targets under the sticky header with
	 * scroll-padding-top; this is the small breathing space on top of it, so
	 * the card's rounded edge is not glued to the header's shadow. The two
	 * add up (I-anchor lesson from WPS-023), which is why this one is small.
	 */
	scroll-margin-top: var( --space-3 );
}

/*
 * The question carries the padding until main.js turns it into a button, and
 * hands it over once it has: the whole row has to be clickable, and a button
 * inside a padded heading would leave a dead border around the control.
 * [data-duk-ready] is set on the wrapper once, so both states are described in
 * one place rather than by a class on each of eighteen cards.
 */
.duk-item__question {
	margin: 0;
	padding: clamp( 16px, 2.2vw, 20px ) clamp( 18px, 2.4vw, 24px );
	color: var( --text-heading );
	font-size: clamp( 15.5px, 1.9vw, 17px );
	font-weight: var( --fw-bold );
	line-height: 1.4;
	text-wrap: pretty;
}

[data-duk-ready] .duk-item__question {
	padding: 0;
}

.duk-item__toggle {
	display: flex;
	align-items: center;
	width: 100%;
	padding: clamp( 16px, 2.2vw, 20px ) clamp( 18px, 2.4vw, 24px );
	background: transparent;
	border: 0;
	color: inherit;
	font: inherit;
	text-align: left;
	gap: var( --space-4 );
	cursor: pointer;
	transition: background var( --dur ) var( --ease );
}

/*
 * --tint-ice, not --color-bg. The hover used to be --color-bg, which IS the
 * page background: hovering a white card turned it exactly the colour of the
 * page behind it, so the row appeared to dissolve rather than respond
 * (Andrius on dev, 2026-08-29). A hover state has to differ from BOTH the
 * resting surface and the page, and the accent wash is the one already in the
 * palette that does.
 */
.duk-item__toggle:hover {
	background: var( --tint-ice );
}

/*
 * The focus ring is drawn INSIDE the button, and that is not a preference.
 *
 * The button fills its card exactly - same x, same y, same width, same height,
 * measured - and the card clips with overflow: hidden so the answer cannot
 * paint outside its rounded corners. The shared ring in base.css sits at
 * outline-offset: 2px, i.e. entirely outside that box, so the card clipped it
 * away: keyboard focus on the page's eighteen primary controls painted ZERO
 * pixels. Measured by counting accent-coloured pixels around the focused
 * button - 0 as it stood, 2604 with the clip lifted, 2258 with this rule.
 *
 * qa-a11y cannot see this and says so: A15.2 asserts that a :focus-visible rule
 * EXISTS somewhere in the stylesheets, never that it survives to the screen.
 */
.duk-item__toggle:focus-visible {
	outline-offset: -3px;
}

/*
 * prefers-reduced-motion, the half base.css cannot reach.
 *
 * That file zeroes transition-DURATION for everything, which is the right rule
 * and not enough here: the answer's visibility is switched by a transition
 * DELAY, so a visitor who asked for no motion still kept a collapsed answer in
 * the accessibility tree for the length of an animation that is not running.
 * Measured: visibility stayed "visible" for 339 ms after the collapse.
 */
@media ( prefers-reduced-motion: reduce ) {
	.duk-item__answer,
	.duk-item__answer[data-collapsed="false"] {
		transition-delay: 0s;
	}
}

.duk-item__label {
	flex: 1;
}

.duk-item__chevron {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	background: var( --tint-panel );
	border-radius: 50%;
	color: var( --text-body );
	transition:
		background var( --dur ) var( --ease ),
		color var( --dur ) var( --ease );
}

.duk-item__chevron .material-symbols-outlined {
	font-size: 20px;
}

.duk-item__toggle[aria-expanded="true"] .duk-item__chevron {
	background: var( --color-accent );
	color: var( --color-surface );
}

/*
 * The collapse.
 *
 * grid-template-rows between 1fr and 0fr rather than the mockup's
 * `max-height: 640px`: finding AS-78 measured the tallest answer at 233 px and
 * wrote down that the cap is a trap - the first answer that outgrows it would be
 * cut off with no warning anywhere. A row that resolves to the content's own
 * height has no such number in it.
 *
 * `visibility` is the half that matters to a screen reader: a row of zero height
 * still holds readable text and focusable links, so without it a collapsed
 * accordion reads out in full. It is delayed on the way closed so the animation
 * is still visible, and immediate on the way open.
 *
 * WHICH state is the default is decided by the media query below, not here, and
 * for a measured reason: see the block under these rules.
 */

.duk-item__answer {
	display: grid;
	grid-template-rows: 0fr;
	opacity: 0;
	visibility: hidden;
	transition:
		grid-template-rows 0.3s var( --ease ),
		opacity var( --dur ) var( --ease ),
		visibility 0s linear 0.3s;
}

.duk-item__answer[data-collapsed="false"] {
	grid-template-rows: 1fr;
	opacity: 1;
	visibility: visible;
	transition:
		grid-template-rows 0.3s var( --ease ),
		opacity var( --dur ) var( --ease ),
		visibility 0s;
}

/*
 * WHICH STATE IS THE DEFAULT, and why the browser decides rather than the
 * server.
 *
 * Closed has to be the state the first paint shows: main.js cannot run before
 * the browser has painted, so a page that arrives open spends its first moment
 * folding eighteen answers shut. That is not a matter of taste - it was
 * measured. Open by default scored a CLS of 0.114 with the collapse animated
 * and 0.088-0.101 with it suppressed, against 0.0047 on the About page, and
 * Google's threshold for "good" is 0.1. Cumulative Layout Shift is a ranking
 * signal and this page is 51 % of the site's search traffic, so a page that
 * straddles the threshold is not one to ship.
 *
 * Readable has to be the state a visitor without scripting sees, because
 * nothing else on the page can show them an answer. `scripting: none` is the
 * one mechanism that answers both: the browser tells the stylesheet whether the
 * control will ever exist, before any script has run. Measured rather than
 * assumed - the behaviour check drives this branch with scripting switched off
 * and counts eighteen readable answers.
 *
 * TWO LIMITS, stated rather than hidden. A browser that runs scripts but never
 * receives main.js keeps eighteen closed answers with no way to open them; that
 * is a broken deployment rather than a visitor's configuration, it breaks the
 * burger menu on every other page at the same time, and qa-console gates every
 * pull request on zero failed requests in both environments. And a browser too
 * old to know the `scripting` feature at all (before Firefox 113, Safari 17 or
 * Chrome 120) never matches the query, so scripting switched off there lands in
 * the same place. In both cases the answers are still in the document and in the
 * FAQPage JSON-LD, which is what a search engine reads.
 */
@media ( scripting: none ) {
	.duk-item__answer {
		grid-template-rows: 1fr;
		opacity: 1;
		visibility: visible;
	}
}

/* The clipped element, and the reason it carries no padding: padding sits
 * outside the content box a zero-height row sizes, so it would survive the
 * collapse and leave every closed card its own bottom padding taller - the
 * 16-20 px this file gives .duk-item__answer-body. */
.duk-item__answer-clip {
	min-height: 0;
	overflow: hidden;
}

.duk-item__answer-body {
	padding: 0 clamp( 18px, 2.4vw, 24px ) clamp( 16px, 2.2vw, 20px );
	color: var( --text-body );
	font-size: clamp( 14.5px, 1.7vw, 15.5px );
	line-height: 1.66;
	text-wrap: pretty;
}

.duk-item__answer-body > p {
	margin: 0 0 16px;
}

.duk-item__answer-body h4 {
	margin: 20px 0 8px;
	color: var( --text-heading );
	font-size: clamp( 16px, 1.9vw, 18px );
	font-weight: var( --fw-bold );
	line-height: 1.3;
}

.duk-item__answer-body > h4:first-child {
	margin-top: 0;
}

/* The answer is rendered through wpautop (sypsena_duk_render_answer), so its
 * paragraphs carry the shared bottom margin. The last one would push the card
 * open past its own padding. */
.duk-item__answer-body > :last-child {
	margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
 * Closing call to action
 */

.duk-cta {
	padding-block: clamp( 20px, 3vw, 32px ) clamp( 48px, 7vw, 80px );
}

.duk-cta__panel {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: clamp( 28px, 4vw, 48px );
	background: var( --surface-inverse );
	border-radius: clamp( 20px, 2.5vw, 28px );
	gap: var( --space-4 );
	text-align: center;

	color: var( --color-surface );
}

.duk-cta__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	margin: 0;
	background: var( --text-body );
	border-radius: 50%;
	color: var( --color-surface );
}

.duk-cta__icon .material-symbols-outlined {
	font-size: 30px;
}

.duk-cta__title {
	margin: 0;
	font-size: clamp( 24px, 3.4vw, 34px );
	letter-spacing: -0.01em;
	line-height: 1.14;

	color: var( --color-surface );
}

/* See the note at the top of the file: the mockup's own green has no token. */
.duk-cta__lead {
	max-width: 540px;
	margin: 0;
	color: var( --color-surface );
	font-size: clamp( 15px, 1.9vw, 17px );
	line-height: var( --lh-body );

	opacity: 0.75;
}

.duk-cta__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	margin: var( --space-1 ) 0 0;
	gap: var( --space-3 );
}

/*
 * Both buttons are .btn, so the pill shape, the 44 px floor and the transition
 * stay shared; only the padding and the colours are local. .btn--lg would put
 * them at 57.6 px against the mockup's 52; the mockup's own padding brings them
 * to 54, and the two remaining pixels are the shared line-height, which is not
 * worth forking a component over. .btn--primary would hover into the accent
 * blue, and on a mint panel the mockup hovers into the panel's own dark green
 * instead - white on it measures 6.59:1.
 */
.duk-cta__primary,
.duk-cta__secondary {
	padding: 14px 30px;
}

.duk-cta__primary {
	background: transparent;
	color: var( --color-surface );

	border-color: var( --text-meta );
}

.duk-cta__primary:hover {
	background: var( --surface-card );

	color: var( --text-heading );
}

/*
 * Not .btn--secondary: that variant carries a hairline border, and on mint the
 * mockup draws none. .btn's own transparent border keeps the two buttons the
 * same height.
 */
.duk-cta__secondary {
	background: var( --surface-card );
	color: var( --text-heading );
}

.duk-cta__secondary:hover {
	color: var( --text-link );
}

.duk-cta__primary .material-symbols-outlined {
	font-size: 20px;
}

.duk-cta__secondary .material-symbols-outlined {
	font-size: 18px;
}
