/* Day 4/30 — Reaction
   Instrument-brutalist: no radii, no shadows, one variable family working its
   width axis for hierarchy. The surface colour is the whole interface. */

:root {
  color-scheme: dark;

  /* surfaces */
  --ink:    #0C0D0F;   /* idle + result */
  --red:    #C81E14;   /* armed */
  --green:  #00E05C;   /* go */
  --chalk:  #F4F4F1;   /* false start flood */

  /* type on those surfaces */
  --on-ink:   #F2F2EF;
  --on-ink-2: #A2A5A9;
  --on-red:   #FFFFFF;
  --on-red-2: #F6C9C6;
  --on-flood: #0C0D0F;

  /* live tokens, re-pointed per state */
  --surface: var(--ink);
  --fg:      var(--on-ink);
  --fg-2:    var(--on-ink-2);

  --pad: 1.25rem;
  --expo: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--ink);
}

body {
  font-family: "Archivo", system-ui, sans-serif;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

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

/* ---------- the surface, which is also the button ---------- */

.stage {
  position: fixed;
  inset: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
  padding:
    calc(var(--pad) + env(safe-area-inset-top))
    calc(var(--pad) + env(safe-area-inset-right))
    calc(var(--pad) + env(safe-area-inset-bottom))
    calc(var(--pad) + env(safe-area-inset-left));

  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  transition: background-color 120ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* The go flash must not animate. A fade would add perceived latency to the
   thing being measured, which would make the measurement a lie. Same for the
   false start: it should land like a slap, not a dissolve. */
.stage[data-state="go"],
.stage[data-state="foul"] { transition: none; }

.stage:focus-visible {
  outline: 3px solid var(--fg);
  outline-offset: -6px;
}

.stage[data-state="armed"] { --surface: var(--red);   --fg: var(--on-red);   --fg-2: var(--on-red-2); }
.stage[data-state="go"]    { --surface: var(--green); --fg: var(--on-flood); --fg-2: var(--on-flood); }
.stage[data-state="foul"]  { --surface: var(--chalk); --fg: var(--on-flood); --fg-2: #4A4D50; }

/* ---------- session best ---------- */

.hud { min-height: 1.5rem; }

.meter {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-stretch: 78%;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.meter__k { color: var(--fg-2); }

.meter__v {
  font-stretch: 100%;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg);
}

/* the readout is noise while a round is live */
.stage[data-state="armed"] .hud,
.stage[data-state="go"] .hud { opacity: 0; }

/* ---------- view switching ---------- */

.panel {
  display: grid;
  place-items: center;
  min-height: 0;
}

.view { display: none; width: 100%; text-align: center; }

.stage[data-state="idle"]   .view--idle,
.stage[data-state="armed"]  .view--armed,
.stage[data-state="go"]     .view--go,
.stage[data-state="result"] .view--result,
.stage[data-state="foul"]   .view--foul { display: block; }

/* ---------- idle ---------- */

.headline {
  font-stretch: 118%;
  font-weight: 800;
  font-size: clamp(2rem, min(10.5vw, 8.5vh), 4.5rem);
  line-height: 0.94;
  letter-spacing: -0.035em;
  word-spacing: 0.08em;   /* the negative tracking eats the word space */
  text-transform: uppercase;
  text-wrap: balance;
}

.lede {
  margin: 1.25rem auto 0;
  max-width: 34ch;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--fg-2);
  text-wrap: pretty;
}

/* ---------- armed / go ---------- */

.cue {
  font-stretch: 125%;
  font-weight: 900;
  font-size: clamp(3rem, min(19vw, 16vh), 9rem);
  line-height: 0.86;
  letter-spacing: -0.045em;
  text-transform: uppercase;
}

/* ---------- result ---------- */

.crown {
  visibility: hidden;
  margin-bottom: 0.75rem;
  font-stretch: 78%;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--green);
}
.view--result.is-best .crown { visibility: visible; }

.score {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.14em;
  font-variant-numeric: tabular-nums;
}

.score__n {
  font-stretch: 125%;
  font-weight: 800;
  font-size: clamp(4.5rem, min(26vw, 23vh), 12rem);
  line-height: 0.8;
  letter-spacing: -0.05em;
}
.score.is-wide .score__n { font-size: clamp(3.5rem, min(19vw, 18vh), 9rem); }

.score__u {
  font-stretch: 78%;
  font-weight: 700;
  font-size: clamp(1rem, 4vw, 1.5rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-2);
}

/* ---------- the scale: where that number actually sits ---------- */

.scale {
  margin: clamp(1.75rem, 6vh, 3rem) auto 0;
  max-width: 30rem;
}

.scale__track {
  position: relative;
  height: 1.5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--fg) 32%, transparent);
}

.tick {
  position: absolute;
  bottom: 0;
  left: var(--at);
  width: 1px;
  height: 0.4rem;
  background: color-mix(in srgb, var(--fg) 32%, transparent);
}
.tick--major { height: 0.85rem; background: color-mix(in srgb, var(--fg) 55%, transparent); }

.you {
  position: absolute;
  bottom: 0;
  left: clamp(0%, var(--at), 100%);
  width: 3px;
  height: 1.5rem;
  margin-left: -1.5px;
  background: var(--green);
  transform-origin: 50% 100%;
}

/* The two references sit close together on a 100-500 axis, so they are
   staggered in depth rather than crowded onto one line, and the lower one
   gets a leader back to its tick. */
.scale__keys {
  position: relative;
  height: 4.25rem;
  margin-top: 0.5rem;
}

.key {
  position: absolute;
  top: 0;
  left: var(--at);
  transform: translateX(-50%);
  display: block;
  width: max-content;
  max-width: 9rem;
  font-stretch: 72%;
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-2);
}
.key b {
  display: block;
  font-stretch: 100%;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

.key--drop { top: 2.15rem; }

.key--drop::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -2.15rem;
  width: 1px;
  height: 1.85rem;
  background: color-mix(in srgb, var(--fg) 22%, transparent);
}

/* ---------- hint ---------- */

.hint {
  min-height: 1.25rem;
  margin-bottom: 0.75rem;
  text-align: center;
  font-stretch: 78%;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-2);
}
.hint span { display: none; }
.stage[data-state="idle"]   .hint [data-for="idle"],
.stage[data-state="result"] .hint [data-for="result"],
.stage[data-state="foul"]   .hint [data-for="foul"] { display: inline; }

/* ---------- series label: same face, same corner, all 30 days ---------- */

.day {
  position: fixed;
  z-index: 5;
  right: max(1rem, env(safe-area-inset-right));
  bottom: max(0.9rem, env(safe-area-inset-bottom));
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  color: var(--fg-2);
  pointer-events: none;
  user-select: none;
  transition: color 120ms linear;
}

/* ---------- motion ----------
   One authored moment: the result landing. Everything else is a state flip.
   Timings are Emil-weighted (the loop is high-frequency) with a Jakub-length
   settle on the payoff, which happens once per round. */

.stage[data-state="result"] .score  { animation: land 300ms var(--expo) both; }
.stage[data-state="result"] .crown  { animation: rise 260ms var(--expo) 60ms both; }
.stage[data-state="result"] .scale  { animation: rise 340ms var(--expo) 140ms both; }
.stage[data-state="result"] .you    { animation: drop 400ms var(--expo) 300ms both; }
.stage[data-state="foul"]   .panel  { animation: recoil 260ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }
.stage[data-state="idle"]   .view--idle { animation: rise 320ms var(--expo) both; }

@keyframes land {
  from { opacity: 0; transform: scale(1.09); filter: blur(10px); }
  to   { opacity: 1; transform: none;        filter: blur(0); }
}
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes drop {
  from { opacity: 0; transform: scaleY(0.12); }
  to   { opacity: 1; transform: none; }
}
@keyframes recoil {
  0%, 100% { transform: none; }
  15%, 45%, 75% { transform: translateX(-7px); }
  30%, 60%      { transform: translateX(7px); }
}

/* The colour flip is the measurement, so it stays. The choreography around it
   is decoration and goes. */
@media (prefers-reduced-motion: reduce) {
  .stage,
  .stage[data-state] .score,
  .stage[data-state] .crown,
  .stage[data-state] .scale,
  .stage[data-state] .you,
  .stage[data-state] .panel,
  .stage[data-state] .view--idle {
    animation: none !important;
    transition: none !important;
  }
}

/* ---------- wider screens ---------- */

@media (min-width: 40rem) {
  :root { --pad: 2rem; }
  .lede { font-size: 1.0625rem; max-width: 42ch; }
  .day  { font-size: 0.6875rem; }
}

@media (hover: hover) {
  .stage[data-state="idle"]:hover   .hint,
  .stage[data-state="result"]:hover .hint,
  .stage[data-state="foul"]:hover   .hint { color: var(--fg); }
}
