/* ==========================================================================
   site.v2.css - shared stylesheet for mypetfirstaid.com.au
   ==========================================================================

   Linked by index.html, privacy.html, terms.html and app-terms.html.

   NOT linked by thanks.html or oops.html, deliberately. Those two are centred
   single-panel pages that reuse the class name .card for a different component,
   and oops.html must stay fully self-contained because nginx serves it for 404
   and for 500/502/503/504: it has to render when other things are failing.

   The design TOKENS are NOT here. They stay in each page's inline <style>, so
   that scripts/css-tokens.py keeps index.html as its canonical set, and so that
   if this file ever fails to arrive the pages degrade to readable rather than to
   padding: 0 with inherited colours (every var() would otherwise be invalid at
   computed-value time). The @font-face declarations stay inline for the same
   reason, which also keeps font discovery off this file's critical path.

   VERSIONED FILENAME, and it matters. mypetfirstaid.conf serves .css with
   Cache-Control: public, max-age=31536000, immutable. This file is write-once
   from its first fetch. Never edit it in place after publishing; ship site.v2.css
   and update the four links. Never delete v1 when v2 ships, because a visitor
   holding cached HTML would get the 404 page returned as their stylesheet.

   Rules were moved here verbatim from the pages. Only the block indentation
   changed. Do not reformat values: css-tokens.py collapses whitespace but not
   numeric forms, so rewriting rgba(0, 19, 33, 0.06) would read as drift.

   WHAT CHANGED FROM v1 (27-07-2026, feature 010). v1 remains on disk and MUST
   NOT be deleted: visitors holding cached HTML still ask for it.

     1. .lead and .site-footer .disclaimer measure caps converted from ch to em.
        A ch is the width of the "0" glyph in the CURRENT font, so a ch cap is
        re-measured when the webfont swaps in and the text re-wraps under the
        reader (audit B15). An em resolves against the element's own font-size,
        which does not change on swap. The measures are unchanged: Nunito Sans
        "0" is 0.600em, so 65ch is exactly 39em and 72ch is exactly 43.2em.
     2. Heading weight split (audit E2). v1 set one flat rule, h1/h2/h3/h4 at 800.
        The design system specifies TWO display weights, not one: the display
        line at Outfit 800 and the SECTION HEADING at Outfit 700. So h1 was
        already right and h2/h3/h4 and .policy h2 were a step heavy.

   STILL OWED TO v3: the .skip-link block is duplicated inline on all four header
   pages and is byte-identical across them, so it belongs here. Consolidating it
   also needs copy-lint.sh check 11 rewritten, which asserts against the four
   inline copies. Deliberately not bundled into v2 (design decision D3).

   Provenance: extracted 26-07-2026 from index.html (chrome) and privacy.html
   (legal components) per feature spec 008, after the polish audit
   (card-1784954379227-0f05) made the copies agree so the move could be reviewed
   as a pure one. Card: card-1785025683812.
   ========================================================================== */

/* ============================ base ============================ */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font-body);
  color: var(--text-body);
  background: var(--surface-page);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  margin: 0;
  -webkit-font-smoothing: antialiased;
}
p { margin: 0 0 var(--space-4); }
a { color: var(--text-link); text-decoration: none; }
a:hover { color: var(--blue-700); text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }
:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

/* Heading base. index.html groups h1-h4 and the legal pages group h1-h3, with
   byte-identical declarations; the union is used here. No legal page contains an
   <h4>, so the extra tag matches nothing there. Heading SIZES deliberately did
   not move: index.html sizes off the type scale, the legal pages size via
   .page-hero h1 and .policy h2/h3. Two different heading systems. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-heading);
  line-height: var(--leading-tight);
  margin: 0;
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  font-weight: 800;
}
/* Audit E2. The design system carries two display weights: the display line at
   Outfit 800 and the section heading at Outfit 700 (see the design system's
   guidelines/type-display.card.html). v1 applied 800 to all four levels, which
   left every heading below h1 a step heavier than specified. h1 keeps 800. */
h2, h3, h4 { font-weight: 700; }

/* ============================ layout ============================ */
.wrap { max-width: var(--container-max); margin: 0 auto; padding: 0 var(--space-5); }
.band-white { background: var(--surface-card); }
.band-tint  { background: var(--surface-tint); }
/* Anchored sections land clear of the sticky header */
[id] { scroll-margin-top: calc(var(--header-h) + 16px); }
/* Eyebrow kicker - the signature move above every H2 */
.eyebrow {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--blue-600);
  margin-bottom: var(--space-3);
}
/* 39em was 65ch. Nunito Sans "0" is 0.600em, so the measure is identical and
   no longer re-measures when the font swaps. See the header note. */
.lead { font-size: var(--text-lg); color: var(--text-muted); max-width: 39em; }

/* .band carries the LEGAL value here. index.html overrides it to --space-9 in
   its own block, which is one override line instead of three. Audit finding A2:
   the difference is deliberate, not drift. */
.band { padding: var(--space-8) 0; }

/* ============================ buttons ============================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--text-base);
  padding: 14px 24px;
  border-radius: var(--radius-md);
  border: 1px solid transparent; /* real border so forced-colors keeps an edge */
  cursor: pointer;
  text-decoration: none;
  transition: background-color 160ms ease-out, transform 120ms ease-out, box-shadow 160ms ease-out;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: scale(0.98); }
.btn-primary { background: var(--blue-600); color: var(--text-on-brand); }
.btn-primary:hover { background: var(--blue-700); color: var(--text-on-brand); }
.btn-ghost { background: transparent; color: var(--blue-600); border-color: var(--border-strong); }
.btn-ghost:hover { background: var(--blue-50); }
.btn svg { flex: none; }

/* Disabled states exist only on index.html today (the notify form). They live
   here so the .btn component is whole rather than split across two files. No
   legal page contains a <button> or an aria-disabled attribute, so these match
   nothing there. */
/* The site had no disabled or busy state at all, so the notify button stayed
   fully live-looking while it was sending. Both selectors are needed: the
   form uses aria-disabled so keyboard focus survives the round trip. */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.62;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.btn:disabled:hover,
.btn[aria-disabled="true"]:hover { background: var(--blue-600); }
.btn:disabled:active,
.btn[aria-disabled="true"]:active { transform: none; }

/* ============================ header ============================ */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: var(--surface-card);
  border-bottom: 1px solid var(--border-subtle);
  height: var(--header-h);
  display: flex; align-items: center;
}
.site-header .wrap {
  width: 100%;
  display: flex; align-items: center; gap: var(--space-5);
}
.site-header .logo img { height: 44px; width: auto; }
.site-nav { display: none; gap: var(--space-5); margin-left: auto; font-family: var(--font-display); font-weight: 600; font-size: var(--text-sm); }
.site-nav a { color: var(--ink-700); }
.site-nav a:hover { color: var(--blue-600); text-decoration: none; }
.header-cta { margin-left: auto; padding: 10px 18px; font-size: var(--text-sm); }
@media (min-width: 900px) {
  .site-nav { display: flex; }
  .header-cta { margin-left: 0; }
}

/* ============================ footer ============================ */
.site-footer { background: var(--surface-ink); color: var(--neutral-300); padding: var(--space-8) 0; }
.site-footer .cols { display: flex; flex-wrap: wrap; gap: var(--space-6); align-items: center; }
.site-footer .logo img { height: 48px; width: auto; }
.site-footer nav { display: flex; flex-wrap: wrap; gap: var(--space-4); font-size: var(--text-sm); }
/* Same reason as .card > a:last-child: nav links are standalone targets. */
.site-footer nav a { display: inline-block; padding: 4px 0; }
.site-footer a { color: var(--neutral-300); }
.site-footer a:hover { color: #fff; }
.site-footer .socials { display: flex; gap: var(--space-4); margin-left: auto; }
.site-footer .socials a { color: var(--neutral-300); display: inline-flex; padding: 4px; }
.site-footer .socials a:hover { color: #fff; }
.site-footer .disclaimer {
  font-size: var(--text-xs); color: var(--neutral-500);
  max-width: 43.2em; margin-top: var(--space-6); /* was 72ch */
  border-top: 1px solid var(--ink-700); padding-top: var(--space-5);
}
/* Inline links in running prose need a non-colour cue: axe measured these at
   1.08:1 and 2.18:1 against the surrounding text, where 3:1 is required when
   colour is the only signal. Navigational and button links are unaffected. */
.form-note a, .site-footer .entity a, .site-footer .disclaimer a,
.page-footer .entity a { text-decoration: underline; }
.site-footer .entity { font-size: var(--text-xs); color: var(--neutral-500); margin-top: var(--space-3); }

/* ==================== legal page components ====================
   Identical across privacy.html, terms.html and app-terms.html, and absent from
   index.html: none of .policy, .toc, .legal-nav, .callout, .contact-panel,
   .back-home, .page-hero or .eff appears in its markup, so these match nothing
   there. This is the larger half of the real duplication, which is why it is
   here rather than copied three times.

   The legal pages' @media print rules are deliberately NOT here. Several target
   .site-footer, .band and bare h1, which DO exist on index.html, so they are not
   inert and must stay inline. */
/* page hero */
.page-hero h1 { font-size: clamp(1.9rem, 5vw, 3rem); margin-bottom: var(--space-3); text-transform: none; letter-spacing: normal; }
.eff { color: var(--text-muted); font-size: var(--text-sm); margin: 0 0 var(--space-4); }
/* shared legal-nav strip (Privacy | Website Terms | App Terms) */
.legal-nav {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0 var(--space-4);
  margin: var(--space-5) 0 0;
  font-family: var(--font-display); font-weight: 600; font-size: var(--text-sm);
}
.legal-nav a { color: var(--blue-600); text-decoration: none; padding: 11px 0; display: inline-flex; }
.legal-nav a:hover { text-decoration: underline; }
.legal-nav a[aria-current="page"] { color: var(--text-muted); pointer-events: none; }
.legal-nav span[aria-hidden] { color: var(--border-strong); }
/* policy reading column */
.policy { max-width: 760px; margin: 0 auto; }
.policy h2 {
  text-transform: none; letter-spacing: normal;
  font-size: var(--text-2xl); font-weight: 700; /* audit E2, was 800 */
  margin: var(--space-7) 0 var(--space-4);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-subtle);
}
.policy h2:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.policy h3 {
  text-transform: none; letter-spacing: normal;
  font-size: var(--text-lg); font-weight: 700;
  margin: var(--space-5) 0 var(--space-2);
}
.policy p { margin: 0 0 var(--space-4); }
.policy ul { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
.policy li { margin-bottom: var(--space-2); line-height: var(--leading-body); }
.policy a { text-decoration: underline; overflow-wrap: anywhere; }
.policy ol { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
.policy ol li { margin-bottom: var(--space-2); }
.toc {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-card);
  padding: var(--space-4) var(--space-5);
  margin: 0 0 var(--space-6);
}
.toc-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--text-sm); text-transform: uppercase;
  letter-spacing: var(--tracking-caps); color: var(--text-muted);
  margin: 0 0 var(--space-3);
}
.toc ul { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: var(--space-6); font-size: var(--text-sm); }
.toc li { margin: 0 0 var(--space-2); break-inside: avoid; }
.toc a { text-decoration: none; overflow-wrap: anywhere; }
.callout {
  background: var(--surface-tint);
  border-left: 4px solid var(--blue-600);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  margin: 0 0 var(--space-6);
  font-family: var(--font-display); font-weight: 700;
  color: var(--text-heading);
}
.contact-panel {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: var(--space-5) var(--space-6);
  margin-top: var(--space-6);
}
.contact-panel p { margin: 0 0 var(--space-2); }
.contact-panel a { overflow-wrap: anywhere; }
.back-home { margin-top: var(--space-7); }
@media (max-width: 640px) {
  .toc ul { columns: 1; }
}

/* ============================ motion ============================
   Smooth scrolling only when motion is welcome. The reduce counterpart for .btn
   is here so the button component is whole; index.html keeps its own wider
   reduce block (.btn, .card, .skip-link) inline, which is a superset, so the
   result is unchanged everywhere. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}

/* ============================ print ============================
   Only the body rule is shared. Every other print declaration differs per page
   and stays inline. Those inline blocks come AFTER this file in the cascade,
   which is what scripts/copy-lint.sh check 9 exists to keep true. */
@media print {
  body { background: #fff; color: #000; }
}
