@font-face{font-family:'Newsreader';src:url(data:font/woff2;base64,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) format('woff2-variations');font-weight:400 600;font-style:normal;font-display:optional}/* ---------------------------------------------------------------------------
   DIRECTION, and design-guardrails.md requires it to live here so the next
   build inherits it instead of re-deciding it:

     The yardage book opened flat. Warm paper held wide, one film framed like a
     plate, and long empty margins so a single line of Newsreader can carry a
     whole screen.

   Axis check against the last three clients, which that file also requires:

     Tasty Gains       Archivo Black grotesk   bright ground   controlled density
     Meridian Roofing  Archivo 600 grotesk     dark industrial controlled density
     River Ridge tour  Newsreader serif        warm paper      controlled density
     THIS SURFACE      Newsreader serif        warm paper      GENEROUS SPACE

   DENSITY is the moved axis and it is the only one available: Contract 5 freezes
   the palette and the display face, and this page sits beside the tour surface
   inside the same document tree. One idea per screen, held.

   MOTION: Tier 2 (GSAP + ScrollTrigger + Lenis), inlined, a club website; the tour it embeds stays Tier 1
   ------------------------------------------------------------------------ */
:root{
  /* colour -- every value resolved from brand.md by brandkit.py. Zero hex
     literals below this block, which is what makes the reskin one file. */
  --hs-primary:#14311C; --hs-accent:#2E7D32; --hs-accent-type:#2B762F;
  --hs-accent-on:#F7F4ED; --hs-primary-on:#F7F4ED;
  --hs-paper:#F7F4ED; --hs-paper-alt:#EBE9E2; --hs-pine:#14311C;
  --hs-line:#D3D5CC; --hs-line-strong:#AAB2A6;
  --hs-ink:#191B16; --hs-ink-muted:#5D5F58;
  --hs-ink-on-pine:#E9E8E0; --hs-ink-muted-on-pine:#AAB2A6;
  --hs-accent-on-pine:#A5C4A1;

  /* depth -- three steps, tinted with the brand's own ink. Never black, never
     a flat shadow-md. */
  --hs-sh-1:0 1px 2px rgba(20,49,28,.06), 0 2px 6px rgba(20,49,28,.05);
  --hs-sh-2:0 2px 6px rgba(20,49,28,.07), 0 10px 24px rgba(20,49,28,.08);
  --hs-sh-3:0 4px 12px rgba(20,49,28,.09), 0 24px 60px rgba(20,49,28,.14);

  --hs-r-s:2px; --hs-r-m:4px; --hs-r-l:10px;

  /* type -- 1.333 from a 17px base. Every font-size on this page is a step. */
  --hs-f-display:'Newsreader', Georgia, 'Times New Roman', serif;
  --hs-f-body:system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --hs-t--2:.7503rem; --hs-t--1:.8752rem; --hs-t-0:1rem;
  --hs-t-1:1.333rem;  --hs-t-2:1.777rem;  --hs-t-3:2.369rem;
  --hs-t-4:3.157rem;  --hs-t-5:4.209rem;  --hs-t-6:5.61rem;
  --hs-t-7:7.478rem;

  /* space -- 4px scale, and the section rhythm is generous on purpose */
  --hs-s-1:.25rem; --hs-s-2:.5rem;  --hs-s-3:.75rem; --hs-s-4:1rem;
  --hs-s-5:1.5rem; --hs-s-6:2rem;   --hs-s-7:3rem;   --hs-s-8:4.5rem;
  --hs-s-9:7rem;   --hs-s-10:10rem;

  --hs-wide:78rem; --hs-mid:60rem; --hs-measure:46ch;
  --hs-gutter:clamp(1.25rem, 5vw, 4.5rem);
  --hs-band:clamp(4rem, 9vw, 8rem);

  /* THE DISTANCE FROM `.hs-s__in`'s CONTENT EDGE TO THE VIEWPORT EDGE, which is
     the one number every grid-break needs and the one nothing could name.
     `.hs-sig__caption` computed it inline as
       max(--hs-gutter, calc((100vw - --hs-wide)/2 + --hs-gutter))
     and the `max()` was guarding the case where the viewport is NARROWER than
     --hs-wide, where the first term goes negative. `min(100vw, --hs-wide)` makes
     that term exactly 0 instead, so the guard is structural rather than a clamp
     bolted on afterwards -- and the expression is then reusable, which is what
     lets the split plate bleed with the SAME arithmetic the caption already
     used rather than a second one that agrees with it by coincidence.

     It lives here rather than in site.css because it is derived purely from
     --hs-wide and --hs-gutter, both of which are emitted here, and a geometric
     token computed one file downstream of its inputs is a token that silently
     stops matching them. Same argument as --hs-t-7. */
  --hs-edge:calc((100vw - min(100vw, var(--hs-wide))) / 2 + var(--hs-gutter));

  /* THE ZONE VARIABLES, DEFAULTED HERE AND NOWHERE ELSE.
     Every section re-declares these for its own ground. The chrome -- header,
     sticky bar, skip link -- sits OUTSIDE every section, so without a default
     it asks for a custom property that does not exist, and AN UNDEFINED CUSTOM
     PROPERTY INVALIDATES THE WHOLE DECLARATION rather than falling back. That
     is how the dashed border on an unresolved placeholder renders as no border
     at all, which is exactly the failure the placeholder exists to prevent.
     Measured on the index build before this line existed. */
  --bg:var(--hs-paper); --fg:var(--hs-ink); --fg-muted:var(--hs-ink-muted);
  --rule:var(--hs-line); --sig:var(--hs-accent-type);

  /* WCAG 2.5.5, width AND height, and the smaller of the two platform minimums.
     --hs-tap-nav is larger because the header is the densest row on the page.
     This surface deliberately does NOT scale its header, so 50px is 50px at
     every scroll position -- the tour surface scales its own to .88 and
     measured a 44px link coming back as a 38.7px hit box. */
  --hs-tap:44px; --hs-tap-nav:50px;
  --hs-sticky-h:60px;
  /* The header is fixed and its height is a token, because the hero is sized as
     `100svh minus this`. A header that changes height would make that number a
     lie, which is the other half of the note on .hs-header. */
  --hs-header-h:60px;
}
/* ===========================================================================
   site.css -- the Tier 2 club-site surface.

   Tokens are emitted ABOVE this file by build_site.py::render_tokens, resolved
   from brand.md through brandkit.py. There is not one hex literal below this
   line and that is what makes a reskin a one-file change. Contract 5 rule 2.

   THREE THINGS IN HERE ARE LOAD-BEARING AND EASY TO UNDO BY TIDYING:

   1. NOTHING RESTS AT opacity:0 ANYWHERE IN THIS FILE. Every entry state is set
      by site.js, and only after it has confirmed motion is wanted. A page whose
      reveals live in CSS is a page that is blank when the script fails, and
      `image-clip-reveal` on the tour surface already taught this repo that an
      element resting invisible can report as fully visible to every probe. If
      JS never runs here, the page is simply the page.

   2. EVERY SECTION PAINTS ITS OWN GROUND, and its foreground colours come from
      --fg / --fg-muted, re-declared per zone. Components never name an ink.
      The Meridian showpiece shipped a form title painting white on white for
      four revision passes because one `.hero p` rule reached into a light card
      inside a dark hero and beat the card's own colour. Zone-scoped variables
      are that bug's fix, not a preference.

   3. THE RAIL IS WIDER THAN THE VIEWPORT ON PURPOSE and lives inside its own
      overflow:hidden box. Deliberate clipped overflow is a technique; a box
      that has outgrown its column is a bug. The gate distinguishes them by
      walking ancestors, so do not "fix" the rail by making it fit.
   ======================================================================== */

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0}
img,video,iframe{max-width:100%}
img,video{height:auto;display:block}

/* The whole of lenis.css, written out rather than fetched -- an external
   stylesheet for 4 declarations is the CDN dependency this system exists to
   avoid.

   DORMANT SINCE 2026-09-03 (club-site-10k directive A2). Lenis is no longer
   constructed on any path, so nothing adds `.lenis` to the document and not one
   of these four selectors matches. They are kept rather than deleted for the
   same reason site.js keeps its `lenis` branch: re-arming smoothing should be
   one line in one file, not an archaeology exercise. The measurement that
   turned it off -- 826 ms of glide against the four references' 20-30 ms -- is
   in site.js's lenis block. */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}

/* Anchors must not land under the fixed header. */
[id]{scroll-margin-top:calc(var(--hs-header-h) + var(--hs-s-5))}

body{
  /* The header is FIXED, not sticky, and this is what pays for it. Fixed is
     what makes `100svh minus the header` a number the hero can be sized in --
     a sticky header is in flow, so the hero would have to know a height nobody
     can compute in CSS. See .hs-header. */
  padding-top:var(--hs-header-h);
  background:var(--hs-paper);
  color:var(--hs-ink);
  font-family:var(--hs-f-body);
  font-size:1.0625rem;
  line-height:1.62;
  /* the mobile CTA bar is fixed; without this it covers the last section */
  padding-bottom:calc(var(--hs-sticky-h) + env(safe-area-inset-bottom,0px));
  /* clip, not hidden: the rail translates X and must never widen the document */
  overflow-x:clip;
}
@media (min-width:56rem){
  body{padding-bottom:0}
  :root{--hs-header-h:72px}
}

/* --------------------------------------------------------------------- zones
   Ground first, then the two inks that land on it, then the rule colour. A
   component that wants "the muted ink" asks for var(--fg-muted) and gets the
   right one in all three zones. */
.hs-z--paper    { --bg:var(--hs-paper);     --fg:var(--hs-ink);         --fg-muted:var(--hs-ink-muted);         --rule:var(--hs-line);        --sig:var(--hs-accent-type) }
.hs-z--paper-alt{ --bg:var(--hs-paper-alt); --fg:var(--hs-ink);         --fg-muted:var(--hs-ink-muted);         --rule:var(--hs-line-strong); --sig:var(--hs-accent-type) }
.hs-z--pine     { --bg:var(--hs-pine);      --fg:var(--hs-ink-on-pine); --fg-muted:var(--hs-ink-muted-on-pine); --rule:var(--hs-accent-on-pine); --sig:var(--hs-accent-on-pine) }

.hs-s{background:var(--bg);color:var(--fg);position:relative}

/* Grain. One SVG turbulence, ~250 bytes, layered under nothing and over
   nothing -- it sits on the section's own ground so a flat fill reads as paper
   rather than as a colour swatch. guardrails: texture where it earns it. */
.hs-z--paper::before,.hs-z--paper-alt::before,.hs-z--pine::before{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.5;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.055'/%3E%3C/svg%3E");
  mix-blend-mode:multiply;
}
.hs-z--pine::before{mix-blend-mode:screen;opacity:.35}

/* ------------------------------------------------------------- the material
   Layered radial light on the ground, per design-guardrails: several radial
   rather than one linear. `::before` is spent on grain, `::after` was free.

   ONE RULE GOVERNS EVERY WASH ON THIS PAGE AND IT IS NOT A STYLE RULE:

     A WASH MAY ONLY MOVE A GROUND AWAY FROM ITS OWN INK.

   contrast_gate.mjs walks ANCESTORS for a ground, and a ::after is not an
   ancestor of anything -- it is not in the tree at all. So a wash is INVISIBLE
   to the gate by construction, and every ratio the audit reports is computed
   against the flat fill underneath it. That is the same blind spot as text on
   a background-image, arriving by a different door, and the amplitude rule is
   the only thing standing in it: move the ground AWAY from its ink and the
   audit's number becomes a conservative floor. Move it toward, and the audit
   passes a page nobody measured.

   The arithmetic, because "keep it subtle" is not a bound. The tightest
   measured element on this surface is `p.hs-eyebrow` at 4.63:1 against a 4.50
   bar -- 0.13 of headroom. Darkening a light ground by even 3% of the way to
   the ink takes that element to ~4.34:1 and the page fails for real while every
   gate stays green. There is no safe amount of "a bit darker" here.

   WHICH GROUNDS GET ONE, AND WHY THE OTHER TWO DO NOT:

   paper-alt   YES. `brandkit` derives it as mix(surface, primary, .055), so
               --hs-paper is provably lighter than this ground for every brand,
               not just this one. Washing toward paper therefore LIGHTENS a
               light ground -- away from its dark ink -- and every ratio on it
               goes up. It is also the ground brandkit itself flags as tightest:
               it darkens ink_muted specifically to clear AA here. The one that
               most needed the help is the one where help is provably safe.

   paper       NO. Lightening it needs a token lighter than --hs-paper and the
               set contains none. --hs-primary-on is near-white for THIS brand
               and would be near-black for a brand with a light primary, so a
               wash built on it would silently invert direction on a reskin.
               A rule that holds for one brand is not a rule in a file whose
               whole claim is that a reskin is one file.

   pine        NO, AND THE TOKEN SET IS WHY. Darkening it needs a token darker
               than the pine ground. `brandkit` sets deep = primary and
               shadow_rgb = primary, so --hs-pine, --hs-primary and the shadow
               colour are THE SAME VALUE. There is nothing darker to reach for.
               Mixing toward --hs-ink happens to work on River Ridge, whose ink
               measures a shade darker than its pine, and that is a coincidence
               of one brand's values rather than a derivation. Nothing in
               brandkit orders those two.

   So one ground of three carries a wash and the other two get their material
   from edge, depth and composition instead. That reads as three grounds with
   three characters rather than three tints of one idea, which is the better
   answer anyway -- but it is not why it was done.

   No colour is written out anywhere above, deliberately. There is not one hex
   literal in this file and `grep -c "#[0-9a-fA-F]" site.css` staying at 0 is how
   anyone confirms that in a second, so even a comment quoting a value to make a
   point costs more than the point is worth. */
.hs-z--paper-alt::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(120% 86% at 14% 0%,
      color-mix(in srgb, var(--hs-paper) 64%, transparent), transparent 58%),
    radial-gradient(96% 72% at 86% 100%,
      color-mix(in srgb, var(--hs-paper) 30%, transparent), transparent 64%);
}

.hs-s__in{
  position:relative;z-index:1;
  max-width:var(--hs-wide);margin-inline:auto;
  padding:var(--hs-band) var(--hs-gutter);
}

/* ----------------------------------------------------------------- typography
   Size, weight and colour are the hierarchy. Nothing here is a card. */
/* The ceiling is --hs-t-4, not --hs-t-3. At 16px root the old cap resolved to
   37.9px against design-guardrails' 3rem/48px floor for a section heading -- 21%
   short, and it is the single measurement behind "the page reads flat".
   The vw term moves with it so the curve still reaches the cap before 1440;
   the 1.9rem minimum does not move, because that is what protects 375. */
.hs-h{
  font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(1.9rem,5.4vw,var(--hs-t-4));
  line-height:1.06;letter-spacing:-.023em;text-wrap:balance;
  margin:0 0 var(--hs-s-5);color:var(--fg);
}
/* --hs-t-7 exists so this line can reach the guardrail's 6rem without a
   hardcoded value. The old cap was --hs-t-6 = 89.8px, and the clamp was
   truncating a vw term that already wanted 121px at 1440 -- so the hero was
   being held small by its token rather than by its viewport. */
.hs-h--display{font-size:clamp(2.55rem,9.2vw,var(--hs-t-7));line-height:.94;letter-spacing:-.034em}
/* A LONGER HEADLINE IS SET SMALLER, so the hero still fits its one viewport.
   Not a workaround for the clamp above: three lines at the two-line size is not
   restraint, and it measured bottom=967 against a 900px viewport on the page
   whose title runs to three. The builder stamps data-lines from the same `|`
   split that produced the lines, so this cannot drift out of step with the
   markup. */
.hs-h--display[data-lines="3"]{font-size:clamp(2.3rem,7vw,var(--hs-t-6))}
.hs-h--display[data-lines="4"]{font-size:clamp(2.1rem,5.6vw,var(--hs-t-5))}
.hs-h--lede   {font-size:clamp(2.1rem,5.8vw,var(--hs-t-5));line-height:1.02;letter-spacing:-.027em;max-width:19ch}

/* ------------------------------------------------- the heading hierarchy
   THE MEASURED PROBLEM: eight type steps are emitted and FOUR rendered. 51px
   carried 32 of the 45 headings on the six-page site; 120px appeared once. A
   page where every heading is the same size has no hierarchy, and "reads flat"
   is what that looks like from outside.

   `house-style.md` diagnosed this and named the fix -- "If the page still reads
   flat, the diagnosis is NOT a twelfth effect. Check composition and type scale
   first" -- and then nothing consumed it. This is the consumption.

   IT ONLY GOES UP, AND THE FIRST ATTEMPT HERE WAS WRONG.
   A quieter `sub` level was written, measured, and removed. `design-guardrails`
   floors a section heading at 3rem/48px and the default is 50.5px: three pixels
   of room. A `sub` at --hs-t-3 renders 37.9px -- the exact figure
   `track-b-surface.md` calls "the single measurement behind the page reads
   flat", and the one B2 raised the default off a session earlier. It would have
   re-introduced the defect the type scale exists to fix, on the sections least
   able to argue for an exception.

   So there are two louder levels and no quieter one:

     statement   --hs-t-6, ~90px. ONE per page, refused at two by compose_page
     lead        --hs-t-5, ~67px. A section that opens a movement
     (default)   --hs-t-4, 50.5px, unchanged -- every existing manifest is
                 byte-identical until it opts in

   EVERY SIZE IS A STEP. Nothing here is a hardcoded px value, which is what
   keeps "every font-size on this page is a step" true and a reskin a one-file
   change. The vw terms move WITH the caps: a clamp whose middle term was tuned
   for a 3.157rem ceiling reaches it early and then flattens, so a bigger cap
   carrying the old vw term is a bigger number that almost never renders. */
.hs-s[data-level="statement"] .hs-h{
  font-size:clamp(2.3rem,7.6vw,var(--hs-t-6));
  line-height:.99;letter-spacing:-.03em;
}
.hs-s[data-level="statement"] .hs-h[data-lines="3"]{font-size:clamp(2.1rem,6.1vw,var(--hs-t-5))}
.hs-s[data-level="statement"] .hs-h[data-lines="4"]{font-size:clamp(2rem,5.4vw,var(--hs-t-4))}
.hs-s[data-level="lead"] .hs-h{
  font-size:clamp(2.1rem,6.2vw,var(--hs-t-5));
  line-height:1.02;letter-spacing:-.026em;
}
.hs-s[data-level="lead"] .hs-h[data-lines="4"]{font-size:clamp(2rem,5.4vw,var(--hs-t-4))}
.hs-h--sig    {font-size:clamp(1.75rem,4vw,var(--hs-t-3));max-width:16ch}
.hs-h--deep   {font-size:clamp(2rem,5.2vw,var(--hs-t-4));line-height:1.04;letter-spacing:-.025em;max-width:22ch;margin-inline:auto}

/* THE EYEBROW CARRIES A RULE TO THE EDGE OF ITS COLUMN, 2026-09-02. Measured
   on the six-page site: nearly every section opens eyebrow-then-heading against
   the left gutter with 40-55% of the row standing empty to the right -- the
   same dead top-right corner on screen after screen, which is the mechanical
   tempo the eye reads as template. A printed yardage book rules its lines to
   the trim; this is that, in the ground's own hairline colour, and it turns
   the empty width into structure at zero contrast cost -- the ::after holds no
   text, so the audit has nothing new to resolve. Centred sections opt out
   below: a rule running one way out of a centred line is an arrow, not a rule. */
.hs-eyebrow{
  font-size:var(--hs-t--2);font-weight:600;line-height:1.2;
  text-transform:uppercase;letter-spacing:.19em;
  color:var(--sig);margin:0 0 var(--hs-s-5);
  display:flex;align-items:center;gap:var(--hs-s-5);
}
.hs-eyebrow::after{content:"";flex:1;min-width:var(--hs-s-6);height:1px;background:var(--rule)}
.hs-s--deep-statement .hs-eyebrow,.hs-s--final-cta .hs-eyebrow{justify-content:center}
.hs-s--deep-statement .hs-eyebrow::after,.hs-s--final-cta .hs-eyebrow::after{display:none}
.hs-body{max-width:var(--hs-measure);color:var(--fg-muted);margin:0 0 var(--hs-s-4)}
.hs-body:last-child{margin-bottom:0}

/* The one line-level entry effect. The wrapper clips, the inner span moves.
   Both rest at their finished position; site.js is what displaces them. */
.hs-rise{display:block;overflow:hidden;padding-bottom:.06em;margin-bottom:-.06em}
.hs-rise__i{display:block;will-change:transform}

/* ------------------------------------------------------------------- links */
/* THE UNDERLINE IS A PSEUDO-ELEMENT, NOT A BACKGROUND IMAGE, and the contrast
   gate is why. A `linear-gradient(currentColor,currentColor)` underline is a
   background IMAGE on the element holding the text, so the audit walks up, hits
   an image, and reports the link UNRESOLVED -- every link on the page, the one
   in the split section and both in the footer included. An element nobody can
   measure is an element nobody is checking. */
.hs-link{
  position:relative;color:var(--sig);text-decoration:none;font-weight:500;
  padding-bottom:1px;transition:color .2s;
}
.hs-link::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:currentColor;transform-origin:left center;
  transition:transform .32s cubic-bezier(.2,.8,.2,1);
}
.hs-link:hover::after{transform:scaleX(0);transform-origin:right center}

a,button,summary{color:inherit}
:focus-visible{
  outline:2px solid var(--sig);outline-offset:3px;border-radius:var(--hs-r-s);
}
/* The outline colour is re-declared per zone by --sig above, which is the
   quality-bar line about an outline that has contrast on EVERY ground the page
   uses. The adult Tasty Gains page does this by hand, per section. */

.hs-skip{
  position:fixed;left:-9999px;top:0;z-index:60;
  background:var(--hs-pine);color:var(--hs-ink-on-pine);
  padding:var(--hs-s-3) var(--hs-s-5);border-radius:0 0 var(--hs-r-m) 0;
}
.hs-skip:focus{left:0}
#main:focus{outline:none}

/* ------------------------------------------------------------------ header */
.hs-header{
  position:fixed;top:0;left:0;right:0;z-index:40;
  height:var(--hs-header-h);
  display:flex;align-items:center;gap:var(--hs-s-5);
  padding:0 var(--hs-gutter);
  background:color-mix(in srgb, var(--hs-paper) 88%, transparent);
  -webkit-backdrop-filter:saturate(1.4) blur(14px);
  backdrop-filter:saturate(1.4) blur(14px);
  border-bottom:1px solid var(--hs-line);
  /* NOTHING HERE CHANGES HEIGHT ON SCROLL. This element is sticky and in flow,
     so a padding change on it shifts every section below and cold CLS stops
     being 0. A transform scale is the other tempting version and it is worse:
     the tour surface measured a 44px link inside a header scaled to .88 and
     got a 38.7px hit box, because getBoundingClientRect and hit testing both
     return the transformed box. Depth only. */
  transition:box-shadow .3s,background-color .3s;
}
.hs-header[data-shrunk]{
  box-shadow:var(--hs-sh-1);
  background:color-mix(in srgb, var(--hs-paper) 97%, transparent);
}
.hs-wordmark{
  display:flex;flex-direction:column;text-decoration:none;
  min-height:var(--hs-tap-nav);justify-content:center;margin-right:auto;
  min-width:0;
}
.hs-wordmark__n{
  font-family:var(--hs-f-display);font-weight:600;
  font-size:var(--hs-t-0);letter-spacing:.01em;color:var(--hs-ink);line-height:1.1;
}
.hs-wordmark__l{
  font-size:var(--hs-t--2);letter-spacing:.15em;text-transform:uppercase;
  color:var(--hs-ink-muted);line-height:1.4;
}
/* Below 34rem the header has one job and the strapline is not it. Dropping the
   second line is what keeps the wordmark inside a fixed 60px bar at 375
   without shrinking the name to something nobody can read. */
@media (max-width:33.999rem){
  /* Two lines maximum, clipped rather than allowed to push the bar open. The
     header height is a token the hero is sized against, so a wordmark that
     grows the bar makes `100svh minus the header` wrong for the whole page. */
  .hs-wordmark__n{
    font-size:var(--hs-t--1);line-height:1.15;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  .hs-wordmark__l{display:none}
  .hs-nav__cta{font-size:var(--hs-t--2);padding-inline:var(--hs-s-4);min-height:40px}
}
.hs-nav{display:none}
.hs-nav__u{display:flex;gap:var(--hs-s-5);list-style:none;margin:0;padding:0}
.hs-nav__l{
  display:inline-flex;align-items:center;min-height:var(--hs-tap-nav);
  text-decoration:none;font-size:var(--hs-t--1);letter-spacing:.03em;
  color:var(--hs-ink-muted);transition:color .2s;
}
.hs-nav__l:hover{color:var(--hs-ink)}
.hs-nav__cta{
  display:inline-flex;align-items:center;white-space:nowrap;
  min-height:var(--hs-tap-nav);padding-inline:var(--hs-s-5);
  background:var(--hs-primary);color:var(--hs-primary-on);
  font-size:var(--hs-t--1);font-weight:600;letter-spacing:.04em;
  text-decoration:none;border-radius:var(--hs-r-m);
  box-shadow:var(--hs-sh-1);
  transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .22s;
}
.hs-nav__cta:hover{transform:translateY(-2px);box-shadow:var(--hs-sh-2)}
.hs-nav__cta:active{transform:translateY(0)}
@media (min-width:56rem){ .hs-nav{display:block} }

/* THE CURRENT PAGE IS MARKED VISIBLY, NOT ONLY SEMANTICALLY -- criterion 22,
   appended cycle 2. `aria-current="page"` was in the markup from the first
   multi-page build and no rule ever painted it; a location cue only a screen
   reader gets is half a cue. Full ink plus an accent rule; the underline sits
   inside the tap box so the target geometry is untouched. */
.hs-nav__l[aria-current="page"]{
  color:var(--hs-ink);
  text-decoration:underline;text-underline-offset:.55em;
  text-decoration-thickness:2px;text-decoration-color:var(--hs-accent-type);
}

/* THE PHONE RIDES THE HEADER -- criterion 21, appended cycle 2. All four
   references put the number in the bar itself (Streamsong, Pinehurst and
   Bandon pair it with the book action). It arrives as a chrome.nav item with a
   tel: href, so it costs the builder nothing; this rule is what stops it
   reading as a sixth page link: full ink against the links' muted, and
   tabular figures so it reads as a number, not a word. */
.hs-nav__l[href^="tel:"]{
  color:var(--hs-ink);font-weight:600;font-variant-numeric:tabular-nums;
}
/* Between the drawer breakpoint and 64rem the bar has no room for six links
   plus a number plus the pill; the phone yields (it keeps the footer on every
   page, and the drawer below 56rem). The refs collapse the same way. */
@media (min-width:56rem) and (max-width:63.999rem){
  .hs-nav__u li:has(> .hs-nav__l[href^="tel:"]){display:none}
}

/* BELOW THE BREAKPOINT THE HEADER CTA IS REDUNDANT AND IT GOES.
   The sticky bar already carries the same decision, full width, pinned to the
   bottom of the viewport and visible at first paint -- Aman's mobile pattern,
   and the third sighting of it in the swipe library. Keeping both crammed the
   bar so hard that the wordmark wrapped to three lines at 375, and it competes
   with itself for the one decision the page offers.

   The room it frees is the room the Menu toggle needs. */
@media (max-width:55.999rem){
  .hs-nav__cta{display:none}
  .hs-header{padding-right:6.75rem}
}

/* ------------------------------------------------------------ mobile drawer
   Rendered as a sibling of the header, not a child -- .hs-header carries
   backdrop-filter, which makes it a containing block for fixed descendants, so
   a panel inside it is trapped in a 60px bar. */
.hs-drawer{position:fixed;top:0;right:0;z-index:41}
.hs-burger{
  display:inline-flex;align-items:center;gap:.6em;cursor:pointer;list-style:none;
  height:var(--hs-header-h);padding-inline:var(--hs-gutter) ;
  font-size:var(--hs-t--2);font-weight:600;letter-spacing:.15em;
  text-transform:uppercase;color:var(--hs-ink);
}
.hs-burger::-webkit-details-marker{display:none}
.hs-burger__b{display:block;width:20px}
.hs-burger__b i{
  display:block;height:1.5px;background:currentColor;border-radius:1px;
  transition:transform .3s cubic-bezier(.2,.8,.2,1);
}
.hs-burger__b i + i{margin-top:5px}
.hs-drawer[open] .hs-burger__b i:first-child{transform:translateY(3.25px) rotate(45deg)}
.hs-drawer[open] .hs-burger__b i:last-child{transform:translateY(-3.25px) rotate(-45deg)}

/* A CLOSED <details> HIDES ITS CONTENTS BY SKIPPING PAINT, NOT BY REMOVING THE
   BOX -- and the panel is `position: fixed`, so it is out of flow and keeps a
   rect. Measured with the drawer closed: a nav link reported 69x93 while
   rendering as nothing at all.

   Invisible to a visitor and visible to every probe in tests/ is the wrong way
   round. The contrast audit, the stuck-entrance probe and the tap-target sweep
   were all being handed text nobody can see and told it was fine, and the
   "audit again with the panels open" pass measured exactly the same 76
   elements twice. One declaration makes the browser and the gates agree. */
.hs-drawer:not([open]) .hs-drawer__p{display:none}

.hs-drawer__p{
  position:fixed;inset:var(--hs-header-h) 0 0 0;
  background:var(--hs-paper);border-top:1px solid var(--hs-line);
  overflow-y:auto;overscroll-behavior:contain;
  padding:var(--hs-s-7) var(--hs-gutter)
          calc(var(--hs-sticky-h) + var(--hs-s-8) + env(safe-area-inset-bottom,0px));
  display:flex;flex-direction:column;gap:var(--hs-s-6);
}
.hs-drawer__u{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.hs-drawer__l{
  display:flex;align-items:center;min-height:calc(var(--hs-tap) + 12px);
  font-family:var(--hs-f-display);font-weight:500;font-size:var(--hs-t-2);
  letter-spacing:-.015em;color:var(--hs-ink);text-decoration:none;
  border-bottom:1px solid var(--hs-line);
}
.hs-drawer__cta{align-self:flex-start;margin-top:var(--hs-s-2)}

/* Criterion 22 in the drawer: the page you are on carries the accent rule.
   The indent appears only when the panel opens -- a user gesture, so the cold
   CLS gate never sees it move. */
.hs-drawer__l[aria-current="page"]{
  border-left:3px solid var(--hs-accent-type);padding-left:var(--hs-s-4);
}
/* The phone in the drawer is an action, not a destination: body face at body
   scale against the page links' display scale. Height comes from .hs-drawer__l
   and stays over the 44px gate. */
.hs-drawer__l[href^="tel:"]{
  font-family:var(--hs-f-body);font-size:var(--hs-t-0);font-weight:600;
  letter-spacing:.02em;font-variant-numeric:tabular-nums;
}
html[data-drawer-open]{overflow:hidden}

@media (min-width:56rem){ .hs-drawer{display:none} }

/* -------------------------------------------------------------------- hero
   Aman's frame: a wide margin above and a gutter both sides, so the film reads
   as a plate rather than as wallpaper. Singita's budget: the frame plus the
   copy occupy ONE viewport, so the first scroll lands on the first line of
   copy and not on nothing. */
/* SINGITA'S RULE, AND IT IS THE ONE MOST WORTH TAKING FROM THAT FOLDER.
   The film gets EXACTLY ONE VIEWPORT and not a pixel more, so the first scroll
   lands on the first line of copy rather than on nothing. Not 100vh plus a
   scroll hint, not 130vh: the hero plus the header equals the screen, and the
   next section's ground begins precisely at the fold.

   `svh` rather than `vh` because on a phone `100vh` is the viewport with the
   browser chrome RETRACTED, so a 100vh hero is taller than the screen the
   visitor is actually looking at and the first scroll lands on the bottom of
   the hero. `svh` is the smallest state, which is the one they see first. */
.hs-s--hero-film .hs-s__in{
  padding-top:var(--hs-s-6);padding-bottom:var(--hs-s-7);
  display:grid;gap:clamp(var(--hs-s-6),4vw,var(--hs-s-8));
  align-content:center;
  min-height:calc(100vh - var(--hs-header-h));
  min-height:calc(100svh - var(--hs-header-h));
}
.hs-hero__frame{
  position:relative;border-radius:var(--hs-r-l);overflow:hidden;
  box-shadow:var(--hs-sh-3);background:var(--hs-pine);
  will-change:transform;
}
.hs-hero__plate{position:relative;aspect-ratio:16/9}
.hs-hero__film{width:100%;height:100%;object-fit:cover;display:block}
/* A colour treatment layer so the render sits IN the brand world rather than
   on top of it. Not a scrim: no type is over it. */
.hs-hero__frame::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  /* Layered, not one linear -- guardrails. A vignette that pulls the corners
     toward pine, plus a top-and-bottom seat so the plate has edges rather than
     fading into the paper. No type sits on this, so it is a treatment and not
     a scrim, and the contrast gate has nothing to resolve here. */
  background:
    radial-gradient(130% 96% at 50% 34%, transparent 52%, color-mix(in srgb,var(--hs-pine) 30%, transparent) 100%),
    linear-gradient(180deg, color-mix(in srgb,var(--hs-pine) 24%, transparent) 0%, transparent 30%, color-mix(in srgb,var(--hs-pine) 30%, transparent) 100%);
  mix-blend-mode:multiply;
}
/* THE 34ch CAP WAS ON THE WRONG ELEMENT AND IT STRANGLED THE HEADLINE.
   `ch` resolves against the element's own font-size, so 34ch on the copy block
   is ~312px of BODY text -- and the h1 inside it is 41 to 120px. Measured, the
   title authored as two lines rendered as four at 375 and six at 768, purely
   because of this line. The standfirst carries its own 38ch measure two rules
   below, which is where a measure belongs: on the thing being read as prose. */
.hs-hero__head{max-width:none}
.hs-hero__copy{max-width:none}
.hs-hero__sub{
  margin:var(--hs-s-5) 0 0;color:var(--hs-ink-muted);
  font-size:var(--hs-t-1);line-height:1.44;max-width:38ch;
}
@media (min-width:56rem){
  /* The copy column is nearly half the width, not a third. Measured: at
     1.55fr/.85fr the display line broke "Every hole" across two lines, which
     is the headline losing an argument to its container. A serif set at 5.6rem
     needs the room or it needs to be smaller, and smaller is the wrong answer
     on the one screen that has to carry the page. */
  /* TWO ROWS. The head spans, the film and the standfirst share the row under
     it. The ratio is arithmetic rather than taste, at 1440:

       container after gutters      1104px
       display step --hs-t-7        119.6px, and it cannot go lower -- the
                                    guardrail floors a hero heading at 6rem/96px
                                    and the next step down, t-6, is 89.8px
       "River Ridge," at 120px      ~744px, so the head needs ~67% of the row
                                    and cannot share it with anything

     Giving the head its own row frees the whole width beneath it, so the film
     takes ~70% at its native 16:9 instead of 44%. That is about twice the area
     with no extra crop, inside the same one viewport. A wider letterbox would
     buy more area still and was rejected: 3.17:1 is the ratio that would fit a
     full-width film here, and it would cut the sky and the foreground out of an
     aerial frame to do it. */
  .hs-s--hero-film .hs-s__in{
    grid-template-columns:minmax(0,1.4fr) minmax(0,.6fr);
    /* THE FILM TAKES THE VIEWPORT THAT IS LEFT, and this is the fix for a real
       failure rather than a refinement.

       Stacking the head above the film makes their heights ADDITIVE where
       sharing a row let the taller of the two set the row. River Ridge's title
       is two lines and fit; the Hero Shots index title is THREE, and the hero
       measured bottom=923 against a 900px viewport -- 23px over, caught by the
       one-viewport gate.

       Tuning the column ratio until three lines happened to fit would have been
       a number that works for the two titles in this repo and breaks on the
       first client with a longer one. `minmax(0,1fr)` on the second row makes
       the film take exactly what the head did not, at any title length, by
       construction. `minmax(0,...)` rather than `1fr` because a bare 1fr floors
       at content height and would overflow again.

       It is also, literally, Singita's rule: the film gets exactly one viewport
       and not a pixel more. */
    grid-template-rows:auto minmax(0,1fr);
    /* A DEFINITE HEIGHT, NOT A MINIMUM, AND THE ROW ABOVE DOES NOT WORK
       WITHOUT IT. `minmax(0,1fr)` distributes AVAILABLE space, and with only a
       `min-height` the container is content-driven once content exceeds it --
       so `1fr` resolves to the content it was supposed to cap and the film
       never shrank. Measured: the index hero stayed 23px over with the fr row
       in place, film unchanged at 732x412.

       With a definite height the second row is exactly what the head left, so a
       two-line title and a three-line title both land on one viewport and the
       film absorbs the difference. Desktop only: below 56rem the hero is one
       column and content-driven, which measures clean at 375, 390 and 768.

       If a title were ever tall enough to consume the whole box the film goes
       to zero rather than the page overflowing -- the wrong-looking failure
       instead of the invisible one, and the gate still sees one viewport. */
    height:calc(100vh - var(--hs-header-h));
    height:calc(100svh - var(--hs-header-h));
    align-items:stretch;
    /* THE DISPLAY BLOCK'S VERTICAL SPEND IS TIGHTENED, 2026-09-02 (club-site-10k
       criterion 1, directive A1). The definite-height grid above already caps
       the hero at one viewport; what it does NOT decide is how the 828px inside
       it are split between type-and-air and film. Measured before this change at
       1440x900: head 287px, dead spend 144px (padding-top 32 + eyebrow margin 24
       + h1 margin 24 + row-gap 32 + padding-bottom 32), film 445px -- 49vh of
       fold on the one asset that costs 15h of GPU, against four references that
       all fill their fold with imagery. The four margins below hand ~64px of
       that dead spend to the film row: ~509px, ~57vh, at 900px wide that is
       1.77:1 -- effectively the film's native 16:9, LESS crop than before, and
       nowhere near the 3.17:1 letterbox this file already rejected. The 58-62vh
       named in the directive was written against the live build's overflowing
       hero; here the fr row caps the film by construction and the type floor
       (t-7, guardrail 6rem) is what bounds the head. Desktop only -- below
       56rem the hero is content-driven and measures clean. */
    row-gap:var(--hs-s-5);
    padding-top:var(--hs-s-4);
    padding-bottom:var(--hs-s-5);
  }
  .hs-hero__head{grid-column:1 / -1}
  /* The h1's own bottom margin duplicates the grid's row-gap here -- the head
     row already ends at the gap, so the margin was pure dead height between the
     headline and the film. Scoped to the hero: everywhere else .hs-h's margin
     is the only separator it has. */
  .hs-hero__head .hs-eyebrow{margin-bottom:var(--hs-s-4)}
  .hs-hero__head .hs-h--display{margin-bottom:0}
  /* THE PLATE IS ANCHORED TO THE VIEWPORT EDGE, 2026-09-02. The film measured
     732px wide at 1440 -- 51% of the viewport, floating in paper on all four
     sides, which is the single cheapest-reading screen on the site for the one
     asset that costs 15 h of GPU. This is the split sections' grid-break
     applied to the hero: the plate leaves .hs-s__in on the side the copy is
     not, computed from the SAME --hs-edge so the two moves cannot drift apart.
     The bled edge squares off, exactly as the split plates do -- a rounded
     corner at the viewport edge says the film stopped there; a square one says
     it continues past.

     The crop this buys is measured, not guessed: 900x445 at 1440 is 2.02:1
     against a 16:9 source, a ~12% vertical crop -- nowhere near the 3.17:1
     full-width letterbox this file already rejected. `object-position` biases
     the crop toward the ground, because what a cover crop discards here is
     sky and these are aerial frames of turf.

     `overflow-x: clip` for the same reason as the splits: --hs-edge is
     computed from 100vw, which includes the scrollbar, and the section is the
     nearest legal place to contain the overshoot. */
  .hs-s--hero-film{overflow-x:clip}
  .hs-hero__frame{
    margin-left:calc(var(--hs-edge) * -1);
    border-top-left-radius:0;border-bottom-left-radius:0;
  }
  .hs-hero__film{object-position:50% 60%}
  /* The plate stops declaring a ratio here and fills its row instead; the media
     is already object-fit:cover, so the crop follows the space rather than the
     space following the crop. */
  .hs-hero__frame,.hs-hero__plate{height:100%}
  .hs-hero__plate{aspect-ratio:auto}
  /* TOP-ALIGNED, and the first attempt was bottom-aligned and looked wrong.
     Bottom-aligning the standfirst put its slack BETWEEN the headline and the
     text -- a void in the middle of the composition, which reads as a column
     that failed to fill rather than as margin. Top-aligned, the same slack
     falls below the text where it reads as air. Same pixels, opposite
     impression, and it is the difference between whitespace that was composed
     and whitespace that was left over. */
  .hs-hero__copy{align-self:start}
  .hs-hero__sub{margin-top:0;padding-top:var(--hs-s-2)}
  /* A hairline seats the standfirst against the film row -- the same rule
     colour every table on the site uses, so the column reads as set beside the
     plate rather than as text that happened to land there. */
  .hs-hero__copy{
    padding-bottom:var(--hs-s-4);max-width:none;
    border-top:1px solid var(--rule);padding-top:var(--hs-s-4);
  }
}

/* --------------------------------------------------------------- page head
   The h1 for every page that is not the home page, and deliberately NOT a
   second hero.

   `hero-film` claims `min-height:100svh` because it IS the first impression.
   Five of those across a five-page site is five first impressions and no
   hierarchy between them, so this one is sized by its content plus one band of
   air -- which puts the first scroll on an interior page onto that page's first
   real idea rather than onto the bottom of its own masthead.

   The plate is optional and the type-only form is the default. A masthead that
   requires a photograph is a masthead that invents one. */
.hs-s--page-head .hs-s__in{
  padding-top:var(--hs-s-8);padding-bottom:var(--hs-s-8);
  display:grid;gap:clamp(var(--hs-s-5),3vw,var(--hs-s-7));
  align-content:center;
}
.hs-h--head{
  font-size:clamp(2.3rem,6.6vw,var(--hs-t-5));
  line-height:.99;letter-spacing:-.029em;max-width:17ch;
}
.hs-head__copy{max-width:40ch}
.hs-head__sub{
  /* --fg-muted, never --hs-ink-muted: this section can be re-grounded from the
     manifest like any other, and a hardcoded paper-zone ink goes invisible the
     first time somebody sets zone:"pine" on a page head. */
  margin:var(--hs-s-5) 0 0;color:var(--fg-muted);
  font-size:var(--hs-t-1);line-height:1.44;max-width:40ch;
}
@media (min-width:56rem){
  .hs-s--page-head .hs-s__in{
    grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
    /* START, NOT END, and this is a stability decision rather than a taste one.
       `align-items: end` bottom-aligns both columns, which COUPLES their
       heights: any change in either one moves both, doubling the area of any
       layout shift. Every CLS failure measured on this surface had that exact
       signature -- two grid children of an `end`-aligned row moving together by
       the same amount.

       The hero keeps `end` because its bottom edge is load-bearing: the film
       plate and the copy have to sit on one line or the frame reads as floating.
       A masthead has no such line, so it pays the coupling for nothing. */
    align-items:start;gap:var(--hs-s-8);
  }
  .hs-head__copy{max-width:none}
  /* THE MASTHEAD PLATE IS EDGE-ANCHORED, 2026-09-02. It rendered 440x350 at
     1440 -- a rounded card floating in paper on all four sides, which reads as
     a thumbnail where the page's opening image should read as a place. Same
     grid-break as the splits and the hero, same --hs-edge, same squared
     corners on the bled edge only; 3:2 because the bled plate is now wide
     enough that 5:4 would be 400px of vertical pushing the title's own air
     off the screen. Type-only page heads are untouched -- no figure, no rule
     fires. */
  .hs-s--page-head{overflow-x:clip}
  .hs-s--page-head .hs-fig--plate{
    margin-right:calc(var(--hs-edge) * -1);
    border-top-right-radius:0;border-bottom-right-radius:0;
    box-shadow:var(--hs-sh-3);
  }
  .hs-s--page-head .hs-fig--plate img{aspect-ratio:3/2}
}

/* --------------------------------------------------------------- jump strip
   Criterion 23, appended cycle 2. Streamsong's 9,533px golf page rides its
   five-course strip along the masthead's bottom edge; this is that pattern
   for a long page composed from this library. IN FLOW on purpose: a fixed
   strip would owe the contrast gate a pass on every ground it can overlay,
   and no reference runs a sticky scrollspy -- checked against the full-page
   captures, refs/streamsong/golf-1440-full.jpg, before this was styled.
   It is navigation, so nothing here is in the line-rise item list: present at
   first paint, working with the script blocked, same argument as the drawer. */
.hs-jump{border-top:1px solid var(--rule);padding-top:var(--hs-s-3)}
.hs-jump__u{
  list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;column-gap:var(--hs-s-6);
}
.hs-jump__l{
  display:inline-flex;align-items:center;min-height:var(--hs-tap);
  text-decoration:none;
  font-size:var(--hs-t--2);font-weight:600;line-height:1.2;
  text-transform:uppercase;letter-spacing:.19em;
  color:var(--fg-muted);transition:color .2s;
}
.hs-jump__l:hover{color:var(--fg)}
@media (min-width:56rem){
  .hs-s--page-head .hs-jump{grid-column:1/-1}
}

/* ------------------------------------------------------------- sequence
   The canvas move. `aspect-ratio` on the WRAPPER, not on the canvas, so the box
   is reserved before a single frame arrives -- a full-bleed element that grows
   on load is the largest layout shift a page can produce.

   The canvas is `display:none` until it has a frame to draw, which is not the
   same as resting hidden: the still underneath is real content with real alt
   text, and a blocked script leaves it exactly where it was. Swapping before
   the first bitmap lands would flash an empty box, which is worse than the
   picture it replaced.

   The copy is OUTSIDE the media box. Type over the canvas would be type over
   moving footage with no resolvable ground, which is the failure the contrast
   gate exists to catch and the render function refuses by construction. */
.hs-s--sequence .hs-s__in{padding-inline:0;padding-block:0;max-width:none}
.hs-seq{
  position:relative;width:100%;aspect-ratio:16/9;overflow:hidden;
  background:var(--hs-pine);
}
.hs-seq__c{display:none;width:100%;height:100%}
.hs-seq__still{width:100%;height:100%;object-fit:cover;display:block}
.hs-seq__copy{
  max-width:var(--hs-wide);margin-inline:auto;
  padding:var(--hs-s-7) var(--hs-gutter) var(--hs-s-6);
}
.hs-h--seq{max-width:22ch}
.hs-seq__cap{max-width:var(--hs-measure);color:var(--fg-muted);margin:var(--hs-s-4) 0 0}
@media (min-width:56rem){
  .hs-seq{aspect-ratio:21/9}
}

/* ---------------------------------------------------------------- hours
   A real table, styled as a rhythm of rules rather than as a grid. Zebra
   striping and cell borders are what make a table look like a spreadsheet; a
   single hairline per row is what makes it look set. */
.hs-s--hours-table .hs-s__in{display:grid;gap:var(--hs-s-6)}
.hs-hours{display:grid;gap:var(--hs-s-7)}
.hs-hours__k{
  font-size:var(--hs-t--1);letter-spacing:.14em;text-transform:uppercase;
  color:var(--sig);margin:0 0 var(--hs-s-4);
}
.hs-hours__span{color:var(--fg-muted);letter-spacing:.04em;text-transform:none}
.hs-hours__t{width:100%;border-collapse:collapse;max-width:var(--hs-measure)}
.hs-hours__t th,.hs-hours__t td{
  text-align:left;padding:var(--hs-s-3) 0;border-top:1px solid var(--rule);
  font-weight:400;vertical-align:baseline;
}
.hs-hours__t th{color:var(--fg-muted);width:11ch}
.hs-hours__t td{color:var(--fg)}
.hs-hours__t tr:last-child th,.hs-hours__t tr:last-child td{border-bottom:1px solid var(--rule)}
@media (min-width:56rem){
  .hs-s--hours-table .hs-s__in{grid-template-columns:.8fr 1.2fr;gap:var(--hs-s-8)}
  /* Sticky, never a pin. No spacer, no refresh, no CLS. */
  .hs-hours__head{position:sticky;top:calc(var(--hs-header-h) + var(--hs-s-6));align-self:start}
  /* auto-fit, NOT repeat(2), 2026-09-02 (club-site-10k criterion 19, the 3A
     deferral). River Ridge publishes ONE season, and a hard two-column grid
     rendered it beside a 285px empty column -- measured in this build's own
     dining page before the change (gridTemplateColumns "285.59px 285.61px",
     children 1). auto-fit collapses the empty track, a second season still gets
     its two columns, and the table's own --hs-measure cap keeps a single
     full-width season from setting 570px lines. */
  .hs-hours{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}
}

/* --------------------------------------------------------------- mosaic
   Club-supplied photography. Every rule here is doing one job: making six
   ordinary pictures read as an edit.

   ONE RATIO for every frame, so the set looks chosen rather than collected.
   ONE LEAD spanning two columns, because a uniform grid of six is six photos
   and a grid with a lead is a layout.
   CAPTIONS BELOW THE FRAME on the section's own ground -- never over the
   picture, which the contrast gate would fail and no visitor could read against
   a photograph nobody has seen. */
.hs-mosaic{list-style:none;margin:var(--hs-s-6) 0 0;padding:0;display:grid;gap:var(--hs-s-4)}
.hs-mosaic__i{margin:0}
.hs-fig--mosaic{margin:0;border-radius:var(--hs-r-m);overflow:hidden;box-shadow:var(--hs-sh-2)}
.hs-fig--mosaic img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.hs-mosaic__cap{
  margin:var(--hs-s-3) 0 0;font-size:var(--hs-t--1);line-height:1.4;color:var(--fg-muted);
}
.hs-mosaic__cr{color:var(--fg-muted);opacity:.8}
@media (min-width:34rem){ .hs-mosaic{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (min-width:56rem){
  .hs-mosaic{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--hs-s-5)}
  .hs-mosaic__i--lead{grid-column:span 2}
}

/* --------------------------------------------------------- hold statement
   One line held still while the picture moves past it.

   TWO CHILDREN, ONE GRID CELL. Stacking them would put the line after the
   figure in flow, where sticky has nothing left to travel through. Sharing a
   cell lets the figure be as tall as the section while the line stays free to
   stick inside it.

   `min-height: 200vh` is what the moment BUYS. A held line that is held for
   half a screen has not been held; two viewports is the shortest distance over
   which the stillness reads as deliberate rather than as a bug.

   The plate is opaque on purpose -- see the render function. It is the whole
   reason the contrast gate can resolve type that is visually over a photograph. */
.hs-s--hold-statement .hs-s__in{padding-inline:0;padding-block:0;max-width:none}
.hs-hold{display:grid;min-height:200vh;position:relative}
.hs-hold > *{grid-column:1;grid-row:1}
.hs-fig--hold{height:100%;overflow:hidden}
.hs-fig--hold img{width:100%;height:100%;object-fit:cover;display:block}
.hs-hold__l{
  align-self:start;position:sticky;top:calc(50svh - 5rem);z-index:1;
  width:min(42rem,86%);margin-inline:auto;
  background:var(--bg);color:var(--fg);
  padding:var(--hs-s-6) var(--hs-s-6) var(--hs-s-5);
  border-radius:var(--hs-r-l);box-shadow:var(--hs-sh-3);
  border-top:1px solid var(--rule);
}
.hs-h--hold{font-size:clamp(1.75rem,4.2vw,var(--hs-t-3));line-height:1.05;max-width:20ch;margin-bottom:0}
.hs-h--hold[data-lines="3"]{font-size:clamp(1.6rem,3.6vw,var(--hs-t-2))}
@media (min-width:56rem){
  .hs-hold__l{width:min(46rem,72%)}
}

/* ------------------------------------------------------------- zone bridge
   The safe form of the moment the contrast gate deleted. An empty band, no
   text, whose own ground tweens across its passage -- see schema.MOMENTS for
   the 1.01:1 measurement that killed the unsafe form.

   Two things here are load-bearing:

   The padding is zeroed. Every other section pays `--hs-band` for its air;
   a bridge IS air, and paying twice makes it a section-sized gap that reads as
   a page break rather than as a transition.

   The height is small and FIXED rather than viewport-sized. A bridge earns no
   scroll of its own. Sized at 100vh it would be a blank screen the visitor has
   to get past, which is the opposite of what buying a quiet moment means. */
.hs-s--zone-bridge .hs-s__in{padding:0;max-width:none}
.hs-bridge{min-height:clamp(6rem,12vh,12rem)}

/* -------------------------------------------------------------------- lede */
.hs-s--lede .hs-s__in{padding-block:var(--hs-s-10)}
.hs-lede__body{margin-top:var(--hs-s-7);max-width:var(--hs-measure)}
@media (min-width:56rem){
  .hs-s--lede .hs-s__in{display:grid;grid-template-columns:1.15fr .85fr;gap:var(--hs-s-8);align-items:start}
  .hs-s--lede .hs-eyebrow{grid-column:1/-1}
  .hs-lede__body{margin-top:.6rem}
}

/* --------------------------------------------------------- signature still
   Principle 2: one slow continuous camera move, and it is the only one on the
   page. The caption sits on its own opaque chip below the plate, never on the
   image -- text on a photograph is a contrast reading no gate can resolve. */
.hs-s--signature-still .hs-s__in{padding-inline:0;padding-block:0;max-width:none}
.hs-fig{margin:0;position:relative}
.hs-fig--bleed{overflow:hidden;background:var(--hs-pine)}
.hs-fig--bleed img{width:100%;aspect-ratio:16/9;object-fit:cover}
@media (min-width:56rem){ .hs-fig--bleed img{aspect-ratio:21/9} }
.hs-drift{will-change:transform}

/* -------------------------------------------------------- the sample badge
   Nik 2026-09-02: an AI-generated sample image renders ONLY visibly badged.
   The chip is the page's own declaration, emitted from the data flag; the
   baked pixel watermark (bottom-right, in the file itself) survives copies
   out of context. Four constraints, each tracing to an existing gate:
     1. OPAQUE ground, always. contrast_gate.mjs walks ancestors for an
        opaque ground and fails type over an image; the chip IS the opaque
        ground -- the .hs-sig__caption pattern. Never rgba.
     2. Top-LEFT, because the baked watermark is bottom-right: a CSS crop
        (object-fit in the mosaic, plate:tall in splits) that hides one
        corner still shows the other.
     3. No motion. Static, no line-rise class, no data-moment -- no new
        moment, Contract 3's budgets untouched.
     4. Zero CLS by construction: absolutely positioned, no layout
        contribution.
   No `position:relative` of its own is needed: every badge sits inside an
   `.hs-fig`, which already carries it (three lines up). z-index lifts it
   over the plate-edge and bleed-gradient ::after overlays. aria-hidden in
   the markup: the alt already declares sample status to assistive tech.
   Type is the eyebrow's stack and size, tracked a step tighter for a chip. */
.hs-fig__sample{
  position:absolute;top:.75rem;left:.75rem;z-index:2;
  background:var(--hs-pine);
  color:var(--hs-paper);
  font-family:var(--hs-f-body);font-size:var(--hs-t--2);font-weight:600;
  line-height:1.2;text-transform:uppercase;letter-spacing:.08em;
  padding:.35em .7em;
}

/* ------------------------------------------------------- the plate edge
   Every framed picture on this page is lit from above: a light hairline on its
   top edge, a dark one on its bottom. One idea, three sections, one rule.

   It gives a plate a physical edge without a border, which matters because a
   full border on a photograph reads as a frame around a picture and this reads
   as the picture having a thickness.

   ON A PSEUDO-ELEMENT AND NOT AS `inset` box-shadow, and the reason is paint
   order rather than preference: an inset shadow paints above the background and
   BELOW in-flow content, so on a figure whose img fills it the highlight would
   be under the photograph and invisible. A positioned ::after paints above it.

   `border-radius: inherit` is what makes this survive the grid-break. The bled
   plate squares off its outer two corners, and inheriting the computed
   shorthand means the highlight squares off with it instead of tracing a
   rounded corner the plate no longer has. */
.hs-fig--plate::after,.hs-fig--card::after,.hs-fig--mosaic::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;
  border-top:1px solid color-mix(in srgb, var(--hs-paper) 42%, transparent);
  border-bottom:1px solid color-mix(in srgb, var(--hs-pine) 24%, transparent);
}
.hs-fig--bleed::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,color-mix(in srgb,var(--hs-pine) 18%,transparent),transparent 45%,color-mix(in srgb,var(--hs-pine) 62%,transparent));
}
/* THE CAPTION PAINTS ITS OWN GROUND AND THAT IS NOT A STYLE CHOICE.
   Type on a photograph is a contrast reading no gate can resolve -- the audit
   reports it UNRESOLVED, which is the exact blind spot that let the Meridian
   showpiece ship white on white through four revision passes. An opaque panel
   sliding over the plate's bottom edge gives the same overlap and gives the
   gate an answer. */
.hs-sig__caption{
  position:relative;z-index:2;background:var(--bg);
  margin:calc(var(--hs-s-8) * -1) 0 0;
  padding:var(--hs-s-7) var(--hs-gutter) var(--hs-s-8);
  border-top-right-radius:var(--hs-r-l);
}
@media (min-width:56rem){
  .hs-sig__caption{
    margin-top:calc(var(--hs-s-9) * -1);
    width:min(58rem,76%);
    /* WAS the inline form of --hs-edge, guarded by a max() that did the same
       job --hs-edge's min() now does structurally. Same computed value at every
       width; the point of the swap is that the split plate's bleed is the SAME
       expression rather than a second one that agrees by coincidence. See the
       grid-break block under `split`. */
    padding-left:var(--hs-edge);
    padding-right:var(--hs-s-8);
  }
}

/* -------------------------------------------------------------------- facts
   Numbers 4rem and up, unit in a smaller sibling, label below in small
   uppercase. And the source named on the page underneath, because a statistic
   whose provenance is a build comment is a claim. */
.hs-facts{list-style:none;margin:var(--hs-s-7) 0 0;padding:0;display:grid;gap:var(--hs-s-7)}
@media (min-width:34rem){ .hs-facts{grid-template-columns:repeat(3,1fr);gap:var(--hs-s-6)} }
.hs-fact{border-top:1px solid var(--rule);padding-top:var(--hs-s-4)}
/* A STEP LOUDER, 2026-09-02. The stats capped at t-5 and rendered ~64px --
   heading scale, so the numbers read as more text rather than as the band's
   reason to exist. t-6 puts them a full step above every section heading
   around them, which is the size contrast `house-style.md` measured the page
   as missing. The vw term moves with the cap, same argument as every other
   clamp in this file. */
.hs-fact__v{
  margin:0;font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(3.2rem,8.6vw,var(--hs-t-6));line-height:1;letter-spacing:-.03em;
  display:flex;align-items:baseline;gap:.28em;color:var(--fg);
}
.hs-fact__u{font-size:var(--hs-t-0);font-family:var(--hs-f-body);font-weight:600;letter-spacing:.02em;color:var(--fg-muted)}
.hs-fact__l{
  margin:var(--hs-s-3) 0 0;font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--fg-muted);
}
.hs-facts__src{
  margin:var(--hs-s-7) 0 0;font-size:var(--hs-t--2);letter-spacing:.04em;
  color:var(--fg-muted);
}

/* -------------------------------------------------------------------- embed
   The frame paints no background of its own -- Contract 4 rule 4 -- so this
   section paints one behind it. A transparent iframe over a transparent
   section is how an embed ends up looking broken on a client's site. */
.hs-count{
  margin:0 0 var(--hs-s-6);font-size:var(--hs-t-1);color:var(--fg-muted);
  max-width:44ch;
}
.hs-embed{
  border:1px solid var(--rule);border-radius:var(--hs-r-l);overflow:hidden;
  background:var(--hs-paper);box-shadow:var(--hs-sh-2);
}
.hs-embed iframe{display:block;width:100%;border:0}
.hs-embed__note{
  margin:var(--hs-s-4) 0 0;font-size:var(--hs-t--1);color:var(--fg-muted);max-width:56ch;
}

/* -------------------------------------------------------------------- split */
.hs-s--split-left .hs-s__in,
.hs-s--split-right .hs-s__in{display:grid;gap:var(--hs-s-7);align-items:center}
@media (min-width:56rem){
  .hs-s--split-left .hs-s__in{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr)}
  .hs-s--split-right .hs-s__in{grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr)}
  .hs-s--split-right .hs-split__copy{order:2}
  .hs-s--split-right .hs-fig--plate{order:1}
}

/* ------------------------------------------------- the grid-break, at 78rem
   THE SPLIT IS THE PAGE'S REPEATED UNIT, so it is the one that decides whether
   the page reads composed or centred. `house-style.md` measured that four
   candidate palettes all cleared AA within half a contrast point of each other
   and concluded the palette was never why the page reads flat. This is the
   composition half of that answer.

   TWO CHANGES, ONE BREAKPOINT, AND THE BREAKPOINT IS THE POINT.

   1. THE RATIO GOES FROM .9/1.1 TO .72/1.28. Nearly-equal columns read as a
      two-up, which is a layout that has not decided anything. A 36/64 split has.

      It engages at 78rem and NOT at the 56rem the columns appear at, because
      the copy column is what pays for it. Measured, at a 17px body:

        1440, .72fr   380px   ~47 characters
        1248, .72fr   387px   ~48 characters      <- 78rem, where this begins
         896, .9fr    341px   ~42 characters      <- 56rem, already shipping

      So the strong ratio never produces a column narrower than one this page
      already ships at its own breakpoint. Applying it at 56rem would: 273px,
      ~34 characters, under every measure guideline there is.

   2. THE PLATE BREAKS THE GRID and runs to the viewport edge on the side the
      copy is not. This is `.hs-sig__caption`'s move -- an element leaving
      `.hs-s__in`'s max-width to touch the edge -- GENERALISED rather than
      reinvented: both now compute from --hs-edge, so they cannot drift apart.

      `overflow-x: clip` ON THE SECTION IS LOAD-BEARING AND IS NOT TIDYING.
      --hs-edge is computed from 100vw, which INCLUDES the scrollbar, so the
      plate overshoots documentElement.clientWidth by the scrollbar's width on
      every desktop browser. Three separate assertions in verify_site.mjs would
      catch that as a horizontally scrolling document, and they would be right.
      Clipping at the section contains it. `clip` rather than `hidden` on
      purpose: hidden forces the other axis to a scroll container, and this
      section has none to give.

      The overflow probe skips `body` and `documentElement` when it walks for a
      clipped ancestor -- deliberately, so a page cannot excuse an escaped box
      by the fact that the body clips everything -- which means the section is
      the nearest place this can legally be done at all.

   3. THE RADIUS DROPS ON THE BLED EDGE ONLY. A rounded corner at the viewport
      edge says the plate stopped there; a square one says it continues past.
      The other three corners keep --hs-r-l, so it is still a plate.

   The ratio and the bleed share a breakpoint because they are one idea: the
   plate takes the space the copy gave up, and then some. */
@media (min-width:78rem){
  .hs-s--split-left .hs-s__in{grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr)}
  .hs-s--split-right .hs-s__in{grid-template-columns:minmax(0,1.28fr) minmax(0,.72fr)}

  .hs-s--split-left,.hs-s--split-right{overflow-x:clip}
  .hs-s--split-left .hs-fig--plate{
    margin-right:calc(var(--hs-edge) * -1);
    border-top-right-radius:0;border-bottom-right-radius:0;
  }
  .hs-s--split-right .hs-fig--plate{
    margin-left:calc(var(--hs-edge) * -1);
    border-top-left-radius:0;border-bottom-left-radius:0;
  }
  /* A 5:4 plate that is now half the viewport wide is 500px of vertical, which
     pushes the copy it is paired with off the screen it is meant to be read
     beside. The wider the plate gets the wider its ratio has to be. */
  .hs-s--split-left .hs-fig--plate img,
  .hs-s--split-right .hs-fig--plate img{aspect-ratio:3/2}
  /* The largest object on the page carries the deepest of the three steps.
     --hs-sh-2 reads as a card at 380px and as nothing at 700. */
  .hs-s--split-left .hs-fig--plate,
  .hs-s--split-right .hs-fig--plate{box-shadow:var(--hs-sh-3)}
}
/* A standalone link is a target, not a word in a sentence, so it carries the
   full 44px. WCAG 2.5.5's inline exception covers a link INSIDE a paragraph and
   nothing else; measured here at 29px before this rule existed. */
.hs-split__copy .hs-link{
  margin-top:var(--hs-s-4);display:inline-flex;align-items:center;
  min-height:var(--hs-tap);
}
.hs-fig--plate{border-radius:var(--hs-r-l);overflow:hidden;box-shadow:var(--hs-sh-2);background:var(--hs-pine)}
.hs-fig--plate img{width:100%;aspect-ratio:4/3;object-fit:cover}
@media (min-width:56rem){ .hs-fig--plate img{aspect-ratio:5/4} }

/* ------------------------------------------------------- the plate mass
   THE MEASURED PROBLEM: `split-*` rendered EIGHT TIMES AT EXACTLY 819px on the
   six-page site. Eight panels of identical mass, alternating only which side
   the picture sits on. It is the most repeated unit on the site, so it sets
   the tempo of the whole thing -- and an unvarying tempo is the mechanical
   rhythm the eye reads as template.

   The grid-break already varies the plate's WIDTH at 78rem. This varies its
   HEIGHT, which is what actually changes the mass of a panel: a taller plate
   pushes the copy's air around it, a shallower one lets the section breathe.

   ONE STEP EITHER SIDE OF THE DEFAULT, AT EACH BREAKPOINT -- and the values
   have to differ per breakpoint because the DEFAULTS differ (5/4 at 56rem,
   3/2 at 78rem once the plate is bled and much wider). A single global `tall`
   would be one step down from one default and three from the other:

              default   tall    inset
     56rem     5/4      1/1     3/2
     78rem     3/2      5/4     16/9

   ASPECT RATIO, NOT HEIGHT. A height is a layout property in a tween's way and
   would put cold CLS at risk; `aspect-ratio` resolves before paint and costs
   nothing. Same argument as the bled plate stepping 5:4 -> 3:2 rather than
   growing a fixed number of pixels.

   It starts at 56rem because below that the grid is one column and the plate
   is already full width -- there is no second column for a taller plate to be
   taller THAN, so the modifier would be mass with nothing to contrast against. */
@media (min-width:56rem){
  .hs-s--split-left[data-plate="tall"] .hs-fig--plate img,
  .hs-s--split-right[data-plate="tall"] .hs-fig--plate img{aspect-ratio:1/1}
  .hs-s--split-left[data-plate="inset"] .hs-fig--plate img,
  .hs-s--split-right[data-plate="inset"] .hs-fig--plate img{aspect-ratio:3/2}
  /* An inset plate is lighter in every sense: shallower, and it gives air back
     to the section instead of filling its column edge to edge. */
  .hs-s--split-left[data-plate="inset"] .hs-fig--plate,
  .hs-s--split-right[data-plate="inset"] .hs-fig--plate{
    margin-block:var(--hs-s-6);box-shadow:var(--hs-sh-2);
  }
}
@media (min-width:78rem){
  .hs-s--split-left[data-plate="tall"] .hs-fig--plate img,
  .hs-s--split-right[data-plate="tall"] .hs-fig--plate img{aspect-ratio:5/4}
  .hs-s--split-left[data-plate="inset"] .hs-fig--plate img,
  .hs-s--split-right[data-plate="inset"] .hs-fig--plate img{aspect-ratio:16/9}
}

/* A split with no plate spans both columns rather than sitting in one of them
   with the other empty. The measure is capped so spanning does not turn a
   column of copy into a wall of it. */
.hs-split__copy--wide{max-width:var(--hs-mid)}
@media (min-width:56rem){ .hs-split__copy--wide{grid-column:1 / -1} }

/* Facts beside a split's copy. A definition list in everything but element:
   the label is small and muted, the value is the thing being read. Rules
   between rather than around, because a card here would be the fourth
   container on a page whose guardrail says text sits on the ground. */
.hs-split__facts{list-style:none;margin:var(--hs-s-6) 0 0;padding:0;max-width:var(--hs-measure)}
.hs-split__f{
  display:flex;gap:var(--hs-s-4);justify-content:space-between;align-items:baseline;
  padding:var(--hs-s-3) 0;border-top:1px solid var(--rule);
}
.hs-split__f:last-child{border-bottom:1px solid var(--rule)}
.hs-split__k{font-size:var(--hs-t--1);letter-spacing:.06em;text-transform:uppercase;color:var(--fg-muted)}
.hs-split__v{text-align:right;color:var(--fg)}

/* --------------------------------------------------------------------- rail
   The track is wider than the viewport ON PURPOSE and is clipped by .hs-rail__vp.
   The last card is cut at the right edge, which advertises scrollability with
   no arrow -- Aman's detail, and the one worth naming.

   Below 56rem it is a real horizontal scroller with snap, because a scrubbed
   rail on a touch device fights the finger. Above it, site.js drives x from
   scroll and the box is not scrollable. */
.hs-s--rail .hs-s__in{padding-inline:0;max-width:none}
.hs-rail__head{max-width:var(--hs-wide);margin-inline:auto;padding-inline:var(--hs-gutter)}
.hs-rail__vp{overflow-x:auto;overflow-y:hidden;margin-top:var(--hs-s-7);
  scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
.hs-rail__track{
  display:flex;gap:var(--hs-s-5);list-style:none;margin:0;
  padding:0 var(--hs-gutter);width:max-content;
}
.hs-rail__card{
  flex:0 0 auto;width:min(78vw,24rem);scroll-snap-align:center;
}
.hs-fig--card{border-radius:var(--hs-r-m);overflow:hidden;box-shadow:var(--hs-sh-2)}
.hs-fig--card img{width:100%;aspect-ratio:3/2;object-fit:cover}
.hs-rail__cap{
  margin:var(--hs-s-4) 0 0;font-size:var(--hs-t--1);color:var(--fg-muted);
}
@media (min-width:56rem){
  .hs-rail__vp{overflow:hidden;scroll-snap-type:none}
  .hs-rail__track{will-change:transform}
  .hs-rail__card{width:26rem}
}

/* --------------------------------------------- the rail is operable, 2026-09-03
   club-site-10k directive A8, delta 8. Measured across the four $10K+
   references: 8 to 18 carousels on a home page -- content the visitor DRIVES.
   Ours was one rail that moved only when the page did, so the answer to "what
   on this page can I touch" was nothing.

   INSIDE `rail-scroll`, NOT BESIDE IT. Same name, same one transform, same
   budget line. A distinct gallery or lightbox would be a ninth moment and that
   is Nik's decision, not a track's (interaction-audit N-IX-2).

   THE CONTROLS ARE INJECTED BY site.js AND THESE RULES ARE THEIR CSS HALF.
   Nothing in `library._r_rail` emits them, so a page with the script blocked
   carries no dead buttons -- and below this breakpoint, and under reduced
   motion, the box is a real scroller and the browser's own drag and keyboard
   are already the controls.

   ABSOLUTE, SO COLD CLS STAYS 0.0000. The nav is injected after first paint;
   in flow it would push the section below it and the gate that asserts zero
   layout shift would be right to fail. Out of flow, nothing already laid out
   moves. `position:relative` on the viewport is what makes that possible and
   costs no layout of its own.

   THE BUTTON PAINTS ITS OWN OPAQUE GROUND. It sits over a card, and a control
   with a translucent ground is a control whose contrast no audit can resolve --
   the same argument `.hs-unresolved` makes two hundred lines down. It carries
   no text node at all: the chevron is this ::before, and the accessible name is
   the aria-label site.js sets, so there is no ink here for the contrast gate to
   measure against something that may still be moving.

   48px SQUARE. WCAG 2.5.5 asks 44; a control that sits over a photograph gets
   the next step up rather than the minimum.

   DISABLED IS A COLOUR, NEVER AN OPACITY. Every probe in tests/ reads a resting
   opacity below 1 as an entrance that never fired, and all three would be right
   to. `--fg-muted` is the same de-emphasis the rest of this file uses. */
.hs-rail__vp{position:relative}
.hs-rail__nav{display:none}
@media (min-width:56rem){
  .hs-rail__nav{
    display:flex;justify-content:space-between;align-items:center;
    position:absolute;top:0;bottom:var(--hs-s-8);
    left:var(--hs-gutter);right:var(--hs-gutter);
    pointer-events:none;   /* the strip is a rail, the buttons are the targets */
  }
  .hs-rail__b{
    pointer-events:auto;
    width:48px;height:48px;padding:0;border:1px solid var(--rule);
    border-radius:50%;background:var(--bg);color:var(--fg);
    display:flex;align-items:center;justify-content:center;cursor:pointer;
    box-shadow:var(--hs-sh-2);
    transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .22s,color .22s;
  }
  .hs-rail__b::before{
    content:"";width:.55em;height:.55em;
    border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;
  }
  .hs-rail__b--prev::before{transform:rotate(-135deg) translate(-.08em,-.08em)}
  .hs-rail__b--next::before{transform:rotate(45deg) translate(-.08em,-.08em)}
  .hs-rail__b:disabled{color:var(--fg-muted);cursor:default;box-shadow:var(--hs-sh-1)}
  /* `pan-y` is the browser half of site.js's axis lock: it keeps vertical
     scrolling with the page on a touch screen wide enough to land in this
     breakpoint, and hands us the horizontal. Without it a tablet at 56rem
     fights the finger, which is the exact failure the mobile fallback below
     this breakpoint exists to avoid. */
  .hs-rail__vp[data-operable]{cursor:grab;touch-action:pan-y}
  .hs-rail__vp[data-grabbing]{cursor:grabbing}
  /* A dragged rail must not paint a text selection across every caption. */
  .hs-rail__vp[data-operable] .hs-rail__track{user-select:none}
}
@media (min-width:56rem) and (hover:hover){
  .hs-rail__b:not(:disabled):hover{transform:scale(1.06);box-shadow:var(--hs-sh-3)}
}

/* ------------------------------------------------- card state, gated on a link
   ONE RULE SET FOR EVERY CARD-SHAPED UNIT, 2026-09-02 (club-site-10k criterion
   15, directive A2). Measured before that change: zero hover rules on any card
   site-wide -- .hs-link, .hs-nav__cta and .hs-cta were the only elements that
   answered a pointer -- while the references spend their budget exactly there
   (Singita: 215 state transitions inside the index, 1 scroll animation across
   13,297px). This is STATE, not a scroll moment: it stamps no data-moment,
   adds nothing to schema.MOMENT_BUDGET's count, and rests untransformed, so
   the no-script and stuck-entrance probes see the same page they always did.

   AND THE SELECTOR MOVED OFF THE CARD CLASSES ON 2026-09-02 (directive A3).
   As first shipped this block read `.hs-rail__card, .hs-mosaic__i,
   .hs-bundle__i, .hs-course` -- every card-shaped unit, whether or not it had
   anywhere to go. A real browser then counted what that decorated across the
   six live pages (research/interaction/13-hovercount.mjs):

       36 units carrying the lift.  0 links.  0 focusable.  0 pointer cursors.
       All four $10K+ references: 37 linked cards, ZERO dead movers.

   A card that lifts under the pointer and goes nowhere promises a click it
   cannot honour, and the flattest case was the rates page: three
   `hs-bundle__i` cards lifting on the page where the money question lands.
   Criterion 15 was scored closed on the strength of the rule shipping; the rule
   shipped and the affordance it promised did not exist.

   `hs-card--link` IS EMITTED BY ONE FUNCTION -- library._card -- and only for a
   card whose manifest item carries a destination. That is what makes this
   un-driftable: nothing can gain the lift without gaining a real <a>, and
   nothing can lose the <a> and keep the lift. tests/probe_site_gates.py asserts
   both halves, including that no `:hover` rule in this file names a card class
   without also naming `hs-card--link`.

   KEYBOARD FIRST, AND OUTSIDE THE HOVER QUERY ON PURPOSE. `:focus-within` gives
   a keyboard visitor exactly what a pointer gives -- criterion 28's "a link, a
   button, or focusable" is satisfied by the anchor, and this is the visible
   half of it. `@media (hover:hover)` guards only the POINTER half, because that
   is the half that leaves a phone with a stuck first-tap state.

   Transform and box-shadow only -- the directive's spend, and invariant B's:
   no layout property, so cold CLS stays 0.0000 by construction. ~220ms, the
   same curve every other transition in this file rides. */
.hs-card__a{display:block;color:inherit;text-decoration:none}
/* `cursor` sits on the CARD rather than on `.hs-card__a` -- the anchor fills the
   card either way, and the card is the unit an affordance probe measures. */
.hs-card--link{
  transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .22s;
  cursor:pointer;
}
/* THE PICTURE MOVES FURTHER AND SLOWER THAN THE CARD, 2026-09-03 (directive
   A9). Measured: ours was scale(1.03) over 220 ms, which the audit calls "close
   to imperceptible" -- and the ONE reference that scales a card image on hover,
   pinehurst, uses scale(1.10) over 500 ms, three times the move and twice the
   time. Splitting the two durations is what buys both readings at once: the
   card answers the pointer instantly at 220 ms, and the picture settles behind
   it at 340 ms, so the state is felt rather than merely measured.

   1.05 RATHER THAN PINEHURST'S 1.10, and the reason is the frame. Their card
   image is untreated; ours sits inside `.hs-fig--card`, which clips to a 4px
   radius and casts sh-2, so the same scale reads larger against a held edge.
   1.10 pushed visible detail out of a 3:2 crop of a hole.

   A9 IS DELIBERATELY DOWNSTREAM OF A3, and the audit says so: a bigger move on
   a card that goes nowhere makes the false affordance worse, not better. It is
   safe here only because the selector is `hs-card--link`, which library._card
   emits alongside a real anchor and nowhere else. */
.hs-fig--card img,.hs-fig--mosaic img,.hs-fig--bundle img,.hs-fig--portrait img{
  transition:transform .34s cubic-bezier(.2,.8,.2,1);
}
.hs-card--link:focus-within{transform:translateY(-4px)}
.hs-card--link:focus-within .hs-fig--card img,
.hs-card--link:focus-within .hs-fig--mosaic img,
.hs-card--link:focus-within .hs-fig--bundle img,
.hs-card--link:focus-within .hs-fig--portrait img{transform:scale(1.05)}
.hs-card--link:focus-within .hs-fig--card,
.hs-card--link:focus-within .hs-fig--mosaic{box-shadow:var(--hs-sh-3)}
.hs-bundle__i.hs-card--link:focus-within,
.hs-people__i.hs-card--link:focus-within{box-shadow:var(--hs-sh-2)}
@media (hover:hover){
  .hs-card--link:hover{transform:translateY(-4px)}
  .hs-card--link:hover .hs-fig--card img,
  .hs-card--link:hover .hs-fig--mosaic img,
  .hs-card--link:hover .hs-fig--bundle img,
  .hs-card--link:hover .hs-fig--portrait img{transform:scale(1.05)}
  /* The shadow deepens one step, never two -- the figure's frame already
     carries sh-2, and jumping to sh-3 on hover is the lift made visible. */
  .hs-card--link:hover .hs-fig--card,
  .hs-card--link:hover .hs-fig--mosaic{box-shadow:var(--hs-sh-3)}
  .hs-bundle__i.hs-card--link:hover,
  .hs-people__i.hs-card--link:hover{box-shadow:var(--hs-sh-2)}
}

/* ------------------------------------------------------------ deep statement */
.hs-s--deep-statement .hs-s__in{
  padding-block:var(--hs-s-10);text-align:center;max-width:var(--hs-mid);
}
.hs-deep__attrib{
  margin:var(--hs-s-6) 0 0;font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--fg-muted);
}

/* ------------------------------------------------------------------ process */
.hs-process__head{max-width:var(--hs-measure)}
.hs-steps{list-style:none;margin:var(--hs-s-8) 0 0;padding:0;counter-reset:s}
.hs-step{
  display:grid;grid-template-columns:3.4rem 1fr;gap:var(--hs-s-5);
  padding:var(--hs-s-6) 0;border-top:1px solid var(--rule);
}
.hs-step__n{
  margin:0;font-family:var(--hs-f-display);font-size:var(--hs-t-1);
  font-weight:500;color:var(--sig);line-height:1.2;letter-spacing:.02em;
}
.hs-step__q{
  margin:0 0 var(--hs-s-3);font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(1.32rem,2.6vw,var(--hs-t-2));line-height:1.16;letter-spacing:-.015em;
  color:var(--fg);text-wrap:balance;
}
.hs-step__a{margin:0 0 var(--hs-s-3);max-width:56ch;color:var(--fg-muted)}
.hs-step__a:last-child{margin-bottom:0}
@media (min-width:56rem){
  .hs-steps{margin-left:auto;margin-right:0;max-width:52rem}
  .hs-step{grid-template-columns:5rem 1fr;gap:var(--hs-s-6)}
  .hs-process__head{position:sticky;top:calc(var(--hs-s-8) + 1rem)}
  .hs-s--process-numbered .hs-s__in{display:grid;grid-template-columns:.75fr 1.25fr;gap:var(--hs-s-8);align-items:start}
  .hs-s--process-numbered .hs-steps{margin-top:0}
}

/* ---------------------------------------------------------------- portfolio */
.hs-portfolio__head{max-width:var(--hs-measure)}
.hs-courses{
  list-style:none;margin:var(--hs-s-8) 0 0;padding:0;
  display:grid;gap:var(--hs-s-6);
}
@media (min-width:34rem){ .hs-courses{grid-template-columns:repeat(2,1fr)} }
@media (min-width:56rem){ .hs-courses{grid-template-columns:repeat(3,1fr);gap:var(--hs-s-7)} }
.hs-course{border-top:1px solid var(--rule);padding-top:var(--hs-s-4)}
/* Region small and above, name large and below. The visitor reads WHERE first
   and WHICH second, which is the order they think in. Singita's card. */
.hs-course__r{
  margin:0 0 var(--hs-s-2);font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--sig);
}
.hs-course__n{
  font-family:var(--hs-f-display);font-size:var(--hs-t-2);font-weight:500;
  line-height:1.14;letter-spacing:-.015em;color:var(--fg);display:block;
}
/* THE COURSE NAME IS NO LONGER THE LINK, 2026-09-02 (directive A3). It used to
   be an inline anchor padded out to clear the 44px tap gate against its own
   33px type box. `library._card` now wraps the WHOLE card in the anchor, so the
   hit area is the card -- far past 44px in both axes -- and the pointer, the
   tab stop and the hover lift describe one rectangle instead of three. The
   padding rule is gone rather than kept "just in case": a selector matching
   nothing is a claim about markup that no longer exists.

   The name keeps `hs-link`'s colour and rule as a SPAN, because a portfolio
   card carries no picture and a text-only card with nothing but a cursor to say
   it is a link is A3's problem pointing the other way. `inline-block` is what
   keeps that rule under the words rather than across the whole column, which is
   the one thing the deleted anchor rule was really buying. */
.hs-card--link .hs-course__n{display:inline-block}
.hs-course__s{margin:var(--hs-s-3) 0 0;font-size:var(--hs-t--1);color:var(--fg-muted)}

/* ------------------------------------------------------------------- bundle
   Three things on one invoice, and it has to READ as three things rather than
   as one thing described three ways. */
.hs-bundle__head{max-width:var(--hs-measure)}
.hs-bundle{list-style:none;margin:var(--hs-s-8) 0 0;padding:0;display:grid;gap:var(--hs-s-6)}
@media (min-width:48rem){ .hs-bundle{grid-template-columns:repeat(3,1fr)} }
.hs-bundle__i{
  background:var(--hs-paper);border:1px solid var(--rule);
  border-radius:var(--hs-r-m);padding:var(--hs-s-6);box-shadow:var(--hs-sh-1);
}
/* THE CARD SHIFTS GROUND OFF ITS SECTION, 2026-09-02 (club-site-10k criterion
   16, directive A3). Measured on the rates page: three 619x207 border-only
   boxes -- the flattest block on the site, on the page where the money question
   lands. A card whose ground IS its section's ground has only its border to
   exist with, which is what "border-only" means. One step off the section's own
   ground -- paper-alt on paper, paper on paper-alt -- gives the card a body at
   zero contrast risk: both grounds share the same ink tokens, and brandkit
   already darkens --hs-ink-muted and --accent-type to clear AA on paper-alt,
   the tighter of the two (the build log prints both ratios). On a pine section
   the default paper card above stands unchanged -- the shift is zone-scoped,
   not unconditional, so a reskin cannot invert it. */
.hs-z--paper .hs-bundle__i{background:var(--hs-paper-alt)}
.hs-z--paper-alt .hs-bundle__i{background:var(--hs-paper)}
/* The optional still or hole plan a bundle item may now carry (library.py
   _r_bundle). It bleeds to the card's edges -- the negative margins are the
   card's own padding -- so it reads as the card's ground surfacing, not as a
   thumbnail pinned inside a box. */
.hs-fig--bundle{
  margin:calc(var(--hs-s-6) * -1) calc(var(--hs-s-6) * -1) var(--hs-s-5);
  border-radius:var(--hs-r-m) var(--hs-r-m) 0 0;overflow:hidden;
}
.hs-fig--bundle img{width:100%;aspect-ratio:21/9;object-fit:cover;display:block}
.hs-bundle__k{
  margin:0 0 var(--hs-s-4);font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--sig);
}
.hs-bundle__t{
  margin:0 0 var(--hs-s-3);font-family:var(--hs-f-display);font-weight:500;
  font-size:var(--hs-t-1);line-height:1.2;color:var(--hs-ink);
}
.hs-bundle__b{margin:0;color:var(--hs-ink-muted);font-size:var(--hs-t--1);max-width:34ch}
.hs-bundle__note{
  margin:var(--hs-s-6) 0 0;font-size:var(--hs-t--1);color:var(--fg-muted);max-width:56ch;
}
@media (min-width:56rem){
  .hs-s--bundle .hs-s__in{display:grid;grid-template-columns:.8fr 1.2fr;gap:var(--hs-s-8);align-items:start}
  .hs-bundle{margin-top:0;grid-template-columns:1fr;gap:var(--hs-s-5)}
  .hs-bundle__note{grid-column:2}
  /* The head holds its position while the three items pass it, so the left
     column is never an empty half-screen. Same device as the process and FAQ
     columns, and it is `position: sticky` rather than a ScrollTrigger pin: no
     spacer element, no refresh, no CLS. */
  .hs-bundle__head{position:sticky;top:calc(var(--hs-header-h) + var(--hs-s-6))}
}

/* ---------------------------------------------------------------------- faq
   <details>, not a hand-rolled accordion: keyboard-operable, announced, and
   open when printed, for zero script and zero aria of our own. */
.hs-faq__head{max-width:var(--hs-measure)}
.hs-faq{margin-top:var(--hs-s-8)}
.hs-faq__i{border-top:1px solid var(--rule)}
.hs-faq__i:last-child{border-bottom:1px solid var(--rule)}
.hs-faq__q{
  cursor:pointer;list-style:none;display:flex;align-items:center;gap:var(--hs-s-4);
  min-height:var(--hs-tap);padding:var(--hs-s-5) 0;
  font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(1.14rem,2.2vw,var(--hs-t-1));line-height:1.28;color:var(--fg);
}
.hs-faq__q::-webkit-details-marker{display:none}
.hs-faq__q::after{
  content:"";margin-left:auto;flex:0 0 auto;width:.68em;height:.68em;
  border-right:1.5px solid var(--sig);border-bottom:1.5px solid var(--sig);
  transform:rotate(45deg) translateY(-.14em);transition:transform .28s cubic-bezier(.2,.8,.2,1);
}
.hs-faq__i[open] .hs-faq__q::after{transform:rotate(-135deg) translateY(-.14em)}
.hs-faq__a{padding:0 0 var(--hs-s-6);max-width:60ch}
.hs-faq__a .hs-body{color:var(--fg-muted)}
@media (min-width:56rem){
  .hs-s--faq .hs-s__in{display:grid;grid-template-columns:.8fr 1.2fr;gap:var(--hs-s-8);align-items:start}
  .hs-faq{margin-top:0}
  .hs-faq__head{position:sticky;top:calc(var(--hs-s-8) + 1rem)}
}

/* -------------------------------------------------------------------- visit */
.hs-s--visit .hs-s__in{display:grid;gap:var(--hs-s-7)}
@media (min-width:56rem){
  .hs-s--visit .hs-s__in{grid-template-columns:1.1fr .9fr;gap:var(--hs-s-8)}
}
.hs-visit__rows{list-style:none;margin:0;padding:0}
.hs-visit__r{
  display:grid;grid-template-columns:7.5rem 1fr;gap:var(--hs-s-4);
  padding:var(--hs-s-4) 0;border-top:1px solid var(--rule);
  align-items:baseline;color:var(--fg-muted);
}
.hs-visit__k{
  font-size:var(--hs-t--2);text-transform:uppercase;letter-spacing:.15em;color:var(--sig);
}
/* The telephone and the email are STANDALONE TARGETS, not words in a sentence,
   so they carry the full 44px -- the same rule and the same measurement as
   .hs-split__copy .hs-link, which was 29px before it existed. WCAG 2.5.5's
   inline exception covers a link inside a paragraph and nothing else.

   This did not fire until 2026-08-27 because until then both rows were
   UNRESOLVED placeholders -- <span>s, not links, so nothing measured them. The
   contact facts landing turned two markers into two undersized tap targets, and
   the gate found it in the same run. Exactly the defect the tour surface already
   records: "the 27px-tall contact links that shipped for as long as this page
   has existed were invisible on the only course anyone was looking at."

   `align-items` on the row is `baseline`, and an inline-flex box aligns on the
   baseline of its first line, so the label still sits level with the value. */
.hs-visit__r .hs-link{
  display:inline-flex;align-items:center;min-height:var(--hs-tap);
}

/* ==========================================================================
   WHAT A CLUB SITE DOES -- the four sections added 2026-09-03.

   Nik: *"it's missing what a club site DOES."* Track FC measured the same gap
   from the other end (handoffs/track-fc-status.md, E6/E7/E9/E10) and its own
   estimate is the reason these are four blocks of CSS and not four designs:
   *"each is one Section declaration and one render function AGAINST CSS THAT
   ALREADY EXISTS."* Every rule below is a re-use of a pattern this file already
   proved -- the sticky head column from `process`/`faq`/`bundle`, the
   ground-shifted card from `bundle`, the bled figure from `hs-fig--bundle`, the
   accent eyebrow from `portfolio-named`, the source line from `facts-band`.

   Zero hex literals, every size a token step, every material effect on a
   pseudo-element. Contract 3, unchanged.
   ========================================================================== */

/* ------------------------------------------------------------ enquiry form
   THE FIRST `<form>` IN THIS SYSTEM. Three of the five in-band comps take a
   written enquiry on the home page alone; this library had none anywhere, and
   `mailto:` in a footer was the substitute (recalibration.md 4.6).

   THE CONTROL PAINTS ONE GROUND STEP OFF ITS SECTION, exactly as
   `.hs-bundle__i` does and for the exact same measured reason: a field whose
   ground IS the section's ground has only its border to exist with, and a form
   of those reads as a wireframe. Both grounds carry the same ink tokens and
   brandkit already clears AA on the tighter of the two, so this costs no
   contrast.

   THE FOCUS RING IS THE PAGE'S, NOT THIS BLOCK'S. `:focus-visible` two hundred
   lines up paints `2px solid var(--sig)` at a 3px offset on every zone, and a
   second ring here would be two rings on a keyboard visitor. The border shift
   is what a POINTER visitor gets, because the outline alone reads as an
   artefact on a box that already has a border.

   44px MINIMUM ON EVERY CONTROL, not only on the button. `TAP_TARGETS` in
   verify_site.mjs measures anchors, buttons and tabindex -- not inputs -- so
   this is the half no gate would have caught. */
.hs-s--enquiry-form .hs-s__in{display:grid;gap:var(--hs-s-7)}
@media (min-width:56rem){
  .hs-s--enquiry-form .hs-s__in{
    grid-template-columns:.85fr 1.15fr;gap:var(--hs-s-8);align-items:start;
  }
  .hs-enq__copy{position:sticky;top:calc(var(--hs-header-h) + var(--hs-s-6))}
}
.hs-enq__copy{max-width:var(--hs-measure)}
.hs-enq__note{font-size:var(--hs-t--1)}
.hs-enq{display:grid;gap:var(--hs-s-5)}
.hs-enq__f{display:grid;gap:var(--hs-s-2)}
.hs-enq__l{
  font-size:var(--hs-t--1);letter-spacing:.06em;text-transform:uppercase;
  font-weight:600;color:var(--fg);
}
/* "optional" is marked and "required" is not -- the asterisk convention needs a
   legend nobody reads. Lower case and unspaced so it reads as an aside inside
   the label rather than as a second label. */
.hs-enq__o{
  font-weight:400;text-transform:lowercase;letter-spacing:.02em;color:var(--fg-muted);
}
.hs-enq__n{
  display:block;margin-top:var(--hs-s-1);
  font-weight:400;text-transform:none;letter-spacing:0;
  font-size:var(--hs-t--1);color:var(--fg-muted);max-width:var(--hs-measure);
}
.hs-enq__c{
  width:100%;min-height:var(--hs-tap);
  padding:var(--hs-s-3) var(--hs-s-4);
  font-family:var(--hs-f-body);font-size:var(--hs-t-0);line-height:1.5;
  color:var(--fg);border:1px solid var(--rule);border-radius:var(--hs-r-s);
  transition:border-color .22s cubic-bezier(.2,.8,.2,1);
}
.hs-z--paper .hs-enq__c{background:var(--hs-paper-alt)}
.hs-z--paper-alt .hs-enq__c{background:var(--hs-paper)}
.hs-enq__c--area{min-height:calc(var(--hs-tap) * 2.6);resize:vertical}
/* THE NATIVE ARROW IS ONLY REMOVED WHERE OURS CAN BE DRAWN, and the guard is
   not caution for its own sake: `appearance:none` outside it would strip the
   arrow in any engine without `:has()` and leave a select that looks exactly
   like a text field. Drawing OUR chevron needs `:has()` because it hangs on the
   LABEL -- a background-image on the select itself is an image under text, the
   one ground `contrast_gate.mjs` cannot resolve a ratio through. Contract 3
   rule 6, and the same argument `.hs-unresolved` makes about its own tint. */
@supports selector(:has(*)) {
  .hs-enq__c--sel{appearance:none;-webkit-appearance:none;padding-right:var(--hs-s-7)}
  .hs-enq__f:has(.hs-enq__c--sel){position:relative}
  .hs-enq__f:has(.hs-enq__c--sel)::before{
    content:"";position:absolute;right:var(--hs-s-4);bottom:1.15rem;
    width:.5rem;height:.5rem;pointer-events:none;
    border-right:1.5px solid var(--fg-muted);border-bottom:1.5px solid var(--fg-muted);
    transform:rotate(45deg);
  }
}
.hs-enq__c:hover{border-color:var(--sig)}
.hs-enq__send{margin-top:var(--hs-s-2);justify-self:start}
/* What a --demo build shows where the endpoint belongs: the questions the form
   WILL ask, and the marker. No <form> is emitted at all -- see _r_enquiry. */
.hs-enq__preview{list-style:none;margin:0;padding:0;display:grid}
.hs-enq__p{
  border-top:1px solid var(--rule);padding:var(--hs-s-4) 0;
  font-size:var(--hs-t--1);letter-spacing:.06em;text-transform:uppercase;
  color:var(--fg-muted);
}
.hs-enq__p:last-child{border-bottom:1px solid var(--rule)}

/* ---------------------------------------------------------------- menu list
   Track FC's E9. A menu is one axis -- dishes under a course -- so it is a
   heading and a list, never the two-axis `<table>` `hours-table` correctly is.
   The sticky head column is the same device as process, faq and bundle. */
.hs-menu__head{max-width:var(--hs-measure)}
.hs-menu{margin-top:var(--hs-s-8);display:grid;gap:var(--hs-s-8)}
.hs-menu__h{
  margin:0 0 var(--hs-s-5);padding-bottom:var(--hs-s-3);
  border-bottom:1px solid var(--rule);
  font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(1.32rem,2.6vw,var(--hs-t-2));line-height:1.16;
  letter-spacing:-.015em;color:var(--fg);
}
.hs-menu__cn{
  margin:calc(var(--hs-s-4) * -1) 0 var(--hs-s-5);
  font-size:var(--hs-t--1);color:var(--fg-muted);max-width:var(--hs-measure);
}
.hs-menu__u{list-style:none;margin:0;padding:0;display:grid;gap:var(--hs-s-5)}
.hs-menu__i{display:grid;gap:var(--hs-s-1)}
.hs-menu__d{
  font-family:var(--hs-f-display);font-weight:500;font-size:var(--hs-t-1);
  line-height:1.25;letter-spacing:-.01em;color:var(--fg);
}
.hs-menu__x{font-size:var(--hs-t--1);color:var(--fg-muted);max-width:var(--hs-measure)}
.hs-menu__note{margin-top:var(--hs-s-7);font-size:var(--hs-t--1)}
@media (min-width:56rem){
  .hs-s--menu-list .hs-s__in{
    display:grid;grid-template-columns:.8fr 1.2fr;gap:var(--hs-s-8);align-items:start;
  }
  .hs-menu{margin-top:0}
  .hs-menu__head{position:sticky;top:calc(var(--hs-header-h) + var(--hs-s-6))}
  .hs-menu__note,.hs-s--menu-list .hs-facts__src{grid-column:2}
  /* The section's own grid gap already separates the note and the source from
     the courses above them; the mobile margin on top of it read as a hole. */
  .hs-menu__note{margin-top:0}
  /* Two columns of dishes once a course is long enough to want them, and the
     rule is the browser's rather than a breakpoint's: `columns` splits on
     content, so a three-item course stays one column and a twelve-item one
     does not run half a screen.

     `display:block` IS LOAD-BEARING, not tidiness. Multi-column layout does
     not apply to a grid container -- the `columns` declaration is simply
     dropped -- so the first version of this rule rendered one column and
     looked exactly like a rule that had been applied. Measured on the
     screenshot before it was believed. */
  .hs-menu__u{display:block;columns:2;column-gap:var(--hs-s-7)}
  .hs-menu__i{break-inside:avoid;margin-bottom:var(--hs-s-5)}
}

/* -------------------------------------------------------------- people grid
   Track FC's E10 -- five named people had to be scattered through `facts` rows
   because there was nowhere to put them. Role above, name below: the same card
   as `portfolio-named`, and the same reason, which is that a visitor looking
   for the professional is scanning for the JOB.

   THE CARD CARRIES A GROUND SHIFT WHETHER OR NOT IT CARRIES A FACE. Criterion
   16: zero border-only card groups. A club that has sent no portrait gets a
   type-only card with a body, not a bordered box. */
.hs-people__head{max-width:var(--hs-measure)}
.hs-people{list-style:none;margin:var(--hs-s-8) 0 0;padding:0;display:grid;gap:var(--hs-s-6)}
@media (min-width:34rem){ .hs-people{grid-template-columns:repeat(2,1fr)} }
@media (min-width:56rem){ .hs-people{grid-template-columns:repeat(3,1fr);gap:var(--hs-s-7)} }
.hs-people__i{
  margin:0;background:var(--hs-paper);border:1px solid var(--rule);
  border-radius:var(--hs-r-m);padding:var(--hs-s-6);box-shadow:var(--hs-sh-1);
  overflow:hidden;
}
.hs-z--paper .hs-people__i{background:var(--hs-paper-alt)}
.hs-z--paper-alt .hs-people__i{background:var(--hs-paper)}
/* The portrait bleeds to the card's edges -- the negative margins are the
   card's own padding -- so it reads as the card's ground surfacing rather than
   as a thumbnail pinned inside a box. Same device as `.hs-fig--bundle`. */
.hs-fig--portrait{
  margin:calc(var(--hs-s-6) * -1) calc(var(--hs-s-6) * -1) var(--hs-s-5);
  border-radius:var(--hs-r-m) var(--hs-r-m) 0 0;overflow:hidden;
}
.hs-fig--portrait img{width:100%;aspect-ratio:4/5;object-fit:cover;display:block}
.hs-person__r{
  margin:0 0 var(--hs-s-2);font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--sig);
}
.hs-person__n{
  margin:0;font-family:var(--hs-f-display);font-size:var(--hs-t-2);font-weight:500;
  line-height:1.14;letter-spacing:-.015em;color:var(--fg);
}
.hs-person__b{margin:var(--hs-s-4) 0 0;font-size:var(--hs-t--1);color:var(--fg-muted)}

/* ----------------------------------------------------------------- quote set
   Track FC's E7, and the defect is worth restating where the CSS lives: two
   testimonials went into `hold-statement`, which declared no `attribution`, and
   rendered WITH NO NAME AGAINST THEM. Every gate passed. An unattributed quote
   on a club's own site reads as copywriting.

   `name` and `source` are both required by the section, so this block never has
   to style an absent attribution. The source line is deliberately present and
   deliberately quiet: it is the same "named ON THE PAGE, not in a comment"
   convention `facts-band` and `hours-table` already set, and under a
   testimonial it is what separates a quote from a slogan.

   THE QUOTE MARK IS A PSEUDO-ELEMENT. Contract 3 rule 6, and it also keeps it
   out of `contrast_gate.mjs`'s element walk and out of `visible_text()`'s copy
   gate -- a glyph the manifest author did not write should not be able to trip
   a rule about words they did. */
.hs-quotes__head{max-width:var(--hs-measure)}
.hs-quotes{list-style:none;margin:var(--hs-s-8) 0 0;padding:0;display:grid;gap:var(--hs-s-7)}
@media (min-width:48rem){
  .hs-quotes{grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));gap:var(--hs-s-7)}
}
.hs-quote__i{margin:0}
/* THE ATTRIBUTIONS SIT ON ONE LINE ACROSS THE ROW. `1fr auto` pushes the
   caption to the bottom of every card regardless of how long its quote ran, so
   three names land on one baseline instead of three. It is the difference
   between a row of quotes and a row of boxes, and it costs one declaration. */
.hs-quote{
  margin:0;height:100%;display:grid;grid-template-rows:1fr auto;gap:var(--hs-s-5);
  border-top:1px solid var(--rule);padding-top:var(--hs-s-5);
}
.hs-quote__q{
  margin:0;font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(1.18rem,2.1vw,var(--hs-t-1));line-height:1.36;
  letter-spacing:-.012em;color:var(--fg);
}
.hs-quote__q p{margin:0}
.hs-quote__q p::before{content:"\201C";color:var(--sig)}
.hs-quote__a{display:grid;gap:var(--hs-s-1);align-content:end}
.hs-quote__n{font-size:var(--hs-t--1);font-weight:600;letter-spacing:.03em;color:var(--fg)}
.hs-quote__r{
  font-size:var(--hs-t--2);text-transform:uppercase;letter-spacing:.15em;color:var(--sig);
}
.hs-quote__s{font-size:var(--hs-t--2);color:var(--fg-muted)}

/* `hold-statement` can attribute a line now (E7, the other half). Same
   treatment as `.hs-deep__attrib`, so the two moments cannot start looking like
   different kinds of thing. */
.hs-hold__attrib{
  margin:var(--hs-s-5) 0 0;font-size:var(--hs-t--2);text-transform:uppercase;
  letter-spacing:.15em;color:var(--fg-muted);
}

/* ---------------------------------------------------------------------- cta */
.hs-cta{
  display:inline-flex;align-items:center;gap:.6em;
  min-height:var(--hs-tap);padding:0 var(--hs-s-6);margin-top:var(--hs-s-6);
  background:var(--hs-primary);color:var(--hs-primary-on);
  border-radius:var(--hs-r-m);text-decoration:none;
  font-weight:600;letter-spacing:.02em;box-shadow:var(--hs-sh-1);
  transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .22s;
}
.hs-cta--light{background:var(--hs-paper);color:var(--hs-ink)}
.hs-cta:hover{transform:translateY(-2px);box-shadow:var(--hs-sh-2)}
.hs-cta:active{transform:translateY(0)}
.hs-cta__a{transition:transform .22s cubic-bezier(.2,.8,.2,1)}
.hs-cta:hover .hs-cta__a{transform:translateX(3px)}
.hs-cta-slot{margin-top:var(--hs-s-6)}

/* ------------------------------------------------------------- unresolved
   What a --demo build renders where a client fact belongs. Deliberately
   unmistakable: an invented phone number that LOOKS real is the failure this
   is preventing, so this must never look like content. */
.hs-unresolved{
  display:inline-block;font-family:var(--hs-f-body);font-size:var(--hs-t--1);
  font-weight:600;letter-spacing:.02em;
  color:var(--fg);
  /* A SOLID TINT, NOT A HATCH, and the reason is the contrast gate rather than
     taste. A repeating-linear-gradient is a background IMAGE, and text on an
     image is a ratio no audit can resolve -- it gets reported UNRESOLVED, which
     is the exact blind spot that let the Meridian showpiece ship white on white
     through four revision passes. The dashed border already says "not real
     content"; the stripes only cost the page its measurability.
     With this, NO text on this surface sits on an image, which is a property
     the gate asserts rather than a habit. */
  background-color:color-mix(in srgb, var(--sig) 12%, var(--bg));
  border:1px dashed var(--sig);border-radius:var(--hs-r-s);
  padding:.35em .7em;line-height:1.35;
}

/* ---------------------------------------------------------------- final-cta
   CENTRED FOR REAL, 2026-09-02. The layout is declared "centred" and only the
   heading obeyed it: `.hs-h--deep` centres itself with margin-inline:auto
   while the eyebrow, the body and the CTA stayed on the left gutter -- a
   centred line floating over a left-set column, which reads as a defect on
   the one section every page ends on. The whole close centres now; the body
   keeps its measure and gains the auto margins the heading already had. */
.hs-s--final-cta .hs-s__in{text-align:center;max-width:var(--hs-mid)}
.hs-s--final-cta .hs-body{margin-inline:auto}
/* The page's last word carries the lead step, not the default. Measured beside
   the recomposed footer: a 50px close over a 67px footer wordmark read
   upside-down. This is a rendered size only -- it stamps no data-level, so the
   one-statement-per-page count in compose_page is untouched. */
.hs-s--final-cta .hs-h{font-size:clamp(2.2rem,6.2vw,var(--hs-t-5));line-height:1.02;letter-spacing:-.026em}

/* ------------------------------------------------------------------- footer */
/* RECOMPOSED 2026-09-02: the footer rendered as one thin row -- a 21px name,
   four links and two lines of licence text -- which is the last thing a GM
   sees and it read as an afterthought. Same markup, restyled: the wordmark is
   set at display scale as the page's sign-off, the navigation sits under a
   hairline the way every table on this surface rules its rows, and the
   attribution keeps its size and its licence text untouched. */
.hs-footer{
  background:var(--hs-pine);color:var(--hs-ink-on-pine);
  padding:var(--hs-s-9) var(--hs-gutter) var(--hs-s-7);
  --fg:var(--hs-ink-on-pine);--fg-muted:var(--hs-ink-muted-on-pine);
  --sig:var(--hs-accent-on-pine);--rule:var(--hs-accent-on-pine);
}
.hs-footer__b{
  max-width:var(--hs-wide);margin:0 auto var(--hs-s-7);
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--hs-s-6);
}
.hs-footer__n{
  margin:0;font-family:var(--hs-f-display);font-weight:500;
  font-size:clamp(2rem,4.6vw,var(--hs-t-5));line-height:1;letter-spacing:-.025em;
}
.hs-footer__u{
  display:flex;flex-wrap:wrap;gap:var(--hs-s-2) var(--hs-s-6);list-style:none;margin:0;padding:0;
  width:100%;padding-top:var(--hs-s-5);
  border-top:1px solid color-mix(in srgb, var(--hs-ink-on-pine) 24%, transparent);
}
.hs-footer__u a{display:inline-flex;align-items:center;min-height:var(--hs-tap)}
/* Criterion 25, appended cycle 2: the footer's contact actions -- the phone
   and the mailbox -- carry weight the page links do not, the way Bandon's
   Contact column and Sand Valley's address row separate reaching the club
   from browsing the site. */
.hs-footer__u a[href^="tel:"],.hs-footer__u a[href^="mailto:"]{
  font-weight:600;font-variant-numeric:tabular-nums;
}
/* ODbL is a licence condition, not chrome. It survives every layout change. */
.hs-attrib,.hs-footer__c{
  max-width:var(--hs-wide);margin:0 auto;font-size:var(--hs-t--2);
  color:var(--hs-ink-muted-on-pine);line-height:1.6;
}
.hs-footer__c{margin-top:var(--hs-s-4)}

/* -------------------------------------------------------------- sticky bar
   Aman pins Reserve to the bottom of the phone viewport, full width. Third
   sighting in the swipe library and the most reliable mobile pattern in it.
   It is present at first paint and it does not animate -- there is no
   animation between the visitor and the one decision this page offers. */
.hs-sticky{
  position:fixed;left:0;right:0;bottom:0;z-index:50;
  display:flex;align-items:center;justify-content:center;gap:var(--hs-s-4);
  min-height:var(--hs-sticky-h);
  padding:var(--hs-s-2) var(--hs-gutter) calc(var(--hs-s-2) + env(safe-area-inset-bottom,0px));
  background:var(--hs-primary);border-top:1px solid var(--hs-line-strong);
}
.hs-sticky__c{
  display:flex;align-items:center;justify-content:center;
  width:100%;min-height:var(--hs-tap);
  color:var(--hs-primary-on);text-decoration:none;
  font-weight:600;letter-spacing:.04em;font-size:var(--hs-t--1);
  text-transform:uppercase;
}
/* THE CALL SLOT -- criterion 24, appended cycle 2. The references keep call
   and book reachable at every scroll depth on a phone; this is the bar's
   second seat for the pro-shop tel. The render half lives in
   build_site.py::render_sticky (chrome is not this track's territory -- the
   queued edit in track-nav-status.md is what emits .hs-sticky__t), so these
   rules are dormant until it lands. Same ink pair as the primary slot, so no
   new ground for the contrast gate; the underline is what separates the two
   actions. When the tel slot renders, the primary gives up full width. */
.hs-sticky__t{
  display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  min-height:var(--hs-tap);padding-inline:var(--hs-s-4);
  color:var(--hs-primary-on);
  text-decoration:underline;text-underline-offset:.3em;text-decoration-thickness:1.5px;
  font-weight:600;letter-spacing:.04em;font-size:var(--hs-t--1);
  text-transform:uppercase;white-space:nowrap;
}
.hs-sticky__t + .hs-sticky__c,.hs-sticky__c:has(+ .hs-sticky__t){width:auto;flex:1 1 auto}
.hs-sticky .hs-unresolved{
  color:var(--hs-primary-on);border-color:var(--hs-primary-on);
  background-color:color-mix(in srgb, var(--hs-primary-on) 12%, var(--hs-primary));
}

/* The chrome variant of the placeholder marker. One line, ellipsised, sized to
   fit a fixed-height bar. It keeps the same class and the same data attribute,
   so the gate that counts unresolved facts counts these too. */
.hs-unresolved--chip{
  display:inline-flex;align-items:baseline;gap:.5em;
  max-width:min(22rem,54vw);white-space:nowrap;overflow:hidden;
  font-size:var(--hs-t--2);padding:.3em .6em;
}
/* De-emphasised by MIXING TOWARD THE GROUND, never by opacity. Translucent text
   is text the gates cannot resolve a contrast for, and the no-script pass reads
   any resting opacity below 1 as an entrance that never fired. Both are correct
   to complain; the fix is an opaque colour. */
.hs-unresolved__n{
  font-weight:400;font-size:.86em;letter-spacing:.06em;text-transform:uppercase;
  color:color-mix(in srgb, currentColor 72%, var(--bg));
  overflow:hidden;text-overflow:ellipsis;
}
.hs-nav__cta--unresolved{background:none;box-shadow:none;padding:0;color:inherit}
.hs-nav__cta--unresolved:hover{transform:none;box-shadow:none}
@media (min-width:56rem){ .hs-sticky{display:none} }

/* ------------------------------------------------------- reduced motion
   site.js never constructs Lenis, kills every ScrollTrigger and never assigns
   the film's src -- the bytes are not requested, not fetched-and-paused. This
   block is the CSS half: no transition anywhere, and nothing to un-hide,
   because nothing was hidden in CSS in the first place. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;
  }
  .hs-rise__i,.hs-drift,.hs-rail__track,.hs-hero__frame{transform:none!important;will-change:auto}
  /* hold-statement is CSS-only, so reduced motion changes nothing about it: a
     sticky line is not an animation, it is a position. It keeps working with the
     script blocked too, which is the argument for sticky over a pin. */
  /* The bridge is never constructed under reduced motion -- site.js returns
     before it -- so it rests as a solid band of its own zone ground. Nothing to
     un-hide and nothing mid-tween, which is the property that makes it legal. */
  .hs-rail__vp{overflow-x:auto;scroll-snap-type:x mandatory}
}

@media print{
  .hs-sticky,.hs-header{display:none}
  .hs-faq__i{border:0}
}
