/* ==========================================================================
   Open Ground — the shared vocabulary: actions, panels, chips, fields,
   figures, the trace, and the plates the map and photographs sit on.
   ========================================================================== */

/* ── Actions ─────────────────────────────────────────────────────────── */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  border-radius: var(--r-pill);
  font-weight: 650;
  font-size: 16px;
  line-height: 1.2;
  text-decoration: none;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--ease-s), box-shadow var(--ease-s), color var(--ease-xs);
  will-change: transform;
}
.btn svg { width: 18px; height: 18px; flex: none; transition: transform var(--spring); }
.btn:hover svg, .btn:focus-visible svg { transform: translateX(5px); }
.btn:active { transform: scale(0.975); }

/* the fill floods from the pointer rather than swapping colour */
.btn::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  transition: background var(--ease-s);
}
.btn::after {
  content: '';
  position: absolute;
  z-index: -1;
  left: var(--px, 50%);
  top: var(--py, 50%);
  width: 40px; height: 40px;
  border-radius: 50%;
  /* a fixed disc that scales: animating width and height here thrashed
     layout on the most-hovered element in the build */
  transform: translate(-50%, -50%) scale(0);
  transition: transform var(--ease);
}
.btn:hover::after, .btn:focus-visible::after { transform: translate(-50%, -50%) scale(18); }

.btn--primary { color: var(--on-brand); box-shadow: var(--lift); }
.btn--primary::before { background: var(--brand); }
.btn--primary::after  { background: var(--brand-hot); }
.btn--primary:hover   { box-shadow: var(--lift-2); }

.btn--pulse { color: var(--on-pulse); box-shadow: var(--lift); }
.btn--pulse::before { background: var(--pulse); }
.btn--pulse::after  { background: var(--pulse-hot); }
.btn--pulse:hover   { box-shadow: var(--lift-2); }

.btn--quiet { color: var(--ink); }
.btn--quiet::before { background: var(--surface); }
.btn--quiet::after  { background: var(--surface-2); }

.btn--onfield { color: var(--field); }
.btn--onfield::before { background: var(--on-field); }
.btn--onfield::after  { background: var(--surface-solid); }
:root[data-mode='dark'] .btn--onfield { color: var(--on-brand); }

.btn--ghost { color: var(--ink); padding-inline: 20px; }
.btn--ghost::before { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line); }
.btn--ghost::after  { background: var(--surface); }

/* An outline drawn in the accent. The landing page's single action sits
   directly under a 96 px wordmark, and a filled block there competes with
   the name instead of pointing past it. */
.btn--line { color: var(--pulse-ink); padding-inline: 24px; }
.btn--line::before { background: transparent; box-shadow: inset 0 0 0 1.6px currentColor; }
.btn--line::after  { background: var(--pulse-wash); }
:root[data-mode='dark'] .btn--line { color: var(--pulse); }

.btn--sm { padding: 10px 18px; font-size: 14.5px; }
.btn--sm svg { width: 15px; height: 15px; }
.btn[aria-disabled='true'], .btn:disabled {
  pointer-events: none;
  color: var(--ink-3);
}
.btn[aria-disabled='true']::before, .btn:disabled::before { background: var(--surface-sunk); }

/* a text action that draws its own underline */
.golink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--brand);
  font-weight: 650;
  text-decoration: none;
  position: relative;
  padding-bottom: 3px;
}
.golink svg { width: 17px; height: 17px; transition: transform var(--spring); }
.golink::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--ease);
}
.golink:hover::after, .golink:focus-visible::after { transform: scaleX(1); transform-origin: left; }
.golink:hover svg { transform: translateX(5px); }

/* ── Panels ──────────────────────────────────────────────────────────── */
.panel {
  background: var(--surface);
  border-radius: var(--r-lg);
  padding: clamp(22px, 3vw, 34px);
  box-shadow: var(--lift);
  transition: background var(--ease-s), box-shadow var(--ease-s), transform var(--ease-s);
}
.panel--lit {
  background: linear-gradient(140deg,
    color-mix(in oklab, var(--surface-2), transparent 12%),
    color-mix(in oklab, var(--brand-soft), transparent 22%));
}

/* a panel that answers the pointer: it tilts a degree and lifts */
.tilt { transform-style: preserve-3d; will-change: transform; }
.tilt:hover {
  background: var(--surface-2);
  box-shadow: var(--lift-2);
}

/* ── Chips & pills ───────────────────────────────────────────────────── */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--ease-s), color var(--ease-xs), transform var(--ease-s);
}
.chip svg { width: 15px; height: 15px; flex: none; }
a.chip:hover, button.chip:hover { background: var(--surface-2); color: var(--ink); transform: translateY(-2px); }
.chip[aria-pressed='true'] { background: var(--brand); color: var(--on-brand); }

.state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px 4px 8px;
  border-radius: var(--r-pill);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.state__dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.state--live { background: var(--pulse-wash); color: var(--pulse-ink); }
:root[data-mode='dark'] .state--live { color: var(--pulse); }
.state--live .state__dot { animation: beat 1.9s ease-in-out infinite; }
@keyframes beat {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  50%      { transform: scale(1.18); box-shadow: 0 0 0 5px transparent; opacity: 0.82; }
}
.state--soon { background: var(--second-soft); color: var(--second); }
.state--past { background: var(--surface-sunk); color: var(--ink-3); }
.state--warn { background: var(--warn-wash); color: var(--warn); }
.state--bad  { background: var(--bad-wash);  color: var(--bad); }

/* ── Fields ──────────────────────────────────────────────────────────── */
.field { display: grid; gap: 7px; }
.lbl { font-size: 14.5px; font-weight: 650; color: var(--ink-2); }
.inp {
  width: 100%;
  background: var(--surface-2);
  border: 1.5px solid transparent;
  border-radius: var(--r);
  padding: 13px 16px;
  color: var(--ink);
  transition: border-color var(--ease-xs), box-shadow var(--ease-s), background var(--ease-s);
}
.inp:hover { border-color: var(--line); }
.inp:focus {
  outline: none;
  border-color: var(--pulse-ink);
  box-shadow: 0 0 0 4px var(--pulse-wash);
}
textarea.inp { min-height: 118px; resize: vertical; }
.inp--sm { padding: 8px 12px; font-size: var(--t-small); border-radius: var(--r-sm); }
select.inp--sm { padding-right: 32px; background-position: right 11px center; }
select.inp {
  appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23888' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
}
.err { color: var(--bad); font-size: 13.5px; font-weight: 600; display: none; }
.field[data-invalid='1'] .inp { border-color: var(--bad); }
.field[data-invalid='1'] .err { display: block; }

/* ── Figures: the platform's own numbers ─────────────────────────────── */
.figrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: clamp(14px, 2vw, 26px);
}
.fig { position: relative; padding-top: 16px; }
.fig::before {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 26px; height: 3px;
  border-radius: 3px;
  background: var(--pulse);
  transform-origin: left;
  transition: transform var(--ease);
}
.fig:hover::before { transform: scaleX(1.77); }
.fig__n {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--t-figure);
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--ink);
  display: block;
}
.fig__n small { font-size: 0.45em; font-weight: 650; letter-spacing: -0.01em; margin-left: 3px; color: var(--ink-2); }
.fig__l { display: block; margin-top: 8px; font-size: 14px; color: var(--ink-3); font-weight: 550; }

/* ── The trace: one GPS line drawn down the whole site ───────────────────
   Page-wide rather than a margin rule: it leaves the wordmark, swings right
   across the first viewport behind the map plate, and settles into the left
   margin where the section headings sit on it as checkpoints. The path is
   authored in viewport percentages and stretched, so the stroke is held to
   its real weight with vector-effect rather than being squashed with it. */
.trace {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
/* the line and its pin share one sticky stage, so a point on the path in
   viewBox units is the same percentage of the stage for both */
.trace__stage {
  position: sticky;
  top: 0;
  height: 100dvh;
}
.trace__line {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.trace__line path {
  fill: none;
  stroke: var(--pulse);
  stroke-width: 2.4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.62;
}
.trace .trace__ghost {
  stroke: var(--ink-3);
  opacity: 0.22;
  stroke-width: 1.8;
  stroke-dasharray: 3 9;
}
/* On a phone the line keeps to the margin, but far enough in and with
   enough swing to be read as the same object rather than as a screen edge. */
@media (max-width: 1180px) {
  .trace__line path { opacity: 0.55; stroke-width: 2.2; }
  .trace .trace__ghost { opacity: 0.26; }
}

/* The pin rides the head of the drawn line, so the course reads as going
   somewhere as the page scrolls — down with it, and back up. */
.trace__pin {
  position: absolute;
  left: 0; top: 0;
  width: 22px; height: 29px;
  transform: translate(-50%, -100%);
  filter: drop-shadow(0 3px 6px rgba(var(--shadow), var(--shadow-a)));
  will-change: left, top;
  /* it fades behind a pane or under copy, the way the line does (motion.js) */
  transition: opacity 240ms var(--out);
}
.trace__pin svg { width: 100%; height: 100%; display: block; }
.trace__pin path { fill: var(--pulse); stroke: var(--surface-solid); stroke-width: 1.6; }
.trace__pin circle { fill: var(--surface-solid); }
/* a ring at the tip, where the pin touches the line */
.trace__pin::after {
  content: '';
  position: absolute;
  left: 50%; bottom: -5px;
  width: 12px; height: 12px;
  margin-left: -6px;
  border-radius: 50%;
  border: 2px solid var(--pulse);
  opacity: 0;
  animation: trace-ping 2.2s var(--out) infinite;
}
@keyframes trace-ping {
  0%   { transform: scale(0.4); opacity: 0.8; }
  100% { transform: scale(2.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .trace__pin { display: none; } }

/* a checkpoint marker that sits on the trace beside a heading */
.cp {
  position: relative;
  padding-left: 0;
}
.cp::before {
  content: '';
  position: absolute;
  left: calc(var(--gutter) * 0.42 - var(--gutter) - 5px);
  top: 0.55em;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--ground);
  box-shadow: 0 0 0 2.5px var(--pulse);
}
@media (max-width: 1180px) {
  .cp::before { left: calc(var(--gutter) * -0.58); width: 10px; height: 10px; }
}
@media (max-width: 520px) {
  .cp::before { left: -14px; width: 9px; height: 9px; box-shadow: 0 0 0 2px var(--pulse); }
}

/* ── Plates: maps and photographs, masked rather than framed ─────────── */
.plate {
  position: relative;
  background: var(--ground-3);
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--lift-2);
}
.plate img { width: 100%; height: 100%; object-fit: cover; }

.credit {
  position: absolute;
  right: 12px;
  bottom: 12px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--ground-2), transparent 8%);
  color: var(--ink-2);
  font-size: 11.5px;
  font-weight: 600;
  backdrop-filter: blur(6px);
}

.plate__tag {
  position: absolute;
  left: 14px;
  top: 14px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px;
  border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--ground-2), transparent 6%);
  color: var(--ink-2);
  font-size: 12.5px;
  font-weight: 650;
  backdrop-filter: blur(8px);
  box-shadow: 0 2px 10px rgba(var(--shadow), calc(var(--shadow-a) * 0.7));
}

/* ── Bands: whole regions owning a hue ───────────────────────────────── */
.band {
  position: relative;
  background: var(--field);
  color: var(--on-field);
  border-radius: var(--r-xl);
  padding-block: clamp(48px, 7vw, 92px);
  overflow: hidden;
}
.band h2, .band h3 { color: var(--on-field); }
.band .lede { color: var(--on-field-2); }
.band .micro { color: var(--on-field-3); }
.band .golink, .band a:not(.btn) { color: var(--pulse-field); }
.band--tide { background: var(--field-2); }

/* A band that is a readout rather than an argument: a label, a row of
   figures, and none of the vertical room a section with a thesis needs. */
.band--slim { padding-block: clamp(26px, 3.2vw, 40px); }
.band__label {
  margin: 0 0 clamp(14px, 1.8vw, 20px);
  font-size: var(--t-legend);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-field-3);
}
.band__inner { position: relative; z-index: 2; }

/* the band carries a faint contour of its own, drawn not tiled */
.band__contour {
  position: absolute;
  inset: -10% -5%;
  z-index: 1;
  opacity: 0.09;
  pointer-events: none;
}
.band__contour path { fill: none; stroke: var(--on-field); stroke-width: 1.4; }

/* ── Notes: an honest label on invented material ─────────────────────── */
.note {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.45;
}
.note svg { width: 15px; height: 15px; flex: none; }

/* ── Loading and empty ───────────────────────────────────────────────── */
.shim {
  background: linear-gradient(100deg, var(--surface-sunk) 30%, var(--surface) 50%, var(--surface-sunk) 70%);
  background-size: 300% 100%;
  animation: shim 1.5s linear infinite;
  border-radius: var(--r);
}
@keyframes shim { from { background-position: 150% 0; } to { background-position: -150% 0; } }

.empty {
  padding: clamp(34px, 6vw, 62px);
  text-align: center;
  color: var(--ink-2);
  background: var(--surface);
  border-radius: var(--r-lg);
}
.empty h3 { margin-bottom: 10px; }
.empty p { max-width: 44ch; margin-inline: auto; color: var(--ink-3); }

/* ── Sport marks ─────────────────────────────────────────────────────── */
.sports { display: flex; flex-wrap: wrap; gap: 8px; }
.sports .chip { background: var(--surface); }
.sports .chip svg { color: var(--brand); }
:root[data-mode='dark'] .sports .chip svg { color: var(--pulse); }

/* ── The backend is unreachable ──────────────────────────────────────────
   An empty map and an empty event list are indistinguishable from a page
   that is simply quiet, so the failure says so rather than showing nothing. */
.apidown {
  position: relative;
  z-index: 70;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 13px clamp(16px, 4vw, 28px);
  background: var(--warn-wash);
  color: var(--ink);
  font-size: var(--t-small);
  line-height: 1.5;
}
.apidown svg { width: 17px; height: 17px; flex: none; margin-top: 2px; color: var(--warn); }
.apidown b { font-weight: 700; }
.apidown em { font-style: normal; color: var(--ink-2); display: block; margin-top: 4px; }
.apidown button {
  margin-left: auto;
  flex: none;
  padding: 7px 15px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink);
  font-size: var(--t-legend);
  font-weight: 650;
  transition: background var(--ease-s);
}
.apidown button:hover { background: var(--surface-solid); }
@media (max-width: 620px) {
  .apidown { flex-wrap: wrap; }
  .apidown button { margin-left: 29px; }
}

/* ── Share to Instagram ─────────────────────────────────────────────────
   Instagram's own button colours, because a share button that does not look
   like the thing it shares to reads as a generic download. It is not wired
   to anything; the sheet it opens says so in as many words. */
.btn--ig { color: #fff; box-shadow: var(--lift); }
.btn--ig::before {
  background: linear-gradient(72deg, #f9ce34 4%, #ee2a7b 47%, #6228d7 96%);
}
.btn--ig::after {
  background: linear-gradient(72deg, #fcd964 4%, #f5459a 47%, #7f45e8 96%);
}
.btn--ig:hover { box-shadow: var(--lift-2); }
.btn--ig svg { width: 17px; height: 17px; }

/* ── The share card ──────────────────────────────────────────────────── */
.share {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: 20px;
  background: color-mix(in oklab, var(--ground), transparent 14%);
  backdrop-filter: blur(10px);
  animation: fade-in 240ms var(--out);
}
.share[hidden] { display: none; }
.share__card {
  width: min(420px, 100%);
  max-height: 92dvh;
  overflow-y: auto;
  padding: 20px;
  border-radius: var(--r-lg);
  background: var(--surface-solid);
  box-shadow: var(--lift-3);
  display: grid;
  gap: 14px;
  animation: sheet-up 420ms var(--out) both;
}
.share__head { display: flex; align-items: center; justify-content: space-between; }
.share__x { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; color: var(--ink-3); }
.share__x:hover { background: var(--surface-sunk); color: var(--ink); }
.share__x svg { width: 17px; height: 17px; }
#shareCv { width: 100%; height: auto; border-radius: var(--r); box-shadow: var(--lift); }
.share__acts { display: flex; gap: 10px; }
