/* ---- Contact modal / wizard — shared pitch-site component -------------------
   Pairs with contact-wizard-v2.js. Palette-agnostic: every colour and the UI
   font come from --wz-* custom properties, so a site maps its own tokens once
   and this file needs no per-site edits.

   Map them on :root in the site's own stylesheet, e.g.
     :root {
       --wz-surface: #fffaf3;  --wz-line: #e6dccf;   --wz-ink: #241712;
       --wz-ink-soft: #6c5d54; --wz-accent: #a8262c; --wz-accent-strong: #7d1b20;
       --wz-accent-tint: rgba(168,38,44,0.06);       --wz-hover-line: #2f7d78;
       --wz-backdrop: rgba(36,23,18,0.66);
       --wz-font-ui: 'YourUIFont', sans-serif;       --wz-radius: 16px;
     }
   The fallbacks below keep it legible if a token is missed.
---------------------------------------------------------------------------- */

#contact-modal {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 1000;
	align-items: center;
	justify-content: center;
	padding: 1.5rem;
}

/* :target is the no-JS path — it still opens the modal when scripts are
   stripped (the portal editor's preview does exactly that). Scoped to
   :not(.has-js): once the wizard script boots it takes full ownership of
   open/close via .is-open, and this rule must go inert. Chromium keeps
   #contact-modal:target matching even after JS clears the URL hash via
   history.replaceState() on close (a real engine quirk — :target does not
   re-evaluate on a non-traversal history change) — if this rule stayed
   unscoped, a visitor arriving here via a cross-page link straight to
   "#contact-modal" would see the modal handed back to :target and
   impossible to close via the X, Escape or the backdrop, all of which only
   ever touch the .is-open class. */
html:not(.has-js) #contact-modal:target {
	display: flex;
}

#contact-modal.is-open {
	display: flex;
}

body.modal-open {
	overflow: hidden;
}

.modal-backdrop {
	position: absolute;
	inset: 0;
	background: var(--wz-backdrop, rgba(20, 18, 16, 0.66));
	backdrop-filter: blur(2px);
}

.modal-dialog {
	position: relative;
	width: 100%;
	max-width: 34rem;
	max-height: calc(100vh - 3rem);
	overflow-y: auto;
	background: var(--wz-surface, #fff);
	border: 1px solid var(--wz-line, #e2ddd6);
	border-radius: var(--wz-radius, 16px);
	box-shadow: 0 20px 60px rgba(20, 18, 16, 0.35);
	padding: 2.4rem 2rem 2rem;
}

@media (prefers-reduced-motion: no-preference) {
	#contact-modal.is-open .modal-dialog,
	#contact-modal:target .modal-dialog {
		animation: modal-pop-in 0.22s ease;
	}
	#contact-modal.is-open .modal-backdrop,
	#contact-modal:target .modal-backdrop {
		animation: modal-fade-in 0.22s ease;
	}
}

@keyframes modal-pop-in {
	from { opacity: 0; transform: translateY(12px) scale(0.98); }
	to { opacity: 1; transform: none; }
}

@keyframes modal-fade-in {
	from { opacity: 0; }
	to { opacity: 1; }
}

.modal-close {
	position: absolute;
	top: 1rem;
	right: 1rem;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 50%;
	color: var(--wz-ink, #241712);
	background: color-mix(in srgb, var(--wz-ink, #241712) 6%, transparent);
	transition: background 0.2s ease, color 0.2s ease;
}

.modal-close:hover {
	background: var(--wz-accent-tint, rgba(0, 0, 0, 0.08));
	color: var(--wz-accent, #a8262c);
}

#contact-modal h2 {
	margin: 0 0 0.3rem;
	padding-right: 2.5rem;
}

.wizard-progress {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 1.6rem;
	font-family: var(--wz-font-ui, sans-serif);
	font-size: 0.82rem;
	color: var(--wz-ink-soft, #6c5d54);
}

.wizard-dots {
	display: flex;
	gap: 0.4rem;
}

.wizard-dots .dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--wz-line, #e2ddd6);
}

.wizard-dots .dot.is-active {
	background: var(--wz-accent, #a8262c);
}

/* Progress + Back/Next are JS-enhanced affordances. Without JS the whole form
   renders as one visible page and doesn't need them — which is what makes the
   script-stripped editor preview render a complete, usable form. */
.wizard-progress,
.wizard-back,
.wizard-next {
	display: none;
}

.has-js .wizard-progress {
	display: flex;
}

.has-js .wizard-back,
.has-js .wizard-next {
	display: inline-block;
}

/* Inactive steps hide with CSS ONLY — never `disabled`. capture.js reads
   new FormData(form), which DOES include display:none fields but does NOT
   include disabled ones, so disabling would silently drop every answer
   from a step the visitor already filled in. */
.has-js .wizard-step:not(.is-active) {
	display: none;
}

.has-js .wizard-intent-field {
	display: none;
}

.has-js .wizard-intent-field.is-visible {
	display: block;
}

.is-hidden {
	display: none !important;
}

.wizard-step .fields {
	display: flex;
	flex-wrap: wrap;
	width: calc(100% + 3rem);
	margin: -1.5rem 0 2rem -1.5rem;
}

.wizard-step .fields > .field {
	flex-grow: 0;
	flex-shrink: 0;
	padding: 1.5rem 0 0 1.5rem;
	width: calc(100% - 1.5rem);
}

.wizard-step .fields > .field.half {
	width: calc(50% - 0.75rem);
}

@media screen and (max-width: 480px) {
	.wizard-step .fields > .field,
	.wizard-step .fields > .field.half {
		width: calc(100% - 1.5rem);
	}
}

/* label/input/textarea have no block-level display of their own in any
   browser default stylesheet (label is inline, textarea is inline-block) —
   without this, a field's label and control flow together like text instead
   of stacking, and on a wide full-row field (e.g. a message textarea next to
   a long label) the control visibly overlaps the row above it. Framer/from-
   scratch builds have no host-site reset to fall back on, so this can't
   depend on one — it's the actual cause of the 2026-08-03 overlap bug. */
.wizard-step .fields > .field label {
	display: block;
	margin: 0 0 0.5rem;
	font-family: var(--wz-font-ui, sans-serif);
	font-weight: 600;
	font-size: 0.9rem;
	color: var(--wz-ink, #241712);
}

.wizard-step .fields > .field input,
.wizard-step .fields > .field textarea {
	display: block;
	width: 100%;
	box-sizing: border-box;
	padding: 0.7rem 0.85rem;
	border: 1px solid var(--wz-line, #e2ddd6);
	border-radius: calc(var(--wz-radius, 16px) - 6px);
	font-family: var(--wz-font-ui, sans-serif);
	font-size: 0.95rem;
	color: var(--wz-ink, #241712);
	background: var(--wz-surface, #fff);
}

.wizard-step .fields > .field textarea {
	resize: vertical;
	min-height: 6rem;
}

.wizard-step .fields > .field input:focus,
.wizard-step .fields > .field textarea:focus {
	outline: none;
	border-color: var(--wz-accent, #a8262c);
}

.wizard-step-label {
	font-family: var(--wz-font-ui, sans-serif);
	font-weight: 700;
	font-size: 0.95rem;
	margin-bottom: 1rem;
}

.wizard-intent-grid {
	display: grid;
	gap: 0.85rem;
	margin-bottom: 0.5rem;
}

.wizard-intent-card {
	display: flex;
	align-items: center;
	gap: 0.85rem;
	padding: 1rem 1.2rem;
	border: 1px solid var(--wz-line, #e2ddd6);
	border-radius: calc(var(--wz-radius, 16px) - 4px);
	cursor: pointer;
	font-family: var(--wz-font-ui, sans-serif);
	font-weight: 600;
	transition: border-color 0.2s ease, background 0.2s ease;
}

.wizard-intent-card input[type="radio"] {
	appearance: radio;
	-webkit-appearance: radio;
	display: block;
	margin: 0;
	width: 1.1rem;
	height: 1.1rem;
	accent-color: var(--wz-accent, #a8262c);
	flex-shrink: 0;
}

.wizard-intent-card:hover {
	border-color: var(--wz-hover-line, var(--wz-accent, #a8262c));
}

.wizard-intent-card:has(input:checked) {
	border-color: var(--wz-accent, #a8262c);
	background: var(--wz-accent-tint, rgba(0, 0, 0, 0.04));
}

.wizard-error {
	color: var(--wz-accent-strong, #7d1b20);
	font-family: var(--wz-font-ui, sans-serif);
	font-size: 0.85rem;
	min-height: 1.2em;
	margin: -0.4rem 0 0.8rem;
}

.wizard-nav {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 0.75rem;
	margin-top: 0.5rem;
}

.wizard-nav .wizard-back {
	margin-right: auto;
}

/* The honeypot must be visually gone but still in the DOM and still
   serializable — offscreen, never display:none, never disabled. */
form .field.honeypot {
	position: absolute !important;
	left: -9999px !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ---- touch input -----------------------------------------------------------
   iOS Safari zooms the whole viewport when a focused field's font-size is under
   16px, and it does NOT zoom back out on blur — the visitor is left panning a
   form they were halfway through filling in. The fields render at 0.95rem =
   15.2px. Missing the threshold by 0.8px costs the same as missing it by ten.

   max() rather than a flat 16px so the control still tracks the component's rem
   scale if that base ever grows; it can only ever clamp upward. Applied at every
   width, not inside a media query — iOS zooms on a wide iPad too. */
.wizard-step .fields > .field input,
.wizard-step .fields > .field textarea,
.wizard-step .fields > .field select {
	font-size: max(16px, 0.95rem);
}

/* Keyed on the input device rather than the viewport: a narrow desktop window
   is still driven by a mouse and does not need fingertip targets, while a large
   touchscreen does. Width is a poor proxy for how the thing is being touched. */
@media (pointer: coarse) {
	.wizard-step .fields > .field input,
	.wizard-step .fields > .field select {
		min-height: 44px;
	}

	/* 2.25rem = 36px. The close control is the escape hatch from a modal that
	   covers the page, so it is the last place to be stingy with the target. */
	.modal-close {
		width: 2.75rem;
		height: 2.75rem;
	}
}

@media screen and (max-width: 480px) {
	.modal-dialog {
		padding: 2rem 1.4rem 1.6rem;
		max-height: calc(100vh - 2rem);
	}
	.wizard-nav { flex-wrap: wrap; }
	.wizard-nav .wizard-back { margin-right: 0; order: 2; }
	.wizard-nav .wizard-next,
	.wizard-nav .wizard-submit { width: 100%; }
}

/* ---- OPTIONAL: HTML5UP-derived templates only -------------------------------
   Sites built on HTML5UP "Story" (and its relatives) ship a global
   input[type="radio"] reset written for an `input + label` pattern, plus
   `form > .fields > .field` DIRECT-child flex rules. Both collide with this
   component. The rules above already restore radio appearance and mirror the
   nested .fields layout, so nothing extra is needed — but if a template also
   floats or absolutely-positions radios, add:

     .wizard-intent-card input[type="radio"] {
       float: none; position: static; opacity: 1; z-index: auto;
     }

   Framer-rebuilt sites (the flagship default) have no such collisions.
---------------------------------------------------------------------------- */

/* ---- focus ------------------------------------------------------------------
   Only the text inputs were styled, so every other control — the close button,
   the intent options, Back/Next/Submit — fell back to the UA's default blue
   ring. That is a foreign colour on every site this wizard is dropped into, and
   it shows on a real path: arriving at <url>#contact-modal focuses the close
   button immediately. Keyboard focus must stay VISIBLE (removing the outline
   would be an accessibility regression), so it is re-drawn in the host site's
   own accent instead. :focus-visible, so a mouse click does not paint a ring.

   Do NOT add border-radius here. `outline` already follows each control's own
   border edge, so the ring is correctly rounded with no help. An earlier version
   set it, and because `.modal :focus-visible` (0,2,0) outranks `.modal-close`
   (0,1,0) it overrode that button's `border-radius: 50%`, squaring the circular
   close button into a 16px-radius rectangle the moment it took focus — on the
   very deep-link path described above. Measured on well-bean 2026-08-05. */
.modal :focus-visible {
	outline: 2px solid var(--wz-accent, #a8262c);
	outline-offset: 2px;
}
