/* ============================================================================
   AESTHETIC DIRECTION, decided before any CSS and written here so the next
   build inherits it instead of re-deciding:

     Late-afternoon course side. A near-black graphite ground so the turf is the
     only saturated thing on the screen, ONE warm sand accent, a printed-card
     serif for every number, a clean grotesk for everything else, and controls
     as heavy tactile slabs pinned to the bottom of a phone.

   The sand accent is deliberate. brand_status on this client is
   placeholder-unverified and the render pipeline's default green is its own, not
   the club's colour, so NOTHING here may read as a club green. The serif
   numerals are the golf idiom - a printed scorecard sets its numbers in a
   serif, and that is the one place this page is allowed to look like the sport.

   No external requests: no webfont, no CDN, no image. Two local stacks pair a
   real serif against a grotesk, which is the guardrail that matters.
   ========================================================================== */

:root {
  /* ground and surface */
  --ink:        #0c100e;
  --ink-2:      #131917;
  --surface:    rgba(14, 19, 17, 0.90);
  --surface-2:  rgba(24, 31, 28, 0.94);
  --line:       rgba(236, 232, 219, 0.16);
  --line-soft:  rgba(236, 232, 219, 0.09);

  /* type colour */
  --paper:      #f1eee4;
  --muted:      #9aa39a;
  --muted-2:    #6d766e;

  /* one signal colour, plus a cool secondary that never competes */
  --accent:     #d9a75c;
  --accent-ink: #2a1d0b;
  --cool:       #7fa3b5;
  --warn:       #c9705a;

  /* three-step shadow, tinted with the ground's own ink. Never black. */
  --sh-1: 0 1px 2px rgba(6, 10, 8, 0.42);
  --sh-2: 0 6px 18px -6px rgba(6, 10, 8, 0.60), 0 2px 5px rgba(6, 10, 8, 0.36);
  --sh-3: 0 26px 60px -22px rgba(6, 10, 8, 0.82), 0 8px 20px -8px rgba(6, 10, 8, 0.50);

  /* 1.25 ratio type scale from 16 */
  --t--2: 0.64rem;
  --t--1: 0.80rem;
  --t-0:  1.00rem;
  --t-1:  1.25rem;
  --t-2:  1.5625rem;
  --t-3:  1.953rem;
  --t-4:  2.441rem;
  --t-5:  3.052rem;

  /* 4 px spacing scale */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px;

  --r-1: 6px; --r-2: 10px; --r-3: 16px; --r-4: 24px;

  --display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --body: ui-sans-serif, -apple-system, "Segoe UI", "Helvetica Neue", sans-serif;

  --sheet-w: 27rem;
  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

/* `hidden` is a UA style at the lowest specificity, so ANY class rule that sets
   display beats it - and `.ghost.wide { display: flex }` duly kept the caddie
   button on screen for every club. One rule, once, rather than a per-component
   `[hidden]` override that the next component forgets. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--body);
  font-size: var(--t-0);
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
  overflow: hidden;            /* the app owns the viewport; no page scroll */
  overscroll-behavior: none;
}

#app { position: fixed; inset: 0; overflow: hidden; }

#view {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------- typography */
.display {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0 0 var(--s-3);
  font-size: var(--t-4);
}
.display.huge { font-size: clamp(var(--t-4), 12vw, var(--t-5)); }

.eyebrow {
  margin: 0 0 var(--s-2);
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--accent);
  font-weight: 600;
}

.lede {
  margin: 0 0 var(--s-5);
  max-width: 42ch;
  color: var(--muted);
  font-size: var(--t-0);
  line-height: 1.6;
}

.fineprint {
  margin: var(--s-3) 0 0;
  font-size: var(--t--2);
  line-height: 1.5;
  color: var(--muted-2);
  max-width: 46ch;
}

/* ------------------------------------------------------------ interaction */
button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 0;
  background: none;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-1);
}

.cta {
  display: block;
  width: 100%;
  padding: var(--s-4) var(--s-5);
  margin-top: var(--s-4);
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--r-2);
  font-weight: 700;
  font-size: var(--t-0);
  letter-spacing: 0.01em;
  box-shadow: var(--sh-2);
  transition: transform 160ms cubic-bezier(.16,1,.3,1), filter 160ms ease;
}
.cta:hover { filter: brightness(1.06); }
.cta:active { transform: translateY(1px) scale(0.995); }
.cta[disabled] { opacity: 0.45; cursor: not-allowed; }

.ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  min-height: 48px;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface-2);
  box-shadow: var(--sh-1);
  transition: transform 160ms cubic-bezier(.16,1,.3,1), border-color 160ms ease;
}
.ghost:hover { border-color: rgba(217, 167, 92, 0.55); }
.ghost:active { transform: translateY(1px); }
.ghost.small { padding: var(--s-2) var(--s-3); min-height: 44px; font-size: var(--t--1); }
.ghost.wide { display: flex; width: 100%; justify-content: center; margin-top: var(--s-4); }
.ghost-k { font-size: var(--t--2); text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); }
.ghost-v { font-family: var(--display); font-size: var(--t-1); }

/* ---------------------------------------------------------------- screens */
.screen {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  /* the attribution footer is fixed over everything at z 50, so a sheet that
     runs to the bottom of a phone reads with the ODbL line printed across its
     fine print. Reserve the footer height plus a gap. */
  padding: var(--s-5) var(--s-4) calc(5rem + var(--safe-b));
  overflow-y: auto;
  overscroll-behavior: contain;
  background:
    radial-gradient(120% 70% at 18% 0%, rgba(217, 167, 92, 0.10), transparent 60%),
    radial-gradient(90% 60% at 88% 100%, rgba(127, 163, 181, 0.10), transparent 62%),
    rgba(6, 9, 8, 0.52);
  backdrop-filter: blur(3px) saturate(0.9);
  z-index: 30;
}
.screen[hidden] { display: none; }

.sheet {
  width: min(100%, var(--sheet-w));
  background: linear-gradient(180deg, rgba(28, 35, 31, 0.96), rgba(15, 20, 18, 0.98));
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  padding: var(--s-6) var(--s-5) var(--s-5);
  box-shadow: var(--sh-3);
  position: relative;
}
.sheet::after {
  /* grain, so the sheet is not a flat rectangle of one colour */
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0.16;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/></filter><rect width='120' height='120' filter='url(%23n)' opacity='0.5'/></svg>");
  mix-blend-mode: overlay;
}

.stamp {
  display: inline-block;
  margin: 0 0 var(--s-4);
  padding: var(--s-1) var(--s-3);
  border: 1px dashed rgba(201, 112, 90, 0.6);
  border-radius: var(--r-1);
  color: var(--warn);
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

.facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-3);
  margin: 0 0 var(--s-5);
  padding: var(--s-4) 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}
.facts dt {
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-2);
}
.facts dd {
  margin: var(--s-1) 0 0;
  font-family: var(--display);
  font-size: var(--t-2);
  line-height: 1;
}

fieldset.tees { border: 0; padding: 0; margin: 0 0 var(--s-4); }
fieldset.tees legend {
  padding: 0;
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-2);
  margin-bottom: var(--s-2);
}

/* ------------------------------------------------------------------ chips */
.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.chips-scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: var(--s-1);
  scroll-snap-type: x proximity;
}
.chips-scroll::-webkit-scrollbar { display: none; }

.chip {
  flex: 0 0 auto;
  scroll-snap-align: center;
  min-height: 44px;
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--paper);
  font-size: var(--t--1);
  line-height: 1.2;
  white-space: nowrap;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}
.chip .sub {
  display: block;
  font-size: var(--t--2);
  color: var(--muted-2);
  letter-spacing: 0.06em;
}
.chip[aria-checked="true"], .chip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}
.chip[aria-checked="true"] .sub, .chip[aria-pressed="true"] .sub { color: rgba(42, 29, 11, 0.72); }
.chip[disabled] { opacity: 0.35; cursor: not-allowed; }

/* -------------------------------------------------------------------- HUD */
#hud {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 10;
  padding: calc(var(--s-3) + env(safe-area-inset-top, 0px)) var(--s-4) var(--s-3);
  background: linear-gradient(180deg, rgba(6, 9, 8, 0.78), rgba(6, 9, 8, 0));
  pointer-events: none;
}
#hud[hidden] { display: none; }
.hud-row { display: flex; align-items: baseline; gap: var(--s-5); }
.hud-cell { display: flex; flex-direction: column; }
.hud-cell .k {
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.hud-cell .v { font-family: var(--display); font-size: var(--t-2); line-height: 1.1; }
.hud-pin { margin-left: auto; text-align: right; }
.hud-pin .v { color: var(--accent); }

.hud-sub { margin-top: var(--s-2); gap: var(--s-2); flex-wrap: wrap; }
.pill {
  padding: 2px var(--s-2);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  font-size: var(--t--2);
  letter-spacing: 0.06em;
  color: var(--muted);
  background: rgba(8, 12, 10, 0.68);
}
.pill-quiet { color: var(--muted); background: rgba(8, 12, 10, 0.72); }

/* --------------------------------------------------------------- controls */
#controls {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  padding: var(--s-3) var(--s-4) calc(var(--s-4) + var(--safe-b));
  background: linear-gradient(180deg, rgba(6, 9, 8, 0), rgba(6, 9, 8, 0.86) 34%, rgba(6, 9, 8, 0.96));
}
#controls[hidden] { display: none; }
@media (min-width: 900px) {
  /* On a phone the control cluster is the bottom of the screen and a full-bleed
     gradient is right. Constrained to a column on a desktop, that same gradient
     is a black rectangle with two hard vertical edges sitting in the middle of
     the hole - so at this width it becomes a panel with edges of its own. */
  #controls {
    left: 50%;
    transform: translateX(-50%);
    width: min(46rem, 92vw);
    bottom: var(--s-5);
    padding: var(--s-4);
    border: 1px solid var(--line);
    border-radius: var(--r-3);
    background: linear-gradient(180deg, rgba(12, 16, 14, 0.90), rgba(8, 11, 10, 0.96));
    box-shadow: var(--sh-3);
  }
  #hud { padding-left: max(var(--s-4), calc(50vw - 23rem)); padding-right: max(var(--s-4), calc(50vw - 23rem)); }
}

/* ---- the club stepper. course-game-feel, Track W ----------------------
   A horizontal scroller cut "5 Iron" off at 390 px and hid nine clubs past
   it. The club in hand is one big slab with a step either way, and tapping it
   opens the bag, where all fourteen sit in a grid that fits the screen. */
.club-row {
  display: grid;
  grid-template-columns: 3.6rem 1fr 3.6rem;
  gap: var(--s-2);
  align-items: stretch;
  margin-bottom: var(--s-3);
}
.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface-2);
  box-shadow: var(--sh-1);
  color: var(--paper);
  transition: transform 120ms cubic-bezier(.16,1,.3,1), border-color 160ms ease;
}
.step:hover { border-color: rgba(217, 167, 92, 0.55); }
.step:active { transform: translateY(1px); }
.step[disabled] { opacity: 0.3; cursor: default; }
.step-glyph { font-family: var(--display); font-size: var(--t-2); line-height: 1; }
.step-k { font-size: 0.56rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin-top: 2px; }

.club-now {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s-3);
  min-height: 56px;
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface-2);
  box-shadow: var(--sh-1);
  text-align: left;
  transition: transform 120ms cubic-bezier(.16,1,.3,1), border-color 160ms ease;
}
.club-now:hover { border-color: rgba(217, 167, 92, 0.55); }
.club-now:active { transform: translateY(1px); }
.club-now-k { font-size: var(--t--2); text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); }
.club-now-v { font-family: var(--display); font-size: var(--t-2); line-height: 1; color: var(--paper); white-space: nowrap; }
.club-now-sub { font-size: var(--t--1); color: var(--muted); letter-spacing: 0.04em; white-space: nowrap; }
.club-now.is-caddie .club-now-sub::after { content: " \00b7 caddie"; color: var(--accent); }

/* the bag sheet */
.bag-note { margin: var(--s-3) 0; color: var(--muted); font-size: var(--t--1); }
.bag-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2);
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  align-content: start;
}
.bag-grid .chip {
  position: relative;
  width: 100%;
  min-height: 48px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-2);
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: left;
}
.bag-grid .chip.is-caddie::after {
  content: "caddie";
  position: absolute;
  top: 6px; right: 8px;
  font-size: 0.56rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent);
}
.bag-grid .chip[aria-checked="true"].is-caddie::after { color: rgba(42, 29, 11, 0.8); }
@media (min-width: 900px) {
  .bag-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.control-row {
  display: grid;
  grid-template-columns: minmax(7rem, 1fr) 2fr;
  gap: var(--s-3);
  align-items: stretch;
}
/* ---- the read chip. course-game-motion, Track Y ------------------------
   With the putter in hand the row gains a third slab between Aim and Swing:
   the caddie's read, one tap, its verdict on the chip. Every slab stays at
   least 44 px tall and the swing keeps the widest column at 390. */
#controls[data-putting="1"] .control-row {
  grid-template-columns: minmax(5.4rem, 1fr) minmax(5.4rem, 1fr) 1.9fr;
}
.read-chip { flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; }
.read-chip .ghost-v { white-space: nowrap; font-size: var(--t-1); line-height: 1.1; }
.read-chip.is-in { border-color: rgba(217, 167, 92, 0.75); }
.read-chip.is-in .ghost-v { color: var(--accent); }
.pill-read { color: var(--accent); border-color: rgba(217, 167, 92, 0.45); }
.pill-read.is-out { color: var(--paper); }

/* ---- the moment. The HUD pulses once when the ball drops -------------- */
#hud.is-holed .hud-pin .v { animation: hud-holed 1.2s cubic-bezier(.16,1,.3,1) both; }
@keyframes hud-holed {
  0%   { transform: scale(1); filter: brightness(1); }
  18%  { transform: scale(1.22); filter: brightness(1.5); }
  100% { transform: scale(1); filter: brightness(1); }
}
#hud.is-holed { animation: hud-flash 1.2s ease-out both; }
@keyframes hud-flash {
  0%   { background: linear-gradient(180deg, rgba(217, 167, 92, 0.34), rgba(6, 9, 8, 0)); }
  100% { background: linear-gradient(180deg, rgba(6, 9, 8, 0.78), rgba(6, 9, 8, 0)); }
}
/* the aim chip is a READOUT of the drag now, and a door to the overhead map */
#aim-open {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
}
#aim-open .ghost-v { white-space: nowrap; font-size: var(--t-1); line-height: 1.1; }

.swing {
  min-height: 64px;
  border-radius: var(--r-3);
  background: linear-gradient(180deg, #e8b96f, var(--accent));
  color: var(--accent-ink);
  font-weight: 800;
  font-size: var(--t-1);
  letter-spacing: 0.02em;
  box-shadow: var(--sh-2), inset 0 1px 0 rgba(255, 255, 255, 0.34);
  transition: transform 120ms cubic-bezier(.16,1,.3,1), filter 160ms ease;
}
.swing:active { transform: translateY(2px); filter: brightness(0.96); }
.swing[disabled] { opacity: 0.5; cursor: default; }
.swing.is-armed { background: linear-gradient(180deg, #f0d2a0, #e0b06a); }
/* every tap lands: a short press-in on the slab, restarted per tap */
.swing.is-hit { animation: swing-hit 260ms cubic-bezier(.16,1,.3,1); }
@keyframes swing-hit {
  0%   { transform: scale(1); }
  35%  { transform: scale(0.955); filter: brightness(1.14); }
  100% { transform: scale(1); }
}

/* ---- the meter. One track, two skins ------------------------------------
   Power stage: the fill grows under the needle and the caddie's notch marks
   the number to stop at. Face stage: the fill dims, a square window lights in
   the middle and the outer quarters tint warn - FACE_RANGE_DEG is 8 and a tap
   out there is a wrecked shot, so the cost is on the track before the tap. */
.meter { margin-top: var(--s-3); }
.meter-track {
  position: relative;
  height: 22px;
  border-radius: 999px;
  background: rgba(8, 12, 10, 0.9);
  border: 1px solid var(--line);
  overflow: hidden;
}
.meter-warn {
  position: absolute; top: 0; bottom: 0; width: 25%;
  background: rgba(201, 112, 90, 0);
  transition: background 160ms ease;
}
.meter-warn-l { left: 0; }
.meter-warn-r { right: 0; }
.meter-zone {
  position: absolute; top: 0; bottom: 0; left: 43.75%; width: 12.5%;
  background: rgba(127, 163, 181, 0);
  transition: background 160ms ease;
}
.meter-fill {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0%;
  background: linear-gradient(90deg, rgba(217, 167, 92, 0.5), var(--accent));
  transition: opacity 160ms ease;
}
.meter-target {
  position: absolute; top: -2px; bottom: -2px; width: 4px; margin-left: -2px;
  background: var(--accent);
  box-shadow: 0 0 0 2px rgba(6, 9, 8, 0.9), 0 0 8px rgba(217, 167, 92, 0.8);
  transition: opacity 160ms ease;
}
.meter-needle {
  position: absolute; top: -3px; bottom: -3px; left: 0; width: 3px; margin-left: -1px;
  background: var(--paper);
  box-shadow: 0 0 6px rgba(241, 238, 228, 0.8);
}
.meter-mark {
  position: absolute; top: -3px; bottom: -3px; width: 3px; margin-left: -1px;
  background: var(--cool);
}
.meter-mark-face { background: var(--paper); opacity: 0.85; }
.meter[data-stage="face"] .meter-warn { background: rgba(201, 112, 90, 0.34); }
.meter[data-stage="face"] .meter-zone { background: rgba(127, 163, 181, 0.46); }
.meter[data-stage="face"] .meter-fill { opacity: 0.22; }
.meter[data-stage="face"] .meter-target { opacity: 0.3; }
.meter[data-stage="fired"] .meter-warn { background: rgba(201, 112, 90, 0.18); }
.meter[data-stage="fired"] .meter-zone { background: rgba(127, 163, 181, 0.24); }
.meter[data-stage="fired"] .meter-fill { opacity: 0.5; }
.meter-legend {
  display: flex;
  justify-content: space-between;
  margin-top: var(--s-1);
  font-size: var(--t--2);
  color: var(--muted);
  letter-spacing: 0.06em;
}
.meter-hint, .swing-verdict {
  margin: var(--s-1) 0 0;
  min-height: 1.45em;
  text-align: center;
  line-height: 1.45;
}
.meter-hint { font-size: var(--t--1); color: var(--muted); }
.swing-verdict {
  font-family: var(--display);
  font-size: var(--t-1);
  color: var(--paper);
  letter-spacing: -0.01em;
}
.swing-verdict[data-grade="pure"] { color: var(--accent); }
.swing-verdict[data-grade="off"] { color: #e0a98a; }
.swing-verdict[data-grade="bad"] { color: var(--warn); }

/* ---- the first-shot coach ------------------------------------------------
   Replaces 11 px grey text nobody read. Three steps, the live one lit, and
   pointer-events: none so it never sits between a thumb and the swing. */
.coach {
  margin: 0 0 var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid rgba(217, 167, 92, 0.5);
  border-radius: var(--r-2);
  background: rgba(14, 19, 17, 0.94);
  box-shadow: var(--sh-2);
  pointer-events: none;
  transition: opacity 320ms ease;
}
.coach.is-leaving { opacity: 0; }
.coach-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-1); }
.coach-steps li {
  display: grid;
  grid-template-columns: 24px 1fr;
  gap: var(--s-3);
  align-items: center;
  font-size: var(--t--1);
  color: var(--muted-2);
  transition: color 160ms ease;
}
.coach-steps li b {
  width: 24px; height: 24px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: grid; place-items: center;
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--t--1);
  color: var(--muted);
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.coach-steps li.is-now { color: var(--paper); }
.coach-steps li.is-now b { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.coach-steps li.is-done { color: var(--muted-2); }
.coach-steps li.is-done b { background: rgba(127, 163, 181, 0.35); border-color: transparent; color: var(--paper); }
.coach-aim { margin: var(--s-2) 0 0; font-size: var(--t--2); color: var(--accent); letter-spacing: 0.06em; text-transform: uppercase; }

/* ---- mute. Lives in the HUD, which is pointer-events none by design ---- */
.mute {
  pointer-events: auto;
  margin-left: auto;
  min-width: 40px;
  min-height: 26px;
  padding: 0 var(--s-2);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  background: rgba(8, 12, 10, 0.68);
  color: var(--muted);
  font-size: var(--t--1);
  line-height: 1;
}
.mute .mute-off { display: none; }
.mute[aria-pressed="true"] .mute-on { display: none; }
.mute[aria-pressed="true"] .mute-off { display: inline; }
.mute[aria-pressed="true"] { color: var(--muted-2); }

.shot-note {
  margin: 0 0 var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-left: 2px solid var(--accent);
  background: rgba(14, 19, 17, 0.8);
  border-radius: 0 var(--r-1) var(--r-1) 0;
  font-size: var(--t--1);
  color: var(--paper);
}
.shot-note[hidden] { display: none; }

/* ---------------------------------------------------------- aim overlay */
.overlay {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  padding: calc(var(--s-4) + env(safe-area-inset-top, 0px)) var(--s-4) calc(var(--s-4) + var(--safe-b));
  background: rgba(6, 9, 8, 0.94);
  backdrop-filter: blur(6px);
}
.overlay[hidden] { display: none; }
.overlay-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.overlay-title { font-family: var(--display); font-weight: 400; font-size: var(--t-2); margin: 0; }
.icon-btn {
  min-height: 44px; padding: var(--s-2) var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-2);
  background: var(--surface-2); font-size: var(--t--1);
}
.map-wrap {
  flex: 1 1 auto;
  min-height: 0;
  margin: var(--s-3) 0;
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
  background: #0a0e0c;
  box-shadow: var(--sh-2);
}
#map { display: block; width: 100%; height: 100%; touch-action: none; }
.aim-readout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-top: 1px solid var(--line-soft);
}
.aim-readout .k, .card-foot .k {
  display: block;
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-2);
}
.aim-readout .v, .card-foot .v { font-family: var(--display); font-size: var(--t-1); }
.aim-buttons { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2); }
.aim-buttons .ghost { justify-content: center; }

/* -------------------------------------------------------------- scorecard */
.card-topar { margin: 0 0 var(--s-4); font-size: var(--t-1); color: var(--accent); }
/* the running card's one line (play mode, Contract H2) */
.card-round { margin: 0 0 var(--s-4); font-size: var(--t--1); color: var(--muted); }
.card-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--s-4);
  font-size: var(--t--1);
}
.card-table th, .card-table td {
  text-align: left;
  padding: var(--s-2) var(--s-1);
  border-bottom: 1px solid var(--line-soft);
}
.card-table th {
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted-2);
  font-weight: 600;
}
.card-table td:first-child { font-family: var(--display); color: var(--accent); width: 2.2rem; }
.card-table tr.is-penalty td { color: var(--warn); }
.card-foot {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line-soft);
}

/* ------------------------------------------------------- claim and reward */
.claim-sheet { padding-top: var(--s-5); }
.award { text-align: center; margin-bottom: var(--s-5); }
.award[hidden] { display: none; }
.award-badge {
  width: 92px; height: 92px;
  margin: 0 auto var(--s-4);
  border-radius: 50%;
  background:
    radial-gradient(60% 60% at 34% 28%, rgba(255, 246, 226, 0.95), rgba(217, 167, 92, 0.95) 58%, rgba(150, 106, 42, 0.95));
  box-shadow: var(--sh-2), inset 0 -6px 14px rgba(94, 62, 16, 0.5);
  position: relative;
}
.award-badge::after {
  content: attr(data-mark);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--display);
  font-size: var(--t-3);
  color: var(--accent-ink);
}
.award-line { margin: 0; color: var(--muted); max-width: 40ch; margin-inline: auto; }

.field { display: block; margin-bottom: var(--s-3); }
.field-k {
  display: block;
  font-size: var(--t--2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted-2);
  margin-bottom: var(--s-2);
}
.field input {
  width: 100%;
  min-height: 52px;
  padding: var(--s-3) var(--s-4);
  font: inherit;
  color: var(--paper);
  background: rgba(8, 12, 10, 0.85);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}
.field input::placeholder { color: var(--muted-2); }
.field-error { margin: 0 0 var(--s-3); color: var(--warn); font-size: var(--t--1); }
.field-error[hidden] { display: none; }

.consent {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: var(--s-3);
  align-items: start;
  margin-bottom: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-2);
  background: rgba(8, 12, 10, 0.5);
  font-size: var(--t--1);
  line-height: 1.5;
  color: var(--muted);
  cursor: pointer;
}
.consent input {
  width: 22px; height: 22px;
  margin: 2px 0 0;
  accent-color: var(--accent);
}

.reveal {
  margin-top: var(--s-5);
  padding: var(--s-5) var(--s-4);
  border: 1px dashed rgba(217, 167, 92, 0.55);
  border-radius: var(--r-3);
  text-align: center;
  background: rgba(217, 167, 92, 0.07);
}
.reveal[hidden] { display: none; }
.reveal-code {
  margin: 0 0 var(--s-2);
  font-family: var(--display);
  font-size: var(--t-3);
  letter-spacing: 0.16em;
  color: var(--accent);
}
.reveal-line { margin: 0; color: var(--muted); font-size: var(--t--1); }

/* ------------------------------------------------------------- attribution */
#attrib {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 50;
  /* THE ONLY LAYOUT SHIFT ON THE PAGE LIVED HERE. The attribution comes from
     the pack, so it is injected after load, and the ODbL line wraps to three
     lines at 390 px where the placeholder took two - a bottom-anchored box that
     grows upward, measured at CLS 0.0011. Reserving the height costs nothing:
     the footer is translucent and the space under it is the canvas. */
  min-height: 4rem;
  /* bottom-aligned inside the reserved box, so the line that GROWS pushes its
     own top upward instead of pushing the stamp below it down */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--s-2) var(--s-4) calc(var(--s-2) + var(--safe-b));
  font-size: 0.6rem;
  line-height: 1.4;
  color: rgba(154, 163, 154, 0.72);
  background: linear-gradient(180deg, rgba(6, 9, 8, 0), rgba(6, 9, 8, 0.8));
  pointer-events: none;
  text-align: center;
}
#attrib p { margin: 0; }
/* Two lines reserved for the attribution itself. The container reserve stops
   the FOOTER moving; this stops the paragraph resizing under it, which is the
   other half of the same shift. Measured to CLS 0.0000 at 390 and at 1440. */
#attrib-text { min-height: 2.8em; }
#attrib.tucked { opacity: 0; pointer-events: none; }
.stamp-inline { color: rgba(201, 112, 90, 0.8); letter-spacing: 0.1em; text-transform: uppercase; }

/* --------------------------------------------------- the diagnostics dump */
/* The stamp is a hold target (course-game-polish Phase 0, Contract H2): a
   700 ms press and release copies __game.report(). No text selection and no
   callout on the press, no scroll stealing the pointer mid-hold. The footer
   line takes pointer events again here because #attrib gives them up; while
   the footer is tucked (in play) it stays inert, or an invisible hold target
   would sit over the view. */
.stamp, .stamp-inline {
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  cursor: pointer;
}
.stamp-inline { pointer-events: auto; }
#attrib.tucked .stamp-inline { pointer-events: none; }
.diag { z-index: 50; }
.diag-text {
  flex: 1;
  min-height: 40vh;
  margin: var(--s-3) 0;
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-2);
  color: var(--paper);
  font: 0.7rem/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  resize: none;
}
.toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--s-7) + var(--safe-b));
  z-index: 70;
  transform: translateX(-50%);
  max-width: calc(100% - var(--s-6));
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-2);
  background: var(--surface-2);
  color: var(--paper);
  font-size: var(--t--1);
  box-shadow: var(--sh-2);
  pointer-events: none;
  white-space: nowrap;
}
.toast[hidden] { display: none; }

/* ---------------------------------------------------------------- loading */
#loading {
  position: absolute; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: var(--ink);
  padding: var(--s-5);
}
#loading[hidden] { display: none; }
.load-inner { width: min(100%, 22rem); text-align: center; }
.load-bar {
  height: 4px;
  border-radius: 999px;
  background: rgba(241, 238, 228, 0.12);
  overflow: hidden;
}
.load-bar i {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 220ms cubic-bezier(.16,1,.3,1);
}
.load-note { margin: var(--s-3) 0 0; font-size: var(--t--1); color: var(--muted-2); }

/* ---- the reward moment. course-game-feel, Track W ----------------------
   The last thing a prospect sees. The card writes itself a row at a time, the
   badge lands, the code arrives. Every value on these screens comes from the
   API response and none is written here. */
.card-table tbody tr { animation: row-in 420ms cubic-bezier(.16,1,.3,1) both; }
@keyframes row-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.award-badge { animation: badge-pop 720ms cubic-bezier(.16,1,.3,1) both; }
@keyframes badge-pop {
  0%   { transform: scale(0.4); opacity: 0; }
  62%  { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.award .display { animation: score-in 600ms 180ms cubic-bezier(.16,1,.3,1) both; }
@keyframes score-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.reveal { animation: reveal-in 520ms cubic-bezier(.16,1,.3,1) both; }
@keyframes reveal-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: none; }
}
/* one line at 390 px: the mock's longest code is seventeen characters */
.reveal-code { font-size: var(--t-2); letter-spacing: 0.12em; white-space: nowrap; }

/* --------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* The wind badge (course-game-polish cycle 6, Track FB). Cycle 5's pill vane
   was correct and unreadable in play; this is the same maths at a size the
   eye catches, under the HUD on the right where nothing else lives. It
   describes the world - direction, strength, relation - and never the shot. */
#wind-badge {
  position: fixed;
  /* below the HUD's own bottom edge (131 px measured) so it never covers the
     mute button, which sits in the HUD's second row (cycle 6, FB) */
  top: 139px;
  right: 12px;
  z-index: 25;
  width: 74px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 8px 4px 6px;
  border-radius: 12px;
  background: rgba(10, 14, 12, 0.62);
  border: 1px solid rgba(241, 238, 228, 0.16);
  backdrop-filter: blur(3px);
  pointer-events: none;
}
#wind-dial { width: 46px; height: 46px; display: block; }
#wind-badge .wind-ring {
  fill: rgba(241, 238, 228, 0.06);
  stroke: rgba(241, 238, 228, 0.34);
  stroke-width: 1.4;
}
#wind-badge .wind-shaft {
  stroke: var(--accent);
  stroke-width: 3.4;
  stroke-linecap: round;
  fill: none;
}
#wind-badge .wind-head { fill: var(--accent); }
#wind-badge[data-calm="1"] .wind-shaft,
#wind-badge[data-calm="1"] .wind-head { opacity: 0.22; }
#wind-mph {
  font-size: 13px;
  font-weight: 700;
  color: #f1eee4;
  letter-spacing: 0.01em;
}
#wind-word {
  font-size: 10px;
  line-height: 1.15;
  text-align: center;
  color: rgba(241, 238, 228, 0.72);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Intent made legible (course-game-polish cycle 5, Track EB). Three fixes
   from watching a real golfer play: the wind vane in the HUD pill (an arrow
   rotated to the view - where the wind pushes the ball on screen), a one-time
   cue on the Read chip until the first read, and the caddie notch given the
   visual weight of a goal. Perception only; nothing answers the shot. */
.pill-wind { display: inline-flex; align-items: center; gap: 5px; }
#wind-vane { width: 13px; height: 13px; flex: 0 0 auto; }
#wind-vane path {
  fill: none;
  stroke: #f1eee4;
  stroke-width: 2.1;
  stroke-linecap: round;
}
@keyframes read-cue-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217, 167, 92, 0); }
  50% { box-shadow: 0 0 0 5px rgba(217, 167, 92, 0.45); }
}
.read-cue {
  animation: read-cue-pulse 1.4s ease-in-out 3;
  border-color: rgba(217, 167, 92, 0.9) !important;
}
/* the notch lights as the needle crosses it (cycle 6, Track FB) - display
   only; the sweep, the bands and the grading are untouched */
.meter-target.is-lit {
  background: #ffffff;
  box-shadow: 0 0 0 2px rgba(6, 9, 8, 0.9), 0 0 14px 3px rgba(255, 255, 255, 0.9);
}
.meter-target.is-lit::after { border-top-color: #ffffff; }
.meter-target::after {
  content: '';
  position: absolute;
  left: 50%;
  top: -8px;
  transform: translateX(-50%);
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--accent);
  filter: drop-shadow(0 0 2px rgba(217, 167, 92, 0.8));
}

/* The ball marker (course-game-polish cycle 3, Track CB): a ring at the
   ball's projected position when it lies under a crown at an address. DOM
   only; main.js positions it with translate() off the renderer's own
   projection, so left/top hold the centre offset. Static - information,
   not decoration - and therefore untouched by reduced motion. */
#ballmark {
  position: fixed;
  left: -13px;
  top: -13px;
  width: 26px;
  height: 26px;
  border: 2px solid rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.5);
  pointer-events: none;
  z-index: 15;
}
