/* The enquiry form: the Book a Demo dialog js/enquiry-form.js builds, and the states both it and
   the contact page's inline form share. Every page that carries either loads this file.

   THE TYPE IS SET ON EVERY PART THAT CARRIES TEXT, not once on the dialog and inherited.
   css/webflow.css styles bare elements, label bold with a margin and p in 70% black among them,
   and a rule that matches an element beats a value inherited into it however specific the
   ancestor's rule is. css/notice-bar.css learned this first.

   THE INK IS A PRIMITIVE, READ ON PURPOSE. css/tokens.css leaves --color-text-default unresolved
   in the light theme, and says why. css/notice-bar.css met the same gap and took
   --primitive-campus-surface-dark, #171820, with the rule in view; this follows it rather than
   adding a second answer. It measures 17.68:1 on the white surface and 14.25:1 on the sunken
   one. The registration is --color-text-default, and it belongs to whoever next opens the design
   system. */
:root {
  --sw-enquiry-ink: var(--primitive-campus-surface-dark);

  /* THE TEXT FIELDS' COLOURS, one set for both forms, and the same set the rebuilt site's fields
     use. css/tokens.css publishes no field boundary and no text or muted text in the light theme,
     so they are set here beside the ink above.
     border       at rest. The authored #717480 neutral's hue and saturation with only its
                  lightness moved, to the lightest step that still clears the 3:1 WCAG 1.4.11 asks
                  of a control boundary: 3.22:1 on the white surface, 3.01:1 on the canvas. Kept
                  that light so that focus reads as a change away from it (below).
     border-focus the darkest interface violet, 8.91:1 on white and 2.77:1 against the resting
                  border, which is what a reader who cannot separate the hues sees change.
     ink          the field's typed text, and its boundary on hover.
     placeholder  muted text, 5.72:1 on white. */
  --sw-field-border: #8D8F9A;
  --sw-field-border-focus: var(--primitive-violet-interface-hover);
  --sw-field-ink: var(--primitive-campus-canvas-dark);
  --sw-field-placeholder: #636671;

  /* THE DIALOG'S LAYER. The dialog is shown non-modally, for the reason js/enquiry-form.js gives,
     so it is not in the browser's top layer and needs a place in the page's own stacking: above
     everything the page draws, whose highest is the navbar at 1000, and above CookieHub's banner
     at 700001, and below the picture challenge reCAPTCHA adds to the body at 2000000000. All three
     figures were measured in a browser on 2026-09-28; neither Google nor CookieHub documents
     them. The backdrop takes this layer and the dialog the one above it. */
  --sw-enquiry-layer: 1000000;
}

/* hidden is how js/enquiry-form.js shows and withdraws every part of the form. A display value
   set by a rule below would otherwise beat the attribute's own display: none. */
[data-enquiry] [hidden],
.sw-enquiry-dialog [hidden] {
  display: none !important;
}

/* ---------- The dialog ---------- */

/* The dialog floats, so it is the one surface here that takes a shadow (tokens.css, Elevation).
   It is fixed and centred in the viewport, which a modal dialog is by default and a non-modal
   one is not. The width holds a 16px gutter on a 390px phone and stops at a comfortable form
   measure on a desktop. The height never exceeds the viewport less that gutter: the dialog
   scrolls inside itself, and the page behind it does not move. */
.sw-enquiry-dialog {
  position: fixed;
  inset: 0;
  z-index: calc(var(--sw-enquiry-layer) + 1);
  box-sizing: border-box;
  width: min(480px, calc(100vw - 2 * var(--space-4)));
  max-width: none;
  max-height: calc(100dvh - 2 * var(--space-4));
  margin: auto;
  padding: 0;
  border: 0;
  border-radius: var(--radius-lg);
  background-color: var(--color-bg-surface);
  color: var(--sw-enquiry-ink);
  box-shadow: 0 24px 64px rgb(16 17 22 / 28%), 0 2px 8px rgb(16 17 22 / 12%);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The backdrop, an element of its own because only an element in the browser's top layer has a
   ::backdrop, and a non-modal dialog is not in it. It covers the page, which is inert behind it,
   and a click on it closes the dialog. */
.sw-enquiry-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--sw-enquiry-layer);
  background-color: rgb(16 17 22 / 60%);
}

/* Motion, tokens.css V4 SS2.4: a dialog crossing a large part of the frame takes the medium
   duration on the entrance curve, and leaves on the shorter one. A browser without
   @starting-style or discrete transitions opens and closes it at once, which loses nothing. */
.sw-enquiry-dialog[open] {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--motion-medium) var(--easing-entrance),
    transform var(--motion-medium) var(--easing-entrance);
}

@starting-style {
  .sw-enquiry-dialog[open] {
    opacity: 0;
    transform: translateY(12px);
  }
}

/* Reduced motion replaces the movement with a fade at the same duration rather than deleting
   it (tokens.css, Law: reduced motion). */
@media (prefers-reduced-motion: reduce) {
  @starting-style {
    .sw-enquiry-dialog[open] {
      transform: none;
    }
  }
}

/* Holds the page still behind the open dialog. The page is already inert; this stops a wheel
   over the backdrop scrolling it. */
html.sw-enquiry-open {
  overflow: hidden;
}

.sw-enquiry-dialog__panel {
  padding: var(--space-5) var(--space-6) var(--space-6);
}

.sw-enquiry-dialog__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.sw-enquiry-dialog__title {
  margin: var(--space-2) 0 0;
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-heading-size);
  line-height: var(--type-heading-line);
  font-weight: var(--type-heading-weight);
  letter-spacing: var(--type-heading-tracking);
}

/* The close mark is drawn rather than set, for the reason css/notice-bar.css gives for its own:
   IBM Plex is served in subsets that do not carry a close glyph. Its name is the word, from
   aria-label. The tap target is 44px square around a 14px mark. */
.sw-enquiry-dialog__close {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0 calc(-1 * var(--space-3)) 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: none;
  color: var(--sw-enquiry-ink);
  cursor: pointer;
}

.sw-enquiry-dialog__mark {
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  fill: none;
}

.sw-enquiry-dialog__close:hover {
  background-color: var(--color-bg-sunken);
}

.sw-enquiry-dialog__close:focus-visible,
.sw-enquiry__done:focus-visible,
.sw-enquiry__submit:focus-visible,
.sw-enquiry__checkbox:focus-visible,
.sw-enquiry-dialog a:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* ---------- The dialog's form ---------- */

.sw-enquiry__form {
  display: grid;
  gap: var(--space-5);
  margin: 0;
}

.sw-enquiry__intro {
  margin: 0;
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  font-weight: var(--font-weight-regular);
}

.sw-enquiry__field {
  display: grid;
  gap: var(--space-2);
}

.sw-enquiry__label {
  display: block;
  margin: 0;
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-ui-size);
  line-height: var(--type-ui-line);
  font-weight: var(--type-ui-weight);
}

/* The colours are the field set at the top of this file, and its states are under "States both
   forms share". The type is 16px so that iOS does not zoom the page when a field takes focus. */
.sw-enquiry__input {
  box-sizing: border-box;
  display: block;
  width: 100%;
  min-height: 48px;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: var(--hairline-screen) solid var(--sw-field-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-bg-surface);
  color: var(--sw-field-ink);
  font-family: var(--font-sans);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  font-weight: var(--font-weight-regular);
}

.sw-enquiry__input--message {
  min-height: 128px;
  resize: vertical;
}

.sw-enquiry__consent {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: var(--space-3);
  margin: 0;
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-ui-size);
  line-height: var(--type-ui-line);
  font-weight: var(--font-weight-regular);
  cursor: pointer;
}

.sw-enquiry__checkbox {
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  accent-color: var(--color-action-primary-bg);
  cursor: pointer;
}

/* Underlined at rest. These two links sit inside a sentence, and colour alone is not what tells
   a reader a phrase in running text is a link. */
.sw-enquiry-dialog a {
  color: var(--color-link);
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.sw-enquiry-dialog a:hover {
  text-decoration-thickness: 2px;
}

/* The honeypot: present for a bot that fills every input, absent for a person. */
.sw-enquiry__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* reCAPTCHA's badge is hidden, and the line below says the form is protected by it instead,
   which Google allows on that condition and with this rule
   (developers.google.com/recaptcha/docs/faq). The badge stays in the page, fixed to the
   viewport and taking no space. */
.grecaptcha-badge {
  visibility: hidden;
}

/* Google's line, under the send button in either form. It is set like the dialog's
   "Fields marked * are required.", the form's other note about itself: caption type in the
   form's ink. */
[data-enquiry] .sw-enquiry__recaptcha {
  margin: 0;
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  font-weight: var(--font-weight-regular);
}

/* It is about the button above it, so it sits 12px under it rather than a whole field gap away. */
.sw-enquiry__form > .sw-enquiry__recaptcha {
  margin-top: calc(var(--space-3) - var(--space-5));
}

/* On the contact page it follows the button: right-aligned beside the form's edge, and centred
   where css/qa-campus.webflow.css centres the button, at 991px and below. */
.contact-form .sw-enquiry__recaptcha {
  margin-top: var(--space-3);
  text-align: right;
}

@media screen and (max-width: 991px) {
  .contact-form .sw-enquiry__recaptcha {
    text-align: center;
  }
}

/* The site's call-to-action fill, the same one the contact page's own submit carries. The busy
   state changes the label and not the colour: tokens.css forbids opacity on an action token. */
.sw-enquiry__submit,
.sw-enquiry__done {
  justify-self: stretch;
  min-height: 48px;
  margin: 0;
  padding: var(--space-3) var(--space-5);
  border: 0;
  border-radius: var(--radius-md);
  background-color: var(--color-data-secondary);
  color: var(--color-action-primary-text);
  font-family: var(--font-sans);
  font-size: var(--type-ui-size);
  line-height: var(--type-ui-line);
  font-weight: var(--font-weight-medium);
  cursor: pointer;
}

.sw-enquiry__submit:hover,
.sw-enquiry__done:hover {
  background-color: var(--color-data-secondary-hover);
}

.sw-enquiry__submit:disabled {
  cursor: progress;
}

/* Close is offered only once the enquiry is sent, beneath the thank-you. */
.sw-enquiry__done {
  display: none;
  width: 100%;
  margin-top: var(--space-5);
}

[data-enquiry-state="sent"] .sw-enquiry__done {
  display: block;
}

/* ---------- States both forms share ---------- */

/* A field that is wrong: its boundary turns to the danger colour and a line beneath it says what
   to do. The line is the label the status rule asks for (tokens.css, Meaning); the colour is not
   carrying the message alone. */
[data-enquiry] [aria-invalid="true"] {
  border-color: var(--color-status-danger-border);
}

/* The text fields, in both forms. The contact page's are Webflow's .input and .textarea, whose
   own colours drew a 1.25:1 boundary at rest that did not change on hover. These rules take only
   their colours, and leave their size, padding, radius and icons as Webflow set them.
   The order is the precedence: hover, then wrong, then focus, so a wrong field still reads as
   wrong under the pointer and a focused one shows focus while keeping its danger fill. */
[data-enquiry="contact"] .input,
[data-enquiry="contact"] .textarea {
  border-color: var(--sw-field-border);
  background-color: var(--color-bg-surface);
  color: var(--sw-field-ink);
}

[data-enquiry] .sw-enquiry__input::placeholder,
[data-enquiry="contact"] .input::placeholder,
[data-enquiry="contact"] .textarea::placeholder {
  color: var(--sw-field-placeholder);
}

[data-enquiry] .sw-enquiry__input:hover,
[data-enquiry="contact"] .input:hover,
[data-enquiry="contact"] .textarea:hover {
  border-color: var(--sw-field-ink);
}

[data-enquiry] .sw-enquiry__input[aria-invalid="true"],
[data-enquiry="contact"] .input[aria-invalid="true"],
[data-enquiry="contact"] .textarea[aria-invalid="true"] {
  border-color: var(--color-status-danger-border);
  background-color: var(--color-status-danger-bg);
}

/* A text field shows focus by its own border turning violet, with no ring around it, the way the
   rebuilt site's fields do; the box does not change size, so nothing moves. Forced colours
   repaints every border with one system colour, so the ring comes back there and only there,
   where it is the one signal left. */
[data-enquiry] .sw-enquiry__input:focus-visible,
[data-enquiry="contact"] .input:focus-visible,
[data-enquiry="contact"] .textarea:focus-visible {
  outline: none;
  border-color: var(--sw-field-border-focus);
}

@media (forced-colors: active) {
  [data-enquiry] .sw-enquiry__input:focus-visible,
  [data-enquiry="contact"] .input:focus-visible,
  [data-enquiry="contact"] .textarea:focus-visible {
    outline: 2px solid;
    outline-offset: 1px;
  }
}

/* The contact page's consent box keeps Webflow's .w-checkbox-input, which sets no accent colour,
   so it drew the browser's own blue beside the dialog's violet. It takes the dialog's colour. */
[data-enquiry="contact"] .w-checkbox-input {
  accent-color: var(--color-action-primary-bg);
}

[data-enquiry] .sw-enquiry__checkbox[aria-invalid="true"],
[data-enquiry] input[type="checkbox"][aria-invalid="true"] {
  outline: 2px solid var(--color-status-danger-border);
  outline-offset: 1px;
}

[data-enquiry] .sw-enquiry__error {
  margin: 0;
  color: var(--color-status-danger-text);
  font-family: var(--font-sans);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  font-weight: var(--font-weight-medium);
}

/* The contact page's fields sit in a grid with a 30px row gap, so its error lines need their own
   space above them; the dialog's field grid supplies it. */
.contact-form .sw-enquiry__error {
  margin-top: var(--space-2);
}

[data-enquiry] .sw-enquiry__summary {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: var(--hairline-screen) solid var(--color-status-danger-border);
  border-radius: var(--radius-md);
  background-color: var(--color-status-danger-bg);
  color: var(--color-status-danger-text);
  font-family: var(--font-sans);
  font-size: var(--type-ui-size);
  line-height: var(--type-ui-line);
  font-weight: var(--font-weight-medium);
}

.contact-form .sw-enquiry__summary {
  margin-bottom: var(--space-5);
}

/* The outcomes. The thank-you sits on a neutral surface rather than a status colour: the status
   palette on this product carries the regulated safety meanings set out in the brand book, where
   "safe" is a physical state rather than a delivery receipt, and a sent form is neutral
   information. The failures take the danger surface with its boundary, so each reads as a
   notice by shape as well as colour. */
[data-enquiry] .sw-enquiry__outcome,
[data-enquiry] .sw-enquiry__noscript {
  margin: var(--space-4) 0 0;
  padding: var(--space-5);
  border-radius: var(--radius-md);
  color: var(--sw-enquiry-ink);
  font-family: var(--font-sans);
  font-size: var(--type-body-size);
  line-height: 150%;
  font-weight: var(--font-weight-regular);
  text-align: center;
}

[data-enquiry] .sw-enquiry__outcome--sent {
  margin-top: 0;
  background-color: var(--color-bg-sunken);
}

[data-enquiry] .sw-enquiry__outcome--not-connected,
[data-enquiry] .sw-enquiry__outcome--send-failed,
[data-enquiry] .sw-enquiry__outcome--check-failed,
[data-enquiry] .sw-enquiry__noscript {
  border: var(--hairline-screen) solid var(--color-status-danger-border);
  background-color: var(--color-status-danger-bg);
}

[data-enquiry] .sw-enquiry__outcome a,
[data-enquiry] .sw-enquiry__noscript a {
  color: var(--color-link);
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
}

/* The page header is sticky and 80px tall at every width, so an outcome scrolled to the top of
   the viewport lands underneath it. This keeps the whole notice, and a field focused for an
   error, clear of the header. */
.contact-form [data-form-state],
.contact-form [data-enquiry-summary],
.contact-form input,
.contact-form textarea {
  scroll-margin-top: 96px;
}

/* ---------- Narrow screens ---------- */

@media screen and (max-width: 479px) {
  .sw-enquiry-dialog__panel {
    padding: var(--space-4) var(--space-4) var(--space-5);
  }

  .sw-enquiry-dialog__title {
    font-size: var(--type-subhead-size);
    line-height: var(--type-subhead-line);
    font-weight: var(--type-subhead-weight);
    letter-spacing: var(--type-subhead-tracking);
  }

  .sw-enquiry__form {
    gap: var(--space-4);
  }
}
