/* site/src/assets/css/page-contact.css
 * The contact page only. Loaded by src/pages/contact.html and nowhere else.
 *
 * The page is one idea: your answers become a message thread that assembles
 * itself next to the form, and that thread is literally what gets sent. So the
 * layout is two halves that have to stay visible together — the form you fill
 * in, and the slab it writes onto. On a phone there is no room for two halves,
 * so the slab sticks to the top of the screen and the form scrolls under it.
 *
 * Order: the shout, the brief (thread + form), the plain ways, the way out.
 */

/* ── the shout ───────────────────────────────────────────────────────── */
/* The homepage opens dark. This one opens the other way round, in full
   yellow, because arriving here should feel like a door opening rather than
   another dim hero. */
.hail {
	background: var(--yellow);
	color: var(--ink);
	padding: clamp(110px, 18vh, 200px) var(--gutter) clamp(56px, 9vh, 110px);
	border-bottom: 3px solid var(--ink);
	position: relative;
	overflow: hidden;
}

/* Two soft blocks of colour bleeding in from the corners, so the yellow is a
   place rather than a flat fill. Decorative, no content, no pointer. */
.hail::before {
	content: '';
	position: absolute; inset: auto -12% -40% -12%; height: 70%;
	background:
		radial-gradient(40vw 28vw at 18% 100%, rgba(255, 95, 143, .55), transparent 68%),
		radial-gradient(38vw 26vw at 84% 92%, rgba(0, 217, 184, .5), transparent 66%);
	pointer-events: none;
}

.hail__inner {
	position: relative;
	max-width: var(--wide);
	margin: 0 auto;
	display: grid;
	gap: clamp(18px, 3vh, 30px);
	justify-items: start;
}

.hail__eyebrow { color: #6b4f00; }

.hail__title {
	font: 800 clamp(40px, 8.4vw, 118px)/.92 var(--display);
	letter-spacing: -.045em;
	max-width: 14ch;
}

/* The one word the whole page turns on, marked the way you would ring it on
   paper. */
.hail__title mark {
	background: var(--pink);
	color: var(--paper);
	padding: 0 .1em .06em;
	border-radius: 8px;
	display: inline-block;
	transform: rotate(-1.6deg);
}

.hail__lead {
	max-width: 48ch;
	font-size: clamp(16px, 1.25vw, 19px);
	color: #40320a;
}

.hail__jump {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px 12px;
	margin-top: 4px;
}
.hail__jump .label { color: #6b4f00; }
.hail__jump a {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 0 18px;
	border: 2px solid var(--ink);
	border-radius: 999px;
	background: transparent;
	font: 600 15px/1 var(--display);
	text-decoration: none;
	transition: background .18s, color .18s, transform .18s;
}
.hail__jump a:hover {
	background: var(--ink);
	color: var(--yellow);
	transform: translateY(-2px);
}

/* ── the brief ───────────────────────────────────────────────────────── */
.brief {
	background: var(--paper);
	padding: clamp(40px, 7vh, 90px) var(--gutter) clamp(60px, 10vh, 120px);
}

.brief__wrap {
	max-width: var(--wide);
	margin: 0 auto;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas: 'head' 'thread' 'form';
	gap: clamp(20px, 3vh, 34px);
	align-items: start;
}

.brief__head { grid-area: head; display: grid; gap: 10px; }
.brief__head .label { color: #a8642a; }
.brief__head h2 {
	font: 800 clamp(30px, 4.6vw, 62px)/.98 var(--display);
	letter-spacing: -.04em;
}
.brief__sub { color: var(--ink-soft); max-width: 52ch; }

@media (min-width: 900px) {
	.brief__wrap {
		grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
		grid-template-areas:
			'head head'
			'form thread';
		column-gap: clamp(30px, 4vw, 64px);
	}
}

/* ── the thread ──────────────────────────────────────────────────────── */
/* A slab, not a phone mock-up: the same ink as the footer, so it reads as the
   studio's own surface rather than a picture of somebody's handset. */
.thread {
	grid-area: thread;
	position: sticky;
	top: 66px;
	z-index: 3;
	display: flex;
	flex-direction: column;
	min-height: 0;
	max-height: min(38svh, 320px);
	background: var(--ink);
	color: var(--paper);
	border-radius: 22px;
	overflow: hidden;
	box-shadow: 0 22px 50px rgba(10, 10, 15, .28);
}

/* The lit edge that tells you the thread is the live part of the page. */
.thread::before {
	content: '';
	position: absolute; inset: 0;
	border-radius: 22px;
	padding: 2px;
	background: linear-gradient(140deg, var(--teal), var(--blue) 45%, var(--pink));
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask-composite: exclude;
	opacity: .55;
	pointer-events: none;
}

@media (min-width: 900px) {
	.thread {
		top: 96px;
		max-height: min(72svh, 620px);
	}
}

.thread__top {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 13px 16px;
	border-bottom: 1px solid rgba(251, 249, 244, .14);
	background: rgba(251, 249, 244, .04);
}
.thread__dot {
	width: 9px; height: 9px; border-radius: 50%;
	background: var(--teal);
	box-shadow: 0 0 12px var(--teal);
	animation: thread-live 2.4s ease-in-out infinite;
	flex: none;
}
@keyframes thread-live { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.thread__title {
	font: 600 15px/1 var(--display);
	letter-spacing: -.01em;
	margin-right: auto;
}
.thread__state {
	color: rgba(251, 249, 244, .55);
	border: 1px solid rgba(251, 249, 244, .22);
	border-radius: 999px;
	padding: 5px 10px;
}
.thread[data-ready] .thread__state {
	color: var(--ink);
	background: var(--teal);
	border-color: var(--teal);
}

.thread__body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	display: flex;
	flex-direction: column;
	gap: 9px;
	padding: 16px;
}

.bubble {
	max-width: 86%;
	padding: 10px 14px;
	border-radius: 16px;
	font-size: .93em;
	line-height: 1.42;
	white-space: pre-wrap;   /* the message keeps the line breaks they typed */
	overflow-wrap: anywhere; /* a pasted URL must not widen the slab */
}

/* Theirs: teal, the studio's own colour, because this is their side of it. */
.bubble--out {
	align-self: flex-end;
	background: var(--teal);
	color: var(--ink);
	font-weight: 600;
	border-bottom-right-radius: 5px;
}
/* Ours: the page reading the answer back. Quieter on purpose — it is a prompt,
   not a person typing. */
.bubble--in {
	align-self: flex-start;
	background: #1b1b26;
	color: rgba(251, 249, 244, .84);
	border-bottom-left-radius: 5px;
}

.bubble--new { animation: bubble-in .34s cubic-bezier(.2, .9, .3, 1.28) both; }
@keyframes bubble-in {
	from { opacity: 0; transform: translateY(9px) scale(.94); }
}

/* Three dots while a reply is coming. Only ever on an incoming bubble, and
   only for the length of one short beat. */
.bubble__dots { display: inline-flex; gap: 4px; padding: 3px 0; }
.bubble__dots i {
	width: 6px; height: 6px; border-radius: 50%;
	background: rgba(251, 249, 244, .6);
	animation: bubble-dot 1s ease-in-out infinite;
}
.bubble__dots i:nth-child(2) { animation-delay: .16s; }
.bubble__dots i:nth-child(3) { animation-delay: .32s; }
@keyframes bubble-dot { 0%, 100% { opacity: .3; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-3px); } }

.thread__foot {
	display: flex;
	align-items: center;
	gap: 9px;
	padding: 11px 16px;
	border-top: 1px solid rgba(251, 249, 244, .14);
	font: 500 12px/1.3 var(--mono);
	letter-spacing: .04em;
	color: rgba(251, 249, 244, .55);
}
.thread__ticks { color: rgba(251, 249, 244, .35); letter-spacing: -.12em; font-size: 14px; }
.thread[data-ready] .thread__ticks { color: var(--teal); }

/* Nothing in the slab animates while it is off screen or the tab is hidden;
   contact.js adds this class. */
.thread.is-still *, .thread.is-still { animation-play-state: paused; }

/* ── the form ────────────────────────────────────────────────────────── */
.form { grid-area: form; display: grid; gap: clamp(22px, 3.4vh, 38px); }

.form__noscript {
	background: var(--amber);
	color: var(--ink);
	border: 2px solid var(--ink);
	border-radius: 14px;
	padding: 14px 16px;
}

.q { border: 0; display: grid; gap: 12px; }
.q legend, .q__legend {
	font: 700 clamp(19px, 1.9vw, 26px)/1.2 var(--display);
	letter-spacing: -.025em;
	padding: 0;
	display: block;
	width: 100%;
	margin-bottom: 4px;
}
.q__no {
	display: inline-block;
	font: 500 12px/1 var(--mono);
	letter-spacing: .1em;
	color: var(--blue);
	vertical-align: .34em;
	margin-right: 10px;
}
.q__opt {
	font: 400 12px/1 var(--mono);
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--ink-soft);
	vertical-align: .18em;
}

.q--pair { gap: 16px; }

/* ── chips ───────────────────────────────────────────────────────────── */
/* Real radio inputs, so arrow keys move within the group and the browser does
   the state. The input stays in the layer under the label rather than being
   display:none, because a hidden input cannot be focused. */
.chips { display: flex; flex-wrap: wrap; gap: 10px; }

.chip { position: relative; display: inline-flex; }
.chip input {
	position: absolute;
	inset: 0;
	opacity: 0;
	margin: 0;
	cursor: pointer;
}
.chip span {
	display: inline-flex;
	align-items: center;
	min-height: 46px;
	padding: 0 18px;
	border: 2px solid var(--line);
	border-radius: 999px;
	background: #fff;
	font: 500 15px/1 var(--display);
	transition: background .16s, border-color .16s, color .16s, transform .16s;
}
.chip:hover span { border-color: var(--ink); transform: translateY(-1px); }
.chip input:checked ~ span {
	background: var(--ink);
	border-color: var(--ink);
	color: var(--paper);
}
.chip input:focus-visible ~ span {
	outline: 3px solid var(--blue);
	outline-offset: 3px;
}

/* ── text fields ─────────────────────────────────────────────────────── */
.field { display: grid; gap: 7px; }
.field label {
	font: 600 15px/1.2 var(--display);
}
.field input, .field textarea {
	font: 400 16px/1.45 var(--display);
	color: var(--ink);
	background: #fff;
	border: 2px solid var(--line);
	border-radius: 14px;
	padding: 13px 15px;
	min-height: 48px;
	width: 100%;
	transition: border-color .16s, box-shadow .16s;
}
.field textarea { resize: vertical; min-height: 130px; }
.field input:hover, .field textarea:hover { border-color: rgba(10, 10, 15, .34); }
.field input:focus-visible, .field textarea:focus-visible {
	outline: 0;
	border-color: var(--blue);
	box-shadow: 0 0 0 4px rgba(47, 107, 255, .2);
}
.field input[aria-invalid='true'], .field textarea[aria-invalid='true'] {
	border-color: var(--pink);
}

.hint { font-size: 14px; color: var(--ink-soft); max-width: 46ch; }

.err {
	display: flex;
	gap: 8px;
	font: 500 14px/1.35 var(--display);
	color: #b3003c;
}
.err::before { content: '→'; font-family: var(--mono); }
/* The display rules above and on .manual would otherwise beat the hidden
   attribute, leaving empty error arrows and the paste box always on show. */
.err[hidden], .manual[hidden] { display: none; }
.q[data-invalid] > legend { color: #b3003c; }

/* ── send ────────────────────────────────────────────────────────────── */
.form__go {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px;
}

.brief-btn {
	font: 500 14px/1 var(--mono);
	letter-spacing: .1em;
	text-transform: uppercase;
	min-height: 52px;
	padding: 0 26px;
	border-radius: 999px;
	border: 2px solid var(--ink);
	cursor: pointer;
	transition: transform .18s, background .18s, color .18s;
}
.brief-btn--send { background: var(--ink); color: var(--paper); }
.brief-btn--send:hover { transform: translateY(-2px) rotate(-1deg); background: #22222c; }
.brief-btn--ghost { background: transparent; color: var(--ink); }
.brief-btn--ghost:hover { transform: translateY(-2px); background: var(--ink); color: var(--paper); }

.form__where {
	flex: 1 1 22ch;
	font: 400 14px/1.4 var(--mono);
	color: var(--ink-soft);
}

.say:not(:empty) {
	background: var(--teal);
	color: var(--ink);
	border-radius: 14px;
	padding: 13px 16px;
	font-weight: 600;
}

.manual { display: grid; gap: 8px; }
.manual label { font: 600 15px/1.2 var(--display); }
.manual textarea {
	font: 400 14px/1.5 var(--mono);
	width: 100%;
	border: 2px solid var(--ink);
	border-radius: 14px;
	padding: 13px 15px;
	background: #fff;
	color: var(--ink);
	resize: vertical;
}

/* ── the plain ways ──────────────────────────────────────────────────── */
.ways {
	background: var(--ink);
	color: var(--paper);
	padding: clamp(60px, 10vh, 120px) var(--gutter);
}
.ways__inner { max-width: var(--wide); margin: 0 auto; }
.ways__inner h2 {
	font: 800 clamp(30px, 4.6vw, 62px)/.98 var(--display);
	letter-spacing: -.04em;
}
.ways__sub { color: rgba(251, 249, 244, .68); margin-top: 10px; }

.ways__grid {
	list-style: none;
	margin-top: clamp(28px, 4vh, 48px);
	display: grid;
	gap: 14px;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.way {
	display: grid;
	gap: 10px;
	align-content: start;
	padding: 20px;
	border-radius: 18px;
	background: rgba(251, 249, 244, .05);
	border: 1px solid rgba(251, 249, 244, .14);
	border-top: 4px solid var(--edge, var(--teal));
}
.way--teal { --edge: var(--teal); }
.way--amber { --edge: var(--amber); }
.way--pink { --edge: var(--pink); }
.way--blue { --edge: var(--blue); }
.way__kind { color: var(--edge); }
.way__link {
	font: 700 clamp(19px, 1.9vw, 25px)/1.2 var(--display);
	letter-spacing: -.025em;
	text-decoration: none;
	overflow-wrap: anywhere;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	border-bottom: 2px solid transparent;
}
.way__link:hover { border-bottom-color: var(--edge); }
.way__note { color: rgba(251, 249, 244, .64); font-size: 15px; }

/* A channel that has not been published yet says so instead of pretending. */
.way[data-unpublished] { opacity: .78; }
.way[data-unpublished] .way__link {
	font-size: 17px;
	color: rgba(251, 249, 244, .74);
	cursor: default;
	border-bottom: 0;
}

/* ── the way out ─────────────────────────────────────────────────────── */
.after {
	background: var(--teal);
	color: var(--ink);
	padding: clamp(56px, 9vh, 110px) var(--gutter);
}
.after__inner { max-width: var(--wide); margin: 0 auto; display: grid; gap: 12px; }
.after__inner h2 {
	font: 800 clamp(28px, 4.2vw, 56px)/1 var(--display);
	letter-spacing: -.04em;
}
.after__sub { color: rgba(10, 10, 15, .7); }
.after__links {
	list-style: none;
	margin-top: 14px;
	display: grid;
	gap: 2px;
	max-width: 56ch;
}
.after__links a {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 48px;
	font: 600 clamp(17px, 1.7vw, 22px)/1.25 var(--display);
	letter-spacing: -.02em;
	text-decoration: none;
	border-bottom: 1px solid rgba(10, 10, 15, .18);
	transition: padding-left .18s;
}
.after__links a::before { content: '→'; font-family: var(--mono); }
.after__links a:hover { padding-left: 8px; }
.after__fine {
	margin-top: 22px;
	font-size: 14px;
	color: rgba(10, 10, 15, .72);
	max-width: 62ch;
}

/* ── motion ──────────────────────────────────────────────────────────── */
/* site.css already flattens durations; this removes the movement itself so a
   new bubble simply appears where it belongs. */
@media (prefers-reduced-motion: reduce) {
	.bubble--new { animation: none; }
	.hail__jump a:hover, .brief-btn:hover, .brief-btn--ghost:hover, .after__links a:hover { transform: none; }
}

/* ── narrow ──────────────────────────────────────────────────────────── */
@media (max-width: 420px) {
	.chip span { padding: 0 15px; font-size: 14.5px; }
	.brief-btn { width: 100%; justify-content: center; text-align: center; }
	.form__where { flex-basis: 100%; }
}

/* The honeypot: clipped rather than display:none, because some bots skip
   fields that are plainly hidden and fill the ones that are merely invisible. */
.form__hp {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}
