/* Contact page: rules specific to contact.html. Shared components live in ../styles.css.
   Selectors stay flat (single class) so they override styles.css by source order alone. */


/* --- Page hero: the phone number in the lead is a link on navy ------------ */

.hero-tel {
  color: #fff;
  font-weight: 600;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(255, 255, 255, 0.55);
  text-underline-offset: 0.2em;
  white-space: nowrap;
}

.hero-tel:hover {
  text-decoration-color: #fff;
}


/* --- Form and details: 7/5 columns, details stick on desktop -------------- */

.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--s-10) clamp(2rem, 6vw, 5rem);
  align-items: start;
}

.contact-form__head {
  margin-bottom: var(--s-8);
}

/* the head is the standard section opener (mono eyebrow, display h2); this hint sits
   under the heading, closer than a lead would but clear of the display type's weight */
.contact-form__note {
  margin-top: var(--s-4);
  color: var(--ink-soft);
  font-size: var(--text-small);
}

.field__req {
  color: var(--blue-700);
  font-weight: 600;
}

/* checkbox row uses .field so the shared .is-invalid rules show its error text */
.field--check {
  gap: 0.5rem;
}

.field--check.is-invalid .checkbox {
  color: var(--danger);
}

/* Without scripting the form cannot send anything - it carries no action, so a submit
   only reloads the page - so this notice sits above it with the two routes that need
   nothing at all.
   It is the shared card (border, padding, split rule) and only the spacing below it
   and the link colour are local. It renders only inside <noscript>, so nothing here
   is ever painted for a visitor who has the script. */
.form-nojs {
  margin-bottom: var(--s-8);
}

.form-nojs__title {
  margin-bottom: var(--s-3);
}

.form-nojs__link {
  color: var(--blue-700);
  overflow-wrap: anywhere;
}

.form__actions {
  margin-top: var(--s-2);
}

/* the live region stays in the document at all times so announcements are not lost;
   while empty it takes up no space */
.form-status {
  display: block;
  margin-top: var(--s-4);
}

.form-status:empty {
  margin: 0;
  padding: 0;
  border: 0;
}

.form-status--error {
  background: #FBEDEB;
}


/* --- Details card ----------------------------------------------------------- */

.contact-details__title {
  margin-bottom: var(--s-4);
}

/* the details are the shared .spec sheet (styles.css), stacked; only the value styling is local */
.contact-details__value {
  margin: 0;
  color: var(--ink);
  font-size: var(--text-small);
  overflow-wrap: anywhere;
}

.contact-details__phone {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 2.25rem;
  font-weight: 600;
  letter-spacing: var(--track-display);
  line-height: 1;
  color: var(--navy-700);
  text-decoration: none;
  padding-block: 0.125rem;
}

.contact-details__phone:hover {
  color: var(--blue-700);
}

.contact-details__link {
  color: var(--blue-700);
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}

.contact-details__link:hover {
  color: var(--navy-700);
}

/* one identifier per line; the element also carries class="mono" and the spec sheet's last
   hairline separates it from the rows above.

   minmax(0, 1fr) rather than the default auto column: an auto column takes its min-content
   width from the longest item, so with a nowrap child the column grows past the card and the
   text is cut off at the card's edge. The card clips, so document.scrollWidth never moves and
   neither gate can see it. Capping the column at the card width is what makes the wrapping
   below actually happen. */
.contact-details__id {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.375rem;
  margin-top: var(--s-4);
  color: var(--ink-soft);
}

/* The row wraps: "Master licence" may fall onto its own line at large text sizes. */
.contact-details__id-item {
  overflow-wrap: break-word;
}

/* The identifier itself never does. These two strings - the Master Security Licence number
   and the ABN - are what a buyer checks, so they have to read as one unbroken token at every
   text size, which is the one thing white-space: nowrap is for here. */
.contact-details__id-value {
  white-space: nowrap;
}

/* At 200% text zoom var(--s-8) of card padding becomes 64px a side, and on a phone that is
   most of the width: the licence number, the one string on this card that must not break,
   no longer has room. The inline padding is therefore measured against the viewport, so it
   stays where it is while the text grows. The 2rem ceiling keeps the card identical to every
   other .card--pad on the site at ordinary text sizes and desktop widths.

   overflow is visible for the same reason. .card clips, which is what hid the cut-off
   credentials from document.scrollWidth and from both gates; this card has no media to clip,
   so at the narrowest combination there is (360px wide at 200%, where the shared gutter alone
   takes 80px) the ABN spends the last few pixels of its own padding rather than losing its
   last digits. It still finishes well inside the card's border. The shared .card::before
   split rule was relying on the clip for its corners, so it gets the radius back explicitly. */
.contact-details {
  padding-inline: clamp(20px, 5vw, var(--s-8));
  overflow: visible;
}

.contact-details::before {
  border-radius: var(--radius) var(--radius) 0 0;
}


/* --- Where we are: street photo | seam | map ------------------------------- */

.locate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--seam) minmax(0, 1fr);
  background: var(--navy-900);
}

.locate__photo {
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.locate__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 50%;
}

.locate__seam {
  background: var(--blue-500);
}

/* tinted ground carries the facade below, and shows the panel's shape while the
   iframe the button builds is still loading */
.locate__map {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--sky-100);
}

.locate__map iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* The map iframe is a tab stop with no ring of its own: Chrome never matches
   :focus-visible on an iframe, so the global rule in styles.css never paints on
   it (WCAG 2.4.7). The wrapper wears the ring instead, in the same
   navy / hi-vis / navy order as that rule, on two selectors because neither
   covers both ways in on its own. Measured in headless Chromium with the real
   cross-origin embed in the panel:

     programmatic frame.focus()   :focus-within true,  iframe:focus false
     Tab in from the page         :focus-within FALSE, iframe:focus false

   Chrome stops propagating focus state to the parent document once focus is
   inside a CROSS-ORIGIN browsing context, so :focus-within alone leaves the
   keyboard path - the one that matters - with no ring at all. `.is-map-focused`
   is contact.js reading the window blur that fires as focus crosses into the
   frame; :focus-within is kept because it is what paints on the programmatic
   focus that follows the button press. Gated on :has(iframe) so the facade
   button keeps its own ring and the panel is never ringed twice. */
.locate__map:has(iframe):focus-within,
.locate__map.is-map-focused {
  outline: 2px solid var(--hivis);
  outline-offset: 3px;
  box-shadow: 0 0 0 7px var(--navy-900);
}

/* The stand-in that ships instead of the embed.

   It is a plain navy panel, not a drawing of streets. An earlier version filled it
   with a schematic city grid, which was an invented street layout sitting under the
   real Elizabeth Street address: a fake map of a real place, and a claim the site
   cannot support. A page may show a real map or no map; this shows no map, and says
   so by looking like a panel rather than like a map. What it carries is what is
   true - the pin, the address and the button that fetches the real thing.

   Absolutely positioned so the panel keeps the aspect ratio it has with the iframe
   in it. */
.map-facade {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-4);
  padding: var(--s-6);
  text-align: center;
  background: var(--navy-900);
}

/* The site's one decorative device, the same 3px split rule that heads every card,
   step and pillar. On this panel the ground is navy-900, where the rule's own
   navy-700 half is all but invisible and the device reads as a half-length blue
   line. On dark the split is drawn white to blue so both halves carry. */
.map-facade::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: var(--rule-h);
  background: linear-gradient(90deg, #fff 0 50%, var(--blue-500) 50% 100%);
}

.map-facade__pin {
  display: block;
}

.map-facade__pin-body {
  fill: var(--sky-100);
}

.map-facade__pin-dot {
  fill: var(--navy-900);
}

.map-facade__where {
  margin: 0;
  color: var(--on-dark);
  line-height: 1.6;
}

.map-facade__note,
.map-facade__nojs {
  max-width: 32ch;
  color: var(--on-dark-soft);
}

/* the button needs contact.js to build the iframe, so without scripting it would
   be a control that does nothing: the <noscript> line takes its place and sends
   the visitor to "Get directions" below, which is a plain link and needs no JS */
.map-facade > button,
.map-facade__note {
  display: none;
}

.js .map-facade > button {
  display: inline-flex;
}

.js .map-facade__note {
  display: block;
}

.locate__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2) var(--s-6);
  margin-top: var(--s-5);
  font-size: var(--text-small);
}

.locate__address {
  color: var(--ink-soft);
}


/* --- What happens next ------------------------------------------------------ */

.next__lead {
  margin-top: var(--s-6);
}

.next__steps {
  gap: var(--s-8);
}


/* --- Responsive --------------------------------------------------------------- */

@media (max-width: 1024px) {
  .contact-layout {
    grid-template-columns: 1fr;
  }

  .contact-details {
    max-width: 560px;
  }
}

@media (max-width: 768px) {
  .locate {
    grid-template-columns: 1fr;
    grid-template-rows: auto var(--seam) auto;
  }

  .locate__photo,
  .locate__map {
    aspect-ratio: 16 / 11;
  }

  /* the panel is shorter here, so the column tightens rather than filling it
     edge to edge */
  .map-facade {
    gap: var(--s-3);
    padding: var(--s-4);
  }

  .contact-details__phone {
    font-size: 2rem;
  }
}
