/* StingRay Boxing — the whole stylesheet. No imports, no dependencies. */

/* ---------- Self-hosted fonts (latin subset, instanced from Archivo VF) ---------- */
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(fonts/archivo-400.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(fonts/archivo-600.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 400;
  font-stretch: 125%;
  font-display: swap;
  src: url(fonts/archivo-expanded-400.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/space-mono-400.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- Tokens ---------- */
:root {
  --ink: #0E1417;
  --body: #2A323A;
  --muted: #454D55;
  --cream: #F7F3EC;
  --stone: #DEDBD4;      /* the ground under the enquiry, so the white card lifts */
  --ember: #FF4D1A;
  --ember-dark: #CF3909;
  --ember-darker: #C33608;
  --ember-deep: #A32C05;
  --hairline: #E6DFD2;
  --card: #FFFFFF;
  --field-border: #CFC8BA;
  --sans: Archivo, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --shadow: 0 18px 30px -20px rgba(14, 20, 23, .35);
  --radius: 16px;
  --header-h: 64px;
  --rail: 320px;
  --rail-gap: 40px;
  --sect: clamp(56px, 5.5vw + 21.8px, 96px);
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--cream);
  color: var(--body);
  font: 400 16px/1.6 var(--sans);
  text-wrap: pretty;
}
h1, h2, h3, p, ul, ol, dl, dd { margin: 0; }
img, svg { max-width: 100%; height: auto; display: block; }
/* Ember dark is 4.48:1 on Cream — just under AA for body text — so links use the
   next shade down (4.93:1) and darken further on hover. The button keeps Ember dark:
   white on it is 4.95:1. */
a { color: var(--ember-darker); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ember-deep); }
:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; border-radius: 3px; }

.wrap { max-width: 1120px; margin-inline: auto; padding-inline: 24px; }
.eyebrow {
  font: 400 11px/1.4 var(--mono);
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--muted);
}
h2.eyebrow, h3.eyebrow { font-weight: 400; }
.display {
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 400;
  font-stretch: 125%;
  text-transform: uppercase;
  letter-spacing: -.025em;
  text-wrap: balance;
}
/* 18ch, not 16: the longest sentence in the headline is 17.3ch, so a 16ch measure
   made it impossible for any of the three sentences to hold its own line. */
h1.display { font-size: clamp(32px, 5.88vw + 10.8px, 64px); line-height: 1.02; max-width: 18ch; }
h2.display { font-size: clamp(26px, 1.56vw + 19.75px, 32px); line-height: 1.08; }
.lede { font-size: clamp(18px, .42vw + 16.5px, 21px); line-height: 1.5; max-width: 48ch; }
.muted { color: var(--muted); }

.skip-link {
  position: absolute;
  left: 24px;
  top: -60px;
  z-index: 50;
  background: var(--ink);
  color: var(--cream);
  padding: 12px 20px;
  border-radius: 10px;
  font-weight: 600;
  text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 12px; color: var(--cream); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 20px;
  border: 1px solid transparent;
  border-radius: 10px;
  font: 600 16px/1.25 var(--sans);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
.btn-primary { background: var(--ember-dark); color: #FFF; }
.btn-primary:hover { background: var(--ember-darker); color: #FFF; }
.btn-primary:active { background: var(--ember-deep); }
.btn-secondary { background: var(--card); border-color: var(--hairline); color: var(--ink); }
.btn-secondary:hover { border-color: var(--ink); color: var(--ink); }
.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }
.hero .btn, .submit-row .btn { padding: 14px 26px; }

/* ---------- Logo ---------- */
.logo {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  text-decoration: none;
}
.logo-mark {
  width: 16px;
  height: 16px;
  flex: none;
  background: var(--ember);
  transform: rotate(45deg);
}
.logo-word {
  font-stretch: 125%;
  text-transform: uppercase;
  letter-spacing: -.025em;
  font-size: 18px;
}

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(247, 243, 236, .92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hairline);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 10px;
}
.site-header .btn { padding: 10px 18px; font-size: 15px; flex: none; }
.site-header .logo { min-width: 0; }
.site-header .logo-word { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lbl-short { display: none; }

/* ---------- Hero ---------- */
.hero { display: grid; gap: 20px; padding-block: calc(var(--sect) + 8px) 40px; }
.hero .accent { color: var(--ember); }

/* ---------- Photo ---------- */
.photo { padding-bottom: var(--sect); }
.photo-frame {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink);
  box-shadow: var(--shadow);
}
/* <picture> is inline by default, which gives the img no definite height to
   resolve 100% against — block it out so object-fit has a box to cover. */
.photo-frame picture { display: block; width: 100%; height: 100%; }
.photo-frame img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- Memberships + Find us ---------- */
.strip .wrap { display: grid; gap: 16px; padding-block: var(--sect); justify-items: start; }
.find .wrap { display: grid; gap: 24px; padding-block: var(--sect); justify-items: start; }
.find p { max-width: 62ch; }
.find .place { color: var(--ink); font-weight: 600; }

/* Find us reads as a spec sheet: four label-over-value pairs on a 2x2 grid, each
   ruled with the same hairline that separates the bands. <address> is italic by
   default in every browser, which would set the whole block apart for no reason,
   and it must stretch — the wrap's justify-items: start would otherwise shrink it
   to its content and the two columns would size themselves off the longest line. */
.find address { font-style: normal; }
.find .wrap > address { justify-self: stretch; }
.find-grid { display: grid; gap: 28px 40px; }
.detail {
  display: grid;
  gap: 8px;
  align-content: start;
  border-top: 1px solid var(--hairline);
  padding-top: 14px;
}
.detail dd { display: grid; gap: 4px; }
/* mike@stingrayboxing.com.au is 26 characters and has no break opportunity of its
   own; without this it pushes the column wider than its track on a narrow phone. */
.detail dd a { overflow-wrap: anywhere; }
.detail-note { font-size: 14.5px; }
@media (min-width: 560px) {
  .find-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- Spine: a hairline per band, ticked in Ember on the content axis. The
   tick is absolutely positioned, so it is not a grid item and cannot stretch; .wrap
   has no border, so `left` is its content edge — but only while `left` matches that
   band's own padding-inline. It is 24px here because .wrap's padding is 24px. If a
   band ever changes its padding-inline at a breakpoint, its ::before must move by the
   same amount in the same block, or its tick drifts off the axis while the other three
   stay put. .enquiry does exactly that below 421px; see the narrow-phone block near the
   end of this file. ---------- */
.strip, .find, .enquiry { border-top: 1px solid var(--hairline); }
.strip .wrap, .find .wrap, .enquiry .wrap { position: relative; }
.strip .wrap::before, .find .wrap::before, .enquiry .wrap::before, .hero .eyebrow::before {
  content: "";
  width: 88px;
  height: 3px;
  background: var(--ember);
}
.strip .wrap::before, .find .wrap::before, .enquiry .wrap::before { position: absolute; top: -1px; left: 24px; }
.hero .eyebrow::before { display: block; margin-bottom: 14px; }

/* ---------- Enquiry ---------- */
.enquiry {
  background: var(--stone);
  scroll-margin-top: calc(var(--header-h) + 16px);
}
/* #enquiry is the skip link's target and takes a real focus ring: Ember is 2.40:1
   on Stone (fails SC 1.4.11), Ink is 13.4:1. */
.enquiry:focus-visible { outline-color: var(--ink); }
.enquiry .wrap { display: grid; gap: 20px; padding-block: var(--sect) calc(var(--sect) + 16px); }
.enq-head { display: grid; gap: 10px; }
.form-card {
  max-width: 720px;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow);
  display: grid;
  /* Named because .confirm.is-empty has to cancel exactly one of these gaps. Change it
     here and the cancellation follows; hard-coding either half lets them drift. */
  --form-gap: 16px;
  gap: var(--form-gap);
}
.field-pair { display: grid; gap: 16px; }
.field { display: grid; gap: 6px; min-width: 0; }
.field > label { font-size: 14px; font-weight: 600; color: var(--ink); }
.opt { font: 400 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.req { font: 400 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .06em; color: var(--ember-darker); }
.field input, .field textarea {
  width: 100%;
  min-height: 44px;
  padding: 11px 12px;
  border: 1px solid var(--field-border);
  border-radius: 8px;
  background: var(--cream);
  color: var(--ink);
  font: 400 16px/1.5 var(--sans);
  transition: background-color .15s ease, border-color .15s ease;
}
.field textarea { resize: vertical; min-height: 132px; }
.field input:hover, .field textarea:hover { border-color: var(--muted); }
/* A focused field lights to white — a state change, not a hover cue. The invalid
   selectors carry :hover/:focus so the red border outranks the two rules above. */
.field input:focus, .field textarea:focus { background: var(--card); border-color: var(--ink); }
.field .is-invalid, .field .is-invalid:hover, .field .is-invalid:focus { border-color: var(--ember-dark); border-width: 2px; }
.field-error { font-size: 13px; color: var(--ember-darker); }
/* :not([role]) spares the live regions. A region that appears and fills in the same
   task is not announced — the empty element has to be in the accessibility tree first.
   #turnstile-error carries role="status", so this rule must never collapse it; it is an
   empty inline span in a grid row and takes no visible space. The four per-field spans
   have no role and keep collapsing as before. */
.field-error:empty:not([role]) { display: none; }
.counter { font: 400 11px/1.4 var(--mono); color: var(--muted); justify-self: end; }
.form-note { font-size: 13px; color: var(--muted); }
.submit-row { display: grid; gap: 10px; justify-items: start; }
/* The Turnstile widget is a cross-origin iframe in a closed shadow root: nothing
   here can reach inside it, only the box it sits in. Its flexible size has a
   300px floor, which the card's interior does not reach at a 360px viewport on the
   default padding — hence the narrow-phone block further down, which does the sum in
   full. overflow-x is the backstop for anything narrower than that block covers. */
.turnstile-row { display: grid; gap: 6px; }
.turnstile { overflow-x: auto; min-height: 65px; }
.confirm {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--cream);
  padding: 16px 18px;
  display: grid;
  gap: 12px;
  justify-items: start;
}
.confirm p { font-size: 14.5px; color: var(--ink); }
/* Never `hidden` and never display:none — see the note on .field-error above. The panel
   stays in the tree and is emptied by class instead, so the message that lands in it is
   announced. site.js also moves focus here, which is the belt to that braces.

   Staying in the tree means staying a grid item of .form-card, so an empty panel would
   still draw one --form-gap below the submit row. The negative margin cancels exactly
   that gap, leaving the card's resting height unchanged from before the panel became
   permanent. */
.confirm.is-empty {
  border: 0;
  padding: 0;
  background: none;
  gap: 0;
  margin-block-start: calc(-1 * var(--form-gap));
}
.confirm:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------- Footer ---------- */
.site-footer { background: var(--ink); color: var(--cream); }
.site-footer .wrap { display: grid; gap: 32px; padding-block: 56px 40px; }
.site-footer .logo, .site-footer a { color: var(--cream); }
.site-footer a:hover { color: var(--ember); }
.site-footer p { max-width: 60ch; font-size: 15px; }
/* 8.7:1 on Ink, so the mono labels stay readable at 11px. The size is restated
   because .site-footer p (a class plus an element) outweighs .eyebrow's font
   shorthand — which is why the old footer set its whole contact block in 15px
   uppercase mono instead of the 11px label size it was asking for. */
.site-footer .eyebrow { color: #A9B2B8; font-size: 11px; }
.foot-brand { display: grid; gap: 16px; justify-items: start; }
.foot-col { display: grid; gap: 24px; align-content: start; }
/* Label over value, not label beside it — the same pair as Find us, so the two
   contact blocks on the page read the same way. */
.foot-group { display: grid; gap: 6px; }
.foot-group a { overflow-wrap: anywhere; }
.site-footer .foot-links { display: flex; flex-wrap: wrap; gap: 8px 20px; font-size: 14px; }
.foot-base {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px 24px;
  justify-content: space-between;
  border-top: 1px solid #263139;
  padding-top: 20px;
  font-size: 13px;
  color: #A9B2B8;
}

/* ---------- Policy + 404 pages ---------- */
.doc { max-width: 760px; scroll-margin-top: calc(var(--header-h) + 16px); }
.doc-head { display: grid; gap: 10px; padding-block: 48px 8px; }
.doc-body { display: grid; gap: 24px; padding-block: 24px 64px; }
.doc-body section { display: grid; gap: 8px; }
.doc-body h2 { color: var(--ink); font-size: 18px; font-weight: 600; }
.doc-body ul { padding-left: 20px; display: grid; gap: 6px; }
.doc-body p, .doc-body li { max-width: 62ch; }
.centred { min-height: 52vh; align-content: center; justify-items: start; gap: 16px; display: grid; padding-block: 64px; }

/* ---------- Larger screens ---------- */
@media (min-width: 768px) {
  .photo-frame { aspect-ratio: 16 / 9; }
  .field-pair { grid-template-columns: 1fr 1fr; }
  .submit-row { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 20px; }
  /* Footer columns. This markup is byte-identical on all four pages. Everything is
     left-aligned: the contact block used to be right-aligned uppercase mono, which
     ragged the left edge of four lines of data and shouted the email address. */
  .site-footer .wrap {
    grid-template-columns: minmax(0, 5fr) minmax(0, 3fr) minmax(0, 4fr);
    grid-template-areas: "brand visit contact" "base base base";
    column-gap: 48px;
    row-gap: 40px;
  }
  .foot-brand { grid-area: brand; }
  .foot-visit { grid-area: visit; }
  .foot-contact { grid-area: contact; }
  .foot-base { grid-area: base; }
}

/* ---------- The rail: section heads in a 320px left column, body beside them, so
   every band hangs off one vertical axis. ---------- */
@media (min-width: 1024px) {
  /* The hero is deliberately NOT on the rail. The rail only reads as structure where
     the left track holds something — a section heading. In the hero it would hold
     only the eyebrow, leaving the sub-copy and CTA indented against an empty column
     with nothing to justify the indent. Hero stays flush left; measure does the work. */
  .strip .wrap, .find .wrap, .enquiry .wrap {
    grid-template-columns: var(--rail) minmax(0, 1fr);
    column-gap: var(--rail-gap);
  }
  .hero { row-gap: 24px; }
  .strip .display, .find .display { grid-column: 1; grid-row: 1; }
  /* Direct children only. As a descendant selector this also matched the paragraphs
     nested inside Find us, which are grid items of their own group — they took
     grid-column: 2 there, opening an implicit first column and stranding each label
     beside its value instead of above it. */
  .strip .wrap > p, .find .wrap > address { grid-column: 2; }
  /* Without this the head stretches to the form's height and its auto rows spread. */
  .enquiry .wrap { align-items: start; }
}

/* Narrow phones: give the enquiry card back the padding the Turnstile widget needs to
   reach its 300px floor. The full sum, border included, because box-sizing is
   border-box and .form-card has a 1px hairline on each side:

     360 - 20 (wrap, both sides) - 2 (card border) - 36 (card padding) = 302

   Two pixels of slack, deliberately. The earlier working here read
   "360 - 24 - 36 = 300 exactly", which omitted the border and landed on 298 — under
   the floor, at the single most common Android width, in the media query written to
   clear it. Do not tighten these numbers back to an exact fit.

   The spine tick moves with the padding. It is absolutely positioned against the
   .wrap's padding box, so a band that changes its own padding-inline must move its
   ::before by the same amount or the tick drifts off the content axis — which is the
   one thing the spine exists to hold. */
@media (max-width: 420px) {
  .enquiry .wrap { padding-inline: 10px; }
  .enquiry .wrap::before { left: 10px; }
  .form-card { padding: 18px; }
}

/* The full "Make an enquiry" label needs ~403px of header row; below that the logo
   and the button collide. Measured against the real font metrics, not guessed. */
@media (max-width: 479px) {
  .site-header .lbl-long { display: none; }
  .site-header .lbl-short { display: inline; }
}

/* Narrowest supported phones: ease the wordmark down one step so the header row
   still clears 360px. The headline clamp already floors at the measured 32px. */
@media (max-width: 399px) {
  .site-header .logo-word { font-size: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ---------- Print (policies) ---------- */
@media print {
  .site-header, .site-footer, .skip-link, .no-print { display: none !important; }
  body { background: #FFF; color: #000; font-size: 12pt; }
  .doc, .wrap { max-width: none; padding: 0; }
  .enquiry { background: none; }
  a { color: #000; text-decoration: underline; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; word-break: break-all; }
}
