/* Cape Ride rider app.
   Chart-derived palette: pale water, land buff, chart magenta for focus.
   The check-in indicator runs channel-marker green -> amber -> deep orange.
   Never red, and never hue alone — the draining bar carries the same state.
   High contrast throughout: this is read outdoors, in sun, one-handed. */

:root{
  /* Chart palette: land buff, shoal, deep water, chart magenta, ink */
  --water:#EDF2F3;
  --shoal:#DCE7E8;
  --sand:#E8DCC0;
  --ink:#132321;
  --ink-soft:#4A5C5A;
  --hair:#C3D2D2;
  --magenta:#B3175E;

  /* Indicator: channel green -> amber -> deep orange. Never red. */
  --good:#2C7A52;
  --soon:#C98A12;
  --now:#BE5219;
  --stale:#6A7A7C;

  --pad:20px;
  --safe-top:env(safe-area-inset-top,0px);
  --safe-bot:env(safe-area-inset-bottom,0px);
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
html,body{margin:0;height:100%;overflow:hidden}
body{
  background:var(--water);
  color:var(--ink);
  font-family:"Archivo",system-ui,-apple-system,"Segoe UI",sans-serif;
  font-variation-settings:"wdth" 100;
  font-size:17px;line-height:1.4;
  -webkit-font-smoothing:antialiased;
  font-feature-settings:"tnum" 1;
}
button,input{font:inherit;color:inherit}
button{border:0;background:none;cursor:pointer}

/* ---------- panel rail ---------- */
.rail{
  display:flex;height:100dvh;width:100%;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  scrollbar-width:none;
  /* Declares this element as the horizontal-pan owner, overriding the
     universal touch-action:manipulation above. Without this, Android
     Chrome's compositor leaves .rail eligible to handle a pan in either
     axis and the gesture can get claimed by a nested vertical scroller
     instead (see .panel below) — never reproduced on iOS Safari, which
     resolves scroll-chaining differently. */
  touch-action:pan-x;
}
.rail::-webkit-scrollbar{display:none}
.panel{
  flex:0 0 100%;height:100dvh;
  scroll-snap-align:center;scroll-snap-stop:always;
  overflow-y:auto;overscroll-behavior:contain;
  padding-bottom:calc(64px + var(--safe-bot));
  /* The other half of the fix above: a panel only ever scrolls vertically.
     Declaring pan-y (instead of inheriting manipulation, which also claims
     pan-x) tells Android Chrome up front that a horizontal drag starting
     inside a panel belongs to .rail, not to this element's own vertical
     scroller — reproduced and confirmed via real touch-event emulation:
     any panel whose content overflows vertically (scrollHeight >
     clientHeight) swallowed 100% of horizontal swipes under the old
     touch-action:manipulation default; panels that exactly fit the
     viewport were unaffected, which is what pointed at touch-action as
     the mechanism rather than the scroll-snap/overscroll-behavior setup.
     .dial below still declares its own touch-action:none and wins by
     source order, so dragging the mileage dial is unaffected. */
  touch-action:pan-y;
}

/* ---------- dashboard: the status field ---------- */
.field{
  padding:calc(var(--safe-top) + 26px) var(--pad) 22px;
  color:#fff;
  transition:background-color 600ms linear;
  position:relative;
}
.field-state{
  font-size:31px;font-weight:700;letter-spacing:-.02em;
  font-variation-settings:"wdth" 92,"wght" 700;
  margin:0 0 4px;line-height:1.1;
}
.field-sub{margin:0;font-size:16px;opacity:.88;font-weight:500}
/* the draining bar: the non-color cue */
.drain{
  margin-top:18px;height:9px;border-radius:5px;
  background:rgba(255,255,255,.26);overflow:hidden;
}
.drain span{
  display:block;height:100%;border-radius:5px;background:#fff;
  transition:width 600ms linear;
}
.field.overdue .field-state{animation:nudge 2.4s ease-in-out infinite}
@keyframes nudge{0%,100%{opacity:1}50%{opacity:.72}}
@media (prefers-reduced-motion:reduce){
  .field.overdue .field-state{animation:none}
  .field,.drain span{transition:none}
}
/* offline: hatched, unmistakably not part of the green-orange scale */
.field.offline{
  background:var(--stale)!important;
  background-image:repeating-linear-gradient(45deg,
    rgba(255,255,255,.10) 0 12px,transparent 12px 24px)!important;
}

/* venue badge riding under the field */
.venue-flag{
  display:flex;align-items:center;gap:12px;
  padding:14px var(--pad);color:#fff;font-weight:600;
}
.venue-flag b{font-weight:800;font-variation-settings:"wdth" 92,"wght" 800}
.venue-flag small{display:block;font-weight:500;opacity:.85;font-size:14px}
.venue-flag[hidden]{display:none}

/* ---------- score blocks ---------- */
.scores{padding:22px var(--pad) 0}
.me{
  display:grid;grid-template-columns:1fr auto;align-items:end;
  gap:4px 16px;padding-bottom:18px;border-bottom:2px solid var(--ink);
}
.me .huge{
  font-size:74px;line-height:.86;font-weight:800;letter-spacing:-.04em;
  font-variation-settings:"wdth" 88,"wght" 800;
}
.me .unit{font-size:19px;font-weight:600;color:var(--ink-soft);padding-bottom:6px}
.me .caption{grid-column:1/-1;font-size:15px;color:var(--ink-soft);font-weight:500}

.split{display:grid;grid-template-columns:1fr 1fr;gap:0}
.split>div{padding:16px 0}
.split>div+div{border-left:1px solid var(--hair);padding-left:18px}
.split .n{font-size:30px;font-weight:700;letter-spacing:-.02em;font-variation-settings:"wdth" 92,"wght" 700}
.split .l{font-size:14px;color:var(--ink-soft);font-weight:500}

.pair{
  margin-top:6px;border-top:1px solid var(--hair);
  display:grid;grid-template-columns:1fr auto;gap:10px;
  padding:16px 0;align-items:baseline;
}
.pair .who{font-weight:600}
.pair .who small{display:block;font-weight:500;font-size:14px;color:var(--ink-soft)}
.pair .tot{font-size:26px;font-weight:700;font-variation-settings:"wdth" 92,"wght" 700}
.team{
  margin-top:2px;background:var(--sand);border-radius:3px;
  padding:16px 18px;display:flex;justify-content:space-between;align-items:baseline;
}
.team .l{font-weight:600}
.team .n{font-size:34px;font-weight:800;letter-spacing:-.03em;font-variation-settings:"wdth" 88,"wght" 800}

.pull{
  margin:22px var(--pad) 0;padding:15px;width:calc(100% - 40px);
  border:1.5px solid var(--ink);border-radius:3px;
  font-weight:600;text-align:center;
}

/* ---------- check-in panel ---------- */
.check{
  min-height:100dvh;display:flex;flex-direction:column;
  padding:calc(var(--safe-top) + 26px) var(--pad) calc(80px + var(--safe-bot));
  transition:background-color 400ms ease;
}
.check h2{
  margin:0 0 2px;font-size:29px;font-weight:800;letter-spacing:-.025em;
  font-variation-settings:"wdth" 90,"wght" 800;
}
.check .lede{margin:0 0 26px;color:var(--ink-soft);font-weight:500}
.check.venue{background:var(--vcolor,#2A9D8F);color:#fff}
.check.venue .lede{color:rgba(255,255,255,.85)}
.check.venue .mile-input{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.5);color:#fff}
.check.venue .hint{color:rgba(255,255,255,.8)}
.check.venue .go{background:#fff;color:var(--vcolor,#2A9D8F)}
.check.venue .chip{border-color:rgba(255,255,255,.55);color:#fff}
.check.venue .chip[aria-pressed="true"]{background:#fff;color:var(--vcolor,#2A9D8F);border-color:#fff}

.mile-label{font-weight:600;margin-bottom:10px;display:block}
.mile-input{
  width:100%;padding:18px 20px;
  border:2px solid var(--ink);border-radius:3px;background:transparent;
  font-size:44px;font-weight:700;letter-spacing:-.02em;
  font-variation-settings:"wdth" 92,"wght" 700;
  text-align:left;
}
.mile-input:focus{outline:3px solid var(--magenta);outline-offset:2px}
.hint{margin:10px 0 0;font-size:15px;color:var(--ink-soft);font-weight:500}

.items{margin-top:26px}
.items h3{margin:0 0 12px;font-size:17px;font-weight:700}
.chips{display:flex;flex-wrap:wrap;gap:9px}
.chip{
  padding:12px 16px;border:1.5px solid var(--ink);border-radius:999px;
  font-weight:600;font-size:16px;
}
.chip[aria-pressed="true"]{background:var(--ink);color:var(--water)}

.go{
  margin-top:auto;width:100%;padding:22px;
  background:var(--ink);color:var(--water);border-radius:3px;
  font-size:21px;font-weight:800;letter-spacing:-.01em;
  font-variation-settings:"wdth" 92,"wght" 800;
}
.go:disabled{opacity:.4}
.go:active{transform:translateY(1px)}

/* ---------- leaderboard ---------- */
.board{padding:calc(var(--safe-top) + 26px) var(--pad) 0}
.board h2{
  margin:0 0 3px;font-size:29px;font-weight:800;letter-spacing:-.025em;
  font-variation-settings:"wdth" 90,"wght" 800;
}
.board .lede{margin:0 0 22px;color:var(--ink-soft);font-weight:500}
.row{
  display:grid;grid-template-columns:34px 1fr auto;gap:14px;align-items:baseline;
  padding:15px 0;border-top:1px solid var(--hair);
}
.row:last-child{border-bottom:1px solid var(--hair)}
.row .rk{font-size:20px;font-weight:800;color:var(--ink-soft);font-variation-settings:"wdth" 88,"wght" 800}
.row .nm{font-weight:600}
.row .nm small{display:block;font-weight:500;font-size:14px;color:var(--ink-soft)}
.row .pt{font-size:26px;font-weight:700;font-variation-settings:"wdth" 92,"wght" 700}
.row.mine{
  background:var(--sand);margin:0 -12px;padding-left:12px;padding-right:12px;
  border-radius:3px;border-top-color:transparent;
}
.row .swatch{
  display:inline-block;width:10px;height:10px;border-radius:2px;
  margin-right:7px;vertical-align:baseline;
}

/* ---------- venue sheet ---------- */
.scrim{
  position:fixed;inset:0;background:rgba(19,35,33,.42);
  opacity:0;pointer-events:none;transition:opacity 260ms ease;z-index:40;
}
.scrim.open{opacity:1;pointer-events:auto}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:50;
  background:var(--water);border-radius:14px 14px 0 0;
  max-height:82dvh;overflow-y:auto;
  transform:translateY(101%);transition:transform 300ms cubic-bezier(.22,1,.36,1);
  padding:10px var(--pad) calc(24px + var(--safe-bot));
  box-shadow:0 -2px 0 var(--ink);
}
.sheet.open{transform:translateY(0)}
.grab{width:42px;height:4px;border-radius:2px;background:var(--hair);margin:0 auto 16px}
.sheet h3{margin:0 0 14px;font-size:22px;font-weight:800;font-variation-settings:"wdth" 90,"wght" 800}
.v{display:grid;grid-template-columns:6px 1fr auto;gap:14px;padding:15px 0;border-top:1px solid var(--hair)}
.v .bar{border-radius:3px}
.v .nm{font-weight:700}
.v .ch{font-size:15px;color:var(--ink-soft);font-weight:500}
.v .mi{font-size:15px;color:var(--ink-soft);font-weight:600;text-align:right;white-space:nowrap}
.v .mi b{display:block;font-size:19px;color:var(--ink);font-variation-settings:"wdth" 92,"wght" 700}
.visits{color:var(--good);font-weight:700;letter-spacing:-.06em;white-space:nowrap;margin-left:6px}
.visits .more{letter-spacing:0;font-size:14px;margin-left:2px}

/* ---------- photo ops ---------- */
.photo{padding:calc(var(--safe-top) + 26px) var(--pad) 0}
.photo h2{
  margin:0 0 3px;font-size:29px;font-weight:800;letter-spacing:-.025em;
  font-variation-settings:"wdth" 90,"wght" 800;
}
.photo .lede{margin:0 0 22px;color:var(--ink-soft);font-weight:500}
.op{padding:16px 0;border-top:1px solid var(--hair)}
.op:last-child{border-bottom:1px solid var(--hair)}
.op-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.op-name{font-weight:700;font-size:17px}
.op-town{font-size:14px;color:var(--ink-soft);font-weight:500;margin-top:2px}
.op-status{margin-top:10px}
.op-note{margin:8px 0 0;font-size:14px;color:var(--ink-soft);font-weight:500}
.op-claim{
  margin-top:10px;width:100%;padding:14px;border:1.5px solid var(--ink);border-radius:3px;
  font-weight:700;text-align:center;
}
.op-claim:active{background:var(--ink);color:var(--water)}
.op-upload{
  display:block;margin-top:10px;width:100%;padding:14px;border-radius:3px;
  background:var(--ink);color:var(--water);font-weight:700;text-align:center;cursor:pointer;
}
.op-upload:active{opacity:.85}

/* status pills, same semantics as the organizer console: never red */
.pill{display:inline-block;padding:4px 10px;border-radius:999px;font-size:13px;font-weight:700}
.pill.ok{background:var(--good);color:#fff}
.pill.warn{background:var(--soon);color:#fff}
.pill.bad{background:var(--now);color:#fff}
.pill.flat{background:var(--shoal);color:var(--ink-soft)}

/* ---------- dots ---------- */
.dots{
  position:fixed;left:0;right:0;bottom:calc(14px + var(--safe-bot));
  display:flex;justify-content:center;gap:9px;z-index:30;pointer-events:none;
}
/* pointer-events is not inherited onto .dot the way the layout comment below
   assumed: without this, every .dot button silently inherited none from its
   .dots container and could never be tapped at all — confirmed by hit-
   testing the real element under the dot's screen position, which returned
   the panel behind it, not the dot. .dots itself stays none so the empty
   gaps in the bar still pass taps through to whatever panel is underneath. */
.dot{width:7px;height:7px;border-radius:50%;background:var(--hair);transition:all 200ms;
  border:0;padding:0;pointer-events:auto}
/* the tap target is bigger than the dot */
.dot::before{content:"";position:absolute;width:34px;height:34px;
  transform:translate(-50%,-50%);margin-left:3.5px;margin-top:3.5px}
.dot.on{background:var(--ink);width:22px;border-radius:4px}




.nudge-link{display:block;margin:12px var(--pad) 0;width:calc(100% - 40px);
  text-align:center;font-size:15px;font-weight:600;color:var(--ink-soft);
  text-decoration:underline;text-underline-offset:3px;padding:8px}
.manual-note{margin-top:16px;padding:12px 14px;border-radius:3px;background:var(--shoal);
  font-size:15px;font-weight:500}
.manual-note[hidden]{display:none}
.items[hidden]{display:none}
.check.venue .manual-note{background:rgba(255,255,255,.16)}
.check.venue .fallback{border-color:rgba(255,255,255,.5)}
.check.venue .fallback .alt{border-color:rgba(255,255,255,.6);color:#fff}
.check.venue .fallback .alt.primary{background:#fff;color:var(--vcolor,#2A9D8F)}
.go{display:flex;align-items:center;justify-content:center;gap:12px}
.go:disabled{opacity:.55}
.go:active:not(:disabled){transform:translateY(1px)}
.spin{width:19px;height:19px;border-radius:50%;border:2.5px solid currentColor;
  border-top-color:transparent;animation:spin .8s linear infinite;display:none}
.go.busy .spin{display:block}
@keyframes spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spin{animation-duration:2.4s}}
.fallback{margin-top:18px;border:1.5px solid var(--ink);border-radius:3px;padding:18px}
.fallback[hidden]{display:none}
.fallback p{margin:0 0 14px;font-weight:600}
.fallback .why{font-weight:500;font-size:15px;opacity:.85}
.fallback .alt{display:block;width:100%;padding:16px;margin-top:10px;
  border:1.5px solid var(--ink);border-radius:3px;font-weight:700;text-align:center}
.fallback .alt.primary{background:var(--ink);color:var(--water)}
.v{width:100%;text-align:left;align-items:center}
.v .bar{align-self:stretch}
.sheet .lede{margin:0 0 14px;font-size:15px;color:var(--ink-soft);font-weight:500}
.sheet h3{margin-bottom:4px}

/* ---- mileage dial: no keyboard, ever ---- */
.dial{
  touch-action:none;user-select:none;-webkit-user-select:none;
  border:2px solid var(--ink);border-radius:3px;
  padding:22px 20px 18px;text-align:center;position:relative;overflow:hidden;
}
.dial.live{background:var(--shoal)}
.dial-num{
  font-size:76px;line-height:.9;font-weight:800;letter-spacing:-.045em;
  font-variation-settings:"wdth" 86,"wght" 800;
}
.dial-unit{font-size:15px;font-weight:600;color:var(--ink-soft);margin-top:2px}
.dial-delta{margin-top:10px;font-size:16px;font-weight:700}
.dial-hint{margin-top:4px;font-size:14px;font-weight:500;color:var(--ink-soft)}
.dial-rate{
  position:absolute;top:10px;right:12px;font-size:12px;font-weight:700;
  color:var(--ink-soft);opacity:0;transition:opacity 160ms
}
.dial.live .dial-rate{opacity:1}
.check.venue .dial{border-color:rgba(255,255,255,.5)}
.check.venue .dial.live{background:rgba(255,255,255,.14)}
.check.venue .dial-unit,.check.venue .dial-hint,.check.venue .dial-rate{color:rgba(255,255,255,.82)}

.steppers{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:12px}
.steppers button{
  padding:16px 0;border:1.5px solid var(--ink);border-radius:3px;
  font-weight:700;font-size:18px;font-variation-settings:"wdth" 92,"wght" 700;
}
.steppers button:active{background:var(--ink);color:var(--water)}
.check.venue .steppers button{border-color:rgba(255,255,255,.55);color:#fff}
.check.venue .steppers button:active{background:#fff;color:var(--vcolor,#2A9D8F)}

.below{margin-top:14px;font-size:15px;font-weight:600;color:var(--now)}
.below[hidden]{display:none}
.check.venue .below{color:#fff}

/* keypad alternative, for side-by-side comparison on the phone */
.pad{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:12px}
.pad[hidden]{display:none}
.pad button{padding:18px 0;border:1.5px solid var(--ink);border-radius:3px;
  font-size:24px;font-weight:700;font-variation-settings:"wdth" 92,"wght" 700}
.pad button:active{background:var(--ink);color:var(--water)}
.check.venue .pad button{border-color:rgba(255,255,255,.55);color:#fff}
.permbar{margin:0;padding:14px var(--pad);background:var(--sand);
  display:flex;gap:12px;align-items:center;justify-content:space-between}
.permbar[hidden]{display:none}
.permbar p{margin:0;font-size:15px;font-weight:500;line-height:1.3}
.permbar button{flex:0 0 auto;padding:11px 15px;background:var(--ink);color:var(--water);
  border-radius:3px;font-weight:700;font-size:15px}
.permbar.denied{background:var(--shoal)}
.permbar.denied button{background:var(--now)}
.toast{
  position:fixed;left:50%;bottom:calc(76px + var(--safe-bot));transform:translate(-50%,14px);
  background:var(--ink);color:var(--water);padding:14px 18px;border-radius:4px;
  font-weight:600;font-size:15px;max-width:82%;text-align:center;
  opacity:0;pointer-events:none;transition:all 240ms ease;z-index:70;
}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ---------- states the mock did not need ---------- */
.boot{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;
  background:var(--water);z-index:90;font-weight:600;color:var(--ink-soft)}
.boot[hidden]{display:none}

/* A failed poll must never look like a zero score. */
.stale{position:fixed;left:50%;transform:translateX(-50%);
  top:calc(var(--safe-top) + 8px);z-index:65;
  background:var(--ink);color:var(--water);padding:8px 14px;border-radius:999px;
  font-size:13px;font-weight:700}
.stale[hidden]{display:none}
