/* ============================================================================
   OROVELL / FORMS
   The enquiry form, shared by contact.html and the landing pages under
   contact/ (their full form and the four-field hero card; the newsletter
   strip is gone: client ruling 2026-09-16). Loads AFTER css/chrome.css and
   uses only its tokens (the four brand colours at graded alphas, the one
   hairline, the 5px radius).
   Client ruling 6: it must look like a form. Visible labels above every
   field, real bordered inputs on an obsidian .6 fill, 14px+ text, a gold
   focus ring, asterisks on required fields with a "* required" note, one
   submit button, inline error text under the field, the whole form visible
   at once. Choice groups are real radio inputs rendered as segmented labels
   with a visible checked state (a square gold mark: no circles, no pills).
   Behaviour lives in js/enquiry.js.
   Client ruling 2026-09-17: the spam gate greys the submit (.btn-off) and
   shows one line (.form-spam) in the error grammar; reCAPTCHA v3's badge is
   hidden and its disclosure (.form-rc) stands in, plate caps, linen .45.
   ========================================================================= */

/* ------------------------------------------------------------- the card */
.form-card{
  position:relative;
  background:var(--l06); border:1px solid var(--hair); border-radius:var(--r);
  padding:clamp(24px,3.2vw,44px);
}
.form-card form{ display:block; }
.form-head{ display:flex; align-items:baseline; justify-content:space-between; gap:16px; flex-wrap:wrap;
  margin-bottom:22px; padding-bottom:16px; border-bottom:1px solid var(--hair); }
.form-head h2{ font-family:Aboreto, Georgia, serif; font-weight:400; text-transform:uppercase; letter-spacing:0;
  font-size:clamp(17px,1.6vw,22px); line-height:1.2; color:var(--linen); }
/* the required note: label rank, so it may track */
.form-note{ font-family:Figtree, system-ui, sans-serif; font-size:11px; font-weight:400; letter-spacing:.12em;
  text-transform:uppercase; color:var(--l45); line-height:1.6; }
.form-note .req,.fld-lbl .req{ color:var(--gold); font-style:normal; text-decoration:none; border:0; }

/* ------------------------------------------------------------- fields */
.fld{ margin-bottom:20px; }
.fld-row{ display:grid; grid-template-columns:1fr 1fr; gap:0 18px; }
.fld-lbl{
  display:block; margin-bottom:8px;
  font-family:Figtree, system-ui, sans-serif; font-size:12px; font-weight:400; line-height:1.5;
  letter-spacing:.12em; text-transform:uppercase; color:var(--l72);
}
.fld-lbl .req{ margin-left:3px; }
.fld input[type="text"],.fld input[type="email"],.fld input[type="tel"],.fld textarea{
  display:block; width:100%;
  font-family:Figtree, system-ui, sans-serif; font-size:15px; font-weight:300; line-height:1.4;
  color:var(--linen); background:rgba(5,5,5,.6);
  border:1px solid var(--hair); border-radius:var(--r);
  padding:14px 16px; outline:none; appearance:none; -webkit-appearance:none;
  transition:border-color .2s ease;
}
.fld textarea{ min-height:128px; resize:vertical; }
.fld input::placeholder,.fld textarea::placeholder{ color:var(--l30); }
.fld input:focus-visible,.fld textarea:focus-visible{
  border-color:var(--gold); outline:1px solid var(--gold); outline-offset:2px;
}
.fld input:-webkit-autofill,.fld input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--linen); -webkit-box-shadow:0 0 0 1000px var(--obsidian) inset; transition:background-color 9999s;
}
/* the invalid state: gold border, the message under the field */
.fld.bad input,.fld.bad textarea{ border-color:var(--gold); }
.fld .err{
  display:none; margin-top:8px;
  font-family:Figtree, system-ui, sans-serif; font-size:12.5px; font-weight:400; line-height:1.5;
  color:var(--gold);
}
.fld.bad .err{ display:block; }
.fld .hint{ display:block; margin-top:8px; font-family:Figtree, system-ui, sans-serif; font-size:12.5px;
  font-weight:300; line-height:1.5; color:var(--l45); }

/* --------------------------------------------------------- choice groups
   A fieldset per question, the question as its legend (styled like a label),
   the options as real radios whose labels render segmented. The native radio
   stays in the tab order (clipped, not display:none) so keyboard and screen
   readers get the real control; the square mark is the visible state. */
.fld fieldset{ border:0; padding:0; margin:0; min-width:0; }
.fld legend{ padding:0; float:left; width:100%; }   /* float so the legend takes the label rhythm */
.fld legend + *{ clear:both; }
.seg{ display:flex; flex-wrap:wrap; gap:8px; }
.opt{ position:relative; display:inline-flex; margin:0; cursor:pointer; }
/* a budget band hidden for the chosen size (js/enquiry.js sets [hidden] on
   the label from its data-hide-size); the [hidden] attribute must beat the
   inline-flex above or the option would still paint */
.opt[hidden]{ display:none; }
.opt input{
  position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}
.opt span{
  display:inline-flex; align-items:center; gap:10px;
  font-family:Figtree, system-ui, sans-serif; font-size:14px; font-weight:300; line-height:1.3;
  color:var(--l72); background:rgba(5,5,5,.6);
  border:1px solid var(--hair); border-radius:var(--r); padding:11px 14px;
  transition:border-color .2s ease, color .2s ease, background-color .2s ease;
}
/* the square mark, never a circle */
.opt span::before{
  content:''; flex:none; width:12px; height:12px; border:1px solid var(--l45);
  background:transparent; transition:background-color .2s ease, border-color .2s ease;
}
.opt:hover span{ border-color:var(--l45); color:var(--linen); }
.opt input:checked + span{ border-color:var(--gold); color:var(--linen); background:rgba(224,184,126,.08); }
.opt input:checked + span::before{ background:var(--gold); border-color:var(--gold); }
.opt input:focus-visible + span{ outline:1px solid var(--gold); outline-offset:2px; }
.fld.bad .opt span{ border-color:var(--gold); }
.fld.bad .opt input:checked + span{ border-color:var(--gold); }

/* the budget group waits for a size (ruling 6): greyed, not selectable */
.fld fieldset:disabled .opt,.fld fieldset[aria-disabled="true"] .opt{ cursor:not-allowed; }
.fld fieldset:disabled .opt span,.fld fieldset[aria-disabled="true"] .opt span{
  color:var(--l30); border-color:var(--l12); background:transparent;
}
.fld fieldset:disabled .opt span::before,.fld fieldset[aria-disabled="true"] .opt span::before{ border-color:var(--l20); }
.fld fieldset:disabled legend .fld-lbl,.fld fieldset[aria-disabled="true"] legend .fld-lbl{ color:var(--l45); }
/* the gate hint stays hint-coloured (gold is for errors only); the greyed
   group and the not-allowed cursor carry the disabled affordance */
.fld fieldset:disabled .hint{ color:var(--l45); }
.fld fieldset:not(:disabled) .hint.gate{ display:none; }

/* ------------------------------------------------------------- honeypot
   Off-canvas, not display:none, so a bot that reads computed styles still
   sees a field and fills it. Never focusable, never read. */
.hp{ position:absolute; left:-9999px; top:auto; width:1px; height:1px; overflow:hidden; }

/* ------------------------------------------------------------- submit row */
.form-actions{ margin-top:26px; padding-top:22px; border-top:1px solid var(--hair);
  display:flex; align-items:center; gap:18px; flex-wrap:wrap; }
button.btn{ cursor:pointer; }
.form-actions .btn[disabled]{ opacity:.55; cursor:progress; }
.form-actions .btn[disabled] .wipe{ display:none; }
.form-privacy{ font-family:Figtree, system-ui, sans-serif; font-size:12.5px; font-weight:300; line-height:1.5; color:var(--l45); max-width:36ch; }

/* the fallback when the post fails (ruling 7): a bordered alert with the
   WhatsApp route; .ok is the quiet success variant */
.form-alert{
  display:none; margin-top:18px; padding:16px 18px;
  border:1px solid var(--gold); border-radius:var(--r); background:rgba(224,184,126,.06);
  font-family:Figtree, system-ui, sans-serif; font-size:14.5px; font-weight:300; line-height:1.6; color:var(--linen);
}
.form-alert.on{ display:block; }
.form-alert a{ color:var(--gold); text-decoration:underline; text-underline-offset:3px; }
.form-alert.ok{ border-color:var(--l20); background:var(--l06); }

/* ------------------------------------------------------ the linen variant
   A form on a linen band (the landing pages' bottom form): the same
   fields, the alphas swapped to the obsidian side. */
.linen .form-card{ background:rgba(5,5,5,.025); border-color:var(--hair-d); }
.linen .fld-lbl{ color:var(--o72); }
.linen .fld input[type="text"],.linen .fld input[type="email"],.linen .fld input[type="tel"],.linen .fld textarea{
  color:var(--obsidian); background:var(--linen); border-color:var(--o20);
}
.linen .fld input::placeholder{ color:var(--o45); }
.linen .fld input:focus-visible{ border-color:var(--wine); outline-color:var(--wine); }
.linen .fld.bad input{ border-color:var(--wine); }
.linen .fld .err{ color:var(--wine); }
.linen .form-note,.linen .form-privacy{ color:var(--o45); }
.linen .form-note .req,.linen .fld-lbl .req{ color:var(--wine); }
.linen .form-alert{ border-color:var(--wine); background:rgba(75,25,40,.06); color:var(--obsidian); }
.linen .form-alert a{ color:var(--wine); }
.linen .form-alert.ok{ border-color:var(--o20); background:rgba(5,5,5,.025); }
.linen .form-actions{ border-top-color:var(--hair-d); }
/* the landing pages' bottom form can sit on linen too: the card heads, the
   segmented radios, the gated budget group and the textarea all swap to the
   obsidian side (wine for the checked and focus states) */
.linen .form-head{ border-bottom-color:var(--hair-d); }
.linen .form-head h2{ color:var(--obsidian); }
.linen .fld .hint{ color:var(--o45); }
.linen .fld textarea::placeholder{ color:var(--o45); }
.linen .fld textarea:focus-visible{ border-color:var(--wine); outline-color:var(--wine); }
.linen .fld input:-webkit-autofill,.linen .fld input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--obsidian); -webkit-box-shadow:0 0 0 1000px var(--linen) inset;
}
.linen .fld.bad textarea{ border-color:var(--wine); }
.linen .opt span{ color:var(--o72); background:var(--linen); border-color:var(--o20); }
.linen .opt span::before{ border-color:var(--o45); }
.linen .opt:hover span{ border-color:var(--o45); color:var(--obsidian); }
.linen .opt input:checked + span{ border-color:var(--wine); color:var(--obsidian); background:rgba(75,25,40,.06); }
.linen .opt input:checked + span::before{ background:var(--wine); border-color:var(--wine); }
.linen .opt input:focus-visible + span{ outline-color:var(--wine); }
.linen .fld.bad .opt span,.linen .fld.bad .opt input:checked + span{ border-color:var(--wine); }
.linen .fld fieldset:disabled .opt span,.linen .fld fieldset[aria-disabled="true"] .opt span{
  color:var(--o45); border-color:var(--o12); background:transparent;
}
.linen .fld fieldset:disabled .opt span::before,.linen .fld fieldset[aria-disabled="true"] .opt span::before{ border-color:var(--o20); }
.linen .fld fieldset:disabled legend .fld-lbl,.linen .fld fieldset[aria-disabled="true"] legend .fld-lbl{ color:var(--o45); }
.linen .fld fieldset:disabled .hint{ color:var(--o45); }

/* ------------------------------------------------------------- spam gate
   js/enquiry.js greys the submit while name, city or message holds a link,
   an offer or rubbish (client ruling 2026-09-17): real disabled, .btn-off,
   an obsidian .35 plate with linen .45 type, no hover wipe, no roll. ONE
   line under the actions row in the .err grammar; the offending field
   carries .spam (the .bad border without a field message). */
.form-actions .btn.btn-off,.form-actions .btn.btn-off[disabled]{
  background:rgba(5,5,5,.35); color:var(--l45); opacity:1; cursor:not-allowed;
}
.btn.btn-off .wipe{ display:none; }
.btn.btn-off:hover .roll > i,.btn.btn-off:focus-visible .roll > i{ transform:none; }
.fld.spam input,.fld.spam textarea{ border-color:var(--gold); }
.form-spam{
  display:block; margin:0;
  font-family:Figtree, system-ui, sans-serif; font-size:12.5px; font-weight:400; line-height:1.5;
  color:var(--gold);
}
/* stays in the tree while empty (an empty p has no height) so the
   aria-live region is already present when its text changes */
.form-spam.on{ margin-top:12px; }

/* --------------------------------------------------------- reCAPTCHA v3
   The badge is hidden; Google's required disclosure line stands in under
   the button, plate caps at linen .45. js/enquiry.js inserts it only when
   the page carries a site key, so an empty key shows nothing. */
.grecaptcha-badge{ visibility:hidden; }
.form-rc{
  margin-top:14px;
  font-family:Figtree, system-ui, sans-serif; font-size:10.5px; font-weight:400; letter-spacing:.12em;
  text-transform:uppercase; line-height:1.6; color:var(--l45);
}
.form-rc a{ color:inherit; text-decoration:underline; text-underline-offset:3px; }
.form-rc a:hover,.form-rc a:focus-visible{ color:var(--l72); }

/* the linen variant of the gate and the disclosure: alphas on the obsidian side */
.linen .form-actions .btn.btn-off,.linen .form-actions .btn.btn-off[disabled]{ background:var(--o12); color:var(--o45); }
.linen .fld.spam input,.linen .fld.spam textarea{ border-color:var(--wine); }
.linen .form-spam{ color:var(--wine); }
.linen .form-rc{ color:var(--o45); }
.linen .form-rc a:hover,.linen .form-rc a:focus-visible{ color:var(--o72); }

/* ------------------------------------------------------------- responsive */
@media (max-width:640px){
  .fld-row{ grid-template-columns:1fr; }
  .seg{ display:grid; grid-template-columns:1fr 1fr; }
  .opt span{ width:100%; }
}
