/* ============================================================
   THE RAFFLE — CHROME
   Dev bar, top navigation, footer.
   Injected by js/nav.js. Tokens per /DESIGN.md.
   ============================================================ */

/* ============================================================
   DEV BAR (wireframe tooling — not part of the design system)
   Deliberately identical to the console's dev bar (css/console.css
   → DEV BAR): the same tool sits on every page of the wireframe,
   so it must not change shape when you cross from the storefront
   into the back office. That is why these values are raw oklch
   rather than tokens — the bar is prototype chrome, outside
   DESIGN.md, and it is duplicated (not shared) so each stylesheet
   layer stays independently liftable.

   It carries two controls: the ROLE switcher (guest → admin) and
   the MODE switcher, which flips the storefront between the two
   ways entries are sold — card decks or direct tickets. The two
   modes never run in the same jurisdiction, so Mode is a hard
   switch, not a preference (see js/platform-mode.js).
   ============================================================ */
#dev-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--dev-bar-h);
  z-index: var(--z-dev-bar);
  display: flex;
  align-items: center;
  gap: 12px;
  /* The bar is pinned to the top edge, so on a notched phone its
     first control sits under the notch in landscape. Pay the inset
     back; `viewport-fit=cover` in every page head is what makes
     these resolve to anything but 0. */
  padding: 0 calc(14px + env(safe-area-inset-right, 0px)) 0 calc(14px + env(safe-area-inset-left, 0px));
  background: oklch(0 0 0);
  color: oklch(0.85 0.02 160);
  border-bottom: 1px solid oklch(1 0 0 / 0.08);
  font-family: var(--font-body);
  font-size: var(--text-body-xs);
}
#dev-bar .dev-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: oklch(0.72 0.02 160);
  white-space: nowrap;
}
#dev-bar .dev-sep { width: 1px; height: 16px; background: oklch(1 0 0 / 0.12); flex-shrink: 0; }

.role-pills { display: flex; gap: 3px; }
.role-pill {
  position: relative;
  padding: 3px 10px;
  border: none;
  background: none;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  color: oklch(0.78 0.02 160);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 160ms var(--ease-deck-out);
}
@media (hover: hover) and (pointer: fine) {
  .role-pill:hover { background: oklch(1 0 0 / 0.08); color: oklch(0.98 0.01 160); }
}
.role-pill:active { transform: scale(0.94); }
.role-pill:focus-visible { outline: 2px solid oklch(0.94 0.05 150); outline-offset: 1px; }
.role-pill.active { background: oklch(0.94 0.05 150); color: oklch(0.22 0.04 168); font-weight: 600; }
/* The one LINK in the bar: the B2B sales site (platform.html) sits
   beside the roles because it is somewhere a reviewer goes, not a
   role they take. It is an anchor worn as a pill, so it is ringed
   rather than bare — every other pill here switches a state, this
   one leaves the app. Duplicated in css/console.css and
   css/layouts/base.css, like the rest of the bar. */
.dev-link { display: inline-flex; align-items: center; flex-shrink: 0; white-space: nowrap; text-decoration: none; box-shadow: inset 0 0 0 1px oklch(1 0 0 / 0.16); }
.dev-link:hover { text-decoration: none; }

/* Mode switcher — a segmented pair inside a tray, so it reads as
   one either/or control rather than two independent pills. */
.mode-pills {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-pill);
  background: oklch(1 0 0 / 0.07);
}
.mode-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border: none;
  background: none;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  color: oklch(0.78 0.02 160);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease, transform 160ms var(--ease-deck-out);
}
.mode-pill .icon { width: 13px; height: 13px; }
@media (hover: hover) and (pointer: fine) {
  .mode-pill:hover { color: oklch(0.98 0.01 160); }
}
.mode-pill:active { transform: scale(0.94); }
.mode-pill:focus-visible { outline: 2px solid oklch(0.94 0.05 150); outline-offset: 1px; }
.mode-pill.active { background: oklch(0.98 0.01 160); color: oklch(0.22 0.04 168); font-weight: 600; }

#dev-bar .dev-page { margin-left: auto; color: oklch(0.62 0.02 160); font-size: 11px; }

@media (max-width: 1024px) {
  #dev-bar .dev-page { display: none; }
  #dev-bar .mode-pills { margin-left: auto; }
}
@media (max-width: 768px) {
  #dev-bar {
    gap: var(--element-gap);
    padding-inline: calc(var(--spacing-12) + env(safe-area-inset-left, 0px)) calc(var(--spacing-12) + env(safe-area-inset-right, 0px));
  }
  #dev-bar .dev-label, #dev-bar .dev-sep { display: none; }
  .role-pills { gap: 2px; }
  .role-pill { padding: 3px 7px; font-size: 10px; }
  .mode-pill { padding: 3px 8px; font-size: 10px; }
  .mode-pill .mode-pill-text { display: none; }
  .mode-pill.active .mode-pill-text { display: inline; }
}
/* Below ~360px five role pills plus the mode tray no longer fit even
   at their smallest, and the bar drags the whole page sideways. It
   scrolls instead: every control stays reachable and the page keeps
   its width. Duplicated in css/console.css — the bar is the same
   object on both sides of the app and must not change shape. */
@media (max-width: 480px) {
  #dev-bar { overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; }
  #dev-bar::-webkit-scrollbar { display: none; }
  #dev-bar > * { flex: 0 0 auto; }
  #dev-bar .mode-pills { margin-left: 0; }
}
/* A 21px pill is a mouse target. The bar is 36px tall and must stay
   that height on both sides of the app, so the pills grow an
   invisible box rather than a bigger one — DESIGN.md's "grow only
   the hit area where the control's size is the design". */
@media (pointer: coarse) {
  .role-pill::after, .mode-pill::after {
    content: "";
    position: absolute;
    top: 50%; left: 0; right: 0;
    height: var(--touch-target);
    transform: translateY(-50%);
  }
}

/* ============================================================
   TOP NAVIGATION
   Sticky Snow bar with inline Inter links and a black pill CTA.
   ============================================================ */
/* THE BAR IS A MATERIAL, NOT A PANEL WITH A LINE UNDER IT.
   It was 96% white with no blur behind it and a 1px Fog rule along
   the bottom, which is the one combination that cannot work: opaque
   enough to be a wall, transparent enough that a prize photograph
   scrolling under it GHOSTED THROUGH the logo and the links, and
   then a hard edge drawn to say where the wall stopped. A floating
   layer either lets the page through properly or it does not.

   So it is a real material now — the page is genuinely blurred and
   saturated behind it, at an opacity low enough for that blur to be
   what you see — and it has no divider, because a material does not
   need a line to say where it is. What replaces the line is the
   thing the line was standing in for: the blur reaches BELOW the
   bar and fades out, so content passes under a softening edge
   instead of hitting a rule. Bigger surfaces read as thicker, which
   is why this is a heavier blur than a chip's.

   BOTH STATES CROSS-FADE ON OPACITY. The bar used to animate its
   own `background` and `border-color` between the two, which the
   system's own motion rule forbids for the reason it forbids every
   paint-driven animation (DESIGN.md → Motion Philosophy: positional,
   opacity, filter and blur only). Each state is a layer now and the
   only thing that moves is which of them you can see. */
#site-nav {
  position: fixed;
  top: var(--dev-bar-h);
  left: 0; right: 0;
  height: var(--nav-h);
  background: transparent;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
}
/* Over the page — the light material, and it STOPS WHERE THE BAR
   STOPS. It reached 20px past the bottom edge and faded out there,
   on the argument that content should pass under a softening edge
   rather than hit a rule. On the page it does not read as an edge:
   it reads as a band of the page itself gone soft, and the thing
   most often sitting in that band is a button or a heading the
   reader is trying to look at. A blur has to have something behind
   it that you are meant to see THROUGH — the bar has that, and the
   20px below the bar does not.
   So the material is the bar's own box, squarely, and the bottom
   edge is the hairline it always was. */
#site-nav::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  backdrop-filter: blur(22px) saturate(180%);
  /* On the layer rather than on the bar, so it cross-fades with the
     material it belongs to: over the hero there is no bar, so there
     is no line under it either. */
  border-bottom: 1px solid var(--color-fog);
  z-index: -1;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.35s ease;
}
/* Over the hero photograph — the dark material, same recipe */
#site-nav::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  bottom: -60px;
  background: linear-gradient(to bottom, rgba(var(--color-brand-primary-strong-rgb), 0.72) 0%, transparent 100%);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  -webkit-mask-image: linear-gradient(to bottom, black 30%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 30%, transparent 100%);
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
}

/* Transparent state — homepage only, toggled by JS when at scroll top */
#site-nav.nav-transparent::after { opacity: 0; }
#site-nav.nav-transparent::before { opacity: 1; }

/* A READER WHO HAS ASKED FOR LESS OF THIS GETS A PANEL BACK.
   `prefers-reduced-transparency` is a legibility setting, not a
   taste one: the answer is to make the surface frostier, not to
   make it prettier — so the ground goes solid, the blur goes with
   it (there is nothing left to see through), and the divider the
   material replaced comes back, because an opaque bar DOES need a
   line to say where it stops. `prefers-contrast: more` asks the
   same question more firmly and gets the same answer with a
   defined edge. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  #site-nav::after {
    background: var(--color-snow);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-bottom-color: var(--color-pebble);
  }
  #site-nav::before {
    background: var(--color-deep-forest);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    -webkit-mask-image: none;
    mask-image: none;
    bottom: 0;
  }
}
#site-nav.nav-transparent .nav-logo-img { filter: brightness(0) invert(1); width: 148px; }
#site-nav.nav-transparent .nav-link { color: rgba(255, 255, 255, 0.82); }
@media (hover: hover) and (pointer: fine) {
  #site-nav.nav-transparent .nav-link:hover { background: rgba(255, 255, 255, 0.1); color: var(--color-snow); }
  #site-nav.nav-transparent .nav-wallet-badge:hover,
  #site-nav.nav-transparent .nav-bell:hover { border-color: rgba(255, 255, 255, 0.65); }
  #site-nav.nav-transparent .btn-ghost:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: var(--glass-border-light);
    color: var(--color-mint-ice-cream);
  }
}
#site-nav.nav-transparent .nav-link.active { color: var(--color-snow); font-weight: var(--font-weight-semibold); }
/* Over a photograph the chevron takes the label's own ink: Ash is a
   quiet grey on Snow and an unreadable one on somebody's hero. */
#site-nav.nav-transparent .nav-link--menu :is(i[data-icon], .icon) { color: currentColor; }
#site-nav.nav-transparent .nav-link--menu[aria-expanded="true"] { background: rgba(255, 255, 255, 0.1); color: var(--color-snow); }
#site-nav.nav-transparent .nav-wallet-badge { border-color: rgba(255, 255, 255, 0.35); color: var(--color-snow); }
#site-nav.nav-transparent .nav-bell { border-color: rgba(255, 255, 255, 0.35); color: rgba(255, 255, 255, 0.8); }
#site-nav.nav-transparent .nav-burger { border-color: rgba(255, 255, 255, 0.35); color: var(--color-snow); }
/* Ghost Button assumes a light surface; over the dark/photographic
   hero it must read as Flat Glass instead (DESIGN.md Button System
   Principles — never leave an outline-only button on a dark bg). */
#site-nav.nav-transparent .btn-ghost {
  background: var(--glass-fill-dark);
  color: var(--color-mint-ice-cream);
  border-color: var(--glass-border-light);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
}

.nav-inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  /* The bar spans the window, so in landscape on a notched phone its
     logo and its action cluster are the two things the notch lands
     on. The gutter absorbs the inset rather than the content. */
  padding: 0 calc(var(--spacing-24) + env(safe-area-inset-right, 0px)) 0 calc(var(--spacing-24) + env(safe-area-inset-left, 0px));
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--spacing-24);
}

.nav-logo {
  text-decoration: none;
  display: flex; align-items: center;
  flex-shrink: 0;
  /* The wordmark is 20px tall and is the way home from every page in
     the shop. Its hit box is the bar's height, not the picture's. */
  align-self: stretch;
  transition: transform 160ms var(--ease-deck-out);
}
.nav-logo:active { transform: scale(0.97); }
.nav-logo:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: -2px; border-radius: var(--radius-md); }
#site-nav.nav-transparent .nav-logo:focus-visible { outline-color: var(--color-mint-ice-cream); }

.nav-logo-img {
  width: 108px;
  height: auto;
  display: block;
  filter: brightness(0);
  transition: width 0.35s ease, filter 0.35s ease;
}

/* Footer: always on dark, always white */
.footer-logo-img { filter: brightness(0) invert(1); }

.nav-links { display: flex; align-items: center; gap: var(--spacing-4); }
.nav-actions { display: flex; align-items: center; gap: var(--element-gap); margin-left: auto; flex-shrink: 0; }

.nav-burger {
  display: none;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--color-pebble);
  border-radius: var(--radius-pill);
  cursor: pointer;
  color: var(--color-ink);
  font-size: var(--text-heading-sm);
  line-height: 1;
  padding: 5px 11px;
  transition: border-color var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-burger:hover { border-color: var(--color-graphite); }
}
.nav-burger:active { transform: scale(0.94); }

.nav-link {
  padding: var(--element-gap) var(--spacing-12);
  color: var(--color-steel);
  font-size: var(--text-body);
  font-weight: var(--font-weight-medium);
  border-radius: var(--radius-pill);
  text-decoration: none;
  transition: color var(--duration-micro) ease, background var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
  white-space: nowrap;
  -webkit-user-select: none; user-select: none;
}
@media (hover: hover) and (pointer: fine) {
  .nav-link:hover { background: var(--color-mist); color: var(--color-ink); text-decoration: none; }
}
.nav-link:active { transform: scale(0.97); }
.nav-link:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: 2px; }
#site-nav.nav-transparent .nav-link:focus-visible { outline-color: var(--color-mint-ice-cream); }
.nav-link.active { color: var(--color-obsidian); font-weight: var(--font-weight-semibold); }

/* ── A bar item that opens rather than navigates ─────────────
   The categories menu (js/nav.js → buildCategoriesMenu). It is a
   <button>, because it goes nowhere on its own, and it is drawn as
   a nav link because that is what it is standing in a row of — the
   chevron is the whole of what says it opens. */
.nav-link--menu {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-4);
  border: none;
  background: none;
  font-family: var(--font-body);
  cursor: pointer;
}
.nav-link--menu :is(i[data-icon], .icon) { color: var(--color-ash); transition: transform var(--duration-micro) ease, color var(--duration-micro) ease; }
@media (hover: hover) and (pointer: fine) {
  .nav-link--menu:hover :is(i[data-icon], .icon) { color: currentColor; }
}
.nav-link--menu[aria-expanded="true"] { background: var(--color-mist); color: var(--color-ink); }
.nav-link--menu[aria-expanded="true"] :is(i[data-icon], .icon) { transform: rotate(180deg); color: currentColor; }
.nav-link--menu:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: 2px; }

/* The panel hangs off the item rather than off the bar's right
   gutter, so it opens under the word that opened it. */
.dropdown--nav { display: inline-flex; }
/* A CATALOGUE IS NOT AN ACCOUNT MENU: how many rows there are is
   the operator's, so the panel is columned and fitted to the
   content rather than run down one 232px strip until it has to
   scroll. Two columns is the shape a dozen categories make; a
   deployment running four gets one. */
.dropdown-panel--nav { min-width: 0; }
.dropdown-panel--wide { width: 340px; max-width: calc(100vw - var(--spacing-24)); }
.dropdown-cols {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 2px var(--spacing-4);
}
/* The way to the page the menu is a shortcut into. It closes the
   list rather than joining it, so it reads as the row that means
   "everything above, laid out". */
.dropdown-item--all { font-weight: var(--font-weight-semibold); color: var(--color-ink); }
.dropdown-item--all :is(i[data-icon], .icon) { margin-left: auto; }

.nav-wallet-badge {
  display: flex; align-items: center;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-pebble);
  font-size: var(--text-body-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-ink);
  text-decoration: none;
  transition: border-color var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .nav-wallet-badge:hover { border-color: var(--color-graphite); text-decoration: none; }
}
.nav-wallet-badge:active { transform: scale(0.96); }
.nav-wallet-badge:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: 2px; }
#site-nav.nav-transparent .nav-wallet-badge:focus-visible { outline-color: var(--color-mint-ice-cream); }

.nav-bell {
  width: 36px; height: 36px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-pebble);
  display: flex; align-items: center; justify-content: center;
  color: var(--color-steel);
  text-decoration: none;
  font-size: var(--text-body-lg);
  position: relative;
  transition: border-color var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-bell:hover { border-color: var(--color-graphite); }
}
.nav-bell:active { transform: scale(0.94); }
.nav-bell:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: 2px; }
#site-nav.nav-transparent .nav-bell:focus-visible { outline-color: var(--color-mint-ice-cream); }

.nav-bell-dot {
  position: absolute;
  top: 6px; right: 6px;
  width: 8px; height: 8px;
  background: var(--color-ember);
  border-radius: 50%;
  border: 2px solid var(--color-snow);
}

/* A <button> now, because it opens the account menu rather than
   navigating — so it must be told the body font a link inherited. */
.nav-avatar {
  width: 36px; height: 36px;
  border-radius: var(--radius-pill);
  background: var(--color-obsidian);
  border: none;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  font-weight: var(--font-weight-bold);
  color: var(--color-snow);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
}
/* It was the one control in the bar with no hover answer at all,
   which read as a picture rather than a button. */
@media (hover: hover) and (pointer: fine) {
  .nav-avatar:hover { background: var(--color-graphite); }
}
.nav-avatar:active { transform: scale(0.94); }
.nav-avatar:focus-visible { outline: 2px solid var(--color-race-green); outline-offset: 2px; }
#site-nav.nav-transparent .nav-avatar:focus-visible { outline-color: var(--color-mint-ice-cream); }

/* THE BAR CARRIES THREE LINKS, and the third one is a menu.
   Two fitted alongside the signed-in action cluster down to the
   small-phone step; Categories does not — at 520px the wallet
   badge was already running off the right-hand edge. So the burger
   takes over at the tablet step instead, which is the step the
   Lite theme's bar has always used and one rung of the ladder
   rather than a number chosen to fit today's link count. */
@media (max-width: 768px) {
  .nav-burger { display: flex; }
  .nav-links { display: none; }
  body.nav-open .nav-links {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: calc(var(--dev-bar-h) + var(--nav-h));
    left: 0; right: 0;
    background: var(--color-snow);
    border-top: 1px solid var(--color-fog);
    border-bottom: 1px solid var(--color-pebble);
    padding: var(--spacing-12) var(--spacing-20) var(--spacing-24);
    gap: 2px;
    z-index: var(--z-mobile-menu);
    box-shadow: var(--shadow-flat-hairline);
    align-items: stretch;
  }
  body.nav-open .nav-links .nav-link {
    display: block;
    padding: var(--spacing-12) var(--spacing-16);
    font-size: var(--text-body-md);
    border-radius: var(--radius-inputs);
  }
  /* THE PANEL IS A SNOW SHEET, WHATEVER THE BAR ABOVE IT IS DOING.
     The transparent state paints the bar's links white so they read
     on the hero photograph — but at this width those same links are
     inside a white sheet hanging below the bar, so the homepage's
     burger menu came out white on white: an open panel with nothing
     visible in it. The bar keeps its transparent ink; the links take
     the ink of the surface they are actually standing on. */
  body.nav-open #site-nav.nav-transparent .nav-links .nav-link { color: var(--color-steel); }
  body.nav-open #site-nav.nav-transparent .nav-links .nav-link.active,
  body.nav-open #site-nav.nav-transparent .nav-links .nav-link--menu[aria-expanded="true"] {
    color: var(--color-ink);
    background: var(--color-mist);
  }
  /* THE CATEGORIES MENU OPENS AS A FOLD, not as a second sheet.
     The panel is a card hanging off a bar item at desktop widths;
     inside the burger panel there is no bar to hang off, and a
     fixed sheet over the list would cover the nav that opened it.
     So it sits in the flow, indented under its own trigger, and
     the list it is part of scrolls as one. */
  body.nav-open .nav-links .dropdown--nav { display: block; width: 100%; }
  body.nav-open .nav-links .nav-link--menu {
    /* The rule above turns every nav link into a block, and a block
       button centres its own content — the label and the chevron
       belong at opposite ends of the row they now span. */
    display: flex;
    width: 100%;
    justify-content: space-between;
    padding: var(--spacing-12) var(--spacing-16);
    font-size: var(--text-body-md);
    border-radius: var(--radius-inputs);
  }
  body.nav-open .nav-links .dropdown-panel--nav {
    display: none;
    position: static;
    width: auto;
    max-width: none;
    max-height: none;
    padding: 0 0 var(--spacing-8) var(--spacing-16);
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    overflow: visible;
  }
  body.nav-open .nav-links .dropdown-panel--nav.open { display: block; }
  body.nav-open .nav-links .dropdown-cols { grid-template-columns: 1fr; }

  /* The mobile menu is a fixed panel below a fixed bar, so a long
     signed-in nav can run past the bottom of the screen with no way
     to reach the last item. Cap it to the space that exists. */
  body.nav-open .nav-links {
    max-height: calc(100dvh - var(--dev-bar-h) - var(--nav-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-bottom: calc(var(--spacing-24) + env(safe-area-inset-bottom, 0px));
  }
}

/* The 108px wordmark, a 24px gutter each side and the signed-in
   action cluster (wallet + bell + avatar + burger) add up to more
   than 320px. The wordmark and the gutters give way; the controls
   do not, because they are the only navigation there is. */
@media (max-width: 480px) {
  .nav-inner { padding: 0 var(--spacing-12); gap: var(--spacing-8); }
  .nav-logo-img,
  #site-nav.nav-transparent .nav-logo-img { width: 92px; }
  .nav-actions { gap: 6px; }
  .nav-wallet-badge { padding-inline: var(--spacing-8); }
  .nav-burger { padding: 5px 9px; }
}

/* Touch — the bar's controls are sized for a cursor (36px circles, a
   32px burger). Grow them to the 44px floor on coarse pointers; the
   bar itself keeps its height, so nothing above the fold shifts. */
@media (pointer: coarse) {
  .nav-burger { min-width: var(--touch-target); min-height: var(--touch-target); padding: 5px 11px; }
  .nav-bell, .nav-avatar { width: var(--touch-target); height: var(--touch-target); }
  .nav-wallet-badge { min-height: var(--touch-target); }
  .nav-link { padding-block: var(--spacing-12); }
  /* The bar's own height is 56px but its content row is only as tall
     as the 36px circles in it, so the wordmark's box came out short
     of the floor even stretched. */
  .nav-logo { min-height: var(--touch-target); }
  /* A 20px line with 8px above and below is 36px, which is not a
     touch target — and the column gap that was holding the rows
     apart is what the padding now does, so the rhythm is the same
     reading with a thumb-sized row behind it. */
  .footer-links { gap: 0; }
  .footer-links a { display: flex; align-items: center; min-height: var(--touch-target); }
}

@media (max-width: 768px) {
  body { padding-top: calc(var(--dev-bar-h) + var(--nav-h)); }
}

/* ============================================================
   FOOTER — Deep Forest surface
   ============================================================ */
#site-footer {
  background: var(--surface-dark-surface);
  color: rgba(255, 255, 255, 0.6);
  /* Last thing on the page, so it is what the home indicator sits on.
     The inset is added to the bottom pad rather than to the content,
     so the Deep Forest still reaches the edge of the glass. */
  padding: var(--spacing-48) 0 calc(var(--spacing-32) + env(safe-area-inset-bottom, 0px));
}
/* Section-flow pages (index, how-it-works, legal) have no <main> wrapper,
   so the footer follows the last .section directly. It pays the same
   half of the gap every block in that flow pays (base.css → Layout
   primitives): 48px here plus the last section's own 48px bottom is
   the 96px rhythm, and 32 + 32 is the 64px one. Pages with a <main>
   get their footer spacing from main's own padding-bottom instead. */
body:not(:has(main)) #site-footer { margin-top: var(--spacing-48); }
@media (max-width: 768px) {
  body:not(:has(main)) #site-footer { margin-top: var(--spacing-32); }
}

.footer-inner { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--spacing-32); }

.footer-brand { margin-bottom: var(--spacing-12); }
.footer-tagline { font-size: var(--text-body-sm); color: rgba(255, 255, 255, 0.45); line-height: var(--leading-body-sm); }

.footer-col-title {
  font-size: var(--text-body-xs);
  font-weight: var(--font-weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.4);
  margin-bottom: var(--spacing-16);
}
.footer-links { display: flex; flex-direction: column; gap: var(--element-gap); }
.footer-links a {
  color: rgba(255, 255, 255, 0.55);
  font-size: var(--text-body-sm);
  text-decoration: none;
  transition: color var(--duration-micro) ease, transform 160ms var(--ease-deck-out);
}
@media (hover: hover) and (pointer: fine) {
  .footer-links a:hover { color: var(--color-snow); }
}
.footer-links a:active { color: var(--color-snow); transform: scale(0.98); transform-origin: left center; }
.footer-links a:focus-visible { outline: 2px solid var(--color-mint-ice-cream); outline-offset: 2px; border-radius: var(--radius-md); }

.footer-bottom {
  margin-top: var(--spacing-40);
  padding-top: var(--spacing-24);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--spacing-16);
}

.trust-badges { display: flex; gap: var(--spacing-16); flex-wrap: wrap; }
.trust-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--element-gap);
  padding: 4px 8px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: var(--radius-badges);
  font-size: var(--text-body-xs);
  font-weight: var(--font-weight-medium);
  color: rgba(255, 255, 255, 0.6);
}
.trust-badge .badge-icon { color: var(--color-ash); }

.footer-copy { font-size: var(--text-body-xs); color: rgba(255, 255, 255, 0.3); }

@media (max-width: 1024px) { .footer-inner { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px) {
  #site-footer .container { padding-inline: calc(var(--spacing-20) + env(safe-area-inset-left, 0px)) calc(var(--spacing-20) + env(safe-area-inset-right, 0px)); }
}
@media (max-width: 768px) {
  .footer-inner { grid-template-columns: 1fr !important; gap: var(--spacing-24); }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
}
