/* src/assets/css/form.css (H5d) — Partners grid, Contact form validation UI, section-title fit.
   Loads after framer.css/brand.css (base.njk head order), so an equal-or-higher-specificity rule
   here wins the cascade without !important, except where noted.
   Strict monochrome (contract, brand.css): every colour below is var(--hwg-black)/--hwg-white/
   --hwg-grey (or the equivalent Framer token — same values, brand.css remaps them) — no red, no
   orange, no accent hue for error/status states.

   FIX ROUND 1 (Fable gate) — summary of what changed in this file, see each rule's own comment for
   detail: (1) blocker — new `[data-section="contact"]` rules give the form wrapper an explicit,
   root-agnostic width instead of depending on framer.css's `.framer-kWufe`-scoped rule, which this
   partial's reused header skeleton never actually matched (see contact-form.njk's file comment).
   (2) minor — partners grid columns now follow `--partners-cols` (set inline per partners.length,
   see partners.njk) instead of a hardcoded 3; the wordmark font-size is one monotonic clamp() with
   nowrap instead of two clamp()s that shrank going 768→1440. (3) minor — text inputs (Name/Email/
   Phone) get their own min-height so the ≥44px target-size predicate measures the *input element*,
   not just its 48px-tall wrapper. */

/* ============================================================
   Partners (R10, D6) — partners.njk reuses the Our Clients grid classes verbatim; framer.css
   already lays it out. Two adjustments: */

/* 1. Column count follows the data (partners.njk sets --partners-cols inline from partners.length).
      framer.css drops home--clients' grid to 2 columns at <=809.98px (it has 10 logos there,
      3/3/3/1); forcing it to the partner count at every width turns a would-be orphaned last row
      into one balanced grid instead — the "must still look intentional with 3 items at every width"
      requirement, generalised (finding 10) to also cover a future 4th/5th partner. Higher
      specificity than framer.css's unscoped `.framer-1qy4992` rule (and its own `[data-section]`
      attribute selector puts it after the plain-class media rule regardless of load order), so no
      !important needed. */
[data-section="partners"] .framer-1qy4992 {
  grid-template-columns: repeat(var(--partners-cols, 3), minmax(0, 1fr));
}
/*    Below 810px, cap at 2 columns (--partners-cols-mobile, set in partners.njk) like the Clients
      grid: with logos in 120px boxes, 3 columns at 390px leaves the logos touching. */
@media (max-width: 809.98px) {
  [data-section="partners"] .framer-1qy4992 {
    grid-template-columns: repeat(var(--partners-cols-mobile, 2), minmax(0, 1fr));
  }
}

/* 2. The wordmark text: Outfit bold (D31 body role — explicitly NOT .hwg-title/Bingo Dilan; the
      task calls this out because every other "card" on the site title-cases its heading in Bingo
      Dilan, and a partner name here stands in for a logo mark, not a heading). Sized to read as a
      logo lockup at every width without ever outgrowing the 120px/180px/240px-tall card
      (framer-1vxfgwq-container) it sits in.
      FIX (minor finding 10): ONE clamp() across every width — the old version used clamp(0.95rem,
      3.6vw, 1.65rem) below 1200px and a separate, smaller clamp(1.1rem, 1.6vw, 1.5rem) at >=1200px,
      which made 768px render LARGER (26.4px) than 1440px (23.04px) — a visible size drop crossing
      the desktop breakpoint. This clamp is monotonically increasing in viewport width by
      construction (a single positive vw coefficient, no breakpoint jump), and `nowrap` + a floor low
      enough that "Design Dock" (the longest of the 3 names) still fits one line in a 320px-wide
      viewport's card (verified: docs/reports/H5d.md, finding 10 table) replaces the old wrapping
      behaviour that let it break to 2 lines at 375/320. */
[data-section="partners"] div.partners-card {
  cursor: default; /* framer-db19t7 sets cursor:pointer for the template's <a> card; unlinked partners are plain divs (D6: no links). Partners with a `url` render as <a> and keep the pointer. */
}
[data-section="partners"] .partners-wordmark {
  margin: 0;
  width: 100%;
  padding: 0 8px;
  text-align: center;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
  font-size: clamp(0.6rem, 0.4rem + 1.6vw, 1.65rem);
  color: var(--token-8a650152-2d6e-46ea-8610-9e6ba7a473d7, #1a1a1a);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================
   Contact form (R11, D25) */

/* FIX (blocker finding 1 / major finding 2): the form wrapper's width. contact-form.njk reuses the
   "Our Clients" header skeleton (framer-1rigns8 etc., see that file's own comment) to hold the
   Contact Form Content block (framer-d5nw3l > framer-1n4h74r-container > form), but framer.css only
   ever sized `.framer-d5nw3l` under `.framer-kWufe` (live's actual /contact page root, which wraps a
   DIFFERENT, un-reused form component) — under any root this partial is actually mounted on (Home's
   framer-BNcNr, or whatever H6 mounts it on for /contact), `.framer-d5nw3l` matched no width/display
   rule at all and fell back to the browser default (shrink-to-fit block, ~190px). These rules give
   it an explicit width keyed only to `[data-section="contact"]`, so it is correct under every root:
     - framer-1rigns8 (the ancestor <header>, "Main Content") is a flex column with
       `padding: 0 48px` at >=1200px and `padding: 0 16px` below that (framer.css, verified against
       the live rendered rule) — its CONTENT width is therefore `100% - 96px` (desktop) or
       `100% - 32px` (tablet/phone) of the section.
     - Below 1200px the form stays a full-width flex child (matches the live deployment's own
       single-column tablet/phone /contact layout — confirmed against it at 768 and 390, see
       docs/reports/H5d.md for the measured numbers).
     - At >=1200px it takes calc((100% - 12px)/2) of that content width and right-aligns
       (margin-left:auto) — reproducing live's 2-column desktop layout's right-hand (form) column
       width to the pixel: framer-1rigns8's content width at 1440 is 1440-96=1344px,
       (1344-12)/2=666px — which is exactly live's measured form width at 1440 (see docs/reports/
       H5d.md). This intentionally approximates live's ACTUAL 4-column grid (327px x4, 12px gutter,
       96px row-gap) as a simple 2-column split of the flex column this partial actually uses, per
       the gate's own instruction ("if you align to the 3-column header grid instead, document it as
       an intended difference") — documented here: this is a deliberate, measured-equivalent
       approximation, not a literal port of live's grid, because this partial's DOM is the reused
       Our-Clients skeleton (flex column), not live's own Contact page markup (CSS grid). */
[data-section="contact"] .framer-d5nw3l {
  display: flex;
  flex-direction: column;
  gap: 48px;
  width: 100%;
  align-self: stretch;
  position: relative;
}
[data-section="contact"] .framer-1n4h74r-container {
  width: 100%;
  position: relative;
}
@media (min-width: 1200px) {
  [data-section="contact"] .framer-d5nw3l {
    width: calc((100% - 12px) / 2);
    margin-left: auto;
  }
}

/* Button row: framer-1m5ta60 is `justify-content:space-between` in framer.css because the template
   puts the checkbox on the left and the button on the right; contact-form.njk removes the checkbox
   (D25 has none), so the lone remaining child needs an explicit alignment or space-between collapses
   it to flex-start. Keeps the submit button where it visually sat before (right-aligned). */
[data-section="contact"] .framer-1m5ta60 {
  justify-content: flex-end;
}

/* FIX (minor finding 8, target size): the Name/Email/Phone wrapper (`.framer-form-text-input`) is
   48px tall but ALSO carries the field's full vertical padding (`--framer-input-padding: 12px 12px
   12px 0px`), so the flex content area inside it is only 48-24=24px — and the <input> itself
   (height:100% of that content area) renders as a 170x24 box even though its clickable LABEL area is
   the full 48px (probe.js flags this: "belowFloor" on the input element, not on the tap target).
   Move the padding off the wrapper and onto the input itself instead, with box-sizing:border-box so
   the input's own box IS the full 48px — visually identical (same padding, same position), but now
   the element the target-size predicate measures is 48px tall, not 24. Scoped to non-textarea inputs
   only (`input.framer-form-input`, not the bare `.framer-form-input` class, which textarea also
   carries): the Message field already gives its own padding to the <textarea> directly in framer.css
   (`.framer-form-textarea-input-type textarea.framer-form-input{padding:var(--framer-input-padding)}`,
   a more specific, tag-qualified rule that still wins for `padding` on that element) and is sized by
   its own min-height:240px, untouched by this fix. Subject's <select> uses a different wrapper class
   (`.framer-form-select-wrapper`) that was never affected by this bug (its own padding is applied to
   the wrapper only, no nested padded child), so it needs no fix here. */
[data-section="contact"] .framer-form-text-input:not(.framer-form-textarea-input-type) {
  padding: 0;
}
[data-section="contact"] .framer-form-text-input:not(.framer-form-textarea-input-type) input.framer-form-input {
  padding: var(--framer-input-padding);
  min-height: 48px;
  box-sizing: border-box;
}

/* Honeypot (D8: "keep one hidden honeypot input") — hidden from sighted users AND from screen
   readers (aria-hidden, set in contact-form.njk) but still present and fillable in the DOM, which is
   the point: a human never encounters it, a form-filling bot typically fills every field it finds. */
.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

/* Inline field errors (R1 input tolerance, R2 sub-400ms feedback — form.js shows/hides these
   synchronously on blur/submit, so the 400ms budget is met trivially). Monochrome: no red — a bold
   label plus a "!" marker carries the "this needs attention" signal instead of colour alone, which
   also keeps the message legible for colour-blind readers per the accessibility half of R1. */
.form-error {
  display: block;
  margin-top: 6px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 600;
  color: var(--token-8a650152-2d6e-46ea-8610-9e6ba7a473d7, #1a1a1a);
}
.form-error::before {
  content: "! ";
}
.form-error[hidden] {
  display: none;
}

/* A field form.js has flagged invalid gets a visible border cue in addition to its text error, so
   the signal isn't carried by the error text's position alone (R1). framer.css draws the field
   border on `.framer-form-input-wrapper:after`, reading `--framer-input-border-*` custom properties
   set inline on that wrapper DIV — the invalid state lives on the <input>/<select>/<textarea> child
   instead (that's what form.js can address by name), so :has() reaches up from the child to
   re-set the wrapper's own inline-set custom properties (needs !important: an inline `style=""`
   attribute otherwise beats any external stylesheet rule regardless of selector specificity). */
[data-contact-form] .framer-form-input-wrapper:has([aria-invalid="true"]) {
  --framer-input-border-color: var(--token-8a650152-2d6e-46ea-8610-9e6ba7a473d7, #1a1a1a) !important;
  --framer-input-border-bottom-width: 2px !important;
}

/* Send button gating (form.js (c)): disabled until every field validates, and again while a request
   is in flight. The template's own "Disabled" button variant was opacity 0.5 (contact-form.njk header,
   point 5) — same cue here, monochrome by construction since it only dims the black pill. Without JS
   the button is never disabled, so the native mailto fallback stays clickable. */
[data-contact-form] button[type="submit"][disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Post-submit status (form.js (f)): one <p> rendered into <div data-form-status>, with an
   `is-sending` / `is-success` / `is-error` class. Strict monochrome: no green for success, no red for
   error — the error state borrows .form-error's bold weight + "!" marker so it reads as the same
   family of message as the inline field errors; success is bold black with no marker; sending is the
   quiet grey used for labels. The error line's mailto link is the "email us directly" fallback. */
.form-status {
  margin-top: 16px;
  font-family: "Outfit", system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  color: var(--token-8a650152-2d6e-46ea-8610-9e6ba7a473d7, #1a1a1a);
}
.form-status[hidden] {
  display: none;
}
.form-status p {
  margin: 0 0 4px;
}
.form-status a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.form-status.is-sending {
  color: var(--token-1f5c424b-0c9b-4797-bb4e-e321473f3c05, #808080);
}
.form-status.is-success {
  font-weight: 600;
}
.form-status.is-error {
  font-weight: 600;
}
.form-status.is-error p::before {
  content: "! ";
}

/* ============================================================
   section-title.njk — reusable sticky/blurred big-title partial (see that file's own comment for
   why this is a clamp(), not the mirror's per-string SVG viewBox fit-text). */
.section-title .framer-yykji3 {
  padding-left: 24px;
  padding-right: 24px;
}
.section-title__wrap {
  position: relative;
  z-index: 3; /* above framer-11l58a0's Overlay Blur (z-index:2) even though its mask already fades to transparent in the middle where this sits */
  width: 100%;
  max-width: 100%;
  overflow: visible; /* R3: this replaces the mirror's overflow:hidden Subheadline wrapper on purpose — see file header */
}
.section-title__text {
  margin: 0;
  width: 100%;
  text-align: center;
  line-height: 1em; /* R3 fix: Bingo Dilan's descender needs a 1em box, same rule brand.css applies to .framer-fit-text > .framer-text */
  font-size: clamp(2rem, 11vw, 14rem);
  letter-spacing: -0.02em;
  white-space: normal; /* not nowrap: arbitrary future title text must be free to wrap rather than overflow horizontally */
  overflow-wrap: break-word;
  color: var(--token-8a650152-2d6e-46ea-8610-9e6ba7a473d7, #1a1a1a);
}
.section-title[data-theme="dark"] .section-title__text {
  color: var(--token-5e4a9a17-35e5-4f0c-b88b-7a6cb15bd7f2, #fff);
}
