/* =============================================================================
   Forms and the contact page layout.

   These rules previously lived at the end of components.css and were destroyed by a
   truncating edit that removed "everything after this marker" while intending to
   remove one block. They live in their own file now, which is both clearer and
   harder to lose.

   The contact form carries every conversion on the site, so it is treated as a
   primary surface rather than an afterthought.
   ============================================================================= */

.form { max-width: 38rem; }

/* space-s, not space-m. Ten fields at 1.5rem apart made the enquiry form scroll further
   than the answer was worth, and a gap wider than the fields themselves reads as ten
   separate questions rather than one form. The label already sits tight to its input, so
   the grouping survives the tighter rhythm. */
.form__row { margin-bottom: var(--space-s); }
.form__row label {
  display: block;
  font-weight: var(--weight-bold);
  font-size: var(--step--1);
  margin-bottom: var(--space-3xs);
}
.form__required { color: var(--brand-ink); margin-inline-start: 2px; }

/* A radio or checkbox GROUP, which needs fieldset/legend rather than a label -- a group
   has no single input for `for` to point at. See contact_form_page.html.

   The browser's default fieldset is a bordered box with its own padding, which would put
   one field on this form in a frame the others are not in. Reset to nothing, and the
   legend styled as the labels around it, so the change is in the markup a screen reader
   reads and nowhere else. */
.form__group {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;      /* fieldset defaults to min-content, which breaks flex/grid */
}
.form__group > legend {
  display: block;
  padding: 0;
  font-weight: var(--weight-bold);
  font-size: var(--step--1);
  margin-bottom: var(--space-3xs);
}
/* Inside a group the label belongs BESIDE its input, not above it -- these are the
   individual options, not the question. */
.form__group label {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-weight: var(--weight-normal);
  margin-bottom: var(--space-3xs);
}
.form__group ul { list-style: none; margin: 0; padding: 0; }

.form__help {
  margin: 0 0 var(--space-3xs);
  font-size: var(--step--2);
  color: var(--text-muted);
  max-width: 46ch;
}
/* Django hands password help text over as a <ul> of validator rules, so this has to hold
   a list as well as a sentence. Same size and colour either way — the rules are a hint
   about the field, not a second paragraph of the page.

   Prefixed with .form to clear `.form ul { list-style: none; padding: 0 }` below, which
   exists to strip the bullets off the <ul> Django wraps a radio group in. Same
   specificity, and that rule is further down the file, so the unprefixed version lost
   silently — the padding-left simply did nothing. The bullets stay off deliberately:
   four one-line rules read as a list without them, and this is the only place in the
   design where a bulleted list appears inside a field. */
.form .form__help ul { list-style: none; margin: 0; padding: 0; }
.form .form__help li + li { margin-top: var(--space-3xs); }

/* Styled by element, not by class: Wagtail's form builder renders the widgets and we
   do not control their markup. */
.form input[type="text"],
.form input[type="email"],
/* password was missing from this list, so the sign-in field rendered as an unstyled
   browser default next to a styled email field. Enumerating types is why: a bare
   `.form input` would also catch checkboxes and radios and stretch them full width. */
.form input[type="password"],
.form input[type="tel"],
.form input[type="search"],
.form input[type="number"],
.form input[type="url"],
.form input[type="date"],
.form input[type="datetime-local"],
.form select,
.form textarea {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--space-2xs) var(--space-xs);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  /* 16px floor. Below that, iOS Safari zooms the viewport on focus and leaves the
     user scrolled sideways in the middle of a form. */
  font-size: max(1rem, var(--step-0));
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
/* height as well as min-height. Django renders a Textarea with rows="10", which came out
   at 330px — a quarter of the whole enquiry form for the one optional question on it.
   resize stays vertical, so anyone with a lot to say can still drag it open. */
.form textarea { min-height: 8rem; height: 8rem; resize: vertical; }

.form input:hover, .form select:hover, .form textarea:hover { border-color: var(--brand-300); }
.form input:focus-visible,
.form select:focus-visible,
.form textarea:focus-visible {
  outline: 3px solid var(--brand-500);
  outline-offset: 1px;
  border-color: var(--brand-ink);
}

/* The `.form ` on the front of each of these is doing real work.

   The base control rule above is `.form input[type="text"]` — a class, an attribute
   and an element, 0-2-1. This was `.form__row--error input`, 0-1-1, and lost to it
   every single time: a field that failed validation was drawn in the ordinary grey
   border like every other field, and the only per-field evidence left was the red
   sentence underneath. The template comment promises errors "repeated on each
   field" precisely because the summary alone is not enough for a sighted user
   scanning ten inputs for the two that are wrong — and half of that promise was
   being silently dropped by the cascade.

   Prefixed rather than fought with !important: it matches the base rule at 0-2-1
   and sits after it, which is also what puts it ahead of the :hover and
   :focus-visible border colours — an invalid field should stay red while you are
   in it, and the focus ring is a separate outline that still shows. */
.form .form__row--error input,
.form .form__row--error select,
.form .form__row--error textarea { border-color: var(--danger); }

.form__error {
  margin: var(--space-3xs) 0 0;
  color: var(--danger);
  font-size: var(--step--1);
  font-weight: var(--weight-semibold);
}

.form__errors {
  border: 2px solid var(--danger);
  border-radius: var(--radius-md);
  padding: var(--space-m);
  margin-bottom: var(--space-l);
  background: var(--surface);
}
.form__errors h2 { font-size: var(--step-1); margin: 0 0 var(--space-2xs); }
.form__errors ul { margin: 0; padding-left: 1.1em; }
.form__errors a { color: var(--danger); }

.form__submit { margin-top: var(--space-2xs); }
.form__note { margin-top: var(--space-s); font-size: var(--step--1); color: var(--text-muted); }
.form__note a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}

.form input[type="checkbox"],
.form input[type="radio"] { width: auto; min-height: 0; margin-inline-end: var(--space-3xs); }
.form ul { list-style: none; padding: 0; margin: 0; }
.form ul li label {
  font-weight: var(--weight-regular);
  display: flex; align-items: center;
  min-height: var(--tap-min);
}

.form__thanks { max-width: 46rem; }
.form__thanks h2 { font-size: var(--step-3); margin-top: 0; }
.form__thanks .btn { margin-top: var(--space-m); }

/* --- Contact page layout -------------------------------------------------------
   A form alone in a wide column reads as a chore and answers none of the questions
   people hesitate over before sending. The aside carries the phone route out, the
   response expectation and the service area. */
/* The page's own name, above the two columns rather than inside either of them.
   --step-4, not the h1 default of --step-5: this is a label for a form, not the
   headline of a page that is selling something, and at --step-5 it starts behaving
   like the hero it replaced. */
.contact-head { margin-bottom: var(--space-l); }
.contact-head h1 { margin: 0; font-size: var(--step-4); }

.contact-layout {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 56rem) {
  .contact-layout { grid-template-columns: minmax(0, 1.35fr) minmax(16rem, .8fr); }
}
.contact-layout__form .form { max-width: none; }

.contact-aside {
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-l);
  position: sticky;
  top: calc(80px + var(--space-m));
}
@media (max-width: 56rem) { .contact-aside { position: static; } }

.contact-aside h2 {
  /* A small uppercase label, not a page heading — the body face carries it without the
     weight of the display face at 18px. */
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--step-0);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-muted);
  margin: var(--space-l) 0 var(--space-2xs);
}
.contact-aside h2:first-child { margin-top: 0; }
.contact-aside p { font-size: var(--step--1); margin: 0; }

.contact-aside__list { list-style: none; margin: 0; padding: 0; }
.contact-aside__list a {
  display: flex;
  align-items: center;
  gap: var(--space-3xs);
  /* min-height alone lost to the flex parent's sizing and measured 43px — one pixel
     under the floor this design system claims. Setting height too is what holds it. */
  min-height: var(--tap-min);
  height: var(--tap-min);
  font-weight: var(--weight-bold);
  text-decoration: none;
}
.contact-aside__list a:hover { text-decoration: underline; }
.contact-aside__list .icon { color: var(--brand-ink); flex: 0 0 auto; }

.contact-aside__list a {
  height: auto;
  min-height: 48px;
  padding-block: var(--space-2xs);
  overflow-wrap: anywhere;
}

.contact-aside__steps {
  margin: 0;
  padding-left: 1.2em;
  font-size: var(--step--1);
  color: var(--text-muted);
}
.contact-aside__steps li { margin-bottom: var(--space-3xs); }

/* --- "You're asking about" -----------------------------------------------------
   Shown when an offering card sends someone here with ?service=<slug>. */
.asking-about {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3xs) var(--space-2xs);
  margin: 0 0 var(--space-l);
  padding: var(--space-s) var(--space-m);
  border-left: 3px solid var(--brand-500);
  border-radius: var(--radius-md);
  background: var(--brand-wash);
}
.asking-about__label {
  font-size: var(--step--2);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  width: 100%;
}
.asking-about strong { font-size: var(--step-1); font-family: var(--font-display); }
.asking-about__price { color: var(--brand-ink-strong); font-weight: var(--weight-bold); }

/* --- Offering cards as links ---------------------------------------------------
   The <li> is a plain list item now; the <a> carries the card styling, so the whole
   card is one tap target rather than a card with a small link inside it. */
.offering-card-item { display: flex; }
a.offering-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  text-decoration: none;
  color: inherit;
}
a.offering-card:hover { box-shadow: var(--shadow-3); transform: translateY(-3px); }
a.offering-card .card__more { color: var(--brand-ink); }
a.offering-card:hover .card__more { text-decoration: underline; }

/* --- Account pages -------------------------------------------------------------
   The no-JavaScript fallback for the header's sign-in modal, and the destination of
   the /m/account and /m/create-account redirects carried over from the old site.
   They previously rendered allauth's stock templates: no stylesheet, no header,
   Times New Roman. */
.auth-page { display: grid; place-items: center; min-height: 60vh; }
.auth-card {
  width: min(100%, 28rem);
  /* .auth-page centres its own child, but that child is the .container — which is
     `width: min(100% - 2rem, ...)` and so fills the row, leaving the 28rem card stuck
     against its left edge. The container earns its place (it is what keeps the card off
     the screen edge on a phone), so the card centres itself inside it instead.
     Invisible until 2026-09-04: the wrapper this all describes was being thrown away by
     a template block-name collision, so no account page had a .container to be off-centre
     in. See allauth/layouts/base.html. */
  margin-inline: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-l);
  box-shadow: var(--shadow-2);
}
.auth-card__title { font-size: var(--step-3); margin: 0 0 var(--space-3xs); }
.auth-card__note { color: var(--text-muted); font-size: var(--step--1); margin: 0 0 var(--space-l); }
.auth-card__alt { margin: var(--space-s) 0 0; font-size: var(--step--1); }
/* .auth-card__messages retired. "You have signed out." and friends now render once,
   for every page, as .site-messages in chrome.css — see the note in base.html. */
/* "I have a password" — the exception, folded away. A closed <details> keeps it one tap
   from anyone who needs it and out of the way of everyone who does not. */
.auth-alt { margin-top: var(--space-m); border-top: 1px solid var(--border); padding-top: var(--space-2xs); }
.auth-alt > summary { cursor: pointer; min-height: var(--tap-min); display: flex; align-items: center; font-size: var(--step--1); color: var(--text-muted); }
.auth-alt[open] > summary { margin-bottom: var(--space-2xs); }
.auth-form { max-width: none; }
.auth-form .form__submit { width: 100%; justify-content: center; }
/* The paragraph allauth puts AFTER the form — "Please contact us if you have any trouble
   resetting your password." — sat hard against the submit button, close enough to read as
   part of it. .auth-card__note only carries a bottom margin, which is right everywhere it
   is a lead-in and wrong in the one place it is a footnote. */
.auth-form + .auth-card__note { margin-top: var(--space-m); }
@media (forced-colors: active) { .auth-card { border-color: CanvasText; } }

/* "Forgotten your password?" sits alone in its paragraph, so it is a standalone target
   rather than a link inside a sentence — WCAG 2.5.8's inline exception does not cover
   it, and it measured 18px. */
.auth-card__alt a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}


/* --- Enquiry form: two columns where the fields are short ---------------------- */
/* Ten fields stacked in one column ran to 1,477px of form on a 2,679px page, and a name
   box the full width of a reading column looks like a mistake. Pairing the short ones is
   the honest fix for "this page is long" — shorter than shrinking type further, and it
   stops the form reading as ten separate questions.
 *
 * The textarea, the submit and the error summary span both columns: a message box is the
 * one field that wants the room, and a button floating in half the width reads as
 * unfinished.
 *
 * Behind @supports selector(:has(*)) deliberately. Without :has() there is no way to say
 * "the row containing a textarea" from CSS, and the fallback has to be the single column
 * this replaces — never a two-column grid with the message box squeezed into half of it.
 * Everything here is layout; nothing depends on it to be usable. */
@supports selector(:has(*)) {
  @media (min-width: 44rem) {
    .contact-layout__form .form {
      display: grid;
      grid-template-columns: 1fr 1fr;
      column-gap: var(--space-m);
    }
    /* The two fields in a row have to end level, and only one of them usually carries a
       hint. `align-items: start` sized each cell to its own content and hung it from the
       top, so "Your name" sat a whole line of help text higher than "Email" beside it,
       "Phone" higher than "What are you planning?", and so on down the form: eight boxes
       in two columns and no two of them aligned. On a page that now opens with this form
       that raggedness is the first thing anybody sees.
       Stretching the cells and pushing the control to the bottom of each one lands every
       input on the same line, whatever is written above it. Labels still sit at the top
       of their own cell, where they belong. */
    .contact-layout__form .form__row {
      display: flex;
      flex-direction: column;
    }
    .contact-layout__form .form__row > input,
    .contact-layout__form .form__row > select,
    .contact-layout__form .form__row > textarea { margin-top: auto; }
    .contact-layout__form .form__row:has(textarea),
    .contact-layout__form .form__errors,
    .contact-layout__form .form__submit,
    .contact-layout__form .form__note {
      grid-column: 1 / -1;
    }
    /* The row order is Craig's, set in the CMS, so the pairing is whatever adjacency he
       chose — name beside email, start time beside end time. Nothing here assumes a
       fixed order, which is why adding a field cannot break the layout. */
  }
}


/* --- Show / hide password ------------------------------------------------------
   The wrapper and button are created by js/password-reveal.js, so none of this exists
   without JavaScript and the field is an ordinary password input.

   A wrapper rather than positioning against the existing parent, because there are four
   different parents: a grid child in the modal, a .form__row on the sign-in page, and
   Django's own form loop on signup and on allauth's password pages. One hook behaves the
   same in all of them. */
.pwfield { position: relative; display: block; }

/* The button sits INSIDE the field, so the text needs to stop before it. Logical
   properties, so this still works if the site is ever served right-to-left. */
.pwfield > input { width: 100%; padding-inline-end: 3rem; }

.pwfield__toggle {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  /* 44px wide, full height of the field: the tap target is the whole right end of the
     input, not just the glyph. */
  width: var(--tap-min);
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: color var(--dur) var(--ease);
}
.pwfield__toggle:hover { color: var(--text); }
.pwfield__toggle:focus-visible {
  outline: 3px solid var(--brand-500);
  outline-offset: -3px;
  color: var(--text);
}
/* Pressed means the password is currently VISIBLE. Worth marking in colour as well as in
   the icon: it is the state you want to notice and undo. */
.pwfield__toggle[aria-pressed="true"] { color: var(--brand-ink); }

/* Chromium and Edge draw their own eye inside a password field, and Safari draws a
   password-manager key. Both would sit beside ours. */
.pwfield > input::-ms-reveal,
.pwfield > input::-ms-clear { display: none; }

@media (prefers-reduced-motion: reduce) { .pwfield__toggle { transition: none; } }


/* --- Select ---------------------------------------------------------------------
   One control and one panel, whatever the browser and whatever the OS theme.

   A <select> renders two things: the closed control, which CSS has always been able to
   style, and the PICKER — the list that drops down — which historically it could not.
   The picker was drawn by the operating system, so on a machine set to dark mode the
   site's light form opened a black panel with a blue Windows highlight in it. That is
   what this is for; `color-scheme: light` on :root (tokens.css) is not enough, because a
   forced-dark browser overrides it.

   TWO LAYERS, deliberately.

   The base rule below is the floor: `appearance: none` and a chevron drawn as a data URI,
   so the CLOSED control is identical in Firefox, Safari and older Chrome instead of
   inheriting whatever arrow the platform draws. The picker in those browsers stays
   native — nothing in CSS can reach it — so `option` colours are set as a best effort
   and are honoured by Firefox and by Chrome on Windows.

   The @supports block is the ceiling: `appearance: base-select` (Chromium 135+) opts the
   element into a fully styleable control AND picker, rendered in the page rather than by
   the OS. Everything there is progressive — a browser without it simply keeps the floor.

   The chevron's colour is hard-coded to --ink-500 because a data URI cannot read a custom
   property or currentColor. base-select uses ::picker-icon instead, which can. */
.venue-filter select,
.form select,
.item-form select {
  appearance: 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='%235c5c5c' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-xs) center;
  background-size: .85rem;
  padding-inline-end: 2.5rem;
}

/* Best effort for the native picker. Firefox honours both; Chrome on Windows honours the
   background. Nothing can be done about Safari's, which is why base-select matters. */
.venue-filter select option,
.form select option,
.item-form select option {
  background-color: var(--surface);
  color: var(--text);
}

@supports (appearance: base-select) {
  .venue-filter select,
  .form select,
  .item-form select {
    appearance: base-select;
    /* base-select draws its own ::picker-icon, so the data-URI chevron would be a second
       arrow beside it. */
    background-image: none;
    padding-inline-end: var(--space-xs);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs);
    text-align: start;
  }
  .venue-filter select::picker-icon,
  .form select::picker-icon,
  .item-form select::picker-icon {
    /* The UA draws a solid triangle here. Replaced with the same chevron the
       fallback rule paints and the same one partials/icons.html uses, so a browser
       with base-select and one without show the same arrow. */
    content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='14' height='14' fill='none' stroke='%235c5c5c' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    color: var(--text-muted);
    transition: rotate var(--dur) var(--ease);
  }
  .venue-filter select:open::picker-icon,
  .form select:open::picker-icon,
  .item-form select:open::picker-icon { rotate: 180deg; }

  /* The panel. Same surface, border and radius as every other floating thing on the
     site, so it reads as part of the page rather than as the operating system. */
  .venue-filter select::picker(select),
  .form select::picker(select),
  .item-form select::picker(select) {
    appearance: base-select;
    margin-block-start: var(--space-3xs);
    padding: var(--space-3xs);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-3);
    max-height: 18rem;
    overflow-y: auto;
    /* The picker is in the top layer, so it needs its own scheme rather than inheriting
       the page's. */
    color-scheme: light;
  }
  .venue-filter select option,
  .form select option,
  .item-form select option {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    min-height: var(--tap-min);
    padding: var(--space-3xs) var(--space-2xs);
    border-radius: var(--radius-sm);
    font: inherit;
    color: var(--text);
  }
  .venue-filter select option:hover,
  .form select option:hover,
  .item-form select option:hover { background: var(--surface-muted); }
  /* Focus follows the arrow keys; hover follows the mouse. Both need to look selected or
     a keyboard user cannot see where they are. */
  .venue-filter select option:focus,
  .form select option:focus,
  .item-form select option:focus,
  .venue-filter select option:checked,
  .form select option:checked,
  .item-form select option:checked {
    background: var(--brand-wash);
    color: var(--brand-ink-strong);
    font-weight: var(--weight-semibold);
    outline: none;
  }
  /* The tick the browser offers for the chosen row. Left in, sized down: it is the only
     thing that says "this is the current value" once the panel is open and the mouse has
     moved somewhere else. */
  .venue-filter select option::checkmark,
  .form select option::checkmark,
  .item-form select option::checkmark {
    order: 1;
    margin-inline-start: auto;
    color: var(--brand-ink);
  }
  @media (prefers-reduced-motion: reduce) {
    .venue-filter select::picker-icon,
    .form select::picker-icon,
    .item-form select::picker-icon { transition: none; }
  }
}
