/* ==========================================================================
   The 801 — lounge.the801lr.com
   Design prototype stylesheet. Plain CSS, custom properties, mobile-first.
   No external font, no external stylesheet, no CSS-in-JS. CSP-safe:
   style-src 'self' · img-src 'self' data: · script-src 'self'.

   TOKENS: a shared token session runs in parallel at design/00-system/.
   Everything this file assumes lives in the ONE :root block below. If the
   shared names differ, only that block changes — nothing below it refers to
   a literal colour, size or font.
   ========================================================================== */

:root {
  /* --- colour ------------------------------------------------------------ */
  --color-ink:            #1a1613;  /* deepest brown-black: the dark shell   */
  --color-ink-raised:     #241f1a;  /* raised surface on dark                */
  --color-ink-line:       #3b322a;  /* hairline on dark                      */

  /* DARK-DOMINANT. The announcement posters carry no light surface at all,
     and the cream band was the only reason the accent had to degrade to a
     bronze (#7a530f) to stay legible. Removing it lets the accent carry every
     role at full strength — copper cu300 since 2026-10-02, the gold before
     that. "paper" keeps its name — it is still the alternating band, it is
     simply no longer light.                                                 */
  --color-paper:          #241f1a;  /* the band            — text 14.41:1    */
  --color-paper-sunken:   #2b2520;  /* inset panels        — text 13.35:1    */
  --color-field:          #1a1613;  /* input + choice wells — text 15.87:1   */
  --color-line:           #3b322a;  /* decorative hairline on dark           */
  --color-line-strong:    #8d8070;  /* control borders — 4.24 band, 3.93 sunken */
  --color-placeholder:    #a89c90;  /* 6.70:1 in a field. Was a hardcoded
                                       #7a6e64, which measures 3.63 here.   */

  --color-text:           #f6f0e7;  /* 14.41:1 on the band                   */
  --color-text-muted:     #c2b6a6;  /*  8.19:1 on the band                   */
  --color-on-dark:        #f6f0e7;  /* 15.87:1 on ink (file said 17.3)       */
  --color-on-dark-muted:  #c2b6a6;  /*  9.02:1 on ink (file said 9.09)       */

  /* Copper, not gold, from 2026-10-02. This retires the gold that was sampled
     from the client's announcement posters (n=28,866 masked pixels, median
     hue 38.4°, median saturation 37.5%) and adopts the property-wide
     oxblood/copper pair instead, so the lounge, the hall and the apex read as
     one address rather than three tenants. The lounge is the DARK-surface
     skin, so it takes the light end of the copper ramp: cu300 at rest, cu200
     on hover and focus. Every figure below is computed against the surface it
     names, with the WCAG 2.x relative-luminance formula.

     THE HEX LITERALS ARE DELIBERATE. This stylesheet is standalone — every
     page in 02-lounge/ links `assets/styles.css` and nothing else, so no
     --c-* primitive from design/00-system/tokens.css is in scope at runtime.
     `var(--c-cu300)` would resolve to NOTHING in the browser and still pass
     check.js, which concatenates the whole design/ tree before testing that
     every var() resolves. Mirror the primitives by value, name them in the
     comment, and never reference them from here.                           */
  --color-accent:         #efb46f;  /* copper cu300 — fills and text ON DARK only.
                                       8.89 band · 8.23 sunken · 9.78 field   */
  --color-accent-soft:    #f6d3a8;  /* copper cu200 — hover, focus on dark.
                                       11.51 band · 10.66 sunken · 12.67 field */
  --color-accent-ink:     #efb46f;  /* no light surface remains, so this is
                                       simply the copper — 8.89 on the band.
                                       Kept as a name because components
                                       reference it.                        */
  --color-accent-wash:    #2f2721;  /* copper-tinted dark panel — copper 7.97:1 */
  --color-on-accent:      #1a1613;  /* text ON the copper fill - 9.78:1.
                                       NOT --color-ink: that token is also a
                                       SURFACE and print remaps it to white,
                                       which printed button labels at 1.00:1 */

  /* DEFECT 1, FIXED 2026-10-02 — the invisible structural rule.
     --color-rule was #1a1613, and it has exactly two uses in this file: the
     2px border of .pay, the box holding the auto-renewal disclosure and its
     affirmative acknowledgement, and the .submit-block top rule, where the
     renewal terms are restated at the point of assent. Both sit on #241f1a
     on BOTH sides — .pay fills with --color-paper, and apply.html's .section
     carries no band class, so body's --color-paper is behind it too. So the
     border measured 1.10:1: it painted, and nobody could see it.

     PRE-EXISTING — NOT WIDENED BY THE PALETTE. Neither colour in that pair
     is an accent, so #1a1613 on #241f1a measured 1.10:1 under the retired
     gold exactly as it does under the copper. (Defect 2, in the @media print
     block at the foot of this file, is the opposite case: the palette did
     widen that one, from 2.44 to 1.72.)

     NOT OVERCLAIMED AS A CONFORMANCE FAILURE. A purely decorative border is
     exempt from SC 1.4.11, and nothing here has to be seen for the form to
     be operated. The argument is narrower and does not need the SC: a rule
     this file itself calls load-bearing for a disclosure that auto-renewal
     statutes want CONSPICUOUS cannot be one that is invisible.

     WHY cu300, AND NOT EITHER OTHER MEASURED CANDIDATE.
       --color-line-strong  4.24:1 — clears 3:1, but it is the ORDINARY
         control border (inputs, .consents, .agree, .card-mount,
         .turnstile-slot), so .pay would read as more chrome. Conspicuous is
         a relative property; this makes the box indistinguishable from the
         fields around it. (4.24 is the figure this file already publishes
         for line-strong on the band, and it is the one that reproduces;
         a 4.38 asserted for this pair elsewhere is not reachable on any
         surface this file holds.)
       --color-text        14.41:1 — the loudest edge on the page, louder
         than the .renewal notice INSIDE it (--color-notice-ink, 7.99:1).
         That inverts the hierarchy and turns the whole application form
         into an alert, and a 2px rule in the body-text cream reads as a
         text element rather than as structure.
       --color-accent       8.89:1 — chosen. Unmistakable, and already this
         file's structural-emphasis border (.panel--accent, .amenity,
         .choice:has(input:checked)), so it introduces no new vocabulary.
         It also leaves the alarm register to the notice salmon: copper
         says "this block matters", salmon says "read this specifically".
         Hue carries the hierarchy, not the ratio alone.
     Every figure above was computed with the WCAG 2.x relative-luminance
     formula against the surface named, and the method was checked by
     reproducing the ratios this file already publishes for the colours the
     fix does not touch.                                                    */
  --color-rule:           #efb46f;  /* copper cu300 — 8.89:1 on the band.
                                       Still NOT --color-ink: that token is
                                       a SURFACE and print remaps it to
                                       white. Print remaps this name on its
                                       own, to #221d18 — 16.71:1 on paper. */

  --color-notice-ink:     #ff9a90;  /* 7.99 on band · 7.73 on notice-wash    */
  --color-notice-wash:    #2e1f1c;  /* body text on it 13.95:1               */
  --color-good-ink:       #7ee2a8;  /* 10.37 on band                         */
  --color-good-wash:      #202e25;  /* good text on it 9.01:1                */

  /* Both focus tokens now target a dark surface; the -light/-dark pair is
     kept so no component has to change.                                     */
  --color-focus-light:    var(--color-accent-soft);
  --color-focus-dark:     var(--color-accent-soft);

  /* --- type --------------------------------------------------------------
     Cinzel for display and Hanken Grotesk for body, both self-hosted from
     /assets/fonts/ (SIL OFL 1.1; see the end of this file). Nothing here loads
     a font from another site.                                              */
  --font-display: "Cinzel", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --font-body:    "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --text-xs:   0.75rem;
  --text-sm:   0.875rem;
  --text-base: 1rem;
  --text-lg:   1.0625rem;
  --text-xl:   1.25rem;
  --display-s: clamp(1.5rem,  1.1rem + 2.0vw, 2.15rem);
  --display-m: clamp(2rem,    1.4rem + 3.0vw, 3.1rem);
  --display-l: clamp(2.6rem,  1.6rem + 5.0vw, 4.6rem);

  --tracking-caps: 0.16em;
  --leading-tight: 1.12;
  --leading-body:  1.62;

  /* --- space, shape ------------------------------------------------------ */
  --space-1: 0.25rem;  --space-2: 0.5rem;   --space-3: 0.75rem;
  --space-4: 1rem;     --space-5: 1.5rem;   --space-6: 2rem;
  --space-7: 2.75rem;  --space-8: 4rem;     --space-9: 6rem;

  --radius-sm: 2px;
  --radius-md: 3px;
  --measure: 34rem;         /* single-column reading + form width */
  --page-max: 68rem;
  --gutter: 1.25rem;
  --tap: 2.75rem;           /* 44px minimum target */
}

/* ==========================================================================
   Base
   ========================================================================== */

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

/* The page is dark throughout, so the UA must be told — otherwise the native
   select arrow and the date-picker glyph render black-on-dark and any popup
   opens white. */
html { -webkit-text-size-adjust: 100%; color-scheme: dark; }

/* WCAG 2.2 SC 2.4.11 Focus Not Obscured (Minimum), Level AA.
   .site-header is position:sticky, so a control reached by shift-tab from
   below is scrolled flush to the top of the viewport and lands UNDERNEATH it.
   Measured before the fix: "member area" was 21px tall and 21px covered —
   fully hidden. The header is content-sized and wraps its nav, so it is
   117px at 1024px but 165px at 600px and below; 11rem (176px) clears the
   taller case with slack. Scroll padding only shifts scroll-into-view
   positioning, so the surplus at wide viewports costs nothing.
   Remove this ONLY if .site-header stops being sticky.                     */
@media (min-width: 768px) {
  html { scroll-padding-top: 11rem; }
}

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-text);
  font: var(--text-base)/var(--leading-body) var(--font-body);
}

img { display: block; max-width: 100%; height: auto; }

h1, h2, h3, h4 {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: -0.015em;
}
h1 { font-size: var(--display-m); }
h2 { font-size: var(--display-s); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); letter-spacing: 0; }

p, ul, ol, dl, table { margin: 0 0 var(--space-4); }
li { margin-bottom: var(--space-2); }

a { color: var(--color-accent-ink); text-underline-offset: 0.22em; }
a:hover { color: var(--color-text); }

strong, b { font-weight: 650; }

hr {
  height: 0; margin: var(--space-7) 0;
  border: 0; border-top: 1px solid var(--color-line);
}

:focus-visible {
  outline: 3px solid var(--color-focus-light);
  outline-offset: 2px;
}
.on-dark :focus-visible, .gate :focus-visible, .site-header :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--color-focus-dark);
}

/* THE SAME CASCADE TRAP notice.css DOCUMENTS FOR `color`, ONE PROPERTY OVER.
   FIXED 2026-10-02, measured in Chrome on the built page.

   build-site.js injects a LIGHT panel — p.form-notice, background #f4ece0 from
   the generated notice.css — into the dark age gate, and the rule directly
   above assumes everything inside .gate sits on a dark surface. It does not:
   the focus ring on the notice's phone link measured #f6d3a8 on #f4ece0 =
   1.21:1. That is the identical ratio, the identical cause and the identical
   control as the text-colour bug notice.css fixed with p.form-notice
   a:not(.btn); that fix set `color` and left `outline-color` on the dark token,
   so the link reads at 10.70:1 and its focus ring was still invisible. When
   this was written every form in the build was disabled, so that number was the
   only working contact route on the first page of the lounge, and a keyboard user
   could not see where focus was. (The gate's form is enabled now and carries no
   notice, so this rule currently matches nothing on a shipped page; it stays for
   any page that gets one.)

   WHY HERE AND NOT IN notice.css. notice.css is generated by build-site.js and
   is not this agent's to edit. It is also the better long-term home — it owns
   the panel and knows its background, and it loads over three design systems —
   but .gate :focus-visible is THIS file's rule and it is the one that is too
   broad, so narrowing it here is correct rather than merely expedient. It also
   covers any future lounge page that gets a notice injected, not just the gate.

   SPECIFICITY, NOT LOAD ORDER. p.form-notice :focus-visible is (0,2,1) and
   beats .gate :focus-visible (0,2,0) OUTRIGHT. notice.css happens to be
   injected last, and — as that file's own comment puts it — "happens to" is
   not a contrast guarantee.

   #5c2018 is the colour notice.css already gives this link's text: 10.70:1 on
   #f4ece0, reproduced here rather than taken on trust. A literal, because the
   panel's #f4ece0 is a notice.css literal and no token in this file tracks it. */
p.form-notice :focus-visible { outline-color: #5c2018; }

/* 2.4.11 Focus Not Obscured — anchored targets clear the sticky header */
[id] { scroll-margin-top: 5rem; }

.skip-link {
  position: absolute; left: var(--space-4); top: -6rem; z-index: 60;
  padding: var(--space-3) var(--space-4);
  background: var(--color-paper); color: var(--color-text);
  border: 2px solid var(--color-accent-ink);
}
.skip-link:focus { top: var(--space-3); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ==========================================================================
   Layout
   ========================================================================== */

.wrap {
  width: 100%; max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: calc(var(--measure) + (var(--gutter) * 2)); }

.section { padding-block: var(--space-7); }
@media (min-width: 48em) { .section { padding-block: var(--space-8); } }

.band-dark {
  background: var(--color-ink);
  color: var(--color-on-dark);
}
.band-dark h1, .band-dark h2, .band-dark h3 { color: var(--color-on-dark); }
/* :not(.btn) matters — without it this rule outranks .btn and repaints a
   solid copper button's label copper-on-copper: cu200 on a cu300 fill is
   1.30:1. (The 1.65 this comment used to assert was not reproducible against
   any accent pair the file has held — gd300 on gd400 computes to 1.52.) */
.band-dark a:not(.btn) { color: var(--color-accent-soft); }
.band-sunken { background: var(--color-paper-sunken); }

.lede {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: 1.45;
  max-width: var(--measure);
}

.eyebrow {
  margin-bottom: var(--space-3);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--color-accent-ink);
}
.band-dark .eyebrow, .gate .eyebrow { color: var(--color-accent); }

.muted { color: var(--color-text-muted); }
.band-dark .muted { color: var(--color-on-dark-muted); }
.small { font-size: var(--text-sm); }

.ornament {
  width: 8.5rem; height: auto; margin: var(--space-5) 0;
  opacity: 0.95;
}
.ornament--center { margin-inline: auto; }

/* The art-deco fans: a generated abstract illustration (assets/README.md says where it came from),
   amber lines on near-black, used as a band at the head of the gate and of the landing page.
   Decoration only (alt=""), and no text ever sits over it. The foot fades out with a mask, so the
   band melts into whatever dark surface is behind it: the gate's own gradient, or .band-dark. */
.fans {
  display: block;
  flex: none;
  width: 100%;
  height: 7rem;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
  mask-image: linear-gradient(to bottom, #000 55%, transparent);
}
@media (min-width: 48em) { .fans { height: 11rem; } }

/* ==========================================================================
   Brand lockup
   ========================================================================== */

.lockup { display: block; text-align: center; text-decoration: none; color: inherit; }
.lockup__name {
  display: block;
  font-family: var(--font-display);
  font-size: var(--display-l);
  line-height: 0.95;
  letter-spacing: 0.02em;
}
.lockup__the {
  display: block;
  font-size: var(--text-xs);
  letter-spacing: 0.55em;
  text-indent: 0.55em;
  text-transform: uppercase;
  color: var(--color-accent);
}
.lockup__descriptor {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--color-on-dark-muted);
}

/* ==========================================================================
   Header / footer
   ========================================================================== */

/* Sticky ONLY from 768px, where the nav fits one row and the header measures
   116.7px. Below that it wraps — 164.7px at 414px, 212.7px at 320px — and a
   sticky header there both re-introduces SC 2.4.11 (two links on member.html
   were fully hidden at 320px) and eats 27% of the viewport. Static below is
   the fix; see the scroll-padding note at the top of this file. */
@media (min-width: 768px) {
  .site-header { position: sticky; top: 0; z-index: 40; }
}

.site-header {
  background: var(--color-ink);
  color: var(--color-on-dark);
  border-bottom: 1px solid var(--color-ink-line);
}
.site-header__bar {
  display: flex; align-items: center; gap: var(--space-4);
  min-height: 3.75rem;
}
.site-header__brand {
  margin-right: auto;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-on-dark);
}
.site-header__brand span { color: var(--color-accent); }

.site-nav ul {
  display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4);
  margin: 0 0 var(--space-3); padding: 0; list-style: none;
}
.site-nav li { margin: 0; }
.site-nav a {
  display: flex; align-items: center; min-height: var(--tap);
  padding-block: var(--space-1);
  color: var(--color-on-dark-muted);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  text-decoration: none;
}
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--color-accent-soft); }
.site-nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: 0.4em; }

@media (min-width: 56em) {
  .site-header__bar { min-height: 4.5rem; }
  .site-nav ul { margin-bottom: 0; }
}

.site-footer {
  background: var(--color-ink);
  color: var(--color-on-dark-muted);
  padding-block: var(--space-7);
  font-size: var(--text-sm);
}
.site-footer h2 { font-size: var(--text-lg); color: var(--color-on-dark); }
.site-footer a:not(.btn) { color: var(--color-accent-soft); }
.site-footer__grid { display: grid; gap: var(--space-6); }
@media (min-width: 48em) {
  .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr; }
}
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: var(--space-2); }
.site-footer__fine {
  margin-top: var(--space-6); padding-top: var(--space-4);
  border-top: 1px solid var(--color-ink-line);
  font-size: var(--text-xs);
}
/* Lauren's website widget (build-site.js puts lauren-widget-page on <body> of /lounge/welcome only; design/ never has it).
   It is the same widget as Zoe's (same bundle, same zoe-widget.js), so its card is fixed to the bottom right and stands
   156px above the bottom of the viewport (measured on Zoe's at 375, 768 and 1280px; the same card here is UNMEASURED
   until the live check). Scrolled to the end it would cover the legal line and the "Powered by" credit, so the footer
   gets 160px more room at its foot. Unlike Zoe's pages there is no width at which it is clear: .site-footer__fine runs
   the whole 68rem wrap, so on a desktop its text can still run under the card's corner (by layout, not measured). Nothing else on this page is
   fixed or sticky at the bottom (.site-header is sticky at the TOP only). */
.lauren-widget-page .site-footer { padding-bottom: calc(var(--space-7) + 160px); }

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap); min-width: var(--tap);
  padding: var(--space-3) var(--space-6);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-on-accent);
  font: 700 var(--text-sm)/1.2 var(--font-body);
  letter-spacing: 0.1em; text-transform: uppercase; text-decoration: none;
  cursor: pointer;
}
.btn:hover { background: var(--color-accent-soft); border-color: var(--color-accent-soft); color: var(--color-on-accent); }
.btn--block { display: flex; width: 100%; }
/* A button the member page hides until it applies (the member area offers a new card only after a missed payment): .btn's display would otherwise win over [hidden]. */
.btn[hidden], .btn-row[hidden] { display: none; }
.btn--quiet {
  background: transparent; color: var(--color-text);
  border-color: var(--color-line-strong);
}
.btn--quiet:hover { background: var(--color-paper-sunken); color: var(--color-text); }
/* .site-header belongs in this list: it is a dark surface but not .band-dark,
   and without it a quiet button's dark label lands on dark ink at 1.08:1. */
.band-dark .btn--quiet, .gate .btn--quiet, .site-header .btn--quiet,
.site-footer .btn--quiet { color: var(--color-on-dark); border-color: var(--color-on-dark-muted); }
.band-dark .btn--quiet:hover, .gate .btn--quiet:hover, .site-header .btn--quiet:hover,
.site-footer .btn--quiet:hover { background: var(--color-ink-raised); color: var(--color-on-dark); }
.btn--lg { padding-block: var(--space-4); font-size: var(--text-base); }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

/* ==========================================================================
   Cards, panels, lists
   ========================================================================== */

.panel {
  padding: var(--space-5);
  background: var(--color-paper);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-md);
}
.panel--sunken { background: var(--color-paper-sunken); border-color: var(--color-line); }
.panel--accent {
  background: var(--color-accent-wash);
  border: 1px solid var(--color-accent-ink);
  border-left-width: 5px;
}
.panel > :last-child { margin-bottom: 0; }

/* Lauren's card (owner 2026-10-30, keys 410, 411 and 448, and the client's decision to move forward with Lauren alone):
   named, labelled "Your host at The 801 Social Lounge" now that the lounge line and the website widget are live (it said
   "Coming soon" until 2026-11-06), and shown at the top right of the welcome page's hero band
   (448: the right half of that band was empty). The picture is a transparent cutout of her standing on the arch, which is
   the accent colour (copper) and nothing else: no room, no scenery. The arch is sized by one variable so its curve is a
   true half circle (radius = half the width). She is a tall, narrow figure, so the picture is sized by its HEIGHT (a
   multiple of the arch width) and centred, which keeps her head inside the curve at every width. The picture is
   meaningful, so it has real alt text (see welcome.html); the card carries one call link, the lounge line. On a phone the
   hero stacks and the card follows the buttons; from 56em it sits to the right of the text. */
.hero-grid { display: grid; gap: var(--space-6); align-items: center; }
.hero-grid__text > :last-child { margin-bottom: 0; }
@media (min-width: 56em) {
  .hero-grid { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: var(--space-7); }
}
.lauren-card { --arch: 14rem; display: grid; justify-items: center; gap: var(--space-4); break-inside: avoid; text-align: center; }
.lauren-card h2, .lauren-card h3, .lauren-card p { margin: 0; }
.lauren-card__arch {
  width: var(--arch); box-sizing: border-box;
  padding: calc(var(--arch) * 0.2) 0 0;
  background: var(--color-accent);
  border-radius: calc(var(--arch) / 2) calc(var(--arch) / 2) 0 0;
}
.lauren-card__pic { display: block; width: auto; max-width: 100%; height: calc(var(--arch) * 1.4); margin: 0 auto; }
.lauren-card__text { display: grid; gap: var(--space-2); justify-items: center; max-width: 24rem; }
.lauren-card__role {
  font-size: var(--text-xs); font-weight: 700; letter-spacing: var(--tracking-caps);
  text-transform: uppercase; color: var(--color-accent);
}
.lauren-card__name { font-size: var(--text-xl); }
/* The number is the whole line, so it gets the 44px floor every standalone link has (see "THE 44px FLOOR" below). */
.lauren-card__tel > a { display: inline-flex; align-items: center; min-height: var(--tap); }
@media (min-width: 40em) {
  .lauren-card { --arch: 18rem; }
}
@media (min-width: 56em) {
  .lauren-card { --arch: 20rem; }
}

.stack > * + * { margin-top: var(--space-5); }
.grid { display: grid; gap: var(--space-5); }
@media (min-width: 40em) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 56em) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }

/* The six photographs on the members' welcome page (behind the age gate): side by side from 56em, stacked below. */
.lounge-photo { margin: 0; }
.lounge-photo img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--color-line); border-radius: var(--radius-sm);
}

.amenity { border-top: 2px solid var(--color-accent-ink); padding-top: var(--space-4); }
.amenity h3 {
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 700;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  margin-bottom: var(--space-2);
}
.amenity p { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); }

.rule-list { list-style: none; margin: 0; padding: 0; counter-reset: rule; }
.rule-list > li {
  counter-increment: rule;
  padding: var(--space-4) 0 var(--space-4) 3rem;
  border-bottom: 1px solid var(--color-line);
  position: relative;
}
.rule-list > li::before {
  content: counter(rule, decimal-leading-zero);
  position: absolute; left: 0; top: var(--space-4);
  font-family: var(--font-display); font-size: var(--text-lg);
  color: var(--color-accent-ink);
}
.rule-list h3 { font-size: var(--text-lg); margin-bottom: var(--space-2); }
.rule-list p:last-child { margin-bottom: 0; }

/* The one number the lounge quotes. */
.dues { display: flex; align-items: baseline; gap: var(--space-2); font-family: var(--font-display); }
.dues__amount { font-size: var(--display-m); line-height: 1; color: var(--color-accent-ink); }
.dues__unit { font-family: var(--font-body); font-size: var(--text-sm); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--color-text-muted); }

/* The price shown as its parts, the total last (owner, 2026-10-08): the membership with its unit,
   the maintenance fee under it, and what they come to. The three lines are one block so the build's
   figure gate (BREAKDOWN in build-site.js) reads them as the one statement they are. */
.price { display: grid; gap: var(--space-2); max-width: 22rem; }
.price > * { margin: 0; }
.price__plus { font-family: var(--font-display); font-size: var(--text-lg); }
.price__total {
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-line);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--color-accent-ink);
}

/* ==========================================================================
   Tables
   ========================================================================== */

.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
caption {
  text-align: left; padding-bottom: var(--space-3);
  font-weight: 700; font-size: var(--text-sm);
}
th, td {
  padding: var(--space-3);
  text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--color-line);
}
thead th {
  border-bottom: 2px solid var(--color-line-strong);
  font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
}
tbody th { font-weight: 600; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   Forms — single column, always
   ========================================================================== */

fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
legend { display: block; width: 100%; padding: 0; }

.form { max-width: var(--measure); }
.form fieldset { margin-bottom: var(--space-7); }
.form legend {
  margin-bottom: var(--space-2);
  font-family: var(--font-display); font-size: var(--display-s);
}
/* a legend that is just a field label, not a section heading */
.legend--plain {
  margin-bottom: var(--space-3);
  font-family: var(--font-body); font-size: var(--text-base); font-weight: 650;
}
.form__step {
  display: block;
  font-family: var(--font-body); font-size: var(--text-xs); font-weight: 700;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--color-accent-ink);
  margin-bottom: var(--space-2);
}
.form__hint { margin-bottom: var(--space-5); color: var(--color-text-muted); font-size: var(--text-sm); }

.field { margin-bottom: var(--space-5); }
.field > label, .field__label {
  display: block; margin-bottom: var(--space-2); font-weight: 650;
}
/* A contact field's own message, filled in when the person leaves the field (assets/apply.js). Empty takes no room. */
.field__error { display: block; margin-top: var(--space-2); font-size: var(--text-sm); color: var(--color-notice-ink); }
.field__error:empty { display: none; }
.apply-error { margin-bottom: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-notice-ink); border-radius: var(--radius-sm); color: var(--color-notice-ink); font-weight: 600; }

.field__help {
  margin: 0 0 var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted);
}
.req { color: var(--color-notice-ink); font-weight: 700; }
.opt { color: var(--color-text-muted); font-weight: 400; font-size: var(--text-sm); }

input[type="text"], input[type="email"], input[type="tel"],
input[type="number"], input[type="password"], textarea, select {
  display: block; width: 100%;
  min-height: var(--tap);
  padding: var(--space-3);
  font: var(--text-base)/1.4 var(--font-body);
  color: var(--color-text);
  background: var(--color-field);
  border: 1px solid var(--color-line-strong);
  border-radius: var(--radius-sm);
}
textarea { min-height: 6rem; resize: vertical; }
input::placeholder { color: var(--color-placeholder); }

/* date of birth — three parts, never a single date picker */
.dob { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.dob > div { flex: 0 0 auto; }
.dob label {
  display: block; margin-bottom: var(--space-2);
  font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase;
  font-weight: 700;
}
.dob input { width: 4.25rem; text-align: center; font-variant-numeric: tabular-nums; }
.dob input.dob__year { width: 6rem; }
/* On the gate the month and the day are lists, so a visitor can pick only a real month and a
   day from 1 to 31; the year is typed. A date that does not exist (31 February) is still
   refused by the server. The widths fit "September" and "31" at the gate's size, and the
   row wraps rather than overflowing on a narrow screen. */
.dob select { width: 9.5rem; }
.dob select.dob__day { width: 6rem; }

/* choice rows: radio and checkbox share one control style */
.choice-set { display: grid; gap: var(--space-3); }
.choice {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3);
  align-items: start;
  padding: var(--space-4);
  border: 1px solid var(--color-line-strong);
  border-radius: var(--radius-md);
  background: var(--color-field);
  cursor: pointer;
}
.choice:hover { background: var(--color-paper-sunken); }
/* The card page (/lounge/card) hides a plan the member is not offered: .choice's display would otherwise win over [hidden]. */
.choice[hidden] { display: none; }
.choice__title { display: block; font-weight: 650; }
.choice__meta { display: block; margin-top: var(--space-1); font-size: var(--text-sm); color: var(--color-text-muted); }

input[type="checkbox"], input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  flex: 0 0 auto;
  width: 1.5rem; height: 1.5rem; margin: 0.1rem 0 0;
  border: 2px solid var(--color-line-strong);
  background: var(--color-field);
  cursor: pointer;
}
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"] { border-radius: var(--radius-sm); }
input[type="checkbox"]:checked {
  background: var(--color-accent-ink);
  border-color: var(--color-accent-ink);
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M3 8.5l3.2 3.3L13 4.8" fill="none" stroke="%231a1613" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>');
  background-size: 1rem; background-position: center; background-repeat: no-repeat;
}
input[type="radio"]:checked {
  border-color: var(--color-accent-ink);
  background-image: radial-gradient(circle at 50% 50%, var(--color-accent-ink) 0 0.34rem, var(--color-field) 0.35rem 100%);
}
.choice:has(input:checked) { border-color: var(--color-accent-ink); box-shadow: inset 0 0 0 1px var(--color-accent-ink); }

/* ==========================================================================
   Payment block — renewal disclosure + the separate affirmative
   acknowledgement. These two rules carry the whole auto-renewal position.
   ========================================================================== */

.pay {
  margin-bottom: var(--space-5);
  border: 2px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-paper);
}
.pay__head {
  padding: var(--space-4) var(--space-5);
  background: var(--color-ink); color: var(--color-on-dark);
}
.pay__head h3 { margin: 0; color: var(--color-on-dark); }
.pay__head p { margin: var(--space-2) 0 0; font-size: var(--text-sm); color: var(--color-on-dark-muted); }
.pay__body { padding: var(--space-5); }
.pay__body > :last-child { margin-bottom: 0; }

/* Looks like the other inputs: the card field is a field to fill in, not a placeholder panel. */
.card-mount {
  min-height: var(--tap);
  padding: var(--space-3);
  border: 1px solid var(--color-line-strong);
  border-radius: var(--radius-sm);
  background: var(--color-field);
  font-size: var(--text-sm); color: var(--color-text-muted);
}

/* the conspicuous renewal disclosure — sits between the card and the tick */
.renewal {
  overflow-wrap: anywhere; /* the member-area address must fit narrow phone screens */
  margin-top: var(--space-5);
  padding: var(--space-5);
  background: var(--color-notice-wash);
  border: 2px solid var(--color-notice-ink);
  border-radius: var(--radius-md);
}
.renewal h4 {
  margin-bottom: var(--space-3);
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 800;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--color-notice-ink);
}
.renewal ul { margin: 0; padding-left: 1.2rem; }
.renewal li { font-size: var(--text-lg); }
.renewal li:last-child { margin-bottom: 0; }

/* the separate affirmative acknowledgement — deliberately unlike a consent */
.ack {
  /* minmax(0, 1fr) and the label's overflow-wrap let the column shrink below its longest word (the member-area
     address): with a plain 1fr it could not, and the page scrolled sideways on a 375px phone. */
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-4);
  align-items: start;
  margin-top: var(--space-5);
  padding: var(--space-5);
  background: var(--color-ink); color: var(--color-on-dark);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.ack input[type="checkbox"] {
  width: 1.85rem; height: 1.85rem;
  border-color: var(--color-accent-soft);
  background: var(--color-ink);
}
.ack input[type="checkbox"]:checked {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M3 8.5l3.2 3.3L13 4.8" fill="none" stroke="%231a1613" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg>');
  background-size: 1.2rem;
}
.ack__label { display: block; font-size: var(--text-lg); overflow-wrap: anywhere; }
.ack__label b { color: var(--color-accent-soft); }
.ack__tag {
  display: inline-block; margin-bottom: var(--space-2);
  padding: 0.15rem var(--space-3);
  background: var(--color-accent); color: var(--color-on-accent);
  font-size: var(--text-xs); font-weight: 800;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.ack a { color: var(--color-accent-soft); }

/* term-dependent amounts inside the acknowledgement, swapped with CSS only.
   No :has() support  ->  every variant shows. Over-disclosure, never under. */
.v { display: none; }
form:has(#term-month:checked) .v--month { display: inline; }
form:has(#term-6:checked)     .v--6mo   { display: inline; }
form:has(#term-12:checked)    .v--12mo  { display: inline; }
@supports not selector(:has(*)) { .v { display: inline; } }
/* The locker's part of the renewal terms shows only when a locker is chosen (apply.js records it the same way). */
.lk { display: none; }
form:has(#locker:checked) .lk, form.has-locker .lk { display: inline; }

/* ==========================================================================
   Consent block — optional, unbundled, visibly lighter than the ack
   ========================================================================== */

.consents { border: 1px solid var(--color-line-strong); border-radius: var(--radius-md); }
.consents__head { padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--color-line); }
.consents__head h3 { margin-bottom: var(--space-2); }
.consents__head p { margin: 0; font-size: var(--text-sm); }
.consent {
  display: grid; grid-template-columns: auto 1fr; gap: var(--space-3);
  align-items: start;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-line);
  cursor: pointer;
}
.consent:last-child { border-bottom: 0; }
/* The server's one-sentence note under the text and call boxes (card page): the same inset as a consent row. */
.consent-note { margin: 0; padding: var(--space-4) var(--space-5); border-top: 1px solid var(--color-line); overflow-wrap: anywhere; }
.consent:hover { background: var(--color-paper-sunken); }
.consent__title { display: block; font-weight: 650; }
.consent__tag {
  display: inline-block; margin-left: var(--space-2);
  padding: 0 var(--space-2);
  border: 1px solid var(--color-line-strong); border-radius: 999px;
  font-size: var(--text-xs); font-weight: 400; color: var(--color-text-muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.consent__body { display: block; margin-top: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
.consent__dark {
  display: block; margin-top: var(--space-2);
  font-size: var(--text-xs); color: var(--color-text-muted); font-style: italic;
}

/* agreement — required, in its own section, never styled like a consent */
.agree {
  display: grid; grid-template-columns: auto 1fr; gap: var(--space-3);
  align-items: start;
  padding: var(--space-5);
  border: 2px solid var(--color-line-strong); border-radius: var(--radius-md);
  background: var(--color-paper-sunken);
  cursor: pointer;
}

/* submit block — the renewal terms restated where the assent happens */
.submit-block {
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: 2px solid var(--color-rule);
}
.submit-summary {
  margin-bottom: var(--space-4);
  font-size: var(--text-lg);
}

.turnstile-slot {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  border: 1px dashed var(--color-line-strong);
  background: var(--color-paper-sunken);
  font-size: var(--text-sm); color: var(--color-text-muted); text-align: center;
}

/* The member area's code box: big, spaced, tabular digits, so eight of them are easy to check. */
.code-input { font-size: var(--text-xl); letter-spacing: 0.3em; text-align: center; font-variant-numeric: tabular-nums; }
/* "I have a private key": the way in for someone who has one. Not a material term, so it may sit in a disclosure. With sign-in off the script opens it and hides the summary. */
.key-path.is-only > summary { display: none; }
.key-path.is-only { border: 0; margin-bottom: 0; }

/* progressive disclosure — help only. Material terms are never in here. */
details {
  margin-bottom: var(--space-4);
  border-top: 1px solid var(--color-line);
  border-bottom: 1px solid var(--color-line);
}
details summary {
  display: flex; align-items: center; min-height: var(--tap);
  padding: var(--space-2) 0;
  font-weight: 650; font-size: var(--text-sm);
  color: var(--color-accent-ink); cursor: pointer;
}
details[open] summary { margin-bottom: var(--space-2); }
details .details__body { padding-bottom: var(--space-3); font-size: var(--text-sm); }
details .details__body > :last-child { margin-bottom: 0; }

/* ==========================================================================
   Age gate — the first impression, full brand, no page furniture
   ========================================================================== */

.gate {
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
  background-color: var(--color-ink);
  background-image:
    /* copper cu300 239,180,111 — the rgba form of --color-accent, which cannot
       be a var() here because these are colour stops inside a shorthand that
       also carries lengths. It has been left behind by two palette changes
       already (copper 200,129,58 then gold 193,163,112), so it is the first
       thing to check when the accent moves again.
       Decorative glow only, but it darkens what sits above it, so the figures
       below are composited rather than taken against the linear-gradient
       stops alone. Worst case is the 20% lobe under the 5% card wash
       (#544333): copper 5.13, copper-soft 6.64, body text 8.32 — all clear
       4.5. Bare stops for reference: copper 9.17 on #221c17, 10.30 on
       #14100d.                                                              */
    radial-gradient(60rem 38rem at 78% 8%,  rgba(239,180,111,0.20), transparent 62%),
    radial-gradient(44rem 30rem at 8%  96%, rgba(239,180,111,0.10), transparent 60%),
    linear-gradient(180deg, #221c17 0%, #14100d 100%);
  color: var(--color-on-dark);
}
.gate__inner {
  flex: 1 0 auto;
  display: flex; flex-direction: column; justify-content: center;
  width: 100%; max-width: 34rem;
  margin-inline: auto;
  padding: var(--space-7) var(--gutter);
  text-align: center;
}
.gate__card {
  margin-top: var(--space-6);
  padding: var(--space-6) var(--space-5);
  background: rgba(246,240,231,0.05);
  border: 1px solid var(--color-ink-line);
  border-radius: var(--radius-md);
  text-align: left;
}
.gate__card h1 { font-size: var(--display-s); text-align: center; }
.gate .dob { justify-content: center; }
.gate .dob label { color: var(--color-on-dark-muted); }
.gate .dob input,
.gate .dob select {
  background: var(--color-ink-raised);
  border-color: var(--color-on-dark-muted);
  color: var(--color-on-dark);
  font-size: var(--text-xl);
  min-height: 3.25rem;
}
/* On a narrow screen the month takes the first row and the day and the year share the second, at
   every width below 30em, so the parts fill their rows instead of leaving a centred orphan. (A basis
   that fits the month and the day on one row at 375px does not fit at 320px, where the card leaves
   about 231px, so the layout used to flip between the two; this one does not depend on that
   arithmetic, and the day's "Select" is never squeezed.) From 30em all three sit in one row at
   fixed widths. */
.gate .dob > div { flex: 1 1 5rem; }
.gate .dob > div:first-child { flex: 1 1 100%; }
.gate .dob select, .gate .dob input { width: 100%; }
@media (min-width: 30em) {
  .gate .dob > div,
  .gate .dob > div:first-child { flex: 0 0 auto; }
  .gate .dob select { width: 9.5rem; }
  .gate .dob select.dob__day { width: 6rem; }
  .gate .dob input.dob__year { width: 6rem; }
}
.gate__note {
  margin-top: var(--space-5); margin-bottom: 0;
  font-size: var(--text-sm); color: var(--color-on-dark-muted);
}
.gate__foot {
  flex: 0 0 auto;
  padding: var(--space-5) var(--gutter);
  text-align: center;
  font-size: var(--text-xs);
  color: var(--color-on-dark-muted);
  border-top: 1px solid var(--color-ink-line);
}
/* Every link on the gate, not just the footer's. The global `a` colour is now
   cu300, which does clear on the gate (9.17 on the top stop, 5.13 in the worst
   composited case under the 20% glow and the card wash), so this rule is no
   longer load-bearing for contrast — it is kept because focus and hover on the
   gate should read as the same -soft step they do everywhere else, and because
   a future accent that is dark again would re-create the original failure.
   The 2.65:1 this comment used to cite belonged to a light-surface accent the
   file no longer holds. */
.gate a:not(.btn) { color: var(--color-accent-soft); }

/* THE WAY HOME. "← The 801 home" at the top of every lounge page that ships, the gate and its refusal
   included (owner, 2026-10-08: "navigation buttons at the top so that people can navigate to the home
   page from anywhere"). The gate and the refusal had no header at all, so the only way out of them was
   the browser's Back button, and the landing page's brand stays inside the lounge. It is a strip in the
   shell's own colour with the hairline the header uses, and the link takes the menu's type (small,
   capitals, spaced) and colours: --color-on-dark-muted on --color-ink is 9.02:1, and hover and focus
   take --color-accent-soft. `.home-bar a.home-link` is as specific as `.gate a:not(.btn)` above (two
   classes and an element each) and comes after it, so the gate's gold link colour does not win here.
   The link is the 44px target. Screen only. */
.home-bar { background: var(--color-ink); border-bottom: 1px solid var(--color-ink-line); }
.home-bar a.home-link {
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: var(--tap);
  color: var(--color-on-dark-muted);
  font-size: var(--text-xs); letter-spacing: var(--tracking-caps); text-transform: uppercase;
  text-decoration: none;
}
.home-bar a.home-link:hover, .home-bar a.home-link:focus-visible { color: var(--color-accent-soft); }

/* The logo at the head of the strip: the little arch in a rounded square the owner chose on 2026-10-08
   ("that can be used at the top of each page for now"), the same drawing as the event center's
   wordmark. Decorative (aria-hidden), in the lounge's copper (--color-accent, 9.78:1 on the shell),
   and 28px square inside the 44px row. */
.home-bar .mini-logo { flex: none; width: 1.75rem; height: 1.75rem; color: var(--color-accent); }

/* The attribution is a line of its own here rather than part of a sentence, so it
   drops the copper and takes the fine print's own --color-on-dark-muted, 9.02:1
   on --color-ink. Ours has to read quieter than the client's legal line above it.
   Both `.site-footer a:not(.btn)` and `.gate a:not(.btn)` match at this same
   specificity, so this block sits after the later of the two.
   --tap is the 44px floor AGENTS.md makes contractual here, and it belongs on the
   anchor rather than on the paragraph, because the anchor is what is tapped. */
.site-footer a.powered,
.gate__foot a.powered {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--color-on-dark-muted);
  text-decoration: none;
}
.site-footer a.powered:hover, .site-footer a.powered:focus-visible,
.gate__foot a.powered:hover, .gate__foot a.powered:focus-visible { text-decoration: underline; }

/* "Powered by StratosDigital.ai", louder (owner, 2026-10-24: "slightly larger and in a bolder color ... a slight special
   effect like a shimmer so that it is more profound"). Still the same link, text and href (facts.js pins them); only its
   look changes. One electric blue on a dark footer, 1.15 times the size and bold. The shimmer is a white highlight that
   sweeps across the letters: in a browser with scroll-driven animations it is tied to scrolling the footer into view
   (nothing runs by time, so there is nothing to pause); everywhere else it plays once, 1.2 seconds, when the link is
   hovered or focused. Never under prefers-reduced-motion, and the colour alone carries the text if the highlight is
   unsupported (the text is only made transparent where background-clip: text exists). The blue is --powered here; to
   change the colour, change that one value. */
.site-footer a.powered,
.gate__foot a.powered {
  --powered: #6cb8ff;
  color: var(--powered);
  font-size: 1.15em;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-decoration-color: var(--powered);
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .site-footer a.powered,
.gate__foot a.powered {
    background-image: linear-gradient(105deg, var(--powered) 0 40%, #ffffff 50%, var(--powered) 60% 100%);
    background-size: 260% 100%;
    background-position: 100% 0;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
@keyframes powered-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .site-footer a.powered,
.gate__foot a.powered { animation: powered-shimmer linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
  }
  .site-footer a.powered:hover, .site-footer a.powered:focus-visible,
  .gate__foot a.powered:hover, .gate__foot a.powered:focus-visible { animation: powered-shimmer 1.2s ease-in-out 1; }
}
@media (forced-colors: active) {
  .site-footer a.powered,
.gate__foot a.powered { background: none; -webkit-text-fill-color: currentColor; color: LinkText; }
}
@media print {
  /* Print remaps --color-on-dark-muted to dark ink; the credit's blue is 2.11:1 on the white sheet. */
  .site-footer a.powered,
.gate__foot a.powered { background: none; -webkit-text-fill-color: currentColor; color: var(--color-on-dark-muted); }
}

/* THE 44px FLOOR FOR EVERY STANDALONE LINK, NOT ONLY THE ATTRIBUTION.
   Measured in Chrome on the built pages, 2026-10-03, before this rule: the gate's
   "House rules" link was 62 x 16, the landing page's brand link 96 x 32, and its
   footer phone and "House rules" links 87 x 19 and 73 x 19. None of those is an AA
   failure -- SC 2.5.8 is met by its spacing exception, since no other target sits
   within 24px of any of them -- but AGENTS.md makes 44px this repository's own
   contractual standard (SC 2.5.5), and `a.powered` above was the only link that
   had been brought up to it.

   "Standalone" is the scope on purpose. A link that is a word in a sentence is
   exempt from both criteria and is not touched: the gate's address line,
   "801 S Chester Street ... 501-387-1040", keeps its phone link inline. These
   selectors name the places a link IS the whole line: an item in a footer list, and
   a footer or gate-foot paragraph that holds nothing but the link. (The header's
   brand gets its height separately, below, for a reason.) `:not(.powered)` because
   that anchor has its own rule just above and keeps it. */
.site-footer li > a,
.site-footer p.tight-top > a:not(.powered),
.gate__foot p.tight-top > a:not(.powered) {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

/* THE BRAND IS NOT IN THAT GROUP, AND PUTTING IT THERE WAS A REGRESSION. The
   wordmark is a text node followed by a <span>, "The <span>801</span>", and in a
   flex container the space between them is dropped, so the header read THE801 on
   every lounge page (found in review; the link had shrunk from 96px to 88px, which
   was the missing space, and a width check alone did not say so). It stays an
   ordinary inline box and gets its 44px from line-height, which keeps the space. */
.site-header__brand {
  display: inline-block;
  min-height: var(--tap);
  line-height: var(--tap);
}

/* A phone number is one word to the person dialling it. Without this the gate's
   address line broke "501-387-" from "1040" at 375px, because a hyphen is a place a
   line may break. Not `.btn`: those are tel: links too, but their text is a
   sentence and has to be allowed to wrap on a narrow screen. */
a[href^="tel:"]:not(.btn) { white-space: nowrap; }

/* The wash is the rgba form of --color-accent-soft (copper cu200
   246,211,168) at 12%, so it tracks the accent; it cannot be a var() because
   a custom property cannot supply the alpha of a colour it does not carry.

   MEASURED IN PLACE. An earlier version of this note composited the wash over
   the gradient's bare stops (#3b3228 and #2f2720) and got 11.08 and 12.95 for
   the text and 8.85 and 10.34 for the border, which were too kind. Headless
   Chrome, sRGB forced, device scale 1, seven viewports from 320 x 568 to
   2560 x 1440, the text compared with every background pixel inside its line
   boxes: the text (#f6f0e7, 14px at normal weight, so 4.5:1 applies) is 9.18:1
   at the worst viewport (320 x 568, over #493e32) and 10.28:1 at the best. The
   2px #f6d3a8 border is at least 7.19:1 against the fill inside it and 9.76:1
   against the card outside it, against the 3:1 SC 1.4.11 wants for the
   boundary of the error block. By calculation, with the box at the centre of
   the gate's 20% copper glow (no tested viewport puts it there), the text is
   6.28:1 and the border 5.02:1. The luminance function was checked first
   against #5e1d27 on white (12.49) and #767676 on white (4.54). */
.gate-error {
  margin-bottom: var(--space-5);
  padding: var(--space-4);
  border: 2px solid var(--color-accent-soft);
  border-radius: var(--radius-md);
  background: rgba(246,211,168,0.12);
  color: var(--color-on-dark);
  font-size: var(--text-sm);
}
.gate-error > :last-child { margin-bottom: 0; }

/* ==========================================================================
   Member area
   ========================================================================== */

.member-head { padding-block: var(--space-6); }
.code-panel {
  padding: var(--space-5);
  background: var(--color-ink); color: var(--color-on-dark);
  border-radius: var(--radius-md);
}
.code-panel h3 { color: var(--color-on-dark); }
.code-panel__code {
  display: block; margin: var(--space-3) 0;
  font-family: var(--font-display);
  font-size: var(--display-m); letter-spacing: 0.22em;
  color: var(--color-accent-soft);
  font-variant-numeric: tabular-nums;
}
.code-panel p { color: var(--color-on-dark-muted); font-size: var(--text-sm); }
.code-panel p:last-child { margin-bottom: 0; }

.kv { margin: 0; }
.kv div {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  justify-content: space-between;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-line);
}
.kv div[hidden] { display: none; }
.kv dt { color: var(--color-text-muted); font-size: var(--text-sm); margin: 0; }
.kv dd { margin: 0; font-weight: 650; text-align: right; }

.status {
  display: inline-block; padding: 0.1rem var(--space-3);
  border-radius: 999px; font-size: var(--text-xs); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.status--on { background: var(--color-good-wash); color: var(--color-good-ink); }
.status--wait { background: var(--color-accent-wash); color: var(--color-accent-ink); }

/* cancellation is a plain, visible link in the main column — never a footer */
.cancel-row {
  margin-top: var(--space-6); padding-top: var(--space-5);
  border-top: 1px solid var(--color-line);
}

/* ==========================================================================
   Prototype-only furniture — never ships
   ========================================================================== */

.proto {
  padding: var(--space-3) var(--gutter);
  background: #2b2f3a; color: #e8eaf0;
  border-bottom: 2px dashed #7d86a1;
  font: var(--text-xs)/1.5 ui-monospace, "Cascadia Mono", Consolas, monospace;
}
.proto b { color: #ffd9a0; }
.proto a { color: #9fd0ff; }
/* The preview banner on the dark application pages: the .proto look, but it must survive print (the print block
   below hides .proto), because it is the only warning that the page is not live. */
.preview-banner {
  margin: 0; padding: var(--space-3) var(--gutter);
  background: #2b2f3a; color: #e8eaf0;
  border-bottom: 2px dashed #7d86a1;
  font: var(--text-xs)/1.5 ui-monospace, "Cascadia Mono", Consolas, monospace;
}
.preview-banner b { color: #ffd9a0; }
.proto__links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); margin-top: var(--space-2); }

/* ==========================================================================
   A very small utility set. No inline style attribute appears anywhere in
   this prototype — style-src 'self' forbids them.
   ========================================================================== */

.flush      { margin: 0; }
.flush-top  { margin-top: 0; }
.tight-top  { margin-top: var(--space-2); }
.gap-top    { margin-top: var(--space-5); }
.gap-top-lg { margin-top: var(--space-7); }
.center     { text-align: center; }

@media print {
  /* The art-deco band is decoration, and a printer would spend its ink on it. */
  .fans { display: none; }

  /* The screen palette is dark; paper is not. Without this block body text
     is #f6f0e7 on a white sheet — invisible. House rules and the terms are
     the pages people actually print, so this is not hypothetical.
     Remap the tokens rather than patching component rules, so everything
     downstream follows. Every value computed on white:
       text 16.71 · muted 9.84 · accent 9.70 · notice 8.29 · good 8.31
       line-strong 5.74 (SC 1.4.11 needs 3)                                 */
  :root {
    --color-paper:          #ffffff;
    --color-paper-sunken:   #ffffff;
    --color-field:          #ffffff;
    --color-ink:            #ffffff;
    --color-ink-raised:     #ffffff;
    --color-accent-wash:    #ffffff;
    --color-notice-wash:    #ffffff;
    --color-good-wash:      #ffffff;
    /* On the DEFAULT print path browsers drop background colours, so a
       label on the accent fill lands on bare paper. Both must be dark,
       never white: #221d18 on white = 16.71:1. Flipping either to white
       would print those labels at 1.00:1 on that path.

       "A REAL FIX NEEDS A SECOND TOKEN, ONE PER PATH" — the claim that used
       to close this comment — IS WRONG, and is fixed at the foot of this
       block rather than restated. Its premise was sound: a reader who
       force-enables background printing puts #221d18 on ox700, which is
       1.72:1, and the retired gold gd700 #7a530f measured 2.44, so this is
       the one defect of the two that the palette WIDENED rather than
       inherited. Its conclusion was not. The second path only exists
       because the FILL exists. Remove the fill in print and there is one
       path, not two, and no print-only token is needed — see the outline
       rules after `body` below. Both of these names stay dark.            */
    --color-on-accent:      #221d18;
    --color-rule:           #221d18;

    --color-text:           #221d18;
    --color-text-muted:     #4a423b;
    --color-on-dark:        #221d18;
    --color-on-dark-muted:  #4a423b;

    /* Paper is a LIGHT surface, and cu300/cu200 are banned there (1.73 and
       1.34 on #fbf8f3), so print cannot use the screen accent. The oxblood
       ramp is the family's light-surface end, and ox700 is its rest value:
       9.70 on white, against the 6.84 the retired gd700 gold managed. One
       value for all three names because print has no hover or focus state. */
    --color-accent:         #7a2733;
    --color-accent-ink:     #7a2733;
    --color-accent-soft:    #7a2733;

    --color-line:           #bbbbbb;
    --color-line-strong:    #666666;
    --color-placeholder:    #4a423b;
    --color-notice-ink:     #8c2f16;
    --color-good-ink:       #2c5738;
  }
  html { color-scheme: light; }
  .proto, .home-bar, .site-nav, .skip-link { display: none !important; }
  .preview-banner { background: #fff; color: #000; border: 2px solid #000; }
  .preview-banner b { color: #000; }
  body { background: #fff; }

  /* DEFECT 2, FIXED 2026-10-02 — the two places where --color-on-accent text
     sits on a --color-accent FILL, which is the whole of the 1.72:1 problem
     described in the token comment above. Dropping the fill collapses the two
     print paths into one: with backgrounds off the paper was always going to
     show through, and with backgrounds forced on `background: none` paints
     nothing, so BOTH paths now render #221d18 on white at 16.71:1 inside a
     #7a2733 ox700 edge at 9.70:1. The edge is what still reads as a button
     or a tag on paper, and 9.70 clears the 3:1 SC 1.4.11 asks of a control
     boundary more than three times over.

     THIS IS THE DEFECT THE PALETTE WIDENED (1.72 on ox700, against 2.44 on
     the retired gd700 gold), as against defect 1 at the head of this file,
     which the palette inherited unchanged at 1.10:1.

     Two things the selectors are doing deliberately. :not(.btn--quiet) —
     quiet buttons already carry `background: transparent`, so they never had
     this defect and already print at 16.71:1 with a 5.74:1 grey edge;
     repainting them would be an unrelated change. And the :hover variant is
     listed because .btn:hover is more specific than .btn and would otherwise
     put the fill straight back wherever a print preview retains hover.      */
  .btn:not(.btn--quiet), .btn:not(.btn--quiet):hover {
    background: none;
    border: 2px solid #7a2733;   /* ox700 edge on white — 9.70:1  */
    color: #221d18;              /* label on bare paper — 16.71:1 */
  }
  .ack__tag {
    background: none;
    border: 1px solid #7a2733;   /* ox700 edge on white — 9.70:1  */
    color: #221d18;              /* tag text on paper   — 16.71:1 */
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

/* --- Motion, once, on load -------------------------------------------------- */
/* Owner, 2026-10-09: the arch logo draws itself and the page title rises in, on every page. Same rules,
   names and timings as apex.css (the home page's stylesheet). Only for a visitor who has not asked for
   less motion; outside the query nothing animates, so the resting state is the finished page. */
@media (prefers-reduced-motion: no-preference) {
  .mini-logo path,
  .mini-logo rect {
    stroke-dasharray: 200;
    animation: lg-draw 1.1s ease-out both;
  }
  .mini-logo path:nth-of-type(1) { animation-delay: 0.25s; }
  .mini-logo path:nth-of-type(2) { animation-delay: 0.7s; }
  h1 { animation: lg-rise 0.7s ease-out 0.15s both; }
}
@keyframes lg-draw { from { stroke-dashoffset: 200; } to { stroke-dashoffset: 0; } }
@keyframes lg-rise { from { opacity: 0; transform: translateY(0.75rem); } to { opacity: 1; transform: none; } }

/* --- Type ------------------------------------------------------------------------------------------- */
/* Self-hosted, open licence (SIL OFL 1.1, texts beside the files in /assets/fonts/). Cinzel, a Roman-capitals
   face, for the display lines; Hanken Grotesk for everything else; the stacks end in the old system fonts.
   See apex.css for the reasoning. */
@font-face {
  font-family: "Cinzel";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/assets/fonts/cinzel-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/assets/fonts/hanken-grotesk-latin.woff2") format("woff2");
}
