/* ==========================================================================
   10th Planet Jiu Jitsu Portland
   components.css — nav, buttons, cards, modal, footer, shared blocks
   ========================================================================== */

/* --------------------------------------------------------------------------
   NAV — a floating dock, not a bar.
   The previous version was a full-width two-tier bar welded to the top of the
   viewport. This one is a single compact dock inset from all three edges, with
   the wordmark left, the sections centred, and the phone plus the trial CTA
   right. It sits translucent over the hero and goes solid and slightly shorter
   once you are past it.
   Mobile is a full-screen sheet rather than a panel hanging off the header:
   large stacked links, Programs on an accordion, and the CTA, phone, live status
   and socials docked at the bottom where a thumb already is.
   Heights come from --nav-h / --nav-inset in base.css; nothing here hardcodes an
   offset, and --nav-total is what the hero and every page header pad by.
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  padding: var(--nav-inset) var(--pad-x);
  /* The padding area must not eat clicks meant for the hero underneath it. */
  pointer-events: none;
  transition: padding-top var(--dur) var(--ease);
}
.nav > * { pointer-events: auto; }
.nav.is-stuck { padding-top: calc(var(--nav-inset) * 0.55); }

.nav-dock { width: 100%; max-width: var(--shell); margin: 0 auto; }

.nav-bar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(0.6rem, 0.4rem + 0.9vw, 1.4rem);
  height: var(--nav-h);
  padding: 0 clamp(0.7rem, 0.55rem + 0.6vw, 1.1rem);
  border-radius: 14px;
  border: 1px solid rgba(140, 188, 255, 0.14);
  background: rgba(4, 16, 38, 0.6);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  box-shadow: 0 18px 40px -26px rgba(0, 6, 20, 0.7);
  transition:
    height var(--dur) var(--ease),
    background var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.nav.is-stuck .nav-bar {
  height: calc(var(--nav-h) - 6px);
  background: rgba(2, 11, 28, 0.93);
  border-color: rgba(140, 188, 255, 0.22);
  box-shadow: 0 20px 44px -22px rgba(0, 6, 20, 0.85);
}

/* The wordmark is deliberately small. In a 64px dock it is a mark, not a banner. */
.nav-logo { display: block; line-height: 0; }
.nav-logo img { width: auto; height: 30px; transition: height var(--dur) var(--ease); }
.nav.is-stuck .nav-logo img { height: 26px; }

/* --- Centre: the sections ------------------------------------------------- */
.nav-mid {
  display: none;
  justify-content: center;
  align-items: center;
  gap: clamp(0.05rem, 0.4vw, 0.4rem);
  min-width: 0;
}
@media (min-width: 1000px) { .nav-mid { display: flex; } }

.nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.55rem clamp(0.6rem, 0.45rem + 0.4vw, 0.9rem);
  border-radius: 8px;
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(206, 224, 250, 0.74);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
/* Underline sweeps in from the left. One accent line, no flashing. */
.nav-link::after {
  content: '';
  position: absolute;
  left: clamp(0.6rem, 0.45rem + 0.4vw, 0.9rem);
  right: clamp(0.6rem, 0.45rem + 0.4vw, 0.9rem);
  bottom: 0.32rem;
  height: 1.5px;
  background: var(--blue);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-fast) var(--ease);
}
.nav-link:hover { color: #fff; background: rgba(255, 255, 255, 0.05); }
.nav-link:hover::after { transform: scaleX(1); }
.nav-link[aria-current='page'],
.nav-link.is-current { color: #fff; }
.nav-link[aria-current='page']::after,
.nav-link.is-current::after { transform: scaleX(1); }

.nav-caret {
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-fast) var(--ease);
}
.nav-drop.is-open .nav-caret { transform: translateY(1px) rotate(-135deg); }

/* --- Right: phone, CTA, menu button -------------------------------------- */
.nav-right {
  display: flex;
  align-items: center;
  gap: clamp(0.35rem, 0.25rem + 0.5vw, 0.85rem);
  justify-self: end;
}
/* The phone is the first thing to go when the dock gets tight — it is duplicated
   in the sheet and in the footer, the CTA is not. */
.nav-phone { display: none; align-items: center; gap: 0.5rem; padding: 0.5rem 0.4rem; }
@media (min-width: 1180px) { .nav-phone { display: inline-flex; } }
.nav-phone span:last-child {
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: rgba(206, 224, 250, 0.86);
  transition: color var(--dur-fast) var(--ease);
}
.nav-phone:hover span:last-child { color: #fff; }
/* Green when a class is actually running — same liveState() the board reads. */
.nav-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgba(190, 208, 236, 0.4);
  flex: 0 0 auto;
  transition: background var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.nav-dot.is-open { background: #2FD08A; box-shadow: 0 0 0 3px rgba(47, 208, 138, 0.2); }

/* `.nav-bar .nav-cta`, not `.nav-cta`: .btn also sets a display and is defined
   further down this file, so at equal specificity source order handed it the win
   and the button kept showing on phones. */
.nav-bar .nav-cta { display: none; }
@media (min-width: 1000px) { .nav-bar .nav-cta { display: inline-flex; } }
.nav-cta svg { transition: transform var(--dur-fast) var(--ease); }
.nav-cta:hover svg { transform: translateX(3px); }

/* Two bars of different lengths, not three of the same. Morphs to a cross. */
.nav-burger {
  display: inline-grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 10px;
  border: 1px solid rgba(140, 188, 255, 0.16);
  background: rgba(255, 255, 255, 0.05);
  color: #fff;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.nav-burger:hover { background: rgba(255, 255, 255, 0.11); border-color: rgba(140, 188, 255, 0.36); }
@media (min-width: 1000px) { .nav-burger { display: none; } }
.nav-burger span { display: grid; gap: 5px; }
.nav-burger i {
  display: block;
  width: 18px; height: 1.6px;
  border-radius: 2px;
  background: currentColor;
  transition: transform var(--dur-fast) var(--ease), width var(--dur-fast) var(--ease);
}
.nav-burger i:last-child { width: 11px; margin-left: auto; }
.nav-burger[aria-expanded='true'] i:first-child { transform: translateY(3.3px) rotate(45deg); }
.nav-burger[aria-expanded='true'] i:last-child { width: 18px; transform: translateY(-3.3px) rotate(-45deg); }

/* --- Programs: a compact editorial panel --------------------------------- */
.nav-drop { position: relative; display: flex; }
.nav-mega {
  position: absolute;
  top: calc(100% + 0.85rem);
  left: 50%;
  transform: translateX(-50%) translateY(-8px);
  width: min(430px, calc(100vw - 2.5rem));
  padding: 0.5rem;
  border-radius: 14px;
  border: 1px solid rgba(140, 188, 255, 0.16);
  /* Fully opaque, and no backdrop-filter. The bar above is translucent on purpose
     — it is meant to sit over the hero — but a menu you are reading should not have
     the page showing through it. Opaque also means one less compositing layer. */
  background: linear-gradient(180deg, #0A1E42 0%, #04122B 100%);
  box-shadow: 0 30px 60px -24px rgba(0, 4, 14, 0.9);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease),
    visibility 0s linear var(--dur-fast);
}
/* Bridges the gap between the link and the panel. Without it, crossing that gap
   counts as leaving .nav-drop and the panel shuts under the pointer. */
.nav-mega::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -0.85rem;
  height: 0.85rem;
}
.nav-drop.is-open .nav-mega {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
  transition:
    opacity var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease),
    visibility 0s linear 0s;
}

.nav-mega-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.8rem;
  padding: 0.7rem 0.8rem;
  border-radius: 10px;
  transition: background var(--dur-fast) var(--ease);
}
.nav-mega-item:hover { background: rgba(255, 255, 255, 0.06); }
.nav-mega-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--rail, var(--blue));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rail, var(--blue)) 20%, transparent);
}
.nav-mega-name {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: 0.875rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #fff;
}
.nav-mega-desc {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  color: var(--on-ink-dim);
}
.nav-mega-arrow {
  color: #8CBCFF;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.nav-mega-item:hover .nav-mega-arrow,
.nav-mega-item:focus-visible .nav-mega-arrow { opacity: 1; transform: none; }
.nav-mega-item[aria-current='page'] { background: rgba(0, 102, 255, 0.14); }
.nav-mega-item[aria-current='page'] .nav-mega-arrow { opacity: 1; transform: none; }

.nav-mega-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.35rem;
  padding: 0.7rem 0.8rem 0.35rem;
  border-top: 1px solid rgba(140, 188, 255, 0.14);
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #8CBCFF;
  transition: color var(--dur-fast) var(--ease);
}
.nav-mega-foot:hover { color: #fff; }

/* --------------------------- MOBILE: the sheet --------------------------- */

.nav-sheet {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: clamp(1.25rem, 1rem + 2vw, 2rem);
  padding:
    max(var(--nav-inset), env(safe-area-inset-top)) var(--pad-x)
    max(1.25rem, env(safe-area-inset-bottom));
  overflow-y: auto;
  overscroll-behavior: contain;
  background:
    radial-gradient(120% 80% at 100% 0%, rgba(0, 102, 255, 0.22), transparent 60%),
    linear-gradient(170deg, #061530 0%, #030F24 52%, #000814 100%);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-1.5%);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s linear var(--dur);
}
.nav-sheet.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s linear 0s;
}
@media (min-width: 1000px) { .nav-sheet { display: none; } }

/* Oversized wordmark at the bottom edge, and one geometric arc. Both sit under
   the content at an opacity that reads as texture rather than decoration. */
.nav-sheet-mark {
  position: absolute;
  right: -0.05em;
  bottom: -0.1em;
  font-family: var(--display);
  font-weight: 900;
  font-stretch: 125%;
  font-size: clamp(5rem, 21vw, 10rem);
  line-height: 0.8;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  text-align: right;
  color: rgba(140, 188, 255, 0.055);
  pointer-events: none;
  user-select: none;
}
.nav-sheet::after {
  content: '';
  position: absolute;
  top: -22%;
  left: -30%;
  width: 78%;
  aspect-ratio: 1;
  border: 1px solid rgba(140, 188, 255, 0.07);
  border-radius: 50%;
  pointer-events: none;
}
/* The wordmark must keep its own `position: absolute` — this rule and
   .nav-sheet-mark have equal specificity, and this one comes later, so without the
   :not() it won the cascade, the mark became a grid item, and it pushed the entire
   menu down by its own height. */
.nav-sheet > *:not(.nav-sheet-mark) { position: relative; z-index: 1; }

.nav-sheet-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.nav-sheet-top .nav-logo img { height: 28px; }
.nav-sheet-close {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 10px;
  border: 1px solid rgba(140, 188, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
  color: rgba(206, 224, 250, 0.85);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav-sheet-close:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }

.nav-sheet-nav { display: flex; flex-direction: column; align-self: start; }

.nav-sheet-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  min-height: 56px;
  padding: 0.75rem 0;
  border-top: 1px solid rgba(140, 188, 255, 0.13);
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 118%;
  font-size: clamp(1.375rem, 1rem + 3.2vw, 2rem);
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: #fff;
  text-align: left;
  transition: color var(--dur-fast) var(--ease), padding-left var(--dur-fast) var(--ease);
}
.nav-sheet-link:last-child { border-bottom: 1px solid rgba(140, 188, 255, 0.13); }
.nav-sheet-link svg { flex: 0 0 auto; color: #8CBCFF; opacity: 0.75; }
.nav-sheet-link[aria-current='page'] { color: #8CBCFF; }

.nav-acc { display: contents; }
.nav-acc-sign { position: relative; width: 14px; height: 14px; flex: 0 0 auto; color: #8CBCFF; }
.nav-acc-sign::before,
.nav-acc-sign::after {
  content: '';
  position: absolute;
  top: 50%; left: 0;
  width: 14px; height: 1.8px;
  margin-top: -0.9px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.nav-acc-sign::after { transform: rotate(90deg); }
[aria-expanded='true'] .nav-acc-sign::after { transform: rotate(0deg); opacity: 0; }

/* Collapsed it is also `visibility: hidden`, which is what keeps the four
   programme links out of the tab order — max-height alone hides them visually but
   leaves them focusable, so a keyboard user tabs into a panel they cannot see. */
.nav-acc-panel {
  display: grid;
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    max-height var(--dur) var(--ease),
    opacity var(--dur-fast) var(--ease),
    visibility 0s linear var(--dur);
}
.nav-acc-panel.is-open {
  max-height: 26rem;
  opacity: 1;
  visibility: visible;
  transition:
    max-height var(--dur) var(--ease),
    opacity var(--dur-fast) var(--ease),
    visibility 0s linear 0s;
}

.nav-sub {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0.75rem;
  min-height: 52px;
  padding: 0.6rem 0 0.6rem 0.9rem;
  border-left: 2px solid var(--rail, var(--blue));
  margin: 0.35rem 0 0.35rem 0.15rem;
}
.nav-sub-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--rail, var(--blue));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rail, var(--blue)) 20%, transparent);
}
.nav-sub b {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
}
.nav-sub em {
  display: block;
  margin-top: 0.1rem;
  font-style: normal;
  font-size: 0.8125rem;
  color: var(--on-ink-dim);
}
.nav-sub[aria-current='page'] b { color: #8CBCFF; }

/* No CTA in here. The menu is for going somewhere; the trial offer lives in the
   hero, in every section CTA band, and in the footer. What is left is contact
   detail, so the footer block is sized for that rather than around a button —
   a top rule and tighter gaps instead of a 52px hole where the button was. */
.nav-sheet-foot {
  display: grid;
  gap: 0.55rem;
  align-content: end;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(140, 188, 255, 0.13);
}
.nav-sheet-addr {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--on-ink-mid);
}
.nav-sheet-addr a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.nav-sheet-phone {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  font-family: var(--mono);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #fff;
}
.nav-sheet-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(206, 224, 250, 0.7);
}
.nav-sheet-social {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.1rem;
  margin-top: 0.15rem;
}
.nav-sheet-social a {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(206, 224, 250, 0.7);
  transition: color var(--dur-fast) var(--ease);
}
.nav-sheet-social a:hover { color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .nav, .nav-bar, .nav-logo img, .nav-sheet, .nav-acc-panel { transition: none; }
  .nav-sheet { transform: none; }
}

/* --------------------------------------------------------------------------
   BUTTONS
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  padding: 1rem 1.6rem;
  border-radius: var(--r);
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition:
    transform var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--blue);
  color: #fff;
  box-shadow: var(--lift-blue);
}
.btn-primary:hover {
  background: #1F7BFF;
  box-shadow: 0 14px 38px rgba(0, 102, 255, 0.42);
  transform: translateY(-2px);
}
.btn-primary:active { transform: translateY(0); }

.btn-ghost {
  background: transparent;
  color: #fff;
  border: 1px solid rgba(160, 195, 245, 0.34);
}
.btn-ghost:hover {
  border-color: rgba(160, 195, 245, 0.7);
  background: rgba(255, 255, 255, 0.05);
}

.btn-outline {
  background: transparent;
  color: var(--ink);
  border: 1px solid rgba(0, 11, 31, 0.2);
}
.btn-outline:hover { border-color: var(--blue); color: var(--blue); }

.btn-sm { padding: 0.7rem 1.1rem; }
.btn-lg { padding: 1.15rem 2rem; font-size: var(--t-sm); }

/* Text link with a sliding arrow. Used for every "read more" affordance
   so the vocabulary stays consistent across pages. */
.link-go {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blue);
}
.link-go svg { transition: transform var(--dur-fast) var(--ease); }
.link-go:hover svg { transform: translateX(4px); }
.on-dark .link-go, .s-ink .link-go, .s-ink-2 .link-go { color: #6FA8FF; }

/* --------------------------------------------------------------------------
   CHIPS & RAILS — the level legend, reused everywhere a class is named
   -------------------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.34rem 0.7rem 0.34rem 0.5rem;
  border-radius: 100px;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: color-mix(in srgb, var(--rail) 14%, transparent);
  color: var(--rail);
  border: 1px solid color-mix(in srgb, var(--rail) 32%, transparent);
}
.chip::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--rail);
}
.s-paper .chip, .s-mist .chip {
  background: color-mix(in srgb, var(--rail) 12%, white);
  color: color-mix(in srgb, var(--rail) 72%, var(--ink));
  border-color: color-mix(in srgb, var(--rail) 30%, transparent);
}

/* Rail tokens by program */
.r-lv1  { --rail: var(--lv1); }
.r-lv2  { --rail: var(--lv2); }
.r-lv3  { --rail: var(--lv3); }
.r-kids { --rail: var(--kids); }
.r-thai { --rail: var(--thai); }
.r-wmn  { --rail: var(--womens); }
.r-spec { --rail: var(--specialty); }
/* Specialty on a light ground. #8FA6C4 was too pale to survive as a 7px dot on a
   white card, and six of Friday's nine rows are specialty classes — that column
   read as though half its markers were missing. Darkened to a steel that holds at
   dot size without competing with the six programme hues. */
.s-paper .r-spec, .s-mist .r-spec { --rail: #5E7BA6; }

/* --------------------------------------------------------------------------
   CARDS
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--lift-1);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.card-link:hover { transform: translateY(-5px); box-shadow: var(--lift-2); }

.card-media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--ink-2);
}
.card-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease);
}
.card-link:hover .card-media img { transform: scale(1.045); }
.card-media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 11, 31, 0.5), transparent 55%);
}
.card-media .chip { position: absolute; left: 0.9rem; bottom: 0.9rem; z-index: 1; }

.card-body {
  padding: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  flex: 1;
}
.card-title {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 118%;
  font-size: 1.25rem;
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--ink);
}
.card-text { font-size: 0.9375rem; line-height: 1.55; color: var(--slate); }
.card-body .link-go { margin-top: auto; padding-top: 0.5rem; }

/* Dark variant, for cards sitting on ink */
.card-dark {
  background: var(--ink-3);
  border-color: var(--rule-dark);
  box-shadow: none;
}
.card-dark .card-title { color: #fff; }
.card-dark .card-text { color: var(--on-ink-mid); }
.card-dark.card-link:hover { border-color: var(--blue-40); }

/* --------------------------------------------------------------------------
   STATS
   -------------------------------------------------------------------------- */

.stats {
  display: grid;
  gap: 1px;
  background: var(--rule-dark);
  border: 1px solid var(--rule-dark);
  border-radius: var(--r-lg);
  overflow: hidden;
}
@media (min-width: 560px) { .stats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 940px) { .stats { grid-template-columns: repeat(4, 1fr); } }

.stat {
  padding: clamp(1.25rem, 1rem + 1.4vw, 2rem) clamp(1rem, 0.8rem + 1vw, 1.5rem);
  background: var(--ink);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.stat .stat-num { font-size: clamp(1.875rem, 1.4rem + 1.9vw, 2.75rem); color: #fff; }
.stat-label {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}
.stat-sub { font-size: var(--t-sm); color: var(--on-ink-mid); line-height: 1.45; }

/* Rating cluster */
.rating { display: inline-flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; }
.rating-stars { display: inline-flex; gap: 2px; color: #FFC53D; }
.rating-stars svg { width: 15px; height: 15px; }
.rating-text {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-ink-mid);
}
.s-paper .rating-text, .s-mist .rating-text { color: var(--slate); }

/* --------------------------------------------------------------------------
   MODAL — the single conversion surface. Every CTA on the site opens this.
   -------------------------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 1.25rem;
  opacity: 0;
  visibility: hidden;
  /* visibility flips instantly on open (so .focus() works) and waits out the
     fade on close. */
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}
.modal.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur) var(--ease), visibility 0s linear 0s;
}

.modal-veil {
  position: absolute;
  inset: 0;
  background: rgba(0, 6, 18, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* The card is a dark premium panel, the same surface as the contact form, so the
   shared .form-panel field styles and the shared programme picker both work here
   without a light-ground variant. The card itself never scrolls — .modal-scroll
   does — which is what keeps the close button anchored on a phone where the form
   is taller than the viewport. dvh first, vh as the fallback for browsers that
   don't have it. */
.modal-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(600px, 100%);
  max-height: calc(100vh - 2.5rem);
  max-height: calc(100dvh - 2.5rem);
  overflow: hidden;
  border-radius: var(--r-xl);
  border: 1px solid rgba(140, 188, 255, 0.18);
  background:
    radial-gradient(120% 110% at 100% 0%, rgba(0, 102, 255, 0.2) 0%, transparent 58%),
    linear-gradient(168deg, #0A1C3A 0%, #04122B 55%, #000B1F 100%);
  box-shadow: 0 40px 80px -30px rgba(0, 4, 14, 0.9);
  transform: translateY(16px) scale(0.985);
  transition: transform var(--dur) var(--ease-out-back);
}
.modal.is-open .modal-card { transform: none; }
/* One lit hairline along the top edge, matching the contact panel. */
.modal-card::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  z-index: 1;
  background: linear-gradient(90deg, transparent, rgba(140, 188, 255, 0.45) 26%, var(--blue) 50%, rgba(140, 188, 255, 0.45) 74%, transparent);
}

.modal-scroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: clamp(1.5rem, 1.1rem + 1.8vw, 2.35rem);
}

/* 44px, because that is the smallest target a thumb reliably hits. */
.modal-close {
  position: absolute;
  top: 0.8rem; right: 0.8rem;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(140, 188, 255, 0.2);
  /* Near-opaque, not a 5% tint: the form scrolls underneath this button, and at
     5% the field labels read straight through it. */
  background: rgba(6, 21, 48, 0.84);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  color: rgba(206, 224, 250, 0.85);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.modal-close:hover {
  background: rgba(12, 34, 74, 0.95);
  border-color: rgba(140, 188, 255, 0.44);
  color: #fff;
}

.modal-head { margin-bottom: 1.4rem; padding-right: 3rem; }
.modal-head .eyebrow { color: #8CBCFF; }
.modal-head .d4 { color: #fff; }
.modal-head p {
  margin-top: 0.7rem;
  color: rgba(206, 224, 250, 0.82);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* The honeypot. Off the canvas rather than display:none — some bots skip hidden
   fields but will fill anything present in the markup. Never announced, never
   tabbable, so a person cannot reach it by accident. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form-step {
  margin-top: 0.9rem;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: rgba(206, 224, 250, 0.72);
}
.form-step b { color: #8CBCFF; font-weight: 700; }

/* Motion stays subtle, and stops entirely when the visitor has asked for that. */
@media (prefers-reduced-motion: reduce) {
  .modal, .modal-card { transition: none; }
  .modal-card { transform: none; }
}

/* --------------------------------------------------------------------------
   FORMS
   -------------------------------------------------------------------------- */

.field { display: block; margin-bottom: 1rem; }
.field-row { display: grid; gap: 1rem; }
@media (min-width: 480px) { .field-row { grid-template-columns: 1fr 1fr; } }

.field > span {
  display: block;
  margin-bottom: 0.4rem;
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--slate);
}
.field > span .req { color: var(--blue); }

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.85rem 1rem;
  background: var(--mist);
  border: 1px solid transparent;
  border-radius: var(--r);
  font-size: 0.9375rem;
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.field textarea { min-height: 110px; resize: vertical; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  background: var(--paper);
  border-color: var(--blue);
  outline: 2px solid var(--blue-24);
  outline-offset: 0;
}
.field input[aria-invalid='true'],
.field select[aria-invalid='true'] { border-color: var(--lv3); background: #FFF5F6; }

/* The label and the error message are both direct spans of .field, so
   `.field > span` was styling the error as well — mono, uppercase, letter-spaced,
   and `display: block`. That last one beat `.field-error { display: none }` on
   specificity (0,1,1 against 0,1,0), which meant an error stayed on screen for
   the rest of the session once it had been shown once, even after the visitor
   fixed the field. Matching the error above the label rule fixes both the
   stuck-message bug and the borrowed typography. */
.field-error,
.field > .field-error {
  display: none;
  margin-top: 0.4rem;
  font-family: var(--body);
  font-size: var(--t-sm);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: normal;
  text-transform: none;
  color: #D63946;
}
.field-error.is-shown,
.field > .field-error.is-shown { display: block; }

.form-note {
  margin-top: 0.9rem;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--slate);
}
.form-status {
  display: none;
  margin-top: 1rem;
  padding: 0.9rem 1.1rem;
  border-radius: var(--r);
  font-size: 0.9375rem;
  background: var(--mist);
  border-left: 3px solid var(--blue);
  color: var(--slate-deep);
}
.form-status.is-shown { display: block; }

.form-actions { margin-top: 1.5rem; }
.form-actions .btn { width: 100%; }

/* --------------------------------------------------------------------------
   FAQ — details/summary, no JS required
   -------------------------------------------------------------------------- */

.faq { border-top: 1px solid var(--rule-light); }
.s-ink .faq, .s-ink-2 .faq { border-top-color: var(--rule-dark); }

.faq details { border-bottom: 1px solid var(--rule-light); }
.s-ink .faq details, .s-ink-2 .faq details { border-bottom-color: var(--rule-dark); }

.faq summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.35rem 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 110%;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
  line-height: 1.25;
  text-transform: uppercase;
  color: var(--ink);
  transition: color var(--dur-fast) var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--blue); }
.s-ink .faq summary, .s-ink-2 .faq summary { color: #fff; }
.s-ink .faq summary:hover, .s-ink-2 .faq summary:hover { color: #6FA8FF; }

.faq summary .sign {
  position: relative;
  flex: 0 0 auto;
  width: 16px; height: 16px;
  margin-top: 0.2rem;
}
.faq summary .sign::before,
.faq summary .sign::after {
  content: '';
  position: absolute;
  background: var(--blue);
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.faq summary .sign::before { inset: 7px 0 auto 0; height: 1.5px; }
.faq summary .sign::after  { inset: 0 auto 0 7px; width: 1.5px; }
.faq details[open] summary .sign::after { transform: rotate(90deg); opacity: 0; }

.faq-answer { padding: 0 0 1.5rem; }
.faq-answer p { max-width: 68ch; color: var(--slate); font-size: 0.9375rem; line-height: 1.6; }
.s-ink .faq-answer p, .s-ink-2 .faq-answer p { color: var(--on-ink-mid); }
.faq-answer p + p { margin-top: 0.8rem; }

/* --------------------------------------------------------------------------
   PAGE HEADER — used on every page except home
   -------------------------------------------------------------------------- */

/* Page header. A single photograph, heavily weighted toward the copy side, with
   the text held to one narrow column so the band reads as a header rather than a
   second hero. The h1 is deliberately smaller than a hero headline — at full
   --t-4xl a three-word page title filled two lines and pushed the lede below the
   fold on a laptop. */
/* PAGE HEADER — the copy beside the photograph, not on top of it.
   The previous version laid the type over a full-bleed photo behind three
   stacked dark washes, and it cost the photograph everything: by the time the
   text was legible the image was grey texture. Split, the copy gets a clean
   navy ground it can be set on properly and the photo is allowed to be a photo.
   Below the split breakpoint the image becomes a band under the copy rather
   than reverting to a backdrop, for exactly the same reason.
   Every background property stays in this one rule — the line-field SVG is
   sizeless, so a `background:` shorthand landing on it elsewhere would let it
   scale to fill the whole header. */
.page-head {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-top: calc(var(--nav-total) + clamp(1.75rem, 1.4rem + 1.8vw, 3rem));
  padding-bottom: clamp(2rem, 1.6rem + 2vw, 3.25rem);
  background-color: var(--ink);
  background-image:
    var(--lines-dark),
    radial-gradient(ellipse 105% 135% at 4% 22%, #10336F 0%, #0A2454 34%, #04122B 68%, #000B1F 100%);
  background-repeat: no-repeat, no-repeat;
  background-position: 50% 50%, 50% 50%;
  background-size: cover, cover;
  color: var(--on-ink);
  border-bottom: 1px solid var(--rule-dark);
}

.page-head-inner {
  position: relative;
  display: grid;
  gap: clamp(1.75rem, 1.25rem + 2vw, 3.25rem);
  align-items: center;
}
/* 940px is where the lede still holds a readable measure at just under half the
   shell. Below it, one column. */
@media (min-width: 940px) {
  .page-head-inner { grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr); }
}

.page-head-copy { min-width: 0; }
.page-head .crumbs { color: rgba(203, 221, 248, 0.78); }
.page-head .eyebrow { color: #8CBCFF; }
.page-head .d2 {
  color: #fff;
  max-width: 20ch;
  font-size: clamp(1.75rem, 1.3rem + 2vw, 3.125rem);
  /* No text-shadow any more: there is no photograph under the type to fight. */
}
.page-head .lede {
  margin-top: 1.1rem;
  max-width: 46ch;
  color: rgba(219, 231, 250, 0.9);
}
.page-head-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.75rem; }

/* --- The photograph, framed as an object rather than used as a ground --- */
.page-head-media {
  position: relative;
  min-width: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--rule-dark);
  box-shadow: 0 30px 60px -34px rgba(0, 6, 20, 0.9);
}
.page-head-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
/* Taller beside the copy, wider when it is a band under it. */
@media (min-width: 940px) {
  .page-head-media img { aspect-ratio: 4 / 3; }
}
/* One hairline of house blue on the top edge, so the frame reads as part of the
   site rather than a stock-photo card dropped into it. */
.page-head-media::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 2px 0 rgba(0, 102, 255, 0.55);
}

.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}
.crumbs a { transition: color var(--dur-fast) var(--ease); }
.crumbs a:hover { color: #fff; }
.crumbs li { display: flex; align-items: center; gap: 0.5rem; }
.crumbs li + li::before { content: '/'; opacity: 0.4; }
.crumbs [aria-current='page'] { color: var(--on-ink); }

/* --------------------------------------------------------------------------
   CTA BAND — closes every page
   -------------------------------------------------------------------------- */

/* The closing CTA is a mat pass: one card split by a perforation, the offer on
   one side and the three things a first-timer actually needs on the other. The
   notches are punched with two radial-gradient masks positioned off the stub
   width, so the tear line reads as a real ticket edge rather than a dashed
   border pretending to be one. */
.cta-band {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  color: var(--on-ink);
  isolation: isolate;
}
.cta-band-bg { position: absolute; inset: 0; z-index: -2; }
.cta-band-bg img { width: 100%; height: 100%; object-fit: cover; }
/* Darker than the old treatment, because a card now sits on top of it. */
.cta-band::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(105deg, rgba(0, 11, 31, 0.96) 0%, rgba(0, 11, 31, 0.9) 46%, rgba(0, 11, 31, 0.72) 100%),
    radial-gradient(ellipse 60% 80% at 12% 50%, var(--blue-24), transparent 70%);
}

.pass {
  --stub: clamp(230px, 25vw, 320px);
  --notch: 13px;
  position: relative;
  border-radius: var(--r-lg);
  border: 1px solid rgba(132, 178, 245, 0.34);
  background: linear-gradient(150deg, rgba(11, 34, 73, 0.92) 0%, rgba(2, 12, 30, 0.94) 100%);
  box-shadow: 0 30px 60px -28px rgba(0, 0, 0, 0.95);
}
@media (min-width: 900px) {
  .pass {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--stub);
    align-items: stretch;
    /* Two half-circles bitten out of the top and bottom edges, exactly on the
       tear line. Unsupported browsers simply get square corners. */
    -webkit-mask:
      radial-gradient(circle var(--notch) at calc(100% - var(--stub)) 0, #0000 98%, #000 100%),
      radial-gradient(circle var(--notch) at calc(100% - var(--stub)) 100%, #0000 98%, #000 100%);
    -webkit-mask-composite: source-in;
            mask:
      radial-gradient(circle var(--notch) at calc(100% - var(--stub)) 0, #0000 98%, #000 100%),
      radial-gradient(circle var(--notch) at calc(100% - var(--stub)) 100%, #0000 98%, #000 100%);
            mask-composite: intersect;
  }
}

.pass-main { padding: clamp(1.75rem, 1.3rem + 2vw, 3.25rem); }
.pass-kicker {
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #6FA8FF;
}
/* A notch smaller than a section headline: the card should read as a pass, and
   at full --d2 the left column alone made it 550px tall. */
.cta-band .d2 {
  color: #fff;
  max-width: 20ch;
  margin-top: 1.1rem;
  font-size: clamp(1.875rem, 1.45rem + 1.85vw, 3rem);
}
.cta-band .lede { color: var(--on-ink-mid); margin-top: 1.1rem; max-width: 46ch; }
.cta-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

/* --- The stub --- */
.pass-stub {
  margin: 0;
  padding: clamp(1.5rem, 1.2rem + 1.4vw, 2.25rem);
  display: grid;
  align-content: center;
  gap: clamp(1.1rem, 0.9rem + 0.8vw, 1.6rem);
  border-top: 1px dashed rgba(132, 178, 245, 0.4);
  background: rgba(0, 8, 22, 0.42);
}
@media (min-width: 900px) {
  .pass-stub { border-top: 0; border-left: 1px dashed rgba(132, 178, 245, 0.4); }
}
.pass-stub dt {
  font-family: var(--mono);
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(160, 190, 232, 0.72);
}
.pass-stub dd {
  margin: 0.4rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: #EEF4FD;
}
.pass-stub a { color: inherit; border-bottom: 1px solid transparent; transition: border-color var(--dur-fast) var(--ease); }
.pass-stub a:hover { border-bottom-color: var(--blue); }
/* paintLive() writes the day and time into an <em>. */
.pass-next em {
  display: block;
  margin-top: 0.15rem;
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  color: #6FA8FF;
}


/* --------------------------------------------------------------------------
   FOOTER
   A hairline trust strip, then four link columns, then the base bar. Hours are
   deliberately not listed here — the Visit column links to the schedule page
   instead, which keeps the four columns close to the same height and stops the
   footer opening up a hole under the two short ones.
   -------------------------------------------------------------------------- */

.foot {
  background: #01081A;
  color: var(--on-ink-mid);
  border-top: 1px solid var(--rule-dark);
  padding-top: clamp(2.25rem, 1.8rem + 2vw, 3.25rem);
}

/* --- Trust strip --- */
.foot-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.85rem 2rem;
  padding-bottom: clamp(1.75rem, 1.5rem + 1.2vw, 2.5rem);
  border-bottom: 1px solid var(--rule-dark);
}
.foot-top p { margin: 0; }
.foot-note,
.foot-badges {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}


/* --- Link columns --- */
.foot-grid {
  display: grid;
  gap: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
  padding-block: clamp(2.25rem, 1.8rem + 2vw, 3.25rem);
}
@media (min-width: 760px)  { .foot-grid { grid-template-columns: 1.5fr 1fr 1fr; } }
@media (min-width: 1040px) { .foot-grid { grid-template-columns: 1.6fr 0.9fr 1fr 1.1fr; } }

.foot-logo img { height: 44px; width: auto; }
.foot-blurb {
  margin-top: 1.15rem;
  max-width: 34ch;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--on-ink-dim);
}
.foot-social { display: flex; gap: 0.5rem; margin-top: 1.35rem; }
.foot-social a {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  /* Brighter than the old hairline, which all but vanished on this ground. */
  border: 1px solid rgba(132, 178, 245, 0.34);
  border-radius: 50%;
  color: #C9DCF7;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.foot-social a:hover { color: #fff; border-color: var(--blue); background: var(--blue-14); }
/* The icon paths carry no fill of their own, so they must inherit one. */
.foot-social svg { width: 17px; height: 17px; fill: currentColor; }

.foot-h {
  margin-bottom: 1rem;
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #fff;
}
.foot-list li + li { margin-top: 0.6rem; }
.foot-list a, .foot-list span { font-size: 0.9375rem; transition: color var(--dur-fast) var(--ease); }
.foot-list a:hover { color: #fff; }

.foot-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.5rem;
  border-top: 1px solid var(--rule-dark);
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}
.foot-base p { margin: 0; }
/* Agency credit. Underline appears on hover only, so it reads as a credit
   rather than competing with the site's own navigation. */
.foot-credit a {
  color: var(--on-ink-mid);
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.foot-credit a:hover { color: #fff; border-bottom-color: var(--blue); }
.foot-base a:hover { color: #fff; }
.foot-up {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--on-ink-mid);
  transition: color var(--dur-fast) var(--ease);
}
.foot-up:hover { color: #fff; }
.foot-up svg { width: 12px; height: 12px; }

/* --------------------------------------------------------------------------
   MOBILE: HERO, PAGE HEADER, FOOTER
   The hero was 938px tall on an 800px viewport with a 736px min-height under it
   (92vh), so it always cost more than a full screen before anything else showed.
   The footer was 1207px: four stacked columns with a 32px gap between them.
   -------------------------------------------------------------------------- */
@media (max-width: 899px) {
  /* 92vh is a desktop idea. On a phone it guarantees the next section is below
     the fold no matter how short the copy is. */
  .hero { min-height: 0; }
  .page-head { padding-bottom: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem); }
  .page-head .lede { margin-top: 0.85rem; }

  .foot { padding-top: clamp(2.25rem, 1.8rem + 2vw, 3rem); }
  .foot-grid { gap: 1.4rem; }
  .foot-base { margin-top: 1.4rem; padding-top: 1.1rem; }
}

/* The three link columns stacked one under another, which put 752px of footer on
   a phone. Two up costs one row instead of three. The gate is 360px, not 400 —
   375 and 390 are the widths most phones actually report, and holding the change
   back until 400 meant the pages people really see kept the tall footer. Below
   360 it stays single-column, where two columns of link text break mid-word. */
@media (max-width: 899px) and (min-width: 360px) {
  .foot-grid { grid-template-columns: 1fr 1fr; gap: 1.5rem 1.25rem; }
  .foot-grid > :first-child { grid-column: 1 / -1; }
}
