/* ============================================================
   Form card — a Ninja Forms form wearing this site's design.
   Ported from the mockup's .nlcard / .nlfield / .nlconsent
   (styles/newsletter.css), to the value.

   TWO cascade facts shape every selector below, and both are the opposite of
   the usual block-CSS advice in BLOCKS.md trap 2:

     · NF enqueues `display-structure.css` while the CONTENT renders — after
       wp_head has already printed this sheet — so NF's rules come LATER and a
       TIE GOES TO NINJA FORMS. Every rule here has to out-specify its NF
       counterpart, not merely match it. The counterpart is named in a comment
       wherever the specificity looks excessive; it always is on purpose.
     · NF's per-form Styles add-on is suppressed for anything rendered inside
       this block (inc/forms.php). Without that, one ID-selector rule
       (specificity 1,4,0) would paint the submit button and no class selector
       could ever win. This sheet therefore only has to beat the structure
       sheet, which is the layout skeleton and nothing more.

   What is deliberately LEFT to Ninja Forms: the row/cell grid, the label
   ordering per label position, the error markup, the required-symbol, the
   character counters. Restyling those would be re-implementing the plugin.
   ============================================================ */

/* ---------- the card ---------- */

.vt-form {
  display: grid;
  gap: 18px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: clamp(28px, 4cqi, 40px);
  /* The mockup's own shadow. Mixed at the use site from --color-ink, because no
     token carries an opacity. */
  box-shadow: 0 18px 40px color-mix(in srgb, var(--color-ink) 6%, transparent);
  /* Trap 9: a grid in a section's content stack must claim its width, or the
     stack's align-items: flex-start collapses it to min-content. */
  width: 100%;
  /* The card is a light panel on any band — including a dark one. A form is
     read and typed into; a white sheet is what says "fill this in", and the
     tokens below are stated rather than inherited so a dark section's --vt-fg
     never reaches the labels. */
  color: var(--color-text);
  /* And the same statement in the section skeleton's own terms, so it also
     holds for BLOCKS placed inside the card (2026-08-26). visitech/text and its
     neighbours read --vt-fg-muted, not `inherit`, so a dark band would
     otherwise put white intro copy on this white sheet. Restoring the light
     triple here is the whole fix — no atom needs a form-specific rule. */
  --vt-fg: var(--color-text);
  --vt-fg-muted: var(--color-text-muted);
  --vt-fg-subtle: var(--color-text-subtle);
}

.vt-form__label {
  font-family: var(--font-display);
  font-weight: var(--fw-medium);
  font-size: 20px;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--color-text);
  margin: 0 0 2px;
}

/* The intro stack — the mockup's `.ctintro` (styles/contact.css): what the
   reader needs to know BEFORE they start filling the form in. A stack of its
   own rather than the card's grid gap, because two sentences of the same note
   belong closer together than the note belongs to the fields.

   `--vt-text-size` is how visitech/text takes its size from what it sits in
   (the card's body does the same), so an inner paragraph wears the mockup's
   15px without this sheet reaching into another block's selectors. */
.vt-form__intro {
  display: flex;
  flex-direction: column;
  gap: 10px;
  --vt-text-size: 15px;
}

/* The mockup's `.ctintro__p strong` — the department name each sentence is
   about, which is the word the eye is looking for. */
.vt-form__intro strong {
  color: var(--color-dark-purple);
  font-weight: var(--fw-bold);
}

.vt-form__fine {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-subtle);
  text-align: center;
}
.vt-form__fine a { color: var(--color-dark-purple); }

/* ---------- NF's own chrome ---------- */

/* NF's loading spinner has `margin: 100px auto` and a 40px box — 240px of
   nothing while its Backbone app boots. Reserving that height in the card is
   worse than a short card that grows, so it is brought down to something that
   reads as a pause rather than a gap. */
.vt-form .nf-loading-spinner { margin: 24px auto; }

/* The no-JS message: NF paints a 40px-padded dashed grey slab with 20px text.
   It is a real fallback and must stay legible, but it is not a hero. */
.vt-form .ninja-forms-noscript-message {
  margin: 0;
  padding: 18px 20px;
  font-size: 14px;
  line-height: 1.5;
  text-align: left;
  color: var(--color-text-muted);
  background: var(--color-bg-subtle);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
}

/* "Fields marked with an * are required" — kept (it is information), quieted. */
.vt-form .nf-form-fields-required {
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-subtle);
  margin-bottom: 14px;
}

.vt-form .ninja-forms-req-symbol { color: var(--color-dark-purple); }

/* ---------- one field ---------- */

/* NF: `.nf-field-container { margin-bottom: 25px }` (0,1,0). The mockup's
   rhythm is the card's 18px gap, and the LAST field must not push the button
   away from it. */
.vt-form .nf-field-container { margin-bottom: 18px; }
.vt-form .nf-row:last-child .nf-field-container { margin-bottom: 0; }

/* NF: `.nf-field-label .nf-label-span, .nf-field-label label { font-weight: 700 }`
   (0,2,0) — hence three classes here. The mockup's field label is 13px medium,
   not bold: bold labels above every input make a form shout. */
.vt-form .nf-field-container .nf-field-label label,
.vt-form .nf-field-container .nf-field-label .nf-label-span {
  font-size: 13px;
  font-weight: var(--fw-medium);
  line-height: 1.4;
  color: var(--color-text);
}

/* NF: `.label-above .nf-field-label { margin-bottom: 10px }` (0,2,0) — the
   mockup's .nlfield gap is 7px. */
.vt-form .label-above .nf-field-label { margin-bottom: 7px; }

/* The text inputs and selects — the mockup's .nlfield input / select.

   NF: `.field-wrap > div input`, `.field-wrap select`, `.field-wrap textarea`
   (0,2,1) set width, and `.nf-field-element input` (0,1,1) sets width/height —
   so the three-class form below is the minimum that wins. The :not() chain
   costs no specificity and keeps checkboxes, radios and the submit button out:
   they are their own components further down. */
.vt-form .field-wrap > .nf-field-element input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
.vt-form .field-wrap > .nf-field-element select,
.vt-form .field-wrap > .nf-field-element textarea {
  width: 100%;
  padding: 12px 16px;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  outline: none;
  box-shadow: none;
  transition: border-color var(--dur-base) var(--ease-standard),
              box-shadow var(--dur-base) var(--ease-standard);
}

.vt-form .field-wrap > .nf-field-element input::placeholder,
.vt-form .field-wrap > .nf-field-element textarea::placeholder {
  color: var(--color-text-subtle);
}

.vt-form .field-wrap > .nf-field-element input:focus,
.vt-form .field-wrap > .nf-field-element select:focus,
.vt-form .field-wrap > .nf-field-element textarea:focus {
  border-color: var(--color-light-purple);
  box-shadow: var(--focus-ring);
}

.vt-form .field-wrap > .nf-field-element textarea { min-height: 120px; resize: vertical; }

/* 16px stops iOS Safari zooming the page when a field takes focus (Petter,
   2026-06-24 — the mockup states the same rule at 768px). Keyed on the SECTION
   rather than the viewport, which is this stack's rule; below a 768px band the
   card is full width and the reader is on a phone, which is exactly the case
   the rule is for. */
@container vt-section (max-width: 768px) {
  .vt-form .field-wrap > .nf-field-element input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
  .vt-form .field-wrap > .nf-field-element select,
  .vt-form .field-wrap > .nf-field-element textarea {
    font-size: 16px;
  }
}

/* The native select's caret, redrawn in the muted ink — the mockup's own
   data-URI, so the arrow is not a second file to load. */
.vt-form .field-wrap > .nf-field-element select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b6478' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px;
}

/* NF prints an empty `<div for="nf-field-N">` after a list select. Nothing
   renders in it and it adds a line box. */
.vt-form .list-wrap .nf-field-element > div:empty { display: none; }

/* The character counter NF prints under a maxlength field ("50 of 50
   Character(s) left"). It is an aria-live region, so it is hidden VISUALLY and
   not with display:none — that would stop the announcement as well as the
   noise. Same clip pattern as NF's own .nf-sr-only. */
.vt-form .nf-input-limit:not(:empty) {
  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;
}

/* ---------- checkboxes and radios ---------- */

/* The consent row — the mockup's .nlconsent / .ctcheck: the box, then the
   sentence beside it. NF's label position puts the label first and the element
   third (`.nf-field-label { order: 5 }`, `.nf-field-element { order: 15 }`),
   which for a single checkbox reads as a heading floating over a lone box. The
   rules below re-order the same three elements; nothing is added or hidden.

   BOTH label positions are handled, because a form builder can choose either
   and the card must not depend on which was chosen. `label-above` is what the
   newsletter form uses; `label-right` is what the contact form uses, and it
   arrives with a second problem — NF keeps the row `nowrap` and gives the
   DESCRIPTION `margin-right: 35%` on the same line, which squeezed "Subscribe
   to our newsletter?" into a five-line column. Wrapping the row and putting the
   description on its own line is the same fix in both cases.

   `.label-above .field-wrap { flex-direction: column }` and
   `.label-right .field-wrap { flex-direction: row }` are (0,2,0), so these
   carry three classes; the child rules need four to beat
   `.label-right .checkbox-wrap .nf-field-element { width: 20px }` (0,3,0). */
.vt-form .label-above .checkbox-wrap,
.vt-form .label-above .listcheckbox-wrap,
.vt-form .label-above .listradio-wrap,
.vt-form .label-right .checkbox-wrap,
.vt-form .label-right .listcheckbox-wrap,
.vt-form .label-right .listradio-wrap {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  column-gap: 10px;
}

/* A single checkbox (consent, opt-in): box first, its sentence beside it. */
.vt-form .label-above .checkbox-wrap > .nf-field-element,
.vt-form .label-right .checkbox-wrap > .nf-field-element {
  order: 0;
  width: auto;
  flex: 0 0 auto;
  margin-top: 2px;
}
.vt-form .label-above .checkbox-wrap > .nf-field-label,
.vt-form .label-right .checkbox-wrap > .nf-field-label {
  order: 1;
  flex: 1 1 0;
  min-width: 0;
  width: auto;
  margin: 0;
  /* NF: `.label-right .nf-field-label { padding-left: 2% }` — an indent for a
     label that sits to the RIGHT of a 35% column, which this one no longer
     does. */
  padding-left: 0;
}
.vt-form .label-above .checkbox-wrap > .nf-field-label label,
.vt-form .label-right .checkbox-wrap > .nf-field-label label {
  font-weight: var(--fw-regular);
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-muted);
}
.vt-form .label-above .checkbox-wrap > .nf-field-description,
.vt-form .label-right .checkbox-wrap > .nf-field-description {
  order: 2;
  flex-basis: 100%;
  /* the margin is NF's 35% indent, and it has to go with the row */
  margin: 6px 0 0;
}

/* A LIST of checkboxes ("I am interested in:") keeps its label as a label —
   the group needs a name — so only the element goes back under it. */
.vt-form .label-above .listcheckbox-wrap > .nf-field-label,
.vt-form .label-above .listradio-wrap > .nf-field-label,
.vt-form .label-right .listcheckbox-wrap > .nf-field-label,
.vt-form .label-right .listradio-wrap > .nf-field-label {
  order: 0;
  flex-basis: 100%;
  width: auto;
  padding-left: 0;
  margin-bottom: 7px;
}
.vt-form .label-above .listcheckbox-wrap > .nf-field-element,
.vt-form .label-above .listradio-wrap > .nf-field-element,
.vt-form .label-right .listcheckbox-wrap > .nf-field-element,
.vt-form .label-right .listradio-wrap > .nf-field-element {
  order: 1;
  flex-basis: 100%;
  width: auto;
}

/* NF's list rules carry !important on the list resets, so only what they leave
   alone is set here. */
.vt-form .list-wrap .nf-field-element li { padding-left: 0; }
.vt-form .list-wrap .nf-field-element li label {
  font-size: 13px;
  font-weight: var(--fw-regular);
  line-height: 1.5;
  color: var(--color-text-muted);
  margin-left: 26px;
}

.vt-form .nf-field-element input[type="checkbox"],
.vt-form .nf-field-element input[type="radio"] {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  accent-color: var(--color-dark-purple);
}
.vt-form .nf-field-element input[type="checkbox"]:focus-visible,
.vt-form .nf-field-element input[type="radio"]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* NF's field description (the opt-in's "read our Privacy Policy" line). */
.vt-form .nf-field-description,
.vt-form .nf-field-description p {
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-subtle);
}
.vt-form .nf-field-description a { color: var(--color-dark-purple); }

/* A CAPTCHA is not a field an editor labelled — NF prints "Cloudflare
   Turnstile" (or "reCAPTCHA") above a widget that draws its own chrome and
   carries its own accessible name. The label is a plugin artifact, so it goes;
   `.label-above .nf-field-label` is (0,2,0), hence three classes. */
.vt-form .turnstile-container .nf-field-label,
.vt-form .recaptcha-container .nf-field-label,
.vt-form .hcaptcha-container .nf-field-label {
  display: none;
}

/* ---------- the file upload (Ninja Forms Uploads) ----------

   The one field type this sheet had never met, and it showed: the Join the team
   card asks for a CV, and NF Uploads renders that as a bare "Choose files"
   with a Bootstrap progress rail under it. Three things were actually wrong,
   and the middle one is a bug this block CAUSED:

     · the button reads as plain text. It carries NF's own `btn` class, so
       components.css already gives it the pill geometry and 15px type — but no
       INTENT class, and `.btn`'s base is `border: 1px solid transparent` on no
       background. So the site's button component was painting it perfectly as
       an invisible button;
     · **Cancel was visible on a field with no file in it.** NF states
       `.nf-fu-button-cancel { display: none }` (file-upload.css) and the THEME
       undoes it: `.btn { display: inline-flex }` is the same specificity (0,1,0)
       and components.css loads later. Restated below rather than in the theme,
       because `.btn` is right for every other button on the site;
     · the progress track is a 20px `#f5f5f5` block with an inset shadow, and its
       bar is Bootstrap blue, sitting there empty before anything is uploaded.

   THE CASCADE HERE IS THE OPPOSITE WAY ROUND FROM THE REST OF THIS SHEET.
   The note at the top of the file is about `display-structure.css`, which NF
   enqueues while the content renders — after this sheet — so a tie goes to NF.
   `file-upload.css` is enqueued EARLY (measured: it sits above this sheet in
   document.styleSheets), so for this one NF stylesheet order is in our favour
   and these selectors only need to match, not out-weigh. They are still written
   with `.vt-form` first, so nothing here leaks to a form embedded elsewhere.

   THE FIELD IS A DROP ZONE — `fieldFile.js` passes `dropZone: $( view.el )` —
   so the dashed edge is a statement about what the control accepts, not a
   decoration borrowed from other upload widgets. */

/* The control row. NF lays the two buttons out with `float: right` on the
   second and no container; a flex row puts the primary control first, lets it
   fill the field, and drops Cancel beside it when it exists. */
.vt-form .file_upload-container .nf-field-element {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* NF's file input is a SIBLING of the button in this markup — not nested inside
   it, as `file-upload.css` assumes — and it is inline-styled
   `width: 0; height: 0; visibility: hidden`. It still ATE 46px of the row: a
   flex item's automatic minimum size (`min-width: auto`) floors it at the
   input's min-content width, so it measured 34px however many zeroes the inline
   style declares, plus the row's 12px gap after it. Taking it out of flow drops
   both — it stops being a flex item. It is already invisible, and the button
   drives it from JS rather than by being its label, so nothing about the
   interaction changes. Measured: the control goes 575px → 621px, flush with
   every input above it. */
.vt-form .file_upload-container .nf-field-element > input[type="file"] {
  position: absolute;
}

/* "Choose files" IS the field: an upload has no input box, so this is the only
   thing to aim at. The paint is `.btn--outline`'s own, from the same tokens —
   one outline button on the site, not a copy of it here — plus the dashed edge
   and the full width that say "this is a drop target". */
.vt-form .file_upload-container .nf-fu-fileinput-button {
  flex: 1 1 auto;
  justify-content: center;
  /* NF: `.nf-fu-fileinput-button { margin-bottom: 10px }` — the row's own gap
     spaces it now, and the stray margin pushed it off Cancel's baseline. */
  margin-bottom: 0;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-dark-purple);
  /* The same fill the text inputs above it carry, so the upload reads as one
     more field in the column rather than a widget dropped into it. */
  background: var(--color-bg-subtle);
}
.vt-form .file_upload-container .nf-fu-fileinput-button:hover {
  border-color: var(--color-dark-purple);
  background: var(--color-light-purple-20);
}
/* NF paints its own focus state — white fill, #919191 edge, grey text — which is
   not this site's focus affordance. The ring is. */
.vt-form .file_upload-container .nf-fu-fileinput-button:focus-visible {
  border-color: var(--color-dark-purple);
  color: var(--color-dark-purple);
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Hidden until there is an upload to cancel — NF's own intent, restored.
   Safe to do from a stylesheet: fieldFile.js toggles this with jQuery
   `.show()`/`.hide()`, and `.show()` detects an element hidden by CSS
   (`isHiddenWithinTree`) and writes the element's default display inline, which
   beats this rule. Verified against jQuery's `showHide()` rather than assumed —
   a CSS-hidden element that jQuery could not reveal would mean an upload nobody
   can abort. */
.vt-form .file_upload-container .nf-fu-button-cancel {
  display: none;
  float: none;
  flex: 0 0 auto;
  /* A destructive secondary action next to the primary one: the quiet ghost
     treatment, not a second bordered button competing with it. */
  padding-left: 6px;
  padding-right: 6px;
  border-color: transparent;
  background: transparent;
  color: var(--color-text-subtle);
}
.vt-form .file_upload-container .nf-fu-button-cancel:hover {
  color: var(--color-danger);
  background: transparent;
}

/* The progress rail. The TRACK is transparent, so there is nothing to see until
   there is something to report — better than hiding the element on a condition
   CSS cannot test (`resetError()` writes `width: 0` inline, so "has an inline
   width" is not the same question as "is uploading"). The BAR is the site's
   button gradient, the same token the submit uses. */
.vt-form .file_upload-container .nf-fu-progress {
  flex: 1 0 100%;
  height: 3px;
  margin-bottom: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  box-shadow: none;
}
.vt-form .file_upload-container .nf-fu-progress-bar {
  border-radius: var(--radius-pill);
  background: var(--gradient-button);
  box-shadow: none;
}

/* The files that made it. NF's structure is one `<p>` per file with an
   `<a class="delete">`; only the type and the spacing are stated here — the
   markup is the plugin's. */
.vt-form .file_upload-container .files_uploaded {
  flex: 1 0 100%;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--color-text-muted);
}
.vt-form .file_upload-container .files_uploaded p {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 4px;
}
.vt-form .file_upload-container .files_uploaded p:last-child { margin-bottom: 0; }
.vt-form .file_upload-container .files_uploaded a { color: var(--color-dark-purple); }
.vt-form .file_upload-container .files_uploaded a.delete { color: var(--color-text-subtle); }
.vt-form .file_upload-container .files_uploaded a.delete:hover { color: var(--color-danger); }

/* ---------- NF's help tooltip ----------

   `help_text` on a field prints a Font Awesome info glyph inside the label
   (`<span class="fa fa-info-circle nf-help">`) with the tooltip in a sibling
   `.nf-sr-only`. It inherits the label's ink, so it lands as a hard black dot
   next to every label that has help — the loudest thing in the card. Toning it
   to the brand's quiet purple is the whole fix; the glyph, the tooltip and the
   accessible name stay Ninja Forms'. */
.vt-form .nf-field-label .nf-help {
  color: var(--color-text-subtle);
  cursor: help;
}
.vt-form .nf-field-label .nf-help:hover,
.vt-form .nf-field-label .nf-help:focus-visible {
  color: var(--color-dark-purple);
}

/* ---------- the button ---------- */

/* The submit input already carries `btn btn--brand btn--lg` — added to NF's own
   `element_class` at render time (inc/forms.php), so components.css paints it
   and this stack has ONE primary button rather than a copy of its gradient
   living in a form stylesheet.

   Three things `.btn` cannot know are stated here:
     · it spans the card (NF: `.field-wrap input[type=submit] { width: auto }`,
       (0,2,1) — hence the three classes);
     · an <input> cannot hold the `<span class="arrow">` every other button
       animates, and it cannot carry a pseudo-element either, so the arrow is a
       background layer. `var(--gradient-button)` is restated as the SECOND
       layer, which is the same token .btn--brand uses — not a copied value;
     · the label in the form builder may be typed in caps ("SUBMIT"); the
       button component is not a shouting component. */
.vt-form .submit-container .vt-form__submit {
  width: 100%;
  text-transform: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E"),
                    var(--gradient-button);
  background-repeat: no-repeat, no-repeat;
  background-position: right 22px center, 0 0;
  background-size: 17px 17px, auto;
}

/* The submit row itself: NF's 25px bottom margin is the card's gap here, and
   the button needs no label above it. */
.vt-form .submit-container .nf-field-label { display: none; }

/* ---------- errors and the response message ---------- */

.vt-form .nf-error-msg,
.vt-form .nf-error-wrap .nf-error-msg {
  font-size: 12.5px;
  line-height: 1.45;
  margin-top: 6px;
  color: var(--color-danger);
}

/* NF: `.nf-error .ninja-forms-field { border: 1px solid #e80000 }` (0,2,0). */
.vt-form .field-wrap.nf-error > .nf-field-element .ninja-forms-field {
  border-color: var(--color-danger);
}

/* The success message NF swaps in for the form. It is the whole point of the
   card at that moment, so it gets the card's own type rather than raw prose. */
.vt-form .nf-response-msg {
  font-size: 15px;
  line-height: 1.6;
  color: var(--color-text);
}
.vt-form .nf-response-msg h2,
.vt-form .nf-response-msg h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-medium);
  font-size: 20px;
  line-height: 1.25;
  margin: 0 0 10px;
  color: var(--color-text);
}
.vt-form .nf-response-msg p { margin: 0 0 10px; }
.vt-form .nf-response-msg p:last-child { margin-bottom: 0; }
.vt-form .nf-response-msg a { color: var(--color-dark-purple); }

/* Cloudflare Turnstile's widget is a fixed-width iframe; on a narrow card it
   would otherwise push the card wider than its column. */
.vt-form .nf-cf-turnstile { max-width: 100%; overflow: hidden; }
