@import "./chrome.css";

/* ==========================================================================
   Grid Lounge — site stylesheet
   Reset, type scale, sections and page components.
   Tokens, chrome, buttons and glass come from chrome.css.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--body);
  font-size: 1.1875rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--white);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 900;
  line-height: 1.03;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  border-radius: 0;
  -webkit-appearance: none;
          appearance: none;
  cursor: pointer;
}
img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }
dl, dd { margin: 0; }

::selection { background: var(--accent); color: #fff; }

:where(a, button, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 4px;
  border-radius: 8px;
}

/* ---------- Type ---------- */

/* Apple's rhythm: an enormous headline, then small quiet caption lines. */
.t-big   { font-size: clamp(2.125rem, 5vw, 4rem);  line-height: 1.05; letter-spacing: -0.035em; }
.t-mid   { font-size: clamp(1.5rem, 2.6vw, 2.25rem); line-height: 1.1; letter-spacing: -0.03em; }

/* Currency mark at 60% of the figure beside it, top-aligned rather than
   sitting on the baseline. Urbanist's cap height is 0.70em, so the digits
   stand 0.70em and the mark 0.42em; the lift is the 0.28em difference, which
   expressed in the mark's own reduced size is 0.28 / 0.6 = 0.4667em. Change
   the size and that second number has to move with it: lift = 0.7 x (1 - k)
   / k, for a scale of k. The lifted glyph still ends below the parent's
   0.95em ascender, so the line box does not grow and nothing shifts. */
.cur { display: inline; font-size: 0.6em; font-weight: inherit; color: inherit; vertical-align: 0.4667em; }

/* Urbanist, not a wide motorsport face: that read futuristic at this size.

   Set as an eyebrow rather than small dark text. At 21px in the heading's own
   face and colour it had nothing of its own — the heading beat it on size,
   weight and mass, so it read as a dropped fragment. Colour and form carry it
   instead, in the register .post__cat already uses. */
.kicker {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  font-family: var(--display);
  font-size: 0.875rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/* A short rule anchors the label to the left margin so it does not float. */
.kicker::before {
  content: "";
  width: 1.75rem;
  height: 2px;
  background: currentColor;
  flex: none;
}

/* Centred heads have no left margin to anchor to. */
.center .kicker { justify-content: center; }

.caption { font-size: 1.0625rem; line-height: 1.5; color: var(--ink-2); }
.sub { font-size: clamp(1.1875rem, 1.7vw, 1.5rem); line-height: 1.45; color: var(--ink-2); }

.center { text-align: center; }
.center .sub, .center .caption { margin-inline: auto; }

/* ---------- Sections ---------- */

.sec { padding-block: 5.5rem; }
@media (min-width: 768px) { .sec { padding-block: 8.5rem; } }

.sec--grey { background: var(--grey); }
.sec--ink  { background: var(--ink); color: #fff; }
.sec--ink .sub, .sec--ink .caption { color: rgba(255, 255, 255, 0.68); }
.sec--tight { padding-block: 3.5rem; }

/* ---------- Reveal ---------- */

.rise { opacity: 0; transform: translateY(22px); }
.rise.shown {
  opacity: 1; transform: none;
  transition: opacity 0.7s var(--ease) var(--d, 0s), transform 0.8s var(--ease) var(--d, 0s);
}
.no-js .rise { opacity: 1; transform: none; }

/* ==========================================================================
   Glow button
   The lit pill, lifted out of the home page it was built for. It now carries
   the primary action on the home stage and in the closing row of every page.
   Dark grounds only: the effect needs its fill reading darker than its ring,
   which no light section can give it. The markup is four layers in a fixed
   order, so pages emit it through glow() in src/layout/chrome.ts rather than
   writing it out.
   ========================================================================== */

@property --a {
  syntax: "<angle>";
  initial-value: 0deg;
  /* Inherited so the single animation on the anchor drives both pseudo
     elements. Two independent animations would drift out of sync and the
     bloom would stop tracking the ring. */
  inherits: true;
}

@keyframes spin-a { to { --a: 360deg; } }

.stage__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0.9375rem 1.75rem;
  border-radius: var(--r-pill);
  font-family: var(--body);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  animation: spin-a 6s linear infinite;
  transition: transform 0.35s var(--ease);
}

/* Four stacked layers, because the fill has to stay a neutral frosted glass:
     0  .glow    the halo — masked on the child, blurred on the parent
     1  ::after  the glass fill — no colour in it at all
     2  .ring    the crisp conic border, masked to a ring
     3  span     the label

   The obvious shortcut — painting the conic on border-box and covering it with
   a padding-box fill — only works when the fill is opaque. Ours is translucent
   by definition, so the gradient bled straight through into the interior. The
   ring therefore has to be its own layer sitting ON TOP of the glass.

   The glow needs the same trick inverted. CSS applies `filter` BEFORE `mask`,
   so blurring and masking on one element yields a blurred fill with a hard-cut
   outer edge — the mask slices the soft falloff clean off. Splitting the two
   across parent and child reverses the order: the child paints the hollow
   ring, then the parent blurs the already-masked result, so both edges come
   out soft. A little inward bleed is wanted; that is what light through glass
   looks like. */

.stage__cta .glow {
  position: absolute;
  inset: -6px;
  z-index: 0;
  border-radius: var(--r-pill);
  pointer-events: none;
  filter: blur(14px) saturate(2.2);
  opacity: 1;
  transition: opacity 0.3s var(--ease), filter 0.3s var(--ease);
}

.stage__cta .glow::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 9px;
  border-radius: inherit;
  background: conic-gradient(
    from var(--a),
    #8b2fe8 0deg,
    #1a9dff 100deg,
    #4fb4ff 165deg,
    #a877f0 250deg,
    #8b2fe8 360deg
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

/* A second, tighter emitter stacked on the first. Both are blurred by the same
   parent, so they compound where they overlap — that concentrates the light
   right at the border and gives the bloom its intensity, which a single band
   at full opacity could not reach. */
.stage__cta .glow::after {
  content: "";
  position: absolute;
  inset: 1px;
  padding: 6px;
  border-radius: inherit;
  background: conic-gradient(
    from var(--a),
    #8b2fe8 0deg,
    #1a9dff 100deg,
    #4fb4ff 165deg,
    #a877f0 250deg,
    #8b2fe8 360deg
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

.stage__cta::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  /* No backdrop-filter available: fall back to an opaque-ish tint. */
  background: rgba(10, 10, 14, 0.62);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .stage__cta::after {
    /* The darkening comes from brightness() INSIDE the backdrop filter rather
       than from a tint on top. A tint heavy enough to carry white text hides
       the footage and kills the glass read; brightness() dims what is behind
       the panel while leaving it visible, so shapes still move through it.
       The inset highlight is the lit bevel that sells it as a real surface. */
    background: rgba(10, 10, 14, 0.1);
    -webkit-backdrop-filter: blur(18px) saturate(1.7) brightness(0.42);
            backdrop-filter: blur(18px) saturate(1.7) brightness(0.42);
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.28),
      inset 0 -1px 1px rgba(255, 255, 255, 0.1);
  }
}

.stage__cta .ring {
  position: absolute;
  inset: 0;
  z-index: 2;
  padding: 2px;
  border-radius: inherit;
  pointer-events: none;
  background: conic-gradient(
    from var(--a),
    #8b2fe8 0deg,
    #1a9dff 100deg,
    #4fb4ff 165deg,
    #a877f0 250deg,
    #8b2fe8 360deg
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

.stage__cta > span {
  position: relative;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

/* Pulses UP from the resting state only. Opacity cannot be the vehicle here —
   it rests at 1, so any keyframe has to start by dimming before it can rise,
   which read as the glow dropping out on hover. saturate() and brightness()
   have no such ceiling, and the 0% frame matches the resting filter exactly so
   the animation starts with no jump. */
@keyframes glow-pulse {
  0%, 100% { filter: blur(14px) saturate(2.2) brightness(1); }
  50%      { filter: blur(14px) saturate(2.7) brightness(1.28); }
}

.stage__cta:hover .glow { animation: glow-pulse 2s ease-in-out infinite; }
.stage__cta:active { transform: scale(0.97); }
.stage__cta svg { transition: transform 0.35s var(--ease); }
.stage__cta:hover svg { transform: translateX(3px); }

@media (max-width: 767px) {
  .stage__cta { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .stage__cta { animation: none; }
}

/* ==========================================================================
   Closing section
   Every page lands on the same thing: its photograph, with the ask on a glass
   panel over it.

   This replaced a standalone photo-with-glass block that sat directly above
   the closer. Two full-width heavy sections back to back, and the first had
   nothing to do but look expensive — it read as an interruption in the page
   rather than a step through it. The photograph was worth keeping; the extra
   section was not.
   ========================================================================== */

/* The panel is small and the photograph is the point, so the section carries a
   minimum height rather than letting the panel's own content decide it. The
   padding alone left 144px of photograph above and below; this gives it room
   to be a photograph. svh rather than vh so a phone's collapsing URL bar does
   not resize the section mid-scroll, and the 50rem ceiling stops a tall
   desktop window turning the closer into another full-screen stage. */
.close {
  position: relative;
  isolation: isolate;
  display: grid;
  align-content: center;
  min-height: clamp(36rem, 90svh, 50rem);
  padding-block: clamp(5rem, 11vw, 9rem);
  background: var(--ink);
  color: #fff;
  overflow: hidden;
}

.close__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The scrim. White type sits on a panel that is only 52% opaque, so whatever
   the photograph is doing behind it reaches the type. Darkening the photograph
   first is what makes the contrast hold on all fourteen of them rather than on
   the ones that happen to be dark already. isolation on the parent keeps both
   negative layers above the section's own background.

   0.58 is measured, not picked. /race/solo-drive is the brightest photograph
   behind a panel: at 0.52 it gave 4.7:1 for white body text, still AA but with
   nothing to spare, and 0.58 took it to 5.8:1. Raising the section's minimum
   height later re-cropped every photograph and moved darker ground behind the
   panels, so it now measures 8.4:1 and the rest sit above 10:1 — re-measure
   before trusting those numbers if the height or the crop changes again. */
.close::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(0, 0, 0, 0.58);
}

.close__panel {
  width: min(48rem, 100%);
  margin-inline: auto;
  padding: clamp(1.75rem, 4vw, 3rem);
  border-radius: var(--r-card);
  text-align: center;
}

.close__panel h2 { text-wrap: balance; }

.close__sub {
  max-width: 34rem;
  margin: 1.25rem auto 0;
  font-size: clamp(1.0625rem, 1.4vw, 1.1875rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.8);
  /* balance, not pretty. These are two or three centred lines, and `pretty`
     only protects against a last line of ONE word — it was happy to leave
     "at $350." stranded under a full-width line. `balance` evens the lines
     instead, which is what a short centred standfirst wants. */
  text-wrap: balance;
}

/* The lit pill's fill is a backdrop-filter, and an ancestor carrying one
   breaks it: the child samples the parent's already-composited group, finds
   nothing painted there, and comes out clear — which would leave white text on
   an almost transparent pill over a photograph. Inside the panel it takes the
   same flat fill the no-backdrop-filter fallback already defines. */
.close__panel .stage__cta::after {
  background: rgba(10, 10, 14, 0.62);
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
}

/* The panel keeps the photograph framed around it on small screens rather than
   running to the viewport edge, matching the inset-card treatment every other
   photo-with-glass on the site uses. */
@media (max-width: 767px) {
  .close { min-height: clamp(30rem, 72svh, 38rem); padding-block: 3.5rem; }
  .close__panel { padding: 1.75rem 1.5rem; border-radius: 22px; }
}


/* ==========================================================================
   Highlight cards
   Colour appears only twice per card: the icon, and the key phrase inside an
   otherwise black sentence. One brand hue per card, never a coloured surface.

   The inline hues use the Grid Lounge brand palette directly: Burnout Orange,
   Hyper Blue, and Violet.
   ========================================================================== */

.facts { display: grid; gap: 1.25rem; }
@media (min-width: 768px)  { .facts { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 768px)  { .facts--four { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1280px) { .facts--four { grid-template-columns: repeat(4, 1fr); } }

.fact {
  position: relative;
  background: var(--white);
  border-radius: 22px;
  padding: 1.75rem;
}

.fact svg { width: 30px; height: 30px; stroke: var(--hue); fill: none; stroke-width: 1.7; }
.fact h3 {
  margin-top: 1.5rem;
  font-family: var(--display);
  font-size: clamp(1.125rem, 1.7vw, 1.375rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
}
.fact h3 em { font-style: normal; color: var(--hue); }
.fact p { margin-top: 0.75rem; font-size: 1.0625rem; color: var(--ink-2); }

.fact--violet { --hue: #5d3a8a; }
.fact--blue   { --hue: #1997ff; }
.fact--orange { --hue: #ff5e40; }

.facts__head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 1rem;
  margin-bottom: 2rem;
}

/* ---- Closing action row ----
   Every page ends on this: the lit pill and an outlined one, on a dark
   section. The two are not the same box — the outline carries a 1.5px border
   and the lit pill carries none — so matching their padding leaves the
   outline 3px taller, which is exactly what the earlier attempt here did.
   A shared min-height settles it instead: box-sizing is border-box globally,
   so both land on --cta-h whatever their padding and border add up to, and
   both centre their own label. */

.close__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2.25rem;
}
.close__row .stage__cta,
.close__row .btn { min-height: var(--cta-h); }


/* ==========================================================================
   Interior pages
   The home page persuades; these answer. Narrower measure, no full-bleed media
   stage, and the practical questions promoted above the prose.
   ========================================================================== */

.shell--narrow { max-width: 46rem; }

/* ---- Page head ----
   Mirrors the home hero one level down: centred, .t-big rather than .t-huge,
   and the same quiet caption lines. No body-scale sub-heading and no button
   row — those made it read louder than the page it is subordinate to. */

.phead { padding-top: 7.5rem; padding-bottom: 3rem; text-align: center; }
@media (min-width: 768px) { .phead { padding-top: 9.5rem; padding-bottom: 4rem; } }

.phead__eyebrow { font-family: var(--display); font-size: 1.25rem; font-weight: 700; letter-spacing: -0.01em; }
.phead__eyebrow a { color: var(--ink-2); }
.phead__eyebrow a:hover { color: var(--asphalt); }

.phead__h { margin-top: 0.5rem; }
/* One standfirst, not a stack of clipped lines. The pair this replaced read as
   two fragments shouted in sequence — "Structured competition, year-round." —
   which is a tone, and not the one the rest of the page uses. A sentence that
   finishes sounds like a person talking.

   Wider measure and `pretty` rather than `balance`: balance evens out the
   lines of a short fragment nicely, but on a real paragraph it fights the
   ragged edge instead of just keeping the last line from running short. */
.phead__lead {
  max-width: 54ch;
  margin: 1.25rem auto 0;
  font-size: 1.0625rem;
  line-height: 1.55;
  text-wrap: pretty;
  color: var(--ink-2);
}

/* ---- Detail page head ----
   Pages two levels down read differently on purpose. The landing heads are
   centred; these are left-aligned under a breadcrumb, which is the clearest
   signal available that you are inside a section rather than at the top of
   one. A lead paragraph replaces the landing pages' pair of caption lines,
   because a detail page has one thing to say up front, not two.

   It still has to stand on its own — someone arriving from search has no
   history to go back through — so the breadcrumb is a real link to the
   parent, and the closing section offers the same route a second time. */

/* ---- Article header ----
   The cover image is the header rather than a picture under it. The page
   opens dark so the bar can run transparent over the photograph, which is the
   same handover the home page makes; [data-dark] in the markup is what tells
   the chrome where the dark run ends.

   align-content:end puts the type on the floor of the header, so a tall
   headline grows upward into the image instead of pushing the image down. */

.ahead {
  position: relative;
  isolation: isolate;
  display: grid;
  align-content: end;
  min-height: clamp(30rem, 78svh, 46rem);
  padding-top: calc(var(--nav-h) + 3rem);
  padding-bottom: clamp(2.5rem, 4.5vw, 4rem);
  background: var(--ink);
  color: #fff;
  overflow: hidden;
}

.ahead__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Weighted to the floor, where the type is, so the photograph keeps its top
   half. The bar brings its own scrim for the controls, so this one does not
   have to carry the whole frame.

   The stops are measured, and they are in rem rather than percentages. The
   text block is anchored to the floor and is roughly a fixed height, so a
   percentage ramp slides away from it every time the header's min-height
   changes — which is exactly what happened: percentage stops read 2.7:1 on the
   breadcrumb at one height and dropped the standfirst to 4.2:1 at the next.
   Lengths keep the dense part of the ramp over the type whatever the header
   does, and leave the top of the photograph alone. */
.ahead::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to top,
    rgba(8, 8, 12, 0.93) 0,
    rgba(8, 8, 12, 0.88) 20rem,
    rgba(8, 8, 12, 0.6)  32rem,
    rgba(8, 8, 12, 0.34) 100%);
}

.ahead__h { margin-top: 1.25rem; max-width: 26ch; text-wrap: balance; }

.ahead__lead {
  margin-top: 1.25rem;
  max-width: 52rem;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.94);
  text-wrap: pretty;
}

.ahead__date {
  margin-top: 1.5rem;
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.72);
}


.crumb ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.crumb li { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9375rem; color: var(--ink-2); }
.crumb li + li::before { content: "/"; color: var(--grey-2); }
.crumb a { color: var(--ink-2); }
.crumb a:hover { color: var(--asphalt); text-decoration: underline; text-underline-offset: 3px; }
.crumb [aria-current] { color: var(--asphalt); font-weight: 600; }

/* The breadcrumb inverted, and set in a pill of its own. Sitting loose on a
   photograph it had to fight whatever was behind it; a glass pill gives it a
   ground, so the type can be plain white rather than a shade chosen to survive
   the worst frame. inline-flex is what makes the pill hug its contents — the
   base .crumb ol is a block-level flex row and would stretch the full measure.

   It has to sit BELOW the base .crumb rules, not above them. Every pair here
   ties on specificity, so source order is the whole fight: written first, the
   modifier lost all of it — a full-width pill with grey type, which is exactly
   what it looked like. */

.crumb--onDark ol {
  display: inline-flex;
  padding: 0.5rem 1.125rem;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
          backdrop-filter: blur(16px) saturate(1.4);
}

.crumb--onDark li,
.crumb--onDark a,
.crumb--onDark [aria-current] { color: #fff; }
.crumb--onDark a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.crumb--onDark li + li::before { color: rgba(255, 255, 255, 0.45); }


/* ---- Spec strip ----
   The at-a-glance answers a detail page owes its reader: what it costs, how
   long it runs, who it is for. Hairline rules rather than cards — this is
   reference, and a row of filled panels would compete with the sections that
   follow. */

.specs { display: grid; gap: 1px; margin-top: 2.5rem; background: rgba(0, 0, 0, 0.09); border-block: 1px solid rgba(0, 0, 0, 0.09); }
@media (min-width: 640px)  { .specs { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .specs { grid-template-columns: repeat(4, 1fr); } }

.spec { background: var(--white); padding: 1.5rem 1.25rem 1.5rem 0; }
@media (min-width: 640px) { .spec { padding-inline: 1.5rem; } .spec:first-child { padding-left: 0; } }
.spec dt { font-family: var(--display); font-size: 0.75rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2); }
.spec dd { margin: 0.5rem 0 0; font-size: 1.0625rem; line-height: 1.5; }

/* ---- Flow ----
   A numbered sequence with no photography — for steps that are procedure
   rather than scene. The numeral is a ghost behind the heading at display
   scale, which keeps the order legible without a row of coloured badges. */

.flow { display: grid; gap: 2.5rem; counter-reset: flow; }
@media (min-width: 1024px) { .flow { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }

.flow__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  padding-top: 1.25rem;
  border-top: 1px solid rgba(0, 0, 0, 0.12);
}
/* The numeral sits behind its own heading rather than above it: at 0.07 ink
   it is a watermark, so it can be large enough to mark the sequence at a
   glance without competing with the words sitting on it. Shared by every
   numbered list on the site — see .step__num below. */
.flow__n,
.step__num {
  grid-area: 1 / 1;
  align-self: center;
  justify-self: start;
  font-family: var(--display);
  font-weight: 900;
  letter-spacing: -0.05em;
  line-height: 1;
  color: rgba(0, 0, 0, 0.07);
  user-select: none;
  pointer-events: none;
}

/* Sized against its own heading, not to a fixed number: the steps heading is
   .t-mid, half again the size of the flow heading, so the same numeral would
   have been almost completely covered. */
.flow__n { font-size: 4rem; }
.step__num { font-size: 5.5rem; }
/* Three parallel points rather than a sequence — same rule and rhythm, no
   numerals, so nothing implies an order that is not there. */
.flow--plain .flow__item { padding-top: 1.5rem; }
.flow--plain .flow__item > h3 { align-self: start; }

.flow__item > h3,
.step__body > h3 { grid-area: 1 / 1; align-self: center; position: relative; }

.flow__item h3 { font-size: clamp(1.1875rem, 1.8vw, 1.375rem); }
.flow__item p { margin-top: 0.75rem; font-size: 1.0625rem; color: var(--ink-2); }

/* A label above the copy, not a second heading — it names the idea the block
   is an example of. */
.flow__sub {
  margin-top: 0.5rem !important;
  font-family: var(--display);
  font-size: 0.75rem !important;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---- Day rate configurator ---- */

.rate { display: grid; gap: 3rem; }
@media (min-width: 1024px) { .rate { grid-template-columns: 1fr 24rem; gap: 4rem; align-items: start; } }

.rate__intro { max-width: 34rem; }

.rate__card {
  background: var(--white);
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: var(--r-card);
  padding: 1.75rem;
}
.rate__card .chips { margin-bottom: 1.5rem; }
.rate__card .tier__cta { margin-top: 2.25rem; }
.rate__list { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid rgba(0, 0, 0, 0.1); display: grid; gap: 0.75rem; }
.rate__list li { position: relative; padding-left: 1.125rem; font-size: 1rem; color: var(--ink-2); }
.rate__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.65em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

/* ---- Practicals ---- */

.practicals { display: grid; gap: 1px; margin-top: 2.5rem; background: rgba(0, 0, 0, 0.09); border-block: 1px solid rgba(0, 0, 0, 0.09); }
@media (min-width: 640px)  { .practicals { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .practicals { grid-template-columns: repeat(4, 1fr); } }

.practical { background: var(--grey); padding: 1.5rem 1.25rem 1.5rem 0; }
@media (min-width: 640px) { .practical { padding-inline: 1.5rem; } .practical:first-child { padding-left: 0; } }
.practical dt { font-family: var(--display); font-size: 0.75rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2); }
/* These are dd, not p, so the global `p { text-wrap: pretty }` never reached
   them and every spec row on the site was free to strand its tail. `pretty` is
   not enough on its own here either: it guards a last line of ONE word, and
   the stub that started this was "50 people." — two words, which it allows.
   At two or three short lines these want balancing, not just orphan control. */
.practical dd { margin: 0.5rem 0 0; font-size: 1.0625rem; line-height: 1.5; text-wrap: balance; }

/* ---- Sticky section rail ----
   A long page should show its own shape. Sits directly under the fixed bar,
   so the offset is the bar's height. */

.rail {
  position: sticky;
  top: var(--nav-h);
  z-index: 40;
  background: rgba(255, 255, 255, 0.92);
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .rail {
    background: rgba(255, 255, 255, 0.78);
    -webkit-backdrop-filter: blur(20px) saturate(1.7);
            backdrop-filter: blur(20px) saturate(1.7);
  }
}

.rail__in { display: flex; align-items: center; gap: 1.5rem; padding-block: 0.75rem; }
.rail__title { font-family: var(--display); font-size: 0.9375rem; font-weight: 700; letter-spacing: -0.01em; flex: none; }
.rail__links { display: flex; gap: 1.5rem; overflow-x: auto; scrollbar-width: none; margin-left: auto; }
.rail__links::-webkit-scrollbar { display: none; }
.rail__links a { flex: none; font-size: 0.8125rem; color: var(--ink-2); white-space: nowrap; }
.rail__links a:hover { color: var(--asphalt); }

/* The scrollbar is hidden, so the row has to say "more this way" some other
   way. Two things do it, the same pair the reviews rail uses: the links run
   off the viewport edge instead of stopping at the shell gutter, and the last
   of them fades rather than being chopped mid-word. A hard cut at a padding
   edge reads as a layout fault; a fade reads as content continuing.

   The fade is still on when you reach the end, which costs a little contrast
   on the final link. That is the price of doing it without script, and it is
   cheaper than the row looking broken on arrival. */
@media (max-width: 1023px) {
  .rail__title { display: none; }

  .rail__in { padding-inline: 0; }
  .rail__links {
    margin-left: 0;
    padding-inline: var(--pad);
    scroll-padding-inline: var(--pad);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
  }
}

/* Anchors must clear the fixed bar plus the sticky rail. */
[id] { scroll-margin-top: calc(var(--nav-h) + 3.5rem); }

/* The sticky rail's links used to jump, which on a long interior page gives no
   sense of how far you moved or which way. Smooth belongs on the scrolling
   element rather than the links, so it is set once here and every in-page
   anchor on the site gets it — the rail, the racing team's Apply, the
   activation enquiry form. Behind the motion query, because for a reader who
   asked for less motion an instant jump is the correct behaviour, not a
   degraded one. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* ---- Section head ---- */

.sechead { max-width: 40rem; margin-bottom: 3rem; }
.sechead .kicker { margin-bottom: 0.875rem; }

/* A lead paragraph under a section head is part of the head, so it closes the
   3rem gap the head would otherwise leave before it. */
.sechead + .sub { margin-top: -2rem; margin-bottom: 2.5rem; max-width: 38rem; }

/* ---- Paths ----
   Two routes into the lounge, each a photo over its own copy. No card fill:
   the section ground is white and the photo is structure enough, so a surface
   behind the text would only add an edge the page does not need. One action
   per card — the whole card is the link — rather than a second booking button
   competing with it. */

.paths { display: grid; gap: 2.5rem; }

/* Only while stacked. Side by side the columns separate themselves. */
@media (max-width: 767px) {
  .paths { gap: 0; }
  .path + .path { margin-top: 2.5rem; padding-top: 2.5rem; border-top: 1px solid rgba(0, 0, 0, 0.1); }
}
@media (min-width: 768px) { .paths { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
@media (min-width: 640px)  { .paths--three { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
@media (min-width: 1024px) { .paths--three { grid-template-columns: repeat(3, 1fr); } }

.path-anchor { min-width: 0; }
.path-anchor > .path { height: 100%; }
.path { display: flex; flex-direction: column; }

.path__media { border-radius: var(--r-card); overflow: hidden; aspect-ratio: 16 / 10; }
.path__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.8s var(--ease); }
.path:hover .path__media img { transform: scale(1.04); }

.path__body { display: flex; flex-direction: column; flex: 1; padding-top: 1.5rem; }

/* Same register as the step numerals: small, letterspaced, 800 — the weight
   display type does not take at this size. */
.path__label {
  font-family: var(--display);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hue);
}

.path h3 { margin-top: 0.75rem; font-size: clamp(1.375rem, 2.2vw, 1.875rem); }
.path__copy { margin-top: 0.875rem; font-size: 1.0625rem; color: var(--ink-2); }

.path__list { display: grid; gap: 0.5rem; margin-top: 1.5rem; }
.path__list li { position: relative; padding-left: 1.125rem; font-size: 1.0625rem; color: var(--ink-2); }
.path__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.7em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--hue);
}

/* mt:auto pins the action to the bottom so both cards agree on it however
   much copy sits above. */
.path .link { margin-top: auto; padding-top: 1.75rem; font-size: 1.0625rem; }

.path--orange { --hue: #ff5e40; }
.path--blue   { --hue: #1997ff; }
.path--violet { --hue: #5d3a8a; }

/* ---- Steps ---- */

.steps { display: grid; gap: 3rem; }
@media (min-width: 1024px) { .steps { gap: 4.5rem; } }

.step { display: grid; gap: 1.75rem; align-items: center; }
@media (min-width: 1024px) {
  .step { grid-template-columns: 1fr 1fr; gap: 3.5rem; }
  .step:nth-child(even) .step__media { order: 2; }
}

.step__media { border-radius: var(--r-card); overflow: hidden; aspect-ratio: 3 / 2; background: var(--grey-2); }
.step__media img { width: 100%; height: 100%; object-fit: cover; }
/* Was a small letterspaced label above the heading. The watermark reads the
   sequence faster and costs no vertical space of its own. */
.step__body { display: grid; grid-template-columns: minmax(0, 1fr); }
.step__body p:last-child { margin-top: 1rem; color: var(--ink-2); line-height: 1.65; }

.sec--ink .flow__n,
.sec--ink .step__num { color: rgba(255, 255, 255, 0.12); }

/* ---- Narrative ---- */

.story { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 1024px) {
  .story { grid-template-columns: 1fr 1fr; gap: 4rem; }
  .story--flip .story__media { order: -1; }
}

.story__text { max-width: 34rem; }
.story__p { margin-top: 1.125rem; color: var(--ink-2); line-height: 1.7; }
.story__media { border-radius: var(--r-card); overflow: hidden; aspect-ratio: 4 / 3; background: var(--grey-2); }
.story__media img { width: 100%; height: 100%; object-fit: cover; }

.pull {
  margin-top: 1.75rem;
  padding-left: 1.25rem;
  border-left: 3px solid var(--asphalt);
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.35;
  color: var(--asphalt);
}

/* ---- Occasions ----
   A chip list, not a card grid: these are labels, and nine filled panels would
   read as nine offers. Sized so the row wraps naturally at any width rather
   than locking to a column count. */

.occs { display: flex; flex-wrap: wrap; gap: 0.625rem; }
.occ {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 1.125rem;
  background: var(--white);
  border-radius: var(--r-pill);
  font-size: 1rem;
  line-height: 1.2;
}
.occ__e { font-size: 1.125rem; line-height: 1; }
.occ__i { display: inline-flex; color: var(--accent); }
.occ__i svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.7; }

/* On a white section the filled chip disappears, so it takes a hairline. */
.occ--line { border: 1px solid rgba(0, 0, 0, 0.14); }

/* ---- Quote card ----
   Built for the home page's scroller, which is gone; the static .trio below
   is now its only user, so it no longer needs the flex basis a rail wanted. */

.voice {
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-radius: var(--r-card);
  padding: 1.75rem;
}
.voice__stars { display: flex; gap: 2px; color: var(--accent); margin-bottom: 1rem; }
.voice__stars svg { width: 15px; height: 15px; }
.voice p { font-family: var(--display); font-size: 1.125rem; font-weight: 700; line-height: 1.4; letter-spacing: -0.02em; flex: 1; }
.voice footer { margin-top: 1.25rem; font-size: 0.875rem; color: var(--ink-2); }

/* On a white section the filled card disappears, so it takes a hairline. */
.voice--line { border: 1px solid rgba(0, 0, 0, 0.1); }

/* ---- Quote trio (static, unlike the home page's scroller) ---- */

.trio { display: grid; gap: 1.25rem; }
@media (min-width: 1024px) { .trio { grid-template-columns: repeat(3, 1fr); } }
.voice--line { border: 1px solid rgba(0, 0, 0, 0.1); }

/* ---- Filter chips ----
   Real buttons with aria-pressed, not links: this filters the list in place,
   it does not navigate. */

/* ---- Chips ----
   Two users, two shapes. The FAQ filters with five of them, which are
   independent pills; the activations rate card picks between exactly two,
   which is a switch. The switch is a modifier, not the default — written as
   the default it put a half-width thumb and a two-column grid onto the FAQ's
   five filters and produced a black blob over three rows of them. */

.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.5rem; margin-bottom: 2.5rem; }
.chip {
  padding: 0.5rem 1rem;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: var(--r-pill);
  font-size: 0.9375rem;
  color: var(--ink-2);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.chip:hover { color: var(--asphalt); border-color: rgba(0, 0, 0, 0.35); }
.chip.is-on { background: var(--asphalt); border-color: var(--asphalt); color: #fff; }

/* ---- Chips as a switch ----
   A track with a thumb that slides between the halves, so the change reads as
   movement rather than two backgrounds taking turns. Exactly two options: the
   thumb is half the track, and a third chip would break it.

   Two 1fr tracks rather than flex:1, because with nowrap each chip holds its
   own min-content — "1 simulator" came out 110px against "2 simulators" at
   120px, and a thumb travelling 50% landed a pixel short of the second. */

.chips--switch {
  position: relative;
  display: inline-grid;
  grid-template-columns: repeat(2, 1fr);
  flex-wrap: nowrap;
  gap: 0;
  padding: 0.25rem;
  background: var(--grey-2);
  border-radius: var(--r-pill);
}

.chips--switch::before {
  content: "";
  position: absolute;
  z-index: 0;
  top: 0.25rem;
  bottom: 0.25rem;
  left: 0.25rem;
  width: calc(50% - 0.25rem);
  background: var(--asphalt);
  border-radius: var(--r-pill);
  transition: transform 0.38s var(--ease);
}

/* Driven off the button's own pressed state, so the thumb cannot disagree with
   what assistive tech is told. */
.chips--switch:has(.chip:last-child[aria-pressed="true"])::before { transform: translateX(100%); }

.chips--switch .chip {
  position: relative;
  z-index: 1;
  padding: 0.5rem 1.125rem;
  border: 0;
  background: none;
  white-space: nowrap;
  transition: color 0.28s var(--ease);
}
.chips--switch .chip:hover { color: var(--asphalt); }
.chips--switch .chip[aria-pressed="true"],
.chips--switch .chip.is-on { background: none; color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .chips--switch::before { transition: none; }
}

.faq__empty { margin-top: 2rem; color: var(--ink-2); }

/* ---- FAQ ----
   details/summary: open, close and keyboard behaviour come free, and every
   answer sits in the DOM for search whether or not it is expanded. */

.faq { border-top: 1px solid rgba(0, 0, 0, 0.1); }
.faq__item { border-bottom: 1px solid rgba(0, 0, 0, 0.1); }

.faq__item summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.25rem 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

.faq__sign { position: relative; flex: none; width: 14px; height: 14px; margin-top: 0.35rem; }
.faq__sign::before, .faq__sign::after {
  content: "";
  position: absolute; inset: 50% 0 auto;
  height: 1.5px; background: var(--asphalt);
  transition: transform 0.3s var(--ease);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item[open] .faq__sign::after { transform: rotate(0deg); }

.faq__a { padding-bottom: 1.5rem; }
.faq__a p { max-width: 60ch; color: var(--ink-2); line-height: 1.7; }

/* ==========================================================================
   Pricing
   ========================================================================== */

.tiers { display: grid; gap: 1.25rem; }
@media (min-width: 768px) { .tiers { grid-template-columns: repeat(2, 1fr); } }

/* A column with the button pushed to the floor, so cards that sit beside each
   other end their CTAs on one line however much description they carry. The
   grid used to align-items:start, which let every card be its own height and
   left the buttons at four different heights down the page. */
.tier {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--white);
  color: var(--ink);
  /* 2px on every card, transparent where it is not the feature. A 1px border
     on the others and 2px on the feature pushed the feature's content a pixel
     down and in — enough to knock its name, price and line out of step with
     the card beside it, which is what read as the cards not lining up. */
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
  border-radius: var(--r-card);
  padding: 2rem 1.75rem 2.25rem;
}

/* Marked by weight, not colour. The lit ring cannot work on this card: the
   brightest colour in it has a luminance of 0.415 against a white card's 1.0,
   so it is darker than the surface it sits on and reads as a printed gradient
   rather than emitted light. The glow lives on this card's button instead,
   where it has the dark fill it needs.

   The ticks, the divider and the flag therefore stay exactly as the other
   card's — nothing about a recommendation should change what the card is. */
.tier--feature { border-color: var(--asphalt); box-shadow: none; }

.tier__flag {
  position: absolute;
  top: -0.75rem; left: 1.75rem;
  padding: 0.25rem 0.625rem;
  background: var(--asphalt);
  color: #fff;
  border-radius: 100px;
  font-family: var(--display);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.tier__name { font-family: var(--display); font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em; }

.tier__price { display: flex; align-items: baseline; gap: 0.375rem; margin-top: 0.75rem; }
.tier__price b { font-family: var(--display); font-size: clamp(2.75rem, 5vw, 3.5rem); font-weight: 900; letter-spacing: -0.045em; line-height: 1; }
.tier__price > span { color: var(--ink-2); font-size: 1rem; }

.tier__line { margin-top: 0.625rem; color: var(--ink-2); }
.tier__cta { margin-top: 1.5rem; width: 100%; justify-content: center; }

/* Only when the CTA is the last thing in the card does it go to the floor, so
   cards beside each other end their buttons on one line. Memberships puts a
   feature list AFTER its button, and there it has to stay where it falls —
   pushing it down would open a hole between the price and the list. The
   element above it carries the gap, because margin-top:auto eats its own. */
.tier > .tier__cta:last-child { margin-top: auto; }
.tier > *:has(+ .tier__cta:last-child) { margin-bottom: 1.5rem; }

.tier__list { margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; gap: 0.75rem; }
.tier__list li { display: flex; gap: 0.75rem; align-items: flex-start; }
.tier__tick { width: 18px; height: 18px; flex: none; margin-top: 0.2rem; color: var(--accent); }

/* ==========================================================================
   Comparison table
   A real <table>: the data is tabular, and row and column headers let a
   screen reader announce which tier a cell belongs to. It scrolls inside its
   own container rather than forcing the page sideways on a phone.
   ========================================================================== */

.cmp { overflow-x: auto; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: var(--r-card); background: var(--white); }
.cmp table { width: 100%; border-collapse: collapse; min-width: 34rem; }

.cmp th, .cmp td { padding: 0.875rem 1.25rem; text-align: left; font-size: 1rem; }
.cmp thead th {
  position: sticky; top: 0;
  background: var(--white);
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.cmp tbody tr + tr th, .cmp tbody tr + tr td { border-top: 1px solid rgba(0, 0, 0, 0.08); }
.cmp tbody th { font-weight: 600; color: var(--ink-2); }
.cmp tbody td { font-family: var(--display); font-weight: 700; letter-spacing: -0.01em; }
.cmp tbody tr:hover th, .cmp tbody tr:hover td { background: var(--grey); }

.cmp__yes { display: inline-flex; color: var(--accent); }
.cmp__yes .tier__tick { margin: 0; }
.cmp__no { color: var(--ink-2); }

/* ==========================================================================
   Add-ons
   ========================================================================== */

.addons { display: grid; gap: 1.25rem; }
@media (min-width: 768px) { .addons { grid-template-columns: repeat(3, 1fr); } }

.addon { background: var(--white); border-radius: var(--r-card); padding: 1.75rem; }
.addon--line { border: 1px solid rgba(0, 0, 0, 0.1); }
.addon__price { display: flex; align-items: baseline; gap: 0.3125rem; }
.addon__price b { font-family: var(--display); font-size: 2rem; font-weight: 900; letter-spacing: -0.04em; line-height: 1; }
.addon__price > span { color: var(--ink-2); font-size: 0.9375rem; }
.addon h3 { margin-top: 0.875rem; font-family: var(--display); font-size: 1.125rem; font-weight: 700; letter-spacing: -0.02em; }
.addon__line { margin-top: 0.375rem; color: var(--ink-2); font-size: 1rem; }
.addon ul { margin-top: 1.125rem; padding-top: 1rem; border-top: 1px solid rgba(0, 0, 0, 0.09); display: flex; flex-direction: column; gap: 0.5rem; }
.addon li { font-size: 0.9375rem; color: var(--ink-2); line-height: 1.5; }

.addons__foot { margin-top: 2rem; }

/* ==========================================================================
   404
   The one page that stays on the dark ground on purpose — it is where the
   socket joke lands, and an inverse treatment marks it as off the main path.
   ========================================================================== */

.oops { background: var(--asphalt); color: #fff; padding-top: 9rem; }
.oops .sub { color: rgba(255, 255, 255, 0.68); }
.oops__tag {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.oops__socket {
  width: clamp(7rem, 16vw, 11rem);
  height: auto;
  margin: 2.5rem auto 2rem;
  transform: rotate(-8deg);
  filter: drop-shadow(0 22px 34px rgba(0, 0, 0, 0.5));
}

.oops__links { margin-top: 4rem; padding-top: 2rem; border-top: 1px solid rgba(255, 255, 255, 0.14); }
.oops__or { font-size: 0.9375rem; color: rgba(255, 255, 255, 0.55); margin-bottom: 1rem; }
.oops__links ul { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; }
.oops__links a {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-pill);
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.78);
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.oops__links a:hover { background: #fff; border-color: #fff; color: var(--asphalt); }

/* ==========================================================================
   Contact
   The reference column sits beside the form, not above it: someone who only
   wants the phone number should not have to scroll past a form to reach it.
   It stacks below the form on a phone for the same reason — on a small screen
   the form is the thing most people came for.
   ========================================================================== */

.contact { display: grid; gap: 3rem; }
@media (min-width: 1024px) {
  .contact { grid-template-columns: 19rem 1fr; gap: 4.5rem; align-items: start; }
  .contact__info { order: 0; }
}
@media (max-width: 1023px) { .contact__info { order: 1; } }

.contact__info { display: grid; gap: 2rem; align-content: start; }

/* min-width:0 so a long email address or a wide select cannot push the grid
   track wider than its share and force the page sideways. */
.contact__form { min-width: 0; }

.info__h {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 0.875rem;
}

/* display:contents lets the dt/dd pair take part in the parent grid, so the
   time stays on the same row as its day instead of wrapping under it. */
.info__hours { display: grid; grid-template-columns: auto auto; gap: 0.5rem 1.5rem; justify-content: start; }
.info__hours > div { display: contents; }
.info__hours dd { font-variant-numeric: tabular-nums; }
.info__hours .is-closed dt, .info__hours .is-closed dd { color: var(--ink-2); }

.info address { font-style: normal; line-height: 1.55; }
.info address a:hover { text-decoration: underline; text-underline-offset: 3px; }
.info__big { font-family: var(--display); font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em; }
.info__big a:hover { color: var(--accent); }

.info__pairs { display: grid; gap: 0.875rem; }
.info__pairs dt { font-size: 0.9375rem; color: var(--ink-2); }
.info__pairs dd { margin-top: 0.125rem; }
.info__pairs a { word-break: break-word; }
.info__pairs a:hover { color: var(--accent); }

.info__links { display: grid; gap: 0.75rem; }

/* ==========================================================================
   Pit Notes
   ========================================================================== */

.posts { display: grid; gap: 2.5rem; }
@media (min-width: 640px)  { .posts { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
@media (min-width: 1024px) { .posts { grid-template-columns: repeat(3, 1fr); } }

.posts__empty { padding: 4rem 0; text-align: center; color: var(--ink-2); }

.post { display: flex; flex-direction: column; }
.post__media {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--grey);
  display: grid;
  place-items: center;
}
.post__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.8s var(--ease); }
.post:hover .post__media img { transform: scale(1.04); }
.post__mark { font-family: var(--display); font-size: 2.5rem; font-weight: 900; color: var(--grey-2); }

.post__body { display: flex; flex-direction: column; flex: 1; padding-top: 1.25rem; }
.post__cat {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.625rem;
}
.post h2 { font-size: clamp(1.1875rem, 1.8vw, 1.375rem); }
.post__ex { margin-top: 0.625rem; font-size: 1.0625rem; color: var(--ink-2); }
.post__date { font-size: 0.9375rem; color: var(--ink-2); }
.post__body .post__date { margin-top: 0.875rem; }
.post .link { margin-top: 1rem; }

/* ---- Article ---- */


.article { display: grid; gap: 3.5rem; }
@media (min-width: 1024px) { .article { grid-template-columns: minmax(0, 1fr) 17rem; gap: 4.5rem; align-items: start; } }

/* The one place editors produce the markup, so everything is styled by
   element — a class the stylesheet has never seen cannot reach the page. */
.prose { max-width: 42rem; min-width: 0; }
.prose > * + * { margin-top: 1.5rem; }
.prose p { font-size: 1.1875rem; line-height: 1.7; }
.prose h2 { margin-top: 3rem; font-size: clamp(1.5rem, 2.6vw, 2.125rem); }
.prose h3 { margin-top: 2.5rem; font-size: clamp(1.25rem, 2vw, 1.5rem); }
.prose h4 { margin-top: 2rem; font-family: var(--display); font-size: 1.125rem; font-weight: 700; letter-spacing: -0.02em; }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--accent-deep); }
.prose strong { font-weight: 700; }
.prose code {
  padding: 0.125em 0.375em;
  background: var(--grey);
  border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}
.prose blockquote {
  padding-left: 1.25rem;
  border-left: 3px solid var(--asphalt);
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.4;
}
.prose figure { margin: 2.5rem 0; }
.prose figure img { width: 100%; border-radius: var(--r-card); }
.prose figcaption { margin-top: 0.75rem; font-size: 0.9375rem; color: var(--ink-2); }

.aside { display: grid; gap: 2.5rem; align-content: start; min-width: 0; }
.aside__block { min-width: 0; }

.aside__h {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 1rem;
}
.aside__list { display: grid; gap: 0.875rem; }
.aside__list a { font-size: 1rem; line-height: 1.4; }
.aside__list a:hover { color: var(--accent); }
.aside__year + .aside__year { margin-top: 1.5rem; }
.aside__year h3 { font-family: var(--display); font-size: 1rem; font-weight: 700; margin-bottom: 0.625rem; }

.rel { display: flex; gap: 0.875rem; align-items: flex-start; }
.rel__media { flex: none; width: 4.5rem; aspect-ratio: 16 / 10; border-radius: 10px; overflow: hidden; background: var(--grey); }
.rel__media img { width: 100%; height: 100%; object-fit: cover; }
.rel__text { display: grid; gap: 0.25rem; }
.rel__t { font-family: var(--display); font-weight: 700; font-size: 0.9375rem; line-height: 1.3; letter-spacing: -0.01em; }
.rel__d { font-size: 0.8125rem; color: var(--ink-2); }

.aside__cta { background: var(--grey); border-radius: var(--r-card); padding: 1.5rem; }
.aside__cta h2 { font-family: var(--display); font-size: 1.125rem; font-weight: 700; letter-spacing: -0.02em; }
.aside__cta p { margin-top: 0.625rem; font-size: 1rem; color: var(--ink-2); }
.aside__cta .link { margin-top: 1rem; }

/* ==========================================================================
   Forms
   Light fields on white: a hairline box rather than a filled one, so a column
   of inputs does not read as a stack of grey bars. Controls inherit the body
   face — a form is for reading back what you typed, not for display type.

   16px minimum on every control: iOS zooms the viewport when a focused field
   is smaller than that, and the zoom does not reverse on blur.
   ========================================================================== */

.form { display: grid; gap: 1.25rem; max-width: 42rem; }
.form__row { display: grid; gap: 1.25rem; }
@media (min-width: 640px) { .form__row { grid-template-columns: repeat(2, 1fr); } }

.field { display: grid; gap: 0.4375rem; }
.field > label {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.field .req { color: #ff5e40; }

.input, .select, .textarea {
  width: 100%;
  padding: 0.8125rem 1rem;
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--ink);
  background: var(--white);
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: 14px;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.input::placeholder, .textarea::placeholder { color: #8a8a90; }
.input:hover, .select:hover, .textarea:hover { border-color: rgba(0, 0, 0, 0.3); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(93, 58, 138, 0.18);
}
.textarea { resize: vertical; min-height: 8rem; }

/* The arrow is painted here because a native select's own control cannot be
   restyled; appearance:none removes it, so one has to be drawn back. */
.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236e6e73' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 16px;
  cursor: pointer;
}

.form__note { font-size: 0.9375rem; color: var(--ink-2); }
.form__msg { padding: 0.875rem 1.125rem; border-radius: 14px; font-size: 1rem; }
.form__msg--err { background: rgba(255, 94, 64, 0.08); color: #ff5e40; }
.form__ok { padding: 2.5rem 0; text-align: center; }
.form__ok h2 { font-size: clamp(1.5rem, 2.6vw, 2.125rem); }
.form__ok p { margin-top: 0.875rem; color: var(--ink-2); }

/* The form scripts predate this stylesheet and toggle a .hidden class rather
   than the hidden attribute. Kept until those modules are rewritten. */
.hidden { display: none !important; }

.phead__brand { display: flex; justify-content: center; }
.phead__brand img { width: auto; height: clamp(26px, 3.4vw, 34px); }

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .rise { opacity: 1; transform: none; }
}

/* ==========================================================================
   Cookie consent
   A bar, not a modal. It asks for one thing and does not hold the page
   hostage to the answer: no overlay, no focus trap, and the content behind it
   stays readable and operable. The regulation wants a real choice, not a
   dark pattern, so Decline sits first and both buttons carry equal weight.
   ========================================================================== */

.consent {
  position: fixed;
  z-index: 80;
  inset-inline: 0;
  bottom: 0;
  background: var(--white);
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0 -18px 40px -24px rgba(0, 0, 0, 0.35);
  transform: translateY(100%);
  transition: transform 0.45s var(--ease);
}
.consent.is-up { transform: none; }

.consent__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem 2rem;
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 1.25rem var(--pad);
}

.consent__copy {
  flex: 1 1 24rem;
  max-width: 54ch;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}
.consent__copy a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

.consent__actions { display: flex; flex-wrap: wrap; gap: 0.625rem; }
.consent__actions .btn { font-size: 0.9375rem; }

@media (max-width: 639px) {
  .consent__actions { width: 100%; }
  .consent__actions .btn { flex: 1; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .consent { transition: none; }
}

/* The bar is fixed, so without this it sits on top of the end of the footer —
   which is where the Cookie settings link lives. The class comes off when the
   choice is made, and the padding with it. */
.has-consent-banner body { padding-bottom: 9rem; }
@media (min-width: 640px) { .has-consent-banner body { padding-bottom: 6rem; } }

/* ---- Legal pages ----
   The prose column, plus the date the document last changed. Sections get a
   scroll margin from the global [id] rule, so the rail lands them clear of the
   bar and of itself. */

.legal__date { margin-top: 1.5rem; font-size: 0.9375rem; color: var(--ink-2); }
.legal { max-width: 44rem; }

/* .prose spaces its own direct children, and wrapping each clause in a
   <section> put every paragraph one level below that — so the rules stacked
   with no air between them. The spacing moves inside the section, and the
   section itself relies on its h2's margin for the gap above. */
.legal section > * + * { margin-top: 1.5rem; }
.legal section + section { margin-top: 0; }
.legal ul { margin-top: 1.25rem; padding-left: 1.25rem; display: grid; gap: 0.625rem; }
.legal li { font-size: 1.0625rem; line-height: 1.6; color: var(--ink-2); }
.legal li strong { color: var(--ink); }
.legal h4 { color: var(--ink); }

/* Withdrawing consent has to be as easy as giving it, so the link that reopens
   the banner sits in the footer of every page beside the documents it relates
   to. */
.foot__legal { display: flex; flex-wrap: wrap; gap: 1.25rem; }

/* ---- Notice ----
   A stated condition, not an alert: something true today that will stop being
   true. It sits in a page head under the standfirst, so it inherits the centred
   measure and stays quieter than the headline above it. Orange edge rather than
   an orange fill, because this is information and not a warning. */

.notice {
  max-width: 44rem;
  margin: 1.75rem auto 0;
  padding: 0.875rem 1.25rem;
  border: 1px solid rgba(255, 94, 64, 0.35);
  border-radius: var(--r-pill);
  background: rgba(255, 94, 64, 0.06);
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}
.notice strong { color: var(--asphalt); }

@media (max-width: 639px) {
  .notice { border-radius: 18px; }
}
