/* Funny layer: letterpress impact in the study's Editorial look. Ink plus the
   level's accent (--fx-accent) and light colour (--fx-light, an r,g,b
   triplet), serif numerals, motion on the keyboard and the stamps only. */

.funny-body {
  --fx-accent: #d6452b;
  --fx-light: 214, 69, 43;
}

.funny-mark {
  font-style: italic;
  color: var(--fx-accent);
}

/* ink particles above the keyboard, below the prompt text */
.funny-ink {
  position: absolute;
  inset: 0;
  z-index: 6;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ---------------------------------------------------------------- stamp */

.funny-stamp {
  position: absolute;
  z-index: 7;
  display: block;
  white-space: nowrap;
  color: var(--fx-accent);
  pointer-events: none;
  transform-origin: 50% 60%;
  animation: funny-stamp 360ms cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
}

.funny-stamp[data-tier="0"] {
  color: var(--ink);
}

@keyframes funny-stamp {
  0% { opacity: 0; transform: scale(1.9) rotate(-4deg); }
  30% { opacity: 1; transform: scale(0.92) rotate(0deg); }
  48% { transform: scale(1.04); }
  70% { opacity: 0.9; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* the typed line takes the blow: a short press */
.funny-body .decoded-text {
  transition: transform 90ms ease;
}

/* ---------------------------------------------------------------- target words */

.funny-w {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 92%;
  background-size: 0% 2px;
  transition: background-size 220ms cubic-bezier(0.3, 0.8, 0.3, 1), color 160ms ease;
}

.funny-w.is-hit {
  color: var(--ink);
  background-size: 100% 2px;
}

/* the finisher: the phrase ripples word by word, a red rule sweeps under it */
.funny-w.is-wave {
  display: inline-block;
  animation: funny-wave 420ms cubic-bezier(0.3, 1.6, 0.4, 1) calc(var(--i) * 45ms) both;
}

@keyframes funny-wave {
  40% { transform: translateY(-0.22em); }
}

.study-title.funny-sweep {
  background-image: linear-gradient(var(--fx-accent), var(--fx-accent));
  background-repeat: no-repeat;
  background-position: 0 100%;
  animation: funny-sweep 520ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes funny-sweep {
  from { background-size: 0% 3px; }
  to { background-size: 100% 3px; }
}

/* ---------------------------------------------------------------- keys and shake */

.funny-body .key.funny-key-hit {
  animation: funny-key 300ms ease-out;
}

@keyframes funny-key {
  0% { background: var(--ink); color: #ffffff; }
  100% { background: transparent; }
}

.keyboard-shell.funny-shake {
  animation: funny-shake 170ms ease-out;
}

@keyframes funny-shake {
  15% { transform: translate(calc(var(--funny-amp) * -1), calc(var(--funny-amp) * 0.4)); }
  35% { transform: translate(var(--funny-amp), calc(var(--funny-amp) * -0.5)); }
  55% { transform: translate(calc(var(--funny-amp) * -0.5), calc(var(--funny-amp) * 0.3)); }
  75% { transform: translate(calc(var(--funny-amp) * 0.3), 0); }
  100% { transform: none; }
}

/* ---------------------------------------------------------------- combo counter */

.funny-combo[hidden] {
  display: none;
}

.funny-combo {
  position: absolute;
  right: 5vw;
  z-index: 8;
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: translateY(-50%);
  pointer-events: none;
}

.funny-combo b {
  font-family: var(--font-serif);
  font-size: clamp(2.2rem, 6.5vmin, 4.2rem);
  font-style: italic;
  font-weight: 400;
  line-height: 1;
  color: var(--ink);
  transition: color 160ms ease, font-size 160ms ease;
}

.funny-combo span {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.funny-combo[data-tier="2"] b {
  font-size: clamp(2.6rem, 7.5vmin, 4.8rem);
}

.funny-combo[data-tier="3"] b,
.funny-combo[data-tier="4"] b {
  color: var(--fx-accent);
  font-size: clamp(3rem, 8.5vmin, 5.6rem);
}

.funny-combo[data-tier="4"] span {
  color: var(--fx-accent);
}

.funny-combo.is-frozen b {
  color: var(--ink-ghost, rgba(17, 17, 17, 0.3));
}

.funny-combo.is-pop b {
  animation: funny-pop 200ms cubic-bezier(0.2, 1.8, 0.4, 1);
}

@keyframes funny-pop {
  0% { transform: scale(1.45); }
  100% { transform: scale(1); }
}

/* a broken combo drops away */
.funny-combo.is-break b {
  color: var(--ink-faint);
  animation: funny-break 480ms cubic-bezier(0.5, 0, 0.9, 0.5) forwards;
}

@keyframes funny-break {
  0% { transform: rotate(0deg); }
  25% { transform: translateX(-4px) rotate(-6deg); }
  100% { transform: translateY(40px) rotate(14deg); opacity: 0; }
}

/* ---------------------------------------------------------------- milestone shout */

.funny-shout {
  position: absolute;
  right: 4vw;
  z-index: 9;
  font-family: var(--font-serif);
  font-size: clamp(2rem, 6.5vmin, 4.4rem);
  font-style: italic;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink);
  opacity: 0;
  pointer-events: none;
  /* top is the combo's centre (set by funny.js); the word sits just above it */
  transform-origin: 100% 100%;
  transform: translateY(-175%) rotate(-7deg);
}

.funny-shout[data-tier="3"],
.funny-shout[data-tier="4"] {
  color: var(--fx-accent);
}

.funny-shout.is-on {
  animation: funny-shout 1000ms cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
}

@keyframes funny-shout {
  0% { opacity: 0; transform: translateY(-175%) rotate(-7deg) scale(2.2); }
  18% { opacity: 1; transform: translateY(-175%) rotate(-7deg) scale(0.94); }
  28% { transform: translateY(-175%) rotate(-7deg) scale(1.03); }
  75% { opacity: 1; transform: translateY(-175%) rotate(-7deg) scale(1); }
  100% { opacity: 0; transform: translateY(-190%) rotate(-7deg) scale(1); }
}

/* ---------------------------------------------------------------- score */

.funny-score[hidden],
.funny-grade[hidden] {
  display: none;
}

/* top centre, between the study label and the session box */
.funny-score {
  position: absolute;
  top: 26px;
  left: 50%;
  z-index: 8;
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: translateX(-50%);
  pointer-events: none;
}

.funny-score b {
  font-family: var(--font-serif);
  font-size: clamp(1.8rem, 5vmin, 3rem);
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.funny-score span {
  margin-top: 3px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.funny-score.is-bump b {
  animation: funny-bump 240ms cubic-bezier(0.2, 1.6, 0.4, 1);
}

@keyframes funny-bump {
  0% { transform: scale(1.18); color: var(--fx-accent); }
  100% { transform: scale(1); }
}

/* "+240" rising from the end of the stroke */
.funny-points {
  position: absolute;
  z-index: 9;
  font-family: var(--font-serif);
  font-size: clamp(1.1rem, 3vmin, 1.8rem);
  font-style: italic;
  white-space: nowrap;
  color: var(--ink);
  pointer-events: none;
  animation: funny-rise 800ms cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}

.funny-points[data-tier="2"],
.funny-points[data-tier="3"],
.funny-points[data-tier="4"] {
  color: var(--fx-accent);
}

.funny-points.is-big {
  font-size: clamp(1.6rem, 4.6vmin, 2.8rem);
}

@keyframes funny-rise {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.6); }
  20% { opacity: 1; transform: translate(-50%, -28px) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%, -80px) scale(1); }
}

/* ---------------------------------------------------------------- grade stamp */

.funny-grade {
  position: absolute;
  right: 4.5vw;
  top: 36%;
  z-index: 9;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.1em 0.35em 0.2em;
  border: 3px solid currentColor;
  color: var(--ink);
  pointer-events: none;
  transform: translateY(-50%) rotate(-9deg);
}

.funny-grade b {
  font-family: var(--font-serif);
  font-size: clamp(4rem, 15vmin, 9rem);
  font-weight: 400;
  line-height: 1;
}

.funny-grade span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.funny-grade[data-grade="S"],
.funny-grade[data-grade="A"] {
  color: var(--fx-accent);
}

.funny-grade.is-on {
  animation: funny-grade 420ms cubic-bezier(0.2, 0.9, 0.3, 1) both;
}

@keyframes funny-grade {
  0% { opacity: 0; transform: translateY(-50%) rotate(-9deg) scale(3); }
  45% { opacity: 1; transform: translateY(-50%) rotate(-9deg) scale(0.9); }
  70% { transform: translateY(-50%) rotate(-9deg) scale(1.04); }
  100% { opacity: 1; transform: translateY(-50%) rotate(-9deg) scale(1); }
}

/* ---------------------------------------------------------------- leaderboard */

.funny-board {
  width: min(520px, 90%);
}

.funny-board h3 {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.funny-board h3 em {
  font-family: var(--font-serif);
  font-size: 1rem;
  font-style: italic;
  letter-spacing: 0;
  text-transform: none;
  color: var(--fx-accent);
}

.funny-board ol {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
}

.funny-board li {
  display: grid;
  grid-template-columns: 2.4em 1fr 6em;
  align-items: baseline;
  gap: 12px;
  padding: 5px 4px;
  border-bottom: 1px solid rgba(17, 17, 17, 0.15);
  font-family: var(--font-serif);
  font-size: 1.1rem;
}

.funny-board li .rank,
.funny-board li .combo {
  color: var(--ink-faint);
}

.funny-board li b {
  font-weight: 400;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.funny-board li.is-me {
  color: var(--fx-accent);
}

/* ---------------------------------------------------------------- frame effects */

/* a hit leans the page in, a hair (--funny-punch is set per hit) */
.display-frame.funny-punch {
  animation: funny-punch 150ms cubic-bezier(0.2, 0.9, 0.3, 1);
}

@keyframes funny-punch {
  0% { transform: scale(var(--funny-punch, 1.01)); }
  100% { transform: none; }
}

/* a broken combo drains the colour for a moment */
.display-frame.funny-drain {
  animation: funny-drain 420ms ease-out;
}

@keyframes funny-drain {
  0% { filter: grayscale(1) contrast(0.8); }
  100% { filter: none; }
}

/* heat: a red glow at the edges, stronger per combo tier, on the beat (124 BPM) */
.funny-body .display-stage {
  transition: box-shadow 400ms ease;
}

.funny-body .display-stage[data-heat="1"] { box-shadow: inset 0 0 9vmin rgba(var(--fx-light), 0.06); }
.funny-body .display-stage[data-heat="2"] { box-shadow: inset 0 0 12vmin rgba(var(--fx-light), 0.12); }
.funny-body .display-stage[data-heat="3"] { box-shadow: inset 0 0 15vmin rgba(var(--fx-light), 0.2); }
.funny-body .display-stage[data-heat="4"] { box-shadow: inset 0 0 18vmin rgba(var(--fx-light), 0.3); }

/* on every kick of the track (fever): the edges flare */
.funny-body .display-stage.on-beat {
  animation: funny-heat 300ms ease-out;
}

@keyframes funny-heat {
  0% { box-shadow: inset 0 0 26vmin rgba(var(--fx-light), 0.5); }
}

/* the milestone flash: the page inverts for an instant, or flares red */
.funny-flash {
  position: absolute;
  inset: 0;
  z-index: 20;
  opacity: 0;
  pointer-events: none;
  background: #ffffff;
  mix-blend-mode: difference;
}

.funny-flash[data-tone="red"] {
  background: #d6452b;
  mix-blend-mode: multiply;
}

.funny-flash.is-on {
  animation: funny-flash 170ms cubic-bezier(0.7, 0, 1, 1);
}

/* crisp: fully inverted for an instant, then gone */
@keyframes funny-flash {
  0%, 40% { opacity: 1; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .display-frame.funny-punch,
  .funny-body .display-stage.on-beat {
    animation: none;
  }
}

/* ---------------------------------------------------------------- decay clock */

.funny-timer {
  display: block;
  width: 100%;
  height: 2px;
  margin-top: 5px;
  background: rgba(17, 17, 17, 0.12);
}

.funny-timer i {
  display: block;
  height: 100%;
  background: var(--ink);
  transform-origin: left center;
}

.funny-combo.is-hurry .funny-timer i {
  background: var(--fx-accent);
}

/* the last second: the number trembles */
.funny-combo.is-last b {
  animation: funny-tremble 90ms linear infinite;
}

@keyframes funny-tremble {
  25% { transform: translate(-1px, 1px) rotate(-1deg); }
  75% { transform: translate(1px, -1px) rotate(1deg); }
}

/* the combo halved: it sinks a little */
.funny-combo.is-decay b {
  animation: funny-decay 380ms ease-out;
}

@keyframes funny-decay {
  0% { transform: translateY(8px) scale(0.85); color: var(--ink-faint); }
  100% { transform: none; }
}

/* ---------------------------------------------------------------- fever */

/* the page turns to ink: everything inverts, red stays red */
.funny-body .display-frame {
  transition: filter 260ms ease;
}

.funny-body.is-fever .display-frame {
  filter: invert(1) hue-rotate(180deg);
}

.funny-body.is-fever .funny-combo span::after {
  content: " · fever ×2";
}

/* ---------------------------------------------------------------- the beat */

/* the combo nods on every kick of the track */
.funny-combo.on-beat b {
  animation: funny-nod 200ms ease-out;
}

@keyframes funny-nod {
  0% { transform: scale(1.12); }
}

/* fever: the keys' lines flash red on the kick */
.funny-body .key {
  transition: border-color 180ms ease;
}

.funny-body .keyboard-shell.beat-flash .key {
  border-color: var(--fx-accent);
  transition: none;
}

/* ---------------------------------------------------------------- background (by level) */

.funny-bg,
.funny-lights {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.funny-bg {
  opacity: 0;
  transition: opacity 500ms ease;
}

.funny-bg[data-bg]:not([data-bg=""]) {
  opacity: 1;
}

.funny-bg[data-bg="dots"] {
  background-image: radial-gradient(rgba(17, 17, 17, 0.09) 1.2px, transparent 1.6px);
  background-size: 22px 22px;
}

.funny-bg[data-bg="stripes"] {
  background-image: repeating-linear-gradient(115deg, rgba(17, 17, 17, 0.06) 0 2px, transparent 2px 34px);
  background-size: 200% 200%;
  animation: funny-stripes 1.94s linear infinite;
}

.funny-bg[data-bg="grid"] {
  background-image: linear-gradient(rgba(17, 17, 17, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(17, 17, 17, 0.07) 1px, transparent 1px);
  background-size: 48px 48px;
  animation: funny-grid 0.968s linear infinite;
}

.funny-bg[data-bg="stars"] {
  background-image: radial-gradient(rgba(17, 17, 17, 0.25) 1px, transparent 1.5px),
    radial-gradient(rgba(17, 17, 17, 0.15) 1.5px, transparent 2px);
  background-size: 90px 70px, 140px 110px;
  background-position: 0 0, 40px 30px;
  animation: funny-stars 6s linear infinite;
}

@keyframes funny-stripes {
  from { background-position: 0 0; }
  to { background-position: -145px 0; }
}

@keyframes funny-grid {
  from { background-position: 0 0; }
  to { background-position: 0 48px; }
}

@keyframes funny-stars {
  from { background-position: 0 0, 40px 30px; }
  to { background-position: 0 70px, 40px 140px; }
}

/* ---------------------------------------------------------------- lights (by level) */

.funny-lights > i {
  position: absolute;
  display: block;
  opacity: 0;
  transition: opacity 500ms ease;
}

/* glow: the light colour rising from the bottom corners */
.funny-lights[data-lights~="glow"] {
  background: radial-gradient(ellipse 45% 55% at 0% 100%, rgba(var(--fx-light), 0.14), transparent 70%),
    radial-gradient(ellipse 45% 55% at 100% 100%, rgba(var(--fx-light), 0.14), transparent 70%);
}

/* pulse / strobe: the lights flare on the kick */
.funny-lights.on-beat {
  animation: funny-light-beat 300ms ease-out;
}

@keyframes funny-light-beat {
  0% { background-color: rgba(var(--fx-light), 0.08); filter: brightness(1.6); }
}

/* beams: two stage lights swinging from the bottom corners */
.funny-lights .beam {
  bottom: -10%;
  width: 70%;
  height: 130%;
  transform-origin: 50% 100%;
  background: conic-gradient(from 180deg at 50% 100%, transparent 0deg 168deg, rgba(var(--fx-light), 0.22) 176deg,
    rgba(var(--fx-light), 0.3) 180deg, rgba(var(--fx-light), 0.22) 184deg, transparent 192deg 360deg);
  mix-blend-mode: multiply;
}

.funny-lights .beam.is-left {
  left: -20%;
  animation: funny-swing 3.9s ease-in-out infinite alternate;
}

.funny-lights .beam.is-right {
  right: -20%;
  animation: funny-swing 3.9s ease-in-out -1.95s infinite alternate-reverse;
}

.funny-lights[data-lights~="fast"] .beam {
  animation-duration: 1.94s;
}

.funny-lights[data-lights~="beams"] .beam {
  opacity: 1;
}

@keyframes funny-swing {
  from { transform: rotate(-28deg); }
  to { transform: rotate(28deg); }
}

/* spot: a soft circle of light under the cursor */
.funny-lights .spot {
  inset: 0;
  background: radial-gradient(circle 16vmin at var(--spot-x, 50%) var(--spot-y, 70%), rgba(var(--fx-light), 0.2), transparent 70%);
}

.funny-lights[data-lights~="spot"] .spot {
  opacity: 1;
}

/* strobe: the page's edges flash on the kick (soft, once a beat) */
.funny-body .display-stage.on-beat {
  animation: funny-heat 300ms ease-out;
}

/* ---------------------------------------------------------------- the page, by level */

/* from 4: the letters lean */
.funny-body.lv-4 .key {
  font-style: italic;
}

/* from 8: the key lines take the accent */
.funny-body.lv-8 .key {
  border-color: rgba(var(--fx-light), 0.75);
}

/* from 12: the typed line glows in the accent */
.funny-body.lv-12 .decoded-text {
  text-shadow: 0 0 22px rgba(var(--fx-light), 0.6);
}

/* from 16 (never below 16 levels): kept for a longer table */
.funny-body.lv-16 .candidate-strip {
  border-color: var(--fx-accent);
}

.funny-body.is-fever .decoded-text,
.funny-body.is-fever .study-title,
.funny-body.is-fever .funny-score b,
.funny-body.is-fever .funny-combo b {
  text-shadow: 0 0 18px rgba(var(--fx-light), 0.55), 0 0 2px rgba(var(--fx-light), 0.4);
}


/* ---------------------------------------------------------------- login */

.funny-login[hidden] {
  display: none;
}

.funny-login {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.funny-login-fields {
  display: flex;
  border: 1px solid var(--ink);
}

.funny-login-fields button {
  border: none;
  border-left: 1px solid var(--ink);
}

.funny-login input {
  width: 11rem;
  height: 46px;
  padding: 0 14px;
  border: none;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 1.3rem;
  text-align: center;
  outline: none;
  -webkit-user-select: text;
  user-select: text;
}


.funny-login button {
  height: 44px;
  padding: 0 20px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 1.15rem;
  cursor: pointer;
}

.funny-login button[type="submit"],
.funny-login-again button {
  background: var(--ink);
  color: #ffffff;
}

.funny-login button:disabled,
.funny-login input:disabled {
  opacity: 0.4;
  cursor: default;
}

.funny-login-again[hidden] {
  display: none;
}

.funny-login-again {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 6px;
}

.funny-login-again a {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- the right candidate */

/* a wrong word: the right one glows in the candidate bar */
.funny-body .candidate-seg.funny-hint {
  color: var(--fx-accent);
  background: rgba(var(--fx-light), 0.12);
  box-shadow: inset 0 -3px 0 var(--fx-accent);
  animation: funny-hint 700ms ease-in-out infinite alternate;
}

@keyframes funny-hint {
  to { background: rgba(var(--fx-light), 0.26); }
}

/* ---------------------------------------------------------------- records and boards */

/* the record rides beside the headline number, a small red tag */
.funny-record {
  align-self: center;
  margin-left: 4px;
  padding: 3px 9px;
  border: 1px solid var(--fx-accent);
  font-family: var(--font-serif);
  font-size: 1rem;
  font-style: italic;
  color: var(--fx-accent);
  transform: rotate(-4deg);
}

/* one board (today's top five) and one line for all time */
.funny-boards {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: min(440px, 92%);
}

.funny-boards .funny-board {
  width: 100%;
}

.funny-alltime {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1rem;
  font-style: italic;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- fever breakdown */

/* the drums drop out: the lights slow down and dim, the motes drift */
.funny-body.is-breakdown .funny-lights .beam {
  animation-duration: 8s;
  opacity: 0.5;
}

.funny-body.is-breakdown .display-stage {
  box-shadow: none;
}

/* ---------------------------------------------------------------- sound toggle */

.funny-sound {
  position: absolute;
  left: 18px;
  bottom: 14px;
  z-index: 10;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}

.funny-sound:hover {
  color: var(--ink);
}

.funny-sound svg {
  width: 22px;
  height: 22px;
}

.funny-sound[aria-pressed="false"] {
  color: var(--ink-ghost, rgba(17, 17, 17, 0.3));
}

@media (prefers-reduced-motion: reduce) {
  .funny-w.is-wave,
  .keyboard-shell.funny-shake {
    animation: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .funny-bg,
  .funny-lights .beam,
  .funny-lights.on-beat {
    animation: none !important;
  }
}

/* the login screen: no keyboard behind the form */
.funny-body[data-screen="setup"] .keyboard-shell,
.funny-body[data-screen="setup"] .cursor-marker {
  visibility: hidden;
}
