/* =============================================================================
   Airside Crew — the Get in touch page
   -----------------------------------------------------------------------------
   Built from apps/site/design/Contact.dc.html and its five siblings, which
   Dylan approved on Oct 27, 2026. The six differ only in preview size and
   default theme, so every value here is Contact.dc.html's and holds for all
   six. Linked AFTER site.css.

   What this page takes from the shared shell rather than redeclaring: `.page`
   (background, ink, clip, hidden scrollbar), the floating header and the
   small-screen menu, `.page-hero` with its glows, title and lead,
   `.eyebrow-pill`, `.hr-blob`, `.hr-in`, `.cta--shine`, the type scale
   (`.t-h1--page`, `.t-h2--card-s`, `.t-h2--card-m`) and the footer. What is
   here is the hero's own measures and the form panel.

   WHY A SEPARATE FILE: other tasks edit site.css, and the git index is shared
   state, so a concurrent write loses one side (docs/coding.md).

   NO `style` ATTRIBUTES AND NO `<style>` ELEMENT on the page or in here
   (docs/security.md §7). The designs set every value inline; none of that
   is carried over.

   THE `[hidden]` OVERRIDES ARE LOAD-BEARING. An author `display` beats the
   user agent's `[hidden] { display: none }`, so every element here that
   scripts/contact.js hides or reveals AND that has a `display` of its own
   gets an override immediately after the rule that creates the need.
   src/html/hidden-display.test.ts checks the pairing across the site.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Tokens this page draws and the shared palette does not carry
   -----------------------------------------------------------------------------
   One: the field error's ink. design/Contact.dc.html's `redInk` is #A3271B by
   day, where site.css's `--red-ink` (How it works' card) is #8a1a10. Night is
   #FFB3A8 in both. Declared in the same three places site.css declares a
   themed token, so the footer's Auto · Day · Night control moves it too. */
:root {
	--ct-red-ink: #a3271b;
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="day"]) {
		--ct-red-ink: #ffb3a8;
	}
}
:root[data-theme="night"] {
	--ct-red-ink: #ffb3a8;
}

/* -----------------------------------------------------------------------------
   The hero: About's shape with this page's measures
   -------------------------------------------------------------------------- */
.ct-hero__blob--a {
	width: 520px;
	height: 520px;
	right: -140px;
	top: -140px;
	background: rgba(4, 97, 248, 0.5);
}
.ct-hero__blob--b {
	width: 360px;
	height: 360px;
	left: -120px;
	bottom: -180px;
	background: rgba(4, 165, 248, 0.28);
	animation-duration: 20s;
}

.ct-hero__inner {
	position: relative;
	padding-top: 140px;
	padding-bottom: 88px;
	display: flex;
	flex-direction: column;
	gap: 18px;
}

/* A max-width is not a type property, so this does not touch the scale. */
.ct-hero__title {
	max-width: 820px;
}

.ct-hero .page-hero__lead {
	max-width: 640px;
}

/* -----------------------------------------------------------------------------
   The panel: one card lifted over the hero's foot
   -------------------------------------------------------------------------- */
.ct-panel {
	position: relative;
	z-index: 3;
	margin-top: -40px;
	padding-bottom: 96px;
}

/* `minmax(0, …)` on both tracks so a long word shrinks the track instead of
   overflowing the card. */
.ct-grid {
	box-sizing: border-box;
	display: grid;
	grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
	gap: 40px;
	align-items: start;
	padding: clamp(20px, 3.4vw, 40px);
	border-radius: 28px;
	background: var(--surface);
	border: 1px solid var(--line);
	box-shadow: var(--lift-big);
}

@media (max-width: 900px) {
	.ct-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 32px;
	}
}

.ct-main {
	min-width: 0;
}

/* -----------------------------------------------------------------------------
   The form state
   -------------------------------------------------------------------------- */
.ct-form {
	display: flex;
	flex-direction: column;
	gap: 22px;
}
.ct-form[hidden] {
	display: none;
}

.ct-head {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

/* The small uppercase labels: "Send a message", "What happens next", "Or
   reach me directly". Not headings in the design, so not on the scale. */
.ct-eyebrow {
	font-size: 13px;
	font-weight: 800;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--muted);
}

/* One labelled control. The design gives the role group 10px and each text
   field's label 8px. */
.ct-field {
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-width: 0;
}
.ct-field[role="radiogroup"] {
	gap: 10px;
}

.ct-label {
	font-size: 15px;
	font-weight: 800;
}

.ct-optional {
	font-weight: 600;
	color: var(--muted);
}

/* "I work with" */
.ct-roles {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px;
}

.ct-role {
	display: flex;
	align-items: center;
	gap: 12px;
	min-height: 64px;
	padding: 10px 14px 10px 10px;
	border-radius: 18px;
	border: 2px solid var(--line);
	background: var(--bg);
	box-shadow: none;
	color: var(--ink);
	text-align: left;
	/* The design's own transition on the tile plus its `.hr-press`. */
	transition: border-color 0.2s ease-out, background-color 0.2s ease-out,
		box-shadow 0.2s ease-out, transform 0.14s ease-out;
}
.ct-role:active {
	transform: scale(0.97);
}

/* The chosen one, off `aria-checked`, so the announced state and the drawn
   state cannot disagree. */
.ct-role[aria-checked="true"] {
	border-color: var(--blue);
	background: var(--surface);
	box-shadow: var(--lift);
}

.ct-role__tile {
	flex-shrink: 0;
	width: 40px;
	height: 40px;
	border-radius: 12px;
	background: var(--chip);
	color: var(--accent);
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.2s ease-out, color 0.2s ease-out;
}
.ct-role[aria-checked="true"] .ct-role__tile {
	background: var(--blue);
	color: #ffffff;
}

.ct-role__label {
	flex: 1;
	min-width: 0;
	font-size: 15px;
	line-height: 1.3;
	font-weight: 800;
}

/* The text fields */
.ct-two {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 16px;
}

.ct-input {
	min-width: 0;
	height: 56px;
	box-sizing: border-box;
	padding: 0 16px;
	border-radius: 16px;
	border: 2px solid var(--line);
	background: var(--bg);
	color: var(--ink);
	font-size: 17px;
}

/* The placeholder's colour, which the design leaves to the browser. The
   default grey apps/site/README.md measured in Chrome, rgb(117, 117, 117),
   computes to 4.26:1 against this page's day field fill #F4F6FA — under the
   4.5:1 docs/ui-rules.md requires — so the README's expectation that it
   "passes" on a light surface does not hold here. `--muted` is the design's
   own quiet ink on this page: 8.07:1 by day (#3D4B68 on #F4F6FA) and 9.66:1
   by night (#A7B6D3 on #030A1C). Scoped to this page's fields,
   for the reason apps/site/README.md gives for Progress's: each field is
   measured on its own surface rather than inheriting a shared rule unmeasured. */
.ct-input::placeholder {
	color: var(--muted);
	opacity: 1;
}

.ct-textarea {
	height: auto;
	padding: 14px 16px;
	line-height: 1.5;
	resize: none;
}

.ct-input[aria-invalid="true"] {
	border-color: var(--red-line);
}

/* A `<span>` whose `display` this file never sets, so the user agent's
   `[hidden]` rule is enough here. */
.ct-error {
	font-size: 14px;
	font-weight: 700;
	color: var(--ct-red-ink);
}

/* Turnstile. In interaction-only mode the widget takes no room for an
   ordinary visitor, but its container is still a flex item, and the form's
   22px gap would open above Send where the design draws none. The negative
   margin takes that gap back; scripts/contact.js sets `data-interactive`
   while Cloudflare is showing a challenge, and the row opens to fit it. */
.ct-turnstile {
	margin-top: -22px;
}
.ct-turnstile[data-interactive] {
	margin-top: 0;
}

.ct-send {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 12px 20px;
}

.ct-submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	min-height: 56px;
	padding: 0 26px;
	border: 0;
	border-radius: 16px;
	background: var(--blue);
	color: #ffffff;
	font-size: 17px;
	font-weight: 800;
	box-shadow: 0 10px 24px rgba(4, 97, 248, 0.38), 0 2px 6px rgba(2, 17, 58, 0.18);
	transition: transform 0.14s ease-out, box-shadow 0.2s ease-out,
		background-color 0.2s ease-out;
}
.ct-submit:hover {
	box-shadow: 0 14px 30px rgba(4, 97, 248, 0.45), 0 2px 6px rgba(2, 17, 58, 0.18);
}
.ct-submit:active {
	transform: scale(0.97);
}
.ct-submit[hidden] {
	display: none;
}
/* While the request is in flight: still a button, clearly pressed. */
.ct-submit[aria-disabled="true"] {
	opacity: 0.6;
	cursor: progress;
}

/* Every sentence that reaches this line is a reason the message did not go
   (success replaces the panel instead), so it takes the error ink. Sets no
   `display`, so it needs no `[hidden]` override. */
.ct-status {
	margin: 0;
	max-width: 420px;
	font-size: 14px;
	font-weight: 700;
	line-height: 1.45;
	color: var(--ct-red-ink);
	overflow-wrap: anywhere;
}

/* -----------------------------------------------------------------------------
   The sent state
   -------------------------------------------------------------------------- */
.ct-sent {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 16px;
	padding: 8px 0;
	animation: hrSwap 0.45s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.ct-sent[hidden] {
	display: none;
}

.ct-tick {
	width: 64px;
	height: 64px;
	border-radius: 32px;
	background: var(--blue);
	color: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 10px 24px rgba(4, 97, 248, 0.38);
	animation: ctTick 0.4s cubic-bezier(0.3, 1.5, 0.5, 1) both;
}
@keyframes ctTick {
	from {
		transform: scale(0);
	}
	to {
		transform: none;
	}
}

/* Focus lands here when the panel swaps in; the ring would be the only
   thing on screen that the design does not draw, and the heading is not a
   control, so it is suppressed for this programmatic focus only. */
.ct-sent__title:focus {
	outline: none;
}

.ct-sent__body {
	margin: 0;
	max-width: 460px;
	font-size: 17px;
	line-height: 1.6;
	color: var(--muted);
	/* The visitor's address is written in here, and an address has no
	   spaces to wrap at. */
	overflow-wrap: anywhere;
}

.ct-again {
	min-height: 48px;
	padding: 0 20px;
	border: 0;
	border-radius: 24px;
	background: var(--chip);
	color: var(--accent);
	font-size: 15px;
	font-weight: 800;
	transition: transform 0.14s ease-out;
}
.ct-again:active {
	transform: scale(0.97);
}

/* -----------------------------------------------------------------------------
   The aside
   -------------------------------------------------------------------------- */
.ct-aside {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 22px;
}

.ct-next {
	box-sizing: border-box;
	padding: 22px;
	border-radius: 22px;
	background: var(--bg);
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.ct-steps {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.ct-step {
	display: flex;
	gap: 12px;
	align-items: flex-start;
}

.ct-step__n {
	flex-shrink: 0;
	width: 28px;
	height: 28px;
	border-radius: 14px;
	background: var(--surface);
	box-shadow: var(--lift);
	color: var(--accent);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 14px;
	font-weight: 800;
}

.ct-step__t {
	font-size: 16px;
	line-height: 1.5;
	padding-top: 2px;
}

.ct-direct {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.ct-direct__title {
	padding: 0 4px;
}

.ct-direct__card {
	border-radius: 20px;
	background: var(--surface);
	border: 1px solid var(--line);
	box-shadow: var(--lift);
	overflow: hidden;
}

/* One row of the card: the mailto link, the copy button that replaces it,
   or the LinkedIn link. `:hover` beside the base for `color`, because
   site.css's `a:hover` (0-1-1) outranks a single class and would turn the
   row's ink blue; the design draws no hover colour. */
.ct-direct__row,
.ct-direct__row:hover {
	color: var(--ink);
}
.ct-direct__row {
	box-sizing: border-box;
	width: 100%;
	display: flex;
	align-items: center;
	gap: 12px;
	min-height: 64px;
	padding: 10px 16px;
	border: 0;
	background: transparent;
	text-align: left;
	text-decoration: none;
	transition: transform 0.14s ease-out;
}
.ct-direct__row:active {
	transform: scale(0.97);
}
.ct-direct__row[hidden] {
	display: none;
}

.ct-direct__row--split {
	border-top: 1px solid var(--line);
}

.ct-direct__tile {
	flex-shrink: 0;
	width: 40px;
	height: 40px;
	border-radius: 12px;
	background: var(--chip);
	color: var(--accent);
	display: flex;
	align-items: center;
	justify-content: center;
}

.ct-direct__text {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	line-height: 1.3;
}

.ct-direct__strong {
	font-size: 16px;
	font-weight: 800;
}

.ct-direct__sub {
	font-size: 13px;
	color: var(--muted);
}

.ct-direct__chev {
	flex-shrink: 0;
	opacity: 0.4;
}

/* The "Copy" chip: a label inside the row's button, not a control of its own
   (the row is the 64px target). */
.ct-copy {
	flex-shrink: 0;
	display: inline-flex;
	align-items: center;
	min-height: 32px;
	padding: 0 12px;
	border-radius: 16px;
	background: var(--chip);
	color: var(--accent);
	font-size: 13px;
	font-weight: 800;
}
/* For two seconds after a copy, as the design does. */
.ct-direct__row--copy[data-copied] .ct-copy {
	background: var(--blue);
	color: #ffffff;
	animation: ctTick 0.35s cubic-bezier(0.3, 1.5, 0.5, 1) both;
}

/* -----------------------------------------------------------------------------
   Narrow screens — the design's own 480px rules
   -------------------------------------------------------------------------- */
@media (max-width: 480px) {
	.ct-two,
	.ct-roles {
		grid-template-columns: minmax(0, 1fr);
	}

	.ct-role {
		min-height: 58px;
	}
}

/* docs/ui-rules.md: reduced motion is honoured everywhere, no exceptions.
   site.css's backstop already cancels every animation and transition on
   every element; this restates it for this file's own two animations so the
   rule is visible where they are declared. */
@media (prefers-reduced-motion: reduce) {
	.ct-sent,
	.ct-tick,
	.ct-direct__row--copy[data-copied] .ct-copy {
		animation: none;
	}
}
