/**
 * Signal Tunnel — base stylesheet.
 *
 * Reset + base element styles + the shared components every future
 * section is built from (icon, button, card, badge, section-label, the
 * Signal Chevron, link-arrow) + a small utility layer. No framework, no
 * build step: hand-rolled CSS custom properties from tokens.css,
 * BEM-ish class names.
 *
 * Load order (see inc/enqueue.php): fonts.css -> tokens.css -> main.css.
 * Nothing in this file hardcodes a color, size, or duration — everything
 * reads from a token. If a future section needs a value that isn't a
 * token yet, add the token to tokens.css (and inc/design-tokens.php)
 * rather than hardcoding it here.
 */

/* =========================================================
   1. Reset & base
   ========================================================= */

*,
*::before,
*::after {
	box-sizing: border-box;
}

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	scroll-behavior: smooth;
	overflow-x: hidden;
	/* Sitewide text bump — every --fs-* step in tokens.css is rem-based, so
	   raising the root size scales all of them proportionally instead of
	   editing each token individually. */
	font-size: 107.5%;
}

body {
	background: var(--color-bg);
	color: var(--color-text);
	font-family: var(--font-body);
	font-size: var(--fs-base);
	line-height: var(--lh-base);
	letter-spacing: var(--ls-base);
	font-weight: var(--fw-regular);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	min-height: 100vh;
	overflow-x: hidden;
}

img,
picture,
svg,
video {
	display: block;
	max-width: 100%;
}

h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-display);
	color: var(--color-text);
	font-weight: var(--fw-semibold);
	overflow-wrap: break-word; /* safety net for a single long/compound word at the 320px viewport floor — normal wrapping between words is always preferred and unaffected */
}

/* Uppercase is opt-in (.text-uppercase), not a global heading default —
   Oswald's condensed caps suit a short hero H1 or section title, but
   forcing every heading uppercase sitewide would hurt readability the
   moment a longer blog H2 or FAQ answer heading runs through this same
   base rule. Future sections judge case-by-case which headings earn it. */
.text-uppercase {
	text-transform: uppercase;
}

h1 { font-size: var(--fs-5xl); line-height: var(--lh-5xl); letter-spacing: var(--ls-5xl); font-weight: var(--fw-black); }
h2 { font-size: var(--fs-4xl); line-height: var(--lh-4xl); letter-spacing: var(--ls-4xl); font-weight: var(--fw-black); }
h3 { font-size: var(--fs-3xl); line-height: var(--lh-3xl); letter-spacing: var(--ls-3xl); }
h4 { font-size: var(--fs-2xl); line-height: var(--lh-2xl); letter-spacing: var(--ls-2xl); }
h5 { font-size: var(--fs-xl);  line-height: var(--lh-xl);  letter-spacing: var(--ls-xl); }
h6 { font-size: var(--fs-lg);  line-height: var(--lh-lg);  letter-spacing: var(--ls-lg); }

p {
	color: var(--color-text-muted);
}

a {
	color: var(--color-accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.15em;
}

a:hover {
	color: var(--color-accent-strong);
}

button,
input,
select,
textarea {
	font: inherit;
	color: inherit;
}

/* Single, consistent focus style for every interactive element — visible
   only for keyboard users, never on mouse/touch click. Square-ish offset
   (radius-sm, not a soft pill) so even the focus ring stays on-brand. */
:focus {
	outline: none;
}

:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

::selection {
	background: var(--color-accent);
	color: var(--color-accent-ink);
}

/* Global motion safety net. Component-level animations (the Signal
   Chevron's snap-flash, etc.) still define their own prefers-reduced-motion
   override below so they stop *entirely* rather than just running
   near-instantly. */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* =========================================================
   2. Layout utilities
   ========================================================= */

.container {
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--container-padding-inline);
}

.container--reading {
	max-width: var(--container-reading);
}

.section {
	padding-block: var(--space-section-y);
}

/* Paints the light-section token override (tokens.css) onto the section
   itself — .section--light only redefines the --color-* custom properties,
   it doesn't paint anything on its own. Children never set their own
   background/color from these tokens explicitly (they inherit `color` or
   use var(--color-surface) etc. per-component), so this is the one place
   that needs an explicit declaration. */
.section--light {
	background: var(--color-bg);
	color: var(--color-text);
}

/* .section--dark's own paint — same reasoning as .section--light above,
   see tokens.css for why a "reassert dark" utility exists at all (secondary
   pages default to a light body now; this opts specific bands, like
   .page-header, back out). */
.section--dark {
	background: var(--color-bg);
	color: var(--color-text);
}

/* top/left: 0 pins this to a fixed hypothetical position instead of
   leaving it to the browser default (the position it WOULD have had in
   normal flow). That default becomes a real bug inside a non-wrapping
   flex row that scrolls horizontally (trust-bar.php's carousel,
   testimonials.php's peek carousel, both intentional UI, not the bug):
   without top/left set, a visually-hidden span's hypothetical position
   sits whatever far-right x-coordinate its unwrapped flex item would
   occupy, and since nothing between it and <html> establishes a
   containing block that also clips, that off-screen-but-geometrically-
   real box was inflating document.documentElement.scrollWidth site-wide
   — the actual source of the horizontal-overflow/responsive bug, not the
   nav bar itself (nothing in header.css/header.js needed to change). */
.visually-hidden {
	position: absolute;
	top: 0;
	left: 0;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* WordPress core hardcodes this exact class name in several of its own
   default markup generators (get_the_posts_pagination()'s heading,
   comment_form(), the default search form) — same visual treatment as
   .visually-hidden above, so core-generated markup never needs extra
   wrapping just to hide its own screen-reader-only headings. */
.screen-reader-text {
	position: absolute;
	top: 0;
	left: 0;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* =========================================================
   3. Component — Icon
   Every get_icon() call outputs <svg class="icon icon--{name}"><use
   href="#icon-{name}"></use></svg>, referencing a <symbol> in the
   self-hosted sprite (assets/icons/sprite.svg). Those symbols are bare
   stroke-based shapes with no fill/stroke of their own — they inherit
   color via currentColor, so set `color` in CSS on the .icon element.
   ========================================================= */

.icon {
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* =========================================================
   4. Component — Button
   SHARP corners: --radius-md tops out at 3px, deliberately far from a
   typical 8-12px "app button" — this reads as a broadcast-graphics
   control, not a soft UI chrome element.
   ========================================================= */

.btn {
	--btn-fill: transparent;
	--btn-fill-hover: transparent;
	--btn-fill-active: transparent;
	--btn-ink: var(--color-text);
	--btn-border: transparent;

	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	border: 1px solid var(--btn-border);
	border-radius: var(--radius-md);
	background: var(--btn-fill);
	color: var(--btn-ink);
	font-family: var(--font-display);
	font-weight: var(--fw-semibold);
	text-transform: uppercase;
	letter-spacing: var(--ls-eyebrow);
	line-height: 1;
	white-space: nowrap;
	cursor: pointer;
	text-decoration: none;
	transition: background-color var(--duration-base) var(--ease-standard),
		border-color var(--duration-base) var(--ease-standard),
		color var(--duration-base) var(--ease-standard),
		box-shadow var(--duration-base) var(--ease-standard),
		transform var(--duration-fast) var(--ease-standard);
}

.btn:hover {
	background: var(--btn-fill-hover);
	color: var(--btn-ink);
}

.btn:active {
	background: var(--btn-fill-active);
	transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
	opacity: 0.45;
	cursor: not-allowed;
	transform: none;
}

/* Sizes. min-height on sm/md guarantees the 44x44px minimum touch target
   (WCAG 2.5.5/2.5.8) even though their padding+line-height alone computes
   a couple px short — .btn--lg already clears 44px without help. Content
   stays vertically centered (align-items:center on .btn above), so this
   only adds tap-area, never changes the visible padding/type. */
.btn--sm { padding: var(--space-2) var(--space-4); font-size: var(--fs-sm); min-height: 2.75rem; }
.btn--md { padding: var(--space-3) var(--space-5); font-size: var(--fs-base); min-height: 2.75rem; }
.btn--lg { padding: var(--space-4) var(--space-6); font-size: var(--fs-md); }

/* Primary — accent fill. Dark ink, never --color-text (see tokens.css
   contrast notes: light text on cobalt fails AA at every step of the ramp). */
.btn--primary {
	--btn-fill: var(--color-accent);
	--btn-fill-hover: var(--color-accent-strong);
	--btn-fill-active: var(--color-accent-dim);
	--btn-ink: var(--color-accent-ink);
}

.btn--primary:hover:not(:disabled) {
	box-shadow: var(--shadow-accent-glow);
}

/* Secondary — outline/ghost. */
.btn--secondary {
	--btn-fill: transparent;
	--btn-fill-hover: var(--color-surface-2);
	--btn-fill-active: var(--color-surface);
	--btn-ink: var(--color-text);
	--btn-border: var(--color-border-strong);
}

.btn--secondary:hover:not(:disabled) {
	--btn-border: var(--color-accent);
	color: var(--color-accent);
}

/* =========================================================
   5. Component — Card
   SHARP corners: --radius-lg is 4px, not the 12-16px "soft glass panel"
   Midnight Broadcast uses.
   ========================================================= */

.card {
	background: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	padding: var(--space-6);
	transition: transform var(--duration-base) var(--ease-standard),
		box-shadow var(--duration-base) var(--ease-standard),
		border-color var(--duration-base) var(--ease-standard);
}

.card--hover {
	cursor: pointer;
}

.card--hover:hover,
.card--hover:focus-visible {
	transform: translateY(-4px);
	border-color: var(--color-border-strong);
	box-shadow: var(--shadow-lg);
}

/* =========================================================
   6. Component — Badge / pill
   Deliberately the ONE place this system keeps a soft, fully-rounded
   shape (--radius-full) — a small pill reads as a status chip regardless
   of corner treatment, and forcing it sharp would hurt legibility of
   short badge text for no brand benefit. Buttons and cards stay sharp.
   ========================================================= */

.badge {
	--badge-fill: var(--color-surface-2);
	--badge-ink: var(--color-text-muted);
	--badge-border: var(--color-border);

	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
	padding: var(--space-1) var(--space-3);
	border: 1px solid var(--badge-border);
	border-radius: var(--radius-full);
	background: var(--badge-fill);
	color: var(--badge-ink);
	font-size: var(--fs-xs);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	line-height: 1.4;
	white-space: nowrap;
}

.badge--accent {
	--badge-fill: color-mix(in srgb, var(--color-accent) 16%, transparent);
	--badge-ink: var(--color-accent-strong);
	--badge-border: color-mix(in srgb, var(--color-accent) 40%, transparent);
}

.badge--success {
	--badge-fill: color-mix(in srgb, var(--color-success) 16%, transparent);
	--badge-ink: var(--color-success);
	--badge-border: color-mix(in srgb, var(--color-success) 40%, transparent);
}

.badge--warning {
	--badge-fill: color-mix(in srgb, var(--color-warning) 16%, transparent);
	--badge-ink: var(--color-warning);
	--badge-border: color-mix(in srgb, var(--color-warning) 40%, transparent);
}

.badge--error {
	--badge-fill: color-mix(in srgb, var(--color-error) 16%, transparent);
	--badge-ink: var(--color-error);
	--badge-border: color-mix(in srgb, var(--color-error) 40%, transparent);
}

.badge--info {
	--badge-fill: color-mix(in srgb, var(--color-info) 16%, transparent);
	--badge-ink: var(--color-info);
	--badge-border: color-mix(in srgb, var(--color-info) 40%, transparent);
}

/* Live badge pairs naturally with the Signal Chevron, e.g.:
   <span class="badge badge--live"><?php get_template_part(...signal-chevron...); ?> En direct</span> */
.badge--live {
	--badge-fill: color-mix(in srgb, var(--color-accent) 12%, transparent);
	--badge-ink: var(--color-accent-strong);
	--badge-border: color-mix(in srgb, var(--color-accent) 35%, transparent);
}

/* =========================================================
   7. Component — Section label (eyebrow + Signal Chevron)
   ========================================================= */

.section-label {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	margin-bottom: var(--space-4);
	color: var(--color-accent);
	font-family: var(--font-display);
	font-size: var(--fs-sm);
	font-weight: var(--fw-semibold);
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
}

/* =========================================================
   8. The Signal Chevron signature mark
   Two angular strokes: a solid "lead" chevron and a dimmer "trail"
   chevron behind it, reading as a channel-change / signal-transmission
   cue. Every join is sharp (miter, not round) — see file docblock in
   template-parts/icons/signal-chevron.php for the full rationale.
   ========================================================= */

.signal-chevron {
	flex-shrink: 0;
	overflow: visible;
}

.signal-chevron__lead,
.signal-chevron__trail {
	fill: none;
	stroke: var(--color-accent);
	stroke-width: 3.5;
	stroke-linecap: square;
	stroke-linejoin: miter;
}

/* The trail sits at a dim resting opacity always — a static "motion
   streak" behind the lead chevron — rather than being fully hidden until
   animated, so the mark still reads as directional/in-motion even under
   prefers-reduced-motion. */
.signal-chevron__trail {
	opacity: 0.32;
	transform-origin: 50% 50%;
}

.signal-chevron--on-accent .signal-chevron__lead,
.signal-chevron--on-accent .signal-chevron__trail {
	stroke: var(--color-accent-ink);
}

.signal-chevron.is-animated .signal-chevron__trail {
	animation: signal-snap 2.2s var(--ease-emphasized) infinite;
}

/* A quick snap/flash, not a slow pulse: the trail sits at its dim resting
   opacity for ~80% of the cycle, then briefly flashes to full opacity with
   a small forward nudge — a single "blip" of transmitted signal — before
   cutting straight back to resting. Nothing here eases slowly in and out
   the way a pulse would. */
@keyframes signal-snap {
	0%, 78% {
		opacity: 0.32;
		transform: translateX(0);
	}

	86% {
		opacity: 1;
		transform: translateX(2px);
	}

	94%, 100% {
		opacity: 0.32;
		transform: translateX(0);
	}
}

/* The snap is decorative, not informational (the lead chevron alone
   already communicates the mark) — under reduced motion it stops
   completely and holds at the static resting opacity, on top of the
   global rule above. */
@media (prefers-reduced-motion: reduce) {
	.signal-chevron__trail {
		animation: none !important;
		opacity: 0.32 !important;
		transform: none !important;
	}
}

/* =========================================================
   9. Component — Link with arrow
   Promoted here while building template-parts/devices.php: the
   "reassurance line + text link with an arrow-right icon that nudges
   right on hover" pattern first appeared in template-parts/how-it-works.php
   (as a locally-styled .how-it-works__cta) and devices.php needed the
   identical behavior. how-it-works.php was updated to add this shared
   class alongside its own margin-top-only rule. Color comes from the
   global `a`/`a:hover` rule in the Reset & base section above, not
   redeclared here.
   ========================================================= */

.link-arrow {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	font-weight: var(--fw-semibold);
}

.link-arrow .icon {
	transition: transform var(--duration-base) var(--ease-standard);
}

.link-arrow:hover .icon {
	transform: translateX(4px);
}

/* =========================================================
   10. Component — Accordion
   Built here (not scoped to one section's stylesheet) while adding
   template-parts/pricing-trust.php's micro-FAQ (Prompt 8b), specifically
   so the full FAQ teaser (Prompt 10, this same batch) can reuse it
   without copy-pasting. Native <details>/<summary>, deliberately zero JS
   and zero manual ARIA: modern browsers already expose the correct
   implicit semantics for this pattern (an expandable/collapsible
   disclosure with the trigger's expanded state and its owned content
   both in the accessibility tree) — adding aria-expanded/aria-controls
   by hand on top of that risks the two falling out of sync, which is
   worse than relying on the native mapping. Markup:
   <div class="accordion">
     <details class="accordion__item" name="some-group">
       <summary class="accordion__trigger">
         <span>Question?</span>
         <?php echo get_icon('chevron-down', array('size' => 18)); ?>
       </summary>
       <div class="accordion__panel"><p>Answer.</p></div>
     </details>
     ...
   </div>
   The shared `name` attribute (HTML's native mutually-exclusive
   <details> grouping) makes only one item open at a time — supported in
   current Chrome/Firefox/Safari; unsupported browsers just allow
   multiple open at once, a harmless degradation, not a broken state.
   Sharp corners throughout (radius-md, already 3px by default — no
   override needed the way Midnight Broadcast's rounder token set would).
   ========================================================= */

.accordion {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
}

.accordion__item {
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background: var(--color-surface);
	overflow: hidden;
}

.accordion__trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	padding: var(--space-4) var(--space-5);
	cursor: pointer;
	font-weight: var(--fw-semibold);
	color: var(--color-text);
}

/* Hide the native disclosure triangle (Firefox uses ::marker, Chrome/
   Safari use the older ::-webkit-details-marker) — the chevron icon
   below is the visual affordance instead. */
.accordion__trigger::marker,
.accordion__trigger::-webkit-details-marker {
	content: "";
	display: none;
}

.accordion__trigger .icon {
	flex-shrink: 0;
	color: var(--color-text-faint);
	transition: transform var(--duration-base) var(--ease-standard);
}

/* Optional: when a trigger's question needs real heading semantics
   (for a future richer FAQ list — content-rich enough to be worth
   H3-level navigation/SEO structure, unlike pricing-trust's 3 short
   items, which don't use this class). The heading goes INSIDE the
   <summary> as its content, not the reverse — a heading wrapping an
   interactive element is the debated pattern; an interactive element
   containing a heading is not. Resets h3's own font-size/weight/family/
   uppercase (set in the Reset & base section near the top of this file)
   back to inheriting .accordion__trigger's, so it reads as trigger text,
   not a full heading-styled headline. */
.accordion__question {
	font: inherit;
	color: inherit;
	text-transform: none;
	margin: 0;
}

.accordion__item[open] .accordion__trigger .icon {
	transform: rotate(180deg);
}

.accordion__panel {
	padding: 0 var(--space-5) var(--space-4);
	color: var(--color-text-muted);
	font-size: var(--fs-sm);
	line-height: var(--lh-sm);
}

/* =========================================================
   11. Component — Star rating
   Moved here from trust-bar.css while building template-parts/final-cta.php,
   which needed the identical two-layer partial-fill star visual a second
   time — see template-parts/icons/star-rating.php for the markup and why
   this stays purely decorative (no built-in visually-hidden text).
   ========================================================= */

.star-rating {
	position: relative;
	display: inline-flex;
	flex-shrink: 0;
}

.star-rating__base,
.star-rating__fill {
	display: flex;
	gap: 1px;
}

.star-rating__base .icon {
	color: var(--color-border-strong);
}

.star-rating__fill {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	overflow: hidden;
	white-space: nowrap;
}

.star-rating__fill .icon {
	flex-shrink: 0;
	color: var(--color-accent);
}

/* =========================================================
   12. Component — Breadcrumb + page-header
   Moved here from abonnements.css while building templates/template-faq.php,
   which needed the identical breadcrumb + plain page-title block a second
   time — see templates/template-abonnements.php's own docblock, which
   flagged this exact extraction in advance. A plainer page-header for
   standalone pages (/abonnements, /faq, and future /tutoriels, /contact,
   /blog), not a second hero pattern.
   ========================================================= */

.breadcrumb {
	margin-bottom: var(--space-5);
}

.breadcrumb__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: var(--fs-sm);
}

.breadcrumb__item a {
	color: var(--color-text-muted);
	font-weight: var(--fw-medium);
	text-decoration: none;
}

.breadcrumb__item a:hover {
	color: var(--color-accent);
}

.breadcrumb__item[aria-current="page"] {
	color: var(--color-text-faint);
}

.breadcrumb__item:not(:first-child)::before {
	content: "/";
	margin-inline-end: var(--space-2);
	color: var(--color-border-strong);
}

.page-header {
	padding-block-start: var(--space-8);
	padding-block-end: var(--space-7);
	border-bottom: 1px solid var(--color-border);
}

.page-header__title {
	max-width: 40ch;
	margin-inline: auto;
	text-align: center;
}

.page-header__subcopy {
	margin-top: var(--space-4);
	max-width: 60ch;
	margin-inline: auto;
	text-align: center;
	font-size: var(--fs-md);
	line-height: var(--lh-md);
}

@media (min-width: 1024px) {
	.page-header {
		padding-block-start: var(--space-10);
		padding-block-end: var(--space-8);
	}
}

/* =========================================================
   13. Component — Device chip
   Promoted here from assets/css/devices.css while building
   templates/template-tutoriels.php (Prompt 16), which needed the
   identical chip (icon + label, .card base surface) a second time — as a
   real link this time, not just a static display chip — same "extract on
   2nd use" rule as everything else in this section of the file.
   Deliberately NOT .card--hover: a light border/background shift only,
   no lift/shadow increase, so it reads as "selectable/subtly
   interactive" without the stronger "clickable card" affordance
   .card--hover implies elsewhere (catalog showcase, pricing cards).
   Works identically whether the element is a non-interactive <li>
   (template-parts/devices.php, chips aren't links there) or a real <a>
   (templates/template-tutoriels.php's device selector) — callers needing
   link-specific resets (e.g. text-decoration) add those in their own
   page-scoped CSS, not here.
   ========================================================= */

.device-chip {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: var(--space-2);
	padding: var(--space-4) var(--space-3);
	transition: border-color var(--duration-base) var(--ease-standard),
		background-color var(--duration-base) var(--ease-standard);
}

.device-chip:hover {
	border-color: var(--color-border-strong);
	background: var(--color-surface-2);
}

.device-chip .icon {
	color: var(--color-accent);
}

.device-chip__label {
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	color: var(--color-text);
}

/* =========================================================
   14. Component — Form field (label, input, error)
   Promoted here from assets/css/order-widget.css (.order-widget__label/
   __input/__field-error) while building templates/template-contact.php
   (Prompt 17), which needed the identical form-field recipe a second
   time — exactly the "if a second form appears anywhere else on the
   site, promote these" flag order-widget.css's own docblock left for
   this moment. template-parts/order-widget.php's markup was updated to
   use these shared classes too, so there is now only ONE form-input
   implementation on the site, not two visually-matching copies.
   .form-input applies identically to <input>, <textarea>, and <select> —
   a <select> keeps its native dropdown affordance/appearance (no
   custom-styled arrow built yet; flagged, not a hidden shortcut) rather
   than fighting cross-browser custom-select quirks for a single dropdown
   field.
   ========================================================= */

.form-label {
	display: block;
	margin-bottom: var(--space-2);
	font-size: var(--fs-sm);
	font-weight: var(--fw-semibold);
	color: var(--color-text);
}

.form-input {
	width: 100%;
	padding: var(--space-3) var(--space-4);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-md);
	background: var(--color-surface-2);
	color: var(--color-text);
	font-size: var(--fs-base);
	transition: border-color var(--duration-base) var(--ease-standard);
}

textarea.form-input {
	resize: vertical;
	min-height: 8rem;
}

.form-input::placeholder {
	color: var(--color-text-faint);
}

.form-input:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 1px;
	border-color: var(--color-accent);
}

.form-input[aria-invalid="true"] {
	border-color: var(--color-error);
}

.form-error {
	margin-top: var(--space-2);
	min-height: 1.2em;
	font-size: var(--fs-xs);
	color: var(--color-error);
}
