/* ── the contact block ──────────────────────────────────────────────────────
   Text on the left, the four-field form on the right. It used to live in
   tech.css, which meant only the families loading that sheet could render it —
   and the homepage, the page with the most traffic, was not one of them. It is
   its own sheet now: one component, one copy, enqueued wherever a form appears.
   Everything resolves to the design-system tokens in base.css. */
.contact-split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: stretch; }
.contact-left { display: flex; flex-direction: column; padding-top: 48px; }
.contact-left p { margin-top: auto; margin-bottom: 120px; }
.contact-left h2 { line-height: var(--lh-h2); font-size: var(--fs-h2); font-weight: 400; margin-bottom: 8px; }
/* the frame draws this as the subtitle role in the muted tone (1497:3400), not
   as a second heading — the headline above it is the h3 */
.contact-left h3 { line-height: var(--lh-subtitle); font-size: var(--fs-subtitle); font-weight: 400; color: var(--text-dim); margin-bottom: 0; }
.contact-left p { font-size: var(--fs-p); color: var(--text-dim); }
.form-card { position: relative; background: #fff; border: none; border-radius: var(--r); overflow: hidden; box-shadow: none; }
.form-card::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; z-index: 2;
    background: linear-gradient(180deg, var(--card-border) 0%, var(--card-border) 42%, rgba(230,235,242,0.35) 74%, rgba(230,235,242,0) 100%);
    -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; }
.form-body { padding: 32px 32px 32px; }
/* The frame's field is 44 tall on 20px of inset with the value at 16 (1315:2010),
   and the groups sit 24 apart. Ours drew 58 — 18px type on 16px of padding — which
   put the card 42px longer over three fields before anything else was counted.
   44 is also exactly §17's floor for a touch target, so this is as tight as it goes. */
.form-body input, .form-body select, .form-body textarea { width: 100%; font-family: var(--ff); font-size: var(--fs-p-small); color: var(--ink); background: #fff; border: 1px solid var(--card-border); border-radius: var(--r-sm); padding: 11px 20px; margin-bottom: 24px; }
.form-body textarea { min-height: 120px; resize: vertical; padding-top: 14px; }
.form-body ::placeholder { color: var(--ink); opacity: 0.8; }
/* The amber border marks focus for everyone; the outline is only suppressed for a
   pointer focus. It used to be suppressed for both — and because form.css loads
   after base.css at equal specificity, it beat the :focus-visible ring there and
   left every field on 121 pages with no keyboard focus indicator at all (§17). */
.form-body input:focus, .form-body select:focus, .form-body textarea:focus { border-color: var(--amber); }
.form-body input:focus:not(:focus-visible), .form-body select:focus:not(:focus-visible), .form-body textarea:focus:not(:focus-visible) { outline: none; }

/* form labels — placeholders alone vanish the moment someone starts typing,
   which leaves the field unidentifiable on review and unusable to a screen reader */
.form-body label { display: block; font-size: var(--fs-p-small); font-weight: 600;
  color: var(--ink); margin-bottom: 7px; }
/* the required marker carries meaning, so it cannot be amber-on-white (1.67:1) —
   the system resolves accent-as-text on light backgrounds to navy */
.form-body label .req { color: var(--ink); }
.form-body ::placeholder { color: var(--muted); opacity: 1; }
/* the legal line is the last thing read before submitting, and it was the least
   readable text in the form: 12px of --muted on a phone */
/* The frame's marketing opt-in (unchecked, optional). It sits above the consent
   copy, the way the frame stacks them. 24px of box is short of §17's 44 on its own,
   so the label carries the target: the whole row is clickable, not just the square. */
/* .form-body .form-optin, not .form-optin: `.form-body label` above is 0,1,1 and this
   was 0,1,0, so display:flex, align-items and gap were all being dropped and the label
   stayed a block. What looked like an 8px gap was the whitespace between the tags. */
.form-body .form-optin { display: flex; align-items: flex-start; gap: var(--s-1);
  cursor: pointer; min-height: 44px; margin-top: 8px; }
/* .form-body label is a field caption — 600 and navy. This one is a sentence beside
   a checkbox, so it takes the supporting tone the frame gives it. */
.form-body .form-optin span { font-size: var(--fs-p-small); font-weight: 400; color: var(--text-dim); line-height: 1.4; }
/* The box matches the text it sits beside — 16px of --fs-p-small — rather than
   standing 4px taller than it. align-items is flex-start, not center, because the
   sentence wraps on a narrow screen and a centred box then floats between the lines.
   2.5px is measured, not derived: the text's ink box is 21px inside a 22.4px line
   box, so the arithmetic answer of 3.2px lands half a pixel low. This centres the
   box on the FIRST line whether the sentence takes one line or three. */
.form-body .form-optin input { width: 16px; height: 16px; flex-shrink: 0; margin: 2.5px 0 0;
  accent-color: var(--navy); cursor: pointer; }
.form-consent { font-size: var(--fs-p-small); color: var(--text-dim); line-height: 1.65; margin: 0 0 24px; }
.form-consent a { color: var(--ink); text-decoration: underline; }

/* ── form submit states ─────────────────────────────────────────────────────
   Replaces the form body once the request is actually accepted, so the visitor
   gets a confirmation instead of the old silence after a mailto: submit. */
.form-state { padding: 8px 0 2px; }
.form-state h3 { line-height: var(--lh-h4); font-size: var(--fs-h4); font-weight: 500; margin-bottom: 8px; }
.form-state p { font-size: var(--fs-p-small); color: var(--text-dim); line-height: var(--lh-p); }
.form-state .btn { margin-top: var(--s-3); }
.form-state.is-ok h3::before { content: "✓"; display: inline-grid; place-items: center;
  width: 32px; height: 32px; margin-right: 16px; border-radius: 50%;
  background: var(--amber); color: var(--navy); font-size: var(--fs-h6); vertical-align: -6px; }
.form-state.is-err { margin-top: 16px; padding: 16px 24px; border-radius: var(--r-md);
  background: var(--amber-soft); border: 1px solid var(--card-border); }
.form-state.is-err h3 { font-size: var(--fs-h5); line-height: var(--lh-h5); }
.form-state-mail { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
form.is-sending button[type="submit"] { opacity: .6; cursor: progress; }
/* the honeypot must be unreachable for people but present for bots */
.form-body .hp { position: absolute !important; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* the one secondary action, identical on every form: proof + the booking path */

@media (max-width: 940px) {
  .contact-split { grid-template-columns: 1fr; gap: 32px; }
}

/* ── "Prefer another way to talk?" ────────────────────────────────────────────
   The frame keeps this in the copy column beside the card (1338:999), not under
   the submit button: the reply promise, the question, then the two ways to reach
   us as labelled links each carrying its own 16px mark after the words. The page
   had the promise and a "or book a call instead / WhatsApp" aside stacked below
   the button instead, with no icons at all. */
.contact-alt { margin-top: 48px; }
/* Scoped through .contact-alt: .cta-lb-text p and .contact-left p are both (0,1,1)
   and would otherwise win, painting the question the same muted grey as the promise
   above it — the frame has it navy (1338:996), which is what separates the two. */
.contact-alt .ca-reply { font-size: var(--fs-p); line-height: var(--lh-p); color: var(--text-dim); margin: 0; max-width: none; }
.contact-alt .ca-lead { font-size: var(--fs-subtitle); line-height: var(--lh-subtitle); color: var(--ink); margin: 0 0 16px; max-width: none; }
.ca-links { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.ca-link { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-p-small);
  color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }
.ca-ic { width: 16px; height: 16px; flex-shrink: 0; }
/* 44px of target under a finger, grown with padding so the row keeps its size (§17) */
@media (hover: none) and (pointer: coarse) {
  .ca-link { padding: 12px 0; }
}

/* ── The contact section, as every master frame draws it ──────────────────────
   Tech (1497:3455), Agency (1497:3400), AI (1497:3345), About (1497:3290) and
   Work (1497:3235) are the same 1438x754 band: "Got an idea? Let's make it real."
   over the short-consent form, on the grey gradient. It lived in home.css, which
   only the homepage loads, so the five masters were each carrying their own older
   variant — a page-specific headline, a team photo in the copy column and the long
   three-link consent paragraph. One block now, here, where every family sees it. */
.cta-lightbulb { padding: 96px 0; background: var(--grad-gray); }
.cta-lightbulb .wrap { max-width: 1340px; padding-left: 32px; padding-right: 32px; }  /* line the content up with the nav/logo */
/* The Secondary Button here is the Secondary Button. It went yellow on hover once,
   then kept a local copy of the grey hover; both are gone — §09 says the component
   owns its own states and no page overrides them. */
.cta-lb-text h2 { line-height: var(--lh-h3); font-size: var(--fs-h3); font-weight: 500; margin-bottom: 8px; }
.cta-lb-text p { font-size: var(--fs-p); color: var(--text-dim); line-height: 1.7; max-width: 560px; }
.cta-lb-text p + p { margin-top: 24px; }
.cta-lb-text .btn { margin-top: var(--s-5); }
/* No artwork in the copy column — the frame has only the copy and the "another way
   to talk" block. The column reads top-down: 32 under the headline, 24 under the
   subtitle, so .contact-left's push-to-bottom paragraph rules are cancelled here. */
.cta-lightbulb .contact-left { padding-top: 0; }
.cta-lightbulb .contact-left p { margin-top: 0; margin-bottom: 0; }
.cta-lightbulb .contact-left h3 { margin-bottom: 24px; }
