/* ==========================================================================
   MyGymDay — base.css  ·  V2 EDITORIAL
   --------------------------------------------------------------------------
   Reset, document defaults, the type ramp and the layout primitives. Nothing
   here belongs to a single page or section — that lives in site.css.

   Loaded after tokens.css and before site.css.

   The two web faces are requested from the <head> of every page, not with an
   @import here: an @import inside this file would not be discovered until this
   file had downloaded and parsed, which lengthens the swap. See any page head
   for the preconnect + display=swap pattern.

   TYPE RAMP CONTRACT. The class names below are a fixed interface, because the
   four legal documents' markup is frozen (their wording is what Google Play
   reads) and they must restyle without an HTML edit. So the interface is fixed
   and the SIZES behind it are not — .t-hero is the proof:

     .t-hero                      (index.html, partners.html — a rung of its
                                   own now, sitting between .t-poster and
                                   .t-display. It WAS a literal alias of
                                   .t-poster, which set eleven elements across
                                   two pages at one size; see the long comment
                                   above the rule for what that cost)
     .t-overline  -> .t-eyebrow   (all four legal pages, always with .t-lime)
     .t-subheading                (kept as a text-face rung; V2's own ramp
                                   has no sub-heading, but prose h3 and the
                                   not-yet-rebuilt pages still ask for one)

   Adding a selector to an existing rule costs nothing and keeps six pages
   working. Splitting one rule into two, as .t-hero needed, costs nothing
   either. Renaming a class in frozen markup does not.
   ========================================================================== */

/* ── Reset ────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The sticky header must not cover an anchor target. */
  scroll-padding-top: calc(var(--mgd-site-header-h) + var(--mgd-space-xl));
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, figcaption, blockquote, dl, dd, ul, ol {
  margin: 0;
}

/* Only opt-in lists lose their markers. A list inside .prose is a legal
   document's list and keeps its bullets — that is why this is scoped to
   role="list" and not to every <ul>. */
ul[role='list'],
ol[role='list'] {
  list-style: none;
  padding: 0;
}

img,
picture,
svg,
video {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* ── Document ─────────────────────────────────────────────────────── */
body {
  font: var(--mgd-site-body);
  color: var(--mgd-color-text);
  /* Set on <body> AND <html> below: iOS paints the overscroll area from the
     html background, and a white flash at the top of a near-black page is the
     single most expensive one-pixel mistake on a site like this. */
  background: var(--mgd-color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-synthesis-weight: none;
  /* clip, not hidden: `hidden` on <body> silently kills position:sticky. */
  overflow-x: clip;
}

html {
  background: var(--mgd-color-bg);
  /* Android Chrome flashes a translucent slate rectangle over whatever you
     tap. On a white page nobody notices. On a #080B0A page it reads as a
     rendering fault — a grey ghost that appears under your thumb and fades
     — and it clips to the element's border box, so it squares off the pill
     buttons for the length of the flash. It is switched off here rather
     than per-control because it inherits, which means one line covers the
     seven pages and anything added later.
     THIS IS ONLY SAFE BECAUSE site.css GIVES BACK A REAL :active STATE on
     .btn and .nav__link. Removing the flash without replacing it would
     leave a phone with no confirmation that a tap registered, which is
     worse than the flash. If those :active rungs are ever deleted, delete
     this line in the same commit. */
  -webkit-tap-highlight-color: transparent;
}

::selection {
  background: var(--mgd-color-primary);
  color: var(--mgd-color-text-inverse);
}

/* ── Focus ────────────────────────────────────────────────────────── */
/* Lime at 2px on near-black is the highest-contrast ring available in the
   palette — 16.4 : 1, where 1.4.11 asks for 3 : 1 — and it is never removed;
   only :focus-visible narrows it to keyboard users.

   The one ground where this ring cannot work is lime itself, and the site has
   exactly one lime field with a focusable control inside it. site.css
   re-points the outline colour to ink under .band--lime, next to the rest of
   that band's inversions, rather than qualifying this rule here. */
:focus-visible {
  outline: 2px solid var(--mgd-color-primary);
  outline-offset: 3px;
  border-radius: var(--mgd-radius-sm);
}

/* The one exception, and the reason it is an exception rather than an omission.
   Every page gives <main> `tabindex="-1"` so the skip link moves FOCUS and not
   only the viewport — Safari and older Chromium scroll to a fragment without
   focusing it, which leaves the next Tab back at the top of the page. That
   attribute makes the container programmatically focusable, so the rule above
   would draw a 2px lime rectangle around the whole page the moment the skip
   link is used, which reads as a rendering fault rather than a focus ring.

   Suppressing it is safe on both counts: -1 keeps <main> out of the tab order,
   so 2.4.7 never asks for a visible indicator here, and nothing is lost to
   assistive tech, which announces the landmark on arrival. The next Tab lands
   on a real control that draws its own ring. */
#main:focus-visible {
  outline: none;
}

/* ── Skip link ────────────────────────────────────────────────────── */
.skip-link {
  position: fixed;
  top: var(--mgd-space-sm);
  left: var(--mgd-space-sm);
  z-index: 999;
  padding: var(--mgd-space-md) var(--mgd-space-lg);
  border-radius: var(--mgd-radius-pill);
  background: var(--mgd-color-primary);
  color: var(--mgd-color-text-inverse);
  font: var(--mgd-site-eyebrow);
  letter-spacing: var(--mgd-site-track-eyebrow);
  text-transform: uppercase;
  text-decoration: none;
  /* Off-screen until focused. transform, not display:none, so it is still in
     the accessibility tree and still the first tab stop. */
  transform: translateY(calc(-100% - var(--mgd-space-xl-2)));
  transition: transform var(--mgd-site-dur-fast) var(--mgd-site-ease);
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline-offset: 2px;
}

/* ══ Type ramp ═════════════════════════════════════════════════════════
   Four display rungs in Anton (uppercase, tight leading, positive tracking)
   and five text rungs in Inter. Each rung carries its own `ch` measure, so a
   headline wraps at two to four words a line at every viewport without a
   single width being declared in the markup. `ch` and not `px`: the measure
   then scales with the clamp() instead of drifting away from it.

   UPPERCASE IS APPLIED HERE, NOT IN THE HTML. The markup keeps sentence case
   so copy stays legible in view-source, in search results and to a screen
   reader, which would otherwise spell some headlines out letter by letter.
   ====================================================================== */

/* .t-poster is a page's opening statement and there is exactly one per page:
   the h1, and nothing else. */
.t-poster {
  font: var(--mgd-site-poster);
  letter-spacing: var(--mgd-site-track-poster);
  text-transform: uppercase;
  max-width: var(--mgd-site-measure-poster);
  text-wrap: balance;
}

/* .t-hero WAS A LITERAL ALIAS OF .t-poster, AND THAT WAS THE BUG. Both
   selectors shared the rule above, so index.html's h1 and its five band
   headlines all set at 148px on a desktop: eleven elements across two pages
   at one size — two .t-poster h1s and nine .t-hero h2s — which is not a
   hierarchy, it is a wall. The h2s now take their own rung — 112px against
   the h1's 148px, a step the eye reads immediately at any width, and one the
   phone keeps too at 39 against 44.

   It keeps the poster's tracking, because both are Anton uppercase and the
   optical correction does not change with size, and it takes the display
   rung's 20ch measure rather than the poster's 16ch, because a band headline
   is a sentence where an h1 is a phrase. Everything else about the two
   rules is identical, which is why the name did not have to change and no
   markup moved: the nine .t-hero h2s simply got smaller and the two h1s
   above them did not move at all. */
.t-hero {
  font: var(--mgd-site-hero);
  letter-spacing: var(--mgd-site-track-poster);
  text-transform: uppercase;
  max-width: var(--mgd-site-measure-display);
  text-wrap: balance;
}

.t-display {
  font: var(--mgd-site-display);
  letter-spacing: var(--mgd-site-track-display);
  text-transform: uppercase;
  max-width: var(--mgd-site-measure-display);
  text-wrap: balance;
}

.t-title {
  font: var(--mgd-site-title);
  letter-spacing: var(--mgd-site-track-title);
  text-transform: uppercase;
  max-width: var(--mgd-site-measure-title);
  text-wrap: balance;
}

/* The largest rung set in the TEXT face. That is deliberate: a section
   heading, a card title and a legal <h2> are read, not shouted, and mixing
   the display face into small sizes is what made V1 speak in one voice. */
.t-heading {
  font: var(--mgd-site-heading);
  letter-spacing: var(--mgd-site-track-heading);
  max-width: var(--mgd-site-measure-heading);
  text-wrap: balance;
}

/* Not part of V2's own ramp — kept because prose h3 and the two pages that
   are rebuilt later still ask for a rung between heading and body. */
.t-subheading {
  font: var(--mgd-type-subheading);
  letter-spacing: -0.005em;
  max-width: var(--mgd-site-measure-heading);
}

.t-lead {
  font: var(--mgd-site-lead);
  color: var(--mgd-color-text-secondary);
  max-width: var(--mgd-site-measure-lead);
}

.t-body {
  font: var(--mgd-site-body);
  max-width: var(--mgd-site-measure-body);
}

/* The one rung that is always uppercase AND always small. Lime is NOT set
   here: every .t-overline in the six pages is already paired with .t-lime in
   the markup, and a section label on a lime band has to be able to go ink. */
.t-eyebrow,
.t-overline {
  font: var(--mgd-site-eyebrow);
  letter-spacing: var(--mgd-site-track-eyebrow);
  text-transform: uppercase;
}

.t-caption {
  font: var(--mgd-site-caption);
  color: var(--mgd-site-text-quiet);
  max-width: var(--mgd-site-measure-lead);
}

/* Frozen-markup rung: the legal pages label small blocks with .t-label. It
   maps to the app's shared label ramp, which is the same 13px/600 the product
   uses, so a label on the site and a label in the app match. */
.t-label {
  font: var(--mgd-type-label);
  max-width: var(--mgd-site-measure-heading);
}

/* ── Colour utilities ─────────────────────────────────────────────── */
/* Four rungs and no more. Any fifth "slightly dimmer grey" is a decision that
   belongs in the palette, not in a utility class.

   .t-faint takes the site's quiet token rather than the mirrored tertiary
   grey: it is applied to 13px captions, and 4.24 : 1 is not enough for text
   at that size. The reasoning, with the measured ratios, is in tokens.css. */
.t-ink { color: var(--mgd-color-text); }
.t-dim { color: var(--mgd-color-text-secondary); }
.t-faint { color: var(--mgd-site-text-quiet); }
.t-lime { color: var(--mgd-color-primary); }

/* ── Inline elements ──────────────────────────────────────────────── */
a {
  color: inherit;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color var(--mgd-site-dur-fast) var(--mgd-site-ease),
    text-decoration-color var(--mgd-site-dur-fast) var(--mgd-site-ease);
}

a:hover {
  color: var(--mgd-color-primary);
  text-decoration-color: currentColor;
}

strong,
b {
  font-weight: 700;
  color: var(--mgd-color-text);
}

/* The hairline is one of only three sources of depth on this site. It is a
   border, never a shadow, and it is always exactly 1px. */
hr {
  height: var(--mgd-layout-hairline);
  margin: 0;
  border: 0;
  background: var(--mgd-color-divider);
}

/* ══ Layout primitives ═════════════════════════════════════════════════
   Four things: a horizontal shell, a vertical section rhythm, a grid and a
   stack. Every page is built out of these, and none of them fills, rounds or
   shadows anything — the editorial look comes from the space they leave.
   ====================================================================== */

.shell {
  width: 100%;
  max-width: var(--mgd-site-page-max);
  margin-inline: auto;
  padding-inline: var(--mgd-site-gutter);
}

.shell--narrow {
  max-width: 860px;
}

/* Two vertical scales live in tokens.css. .section uses the quieter one; a
   full-bleed band asks for --mgd-site-band-y itself, in site.css. */
.section {
  padding-block: var(--mgd-site-section-y);
}

.section--tight {
  padding-block: calc(var(--mgd-site-section-y) * 0.58);
}

/* A hairline above the section, inset to the shell by the section's own
   padding — the rule reads as a chapter break, not as a box edge. */
.section--ruled {
  border-top: var(--mgd-layout-hairline) solid var(--mgd-color-divider);
}

/* One step up the surface ramp. Not a card, not a panel: a whole-width change
   of ground, which is the only way V2 is allowed to group at scale.

   THE HAIRLINES ARE A UI-PASS CORRECTION, and the reason is that the step on
   its own was a step nobody could see. --mgd-color-bg-alt is #0D110F against a
   #080B0A page: about two points of lightness, which survives a designer's
   monitor and disappears on a phone at half brightness in daylight — so the
   one device the site owns for grouping at scale was, in practice, doing
   nothing on the device most of the audience is holding. Rule 1 licenses three
   sources of depth and this now uses two of them together: the ramp step, plus
   a hairline at each edge to say where the ground changed.

   NOT --mgd-color-surface INSTEAD, which was the obvious alternative and is
   wrong. delete-account.html §ownership and the motion section of
   _reference/components.html both put .card elements inside a raised section,
   and a card IS --mgd-color-surface — raising the ground to that value would
   have erased five cards into their own background to make one boundary
   visible. The hairline costs nothing and takes nothing away. */
.section--raised {
  border-block: var(--mgd-layout-hairline) solid var(--mgd-color-border);
  background: var(--mgd-color-bg-alt);
}

/* ── Grid ─────────────────────────────────────────────────────────── */
/* auto-fit + minmax, so the columns collapse on their own and no width media
   query is needed anywhere on the site. */
.grid {
  display: grid;
  gap: var(--mgd-space-xl-2);
}

.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }

/* ── Stack ────────────────────────────────────────────────────────── */
.stack {
  display: grid;
  gap: var(--mgd-space-lg);
  align-content: start;
}

.stack--lg { gap: var(--mgd-space-xl-3); }

/* justify-items, not text-align alone: the type rungs carry a ch max-width,
   so a centred column has to centre the BOX as well as the text inside it. */
.stack--center {
  justify-items: center;
  text-align: center;
}

/* ── Utilities ────────────────────────────────────────────────────── */
.center {
  text-align: center;
  margin-inline: auto;
}

.hidden {
  display: none !important;
}

/* Visually gone, still announced. Used for the <h2> that gives a decorative
   band an accessible name. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ══ Prose ═════════════════════════════════════════════════════════════
   The four legal documents. Their WORDING is frozen — two of these URLs are
   what Google Play reads — so this block is the only place their appearance
   can change, and it styles by ELEMENT, never by adding a class to them.

   Nothing here is a poster. A privacy policy set in a condensed display face
   reads as marketing, which is the opposite of what a policy is for: h2 is the
   text face at heading size with a hairline above it, and the measure is a
   full 68ch because these are documents people actually read top to bottom.
   ====================================================================== */

.prose {
  max-width: var(--mgd-site-measure-prose);
  color: var(--mgd-color-text-secondary);
}

/* A hairline with an uppercase label under it is the same object .rule is,
   one rung larger and drawn by element rather than by class — which is the
   only device this block is allowed, since the wording is frozen and no class
   may be added to the markup. Three things changed in the UI pass and none of
   them touches the face: the label goes uppercase, so a section head is
   distinguishable from bold body at a glance rather than only by size; the
   tracking flips from the heading rung's −0.01em to the title rung's +0.01em,
   because negative tracking closes the counters of uppercase type and every
   other uppercase rung on this site is positive; and the line above steps
   from --mgd-color-divider to --mgd-color-border, because 1px of #1C221D on
   #080B0A is a rumour rather than a rule and this is the only separator a
   twelve-section document has. Still the text face at heading size: a policy
   set in Anton reads as marketing, which is what the note above forbids. */
.prose h2 {
  margin-top: var(--mgd-space-xl-5);
  padding-top: var(--mgd-space-xl-2);
  border-top: var(--mgd-layout-hairline) solid var(--mgd-color-border);
  font: var(--mgd-site-heading);
  letter-spacing: var(--mgd-site-track-title);
  text-transform: uppercase;
  color: var(--mgd-color-text);
  text-wrap: balance;
}

.prose h3 {
  margin-top: var(--mgd-space-xl-3);
  font: var(--mgd-type-subheading);
  color: var(--mgd-color-text);
}

/* THE THREE VERTICAL GAPS HAVE TO BE ORDERED, and before the UI pass they
   were not. Body is 16px at 1.60, so two wrapped lines inside one paragraph
   sit about 9.6px of white apart. A paragraph break was 12px and a list-item
   break was 8px — which made an item boundary TIGHTER than a line break
   inside an item, so a four-item list read as one block of text with stray
   bullets in it. Now: paragraph 16px, item 12px, line 9.6px. Each boundary is
   larger than the one it contains, which is the whole requirement. */
.prose p,
.prose li {
  font: var(--mgd-site-body);
  margin-top: var(--mgd-space-lg);
}

.prose ul,
.prose ol {
  margin-top: var(--mgd-space-lg);
  padding-left: var(--mgd-space-xl-2);
}

.prose li + li {
  margin-top: var(--mgd-space-md);
}

/* An <ol> marker in the legal documents is a numeral the reader may need to
   cite, so it takes the quiet text token rather than the tertiary grey. */
.prose li::marker {
  color: var(--mgd-site-text-quiet);
}

/* First paragraph of a document sets its own top edge — and its own size.
   All three legal pages open their .prose with a standfirst: one paragraph
   that says what the document covers before the first hairline. It was
   setting at body size in secondary grey, identical to the fortieth paragraph
   further down, so a reader arriving from the Play listing had nothing to
   read first. The lead rung and full text colour make it an entry point,
   which is what it already was in the copy. Reaches nothing else: a .prose
   whose first child is an h2 — both reference tools — matches no part of
   this. */
.prose > p:first-child {
  margin-top: 0;
  font: var(--mgd-site-lead);
  color: var(--mgd-color-text);
  max-width: var(--mgd-site-measure-lead);
}

/* A document that opens on a heading sets its own top edge too — no hairline
   with nothing above it. */
.prose > h2:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* ══ Scroll reveal ═════════════════════════════════════════════════════
   One of V2's three motion primitives: a 24px rise and a fade as a block
   enters, staggered --mgd-site-stagger between siblings. Nothing loops,
   nothing floats, nothing pulses.

   THE NO-JAVASCRIPT CONTRACT. The hidden state is scoped to `.js-reveal`,
   which site.js puts on <html> as its first act. With scripts blocked, off,
   or still loading, that class never appears and every [data-reveal] block is
   simply visible — which is why a Play reviewer with JavaScript disabled can
   still read all four legal documents.

   NO will-change, DELIBERATELY. An earlier revision hinted
   `will-change: opacity, transform` here and then cleared it from a `.is-done`
   class that site.js added on transitionend. That is three moving parts
   (a hint, a class, a listener) to promote a layer the compositor already
   promotes for the duration of a transform/opacity transition — and because
   reveals fire at unpredictable scroll positions, the hint sat on some forty
   below-the-fold blocks from first paint to first scroll. Phase 7 deleted all
   three. If a future revision needs the hint back, add it on :hover or on a
   parent's .is-in — never unconditionally on the hidden state.
   ====================================================================== */

.js-reveal [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition: opacity var(--mgd-site-dur-slow) var(--mgd-site-ease),
    transform var(--mgd-site-dur-slow) var(--mgd-site-ease);
  transition-delay: var(--reveal-delay, 0ms);
}

.js-reveal [data-reveal].is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* site.js sets --i on each child; the interval is a token so reduced motion
   collapses it with everything else, and the multiplication stays a CSS
   decision rather than a JavaScript one. */
[data-reveal-stagger] > * {
  --reveal-delay: calc(var(--i, 0) * var(--mgd-site-stagger));
}

/* Reduce Motion removes the movement, not the content. tokens.css already
   collapses every duration to 1ms; this additionally kills the 24px offset and
   the stagger, so a reduced-motion visitor sees the finished page rather than
   a very fast version of the animation. */
@media (prefers-reduced-motion: reduce) {
  .js-reveal [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  [data-reveal-stagger] > * {
    --reveal-delay: 0ms;
  }
}

/* ── Print ────────────────────────────────────────────────────────── */
/* People print policies. Ink on paper, hairlines kept, chrome dropped. */
@media print {
  html,
  body {
    background: #FFFFFF;
    color: #000000;
  }

  .skip-link {
    display: none;
  }

  .prose {
    max-width: none;
    color: #000000;
  }

  /* The standfirst is the one paragraph that carries its own colour rather
     than inheriting .prose's, so the reset above misses it and it would print
     as warm white on white paper — invisible, on the first line of a document
     someone printed on purpose. Named explicitly for that reason. */
  .prose h2,
  .prose h3,
  .prose > p:first-child {
    color: #000000;
  }

  /* Scoped to prose: a printed policy needs its URLs spelled out, a printed
     nav does not. Keeping this off bare `a` also means site.css can own the
     chrome's print behaviour without the two rules fighting. */
  .prose a::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    word-break: break-all;
  }
}
