/* The abacus stepper: how many guests at a table. On the left the number on its reels and the word under it; on
   the right a black lacquer frame 64 pixels tall with minus and plus at the ends and, between them, a carved groove
   with a brass rod and the lacquered beads, made by the script. The light comes from the top left. */
:root {
  --page: #ffffff;          /* the page */
  --ink: #1d1613;           /* the number */
  --muted: #8a7f78;         /* the word under the number */
  --limit: #c2341c;         /* the word when a limit is reached */
  --frame: #171312;         /* the lacquered frame */
  --frame-edge: #3a3330;    /* the frame's top edge, catching the light */
  --groove: #0c0a09;        /* the groove the rod runs in */
  --groove-floor: #241d1a;  /* the bottom of the groove, where the beads' shadows fall */
  --disc: #2b2522;          /* the buttons' discs */
  --icon: #f1e8d9;          /* minus and plus */
  --brass: #c99a4b;         /* the rod */
  --brass-light: #fff0c4;   /* the rod's highlight */
  --brass-dark: #5e3d14;    /* the rod's underside */
  --rubber: #2e201b;        /* the washers at the ends of the rod */
  --red: #cf3a1f;           /* the first five beads, vermilion lacquer */
  --red-light: #ff9572;     /* their lit side */
  --red-dark: #4f0c04;      /* their shaded side */
  --ivory: #e5d8c0;         /* the next five, ivory lacquer */
  --ivory-light: #fffdf6;   /* their lit side */
  --ivory-dark: #6c5838;    /* their shaded side */
}

* {
  box-sizing: border-box;
}

/* quick taps on the buttons never become a double tap that zooms the page */
html {
  touch-action: manipulation;
}

html,
body {
  margin: 0;
}

body {
  min-height: 100svh;
  background: var(--page);
  color: var(--ink);
  font-family: 'Newsreader Variable', Georgia, serif;
  -webkit-font-smoothing: antialiased;
}

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

.stage {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: 32px 16px;
}

/* ---------------------------------------------------------------- the row */
.guests {
  display: flex;
  align-items: center;
  gap: 22px;
}

.guests__head {
  display: grid;
  justify-items: start;
  width: 68px;
  -webkit-user-select: none;
  user-select: none;
}

/* the number: one reel for the tens and one for the units, each a strip of digits that rolls */
.guests__count {
  display: flex;
  font-size: 40px;
  font-weight: 460;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.02em;
  line-height: 1;
}

.guests__reel {
  display: block;
  height: 1.3em;
  margin: -0.12em 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(transparent 0, #000 0.2em, #000 1.1em, transparent 1.3em);
  mask-image: linear-gradient(transparent 0, #000 0.2em, #000 1.1em, transparent 1.3em);
}

.guests__strip {
  display: block;
  padding-top: 0.15em;
  will-change: transform;
}

.guests__strip > span {
  display: block;
  height: 1.1em;
  line-height: 1.1em;
  text-align: center;
}

/* the word under the number: the script stacks its variants in one cell, so the head never changes width */
.guests__note {
  display: grid;
  height: 19px;
  margin-top: 1px;
  clip-path: inset(0 -24px);
}

.guests__note > span {
  grid-area: 1 / 1;
  color: var(--muted);
  font-size: 15px;
  font-weight: 420;
  font-style: normal;
  line-height: 19px;
  white-space: nowrap;
}

.guests__note > .is-limit {
  color: var(--limit);
  font-weight: 520;
}

/* ---------------------------------------------------------------- the frame */
.abacus {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  gap: 4px;
  width: 440px;
  height: 64px;
  padding: 6px;
  border-radius: 999px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--frame-edge) 70%, var(--frame)) 0%, var(--frame) 42%, color-mix(in srgb, var(--frame), #000 35%) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--frame-edge), #ffffff 22%),
    inset 0 -1.5px 1px rgba(0, 0, 0, 0.55),
    0 16px 30px -16px rgba(40, 18, 8, 0.6),
    0 5px 10px -5px rgba(40, 18, 8, 0.4);
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* the lacquer's long reflection along the top */
.abacus::before {
  content: '';
  position: absolute;
  left: 30px;
  right: 30px;
  top: 2px;
  height: 13px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0));
  pointer-events: none;
}

.abacus__btn {
  position: relative;
  z-index: 1;
  flex: none;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--icon);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.abacus__disc {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--disc), #ffffff 9%), var(--disc) 62%, color-mix(in srgb, var(--disc), #000 25%));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.13),
    inset 0 -1px 1px rgba(0, 0, 0, 0.4),
    0 1px 2px rgba(0, 0, 0, 0.5);
  transition: background-color 0.2s ease, box-shadow 0.2s ease, scale 0.45s cubic-bezier(0.34, 1.7, 0.5, 1);
}

.abacus__disc svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.1;
  stroke-linecap: round;
  transition: opacity 0.3s ease;
}

@media (hover: hover) and (pointer: fine) {
  .abacus__btn:hover .abacus__disc {
    background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--disc), #ffffff 16%), color-mix(in srgb, var(--disc), #ffffff 5%) 62%, color-mix(in srgb, var(--disc), #000 18%));
  }
}

/* pressed, the disc sinks into the frame */
.abacus__btn:active .abacus__disc {
  scale: 0.9;
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.55),
    inset 0 -1px 0 rgba(255, 255, 255, 0.05);
  transition: background-color 0.2s ease, box-shadow 0.1s ease, scale 0.1s ease-out;
}

/* at a limit the button stays pressable (the hammer knocks dully) but looks spent */
.abacus__btn[aria-disabled='true'] svg {
  opacity: 0.3;
}

.abacus__btn[aria-disabled='true']:active .abacus__disc {
  scale: 0.96;
}

.abacus__btn:focus-visible {
  outline: none;
}

.abacus__btn:focus-visible .abacus__disc {
  box-shadow: 0 0 0 2px var(--frame), 0 0 0 4px var(--icon);
}

/* ---------------------------------------------------------------- the groove, the rod and the beads */
.abacus__track {
  position: relative;
  flex: 1;
  align-self: stretch;
  min-width: 0;
  border-radius: 999px;
  outline: none;
  cursor: grab;
  touch-action: pan-y;
  -webkit-tap-highlight-color: transparent;
}

.abacus__track.is-grabbing {
  cursor: grabbing;
}

.abacus__track:focus-visible::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--icon) 85%, transparent);
  pointer-events: none;
}

.abacus__groove {
  --bh: 38px;
  --bw: 20px;
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background:
    linear-gradient(180deg, var(--groove) 0%, var(--groove) 30%, var(--groove-floor) 100%);
  box-shadow:
    inset 0 4px 7px rgba(0, 0, 0, 0.85),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -6px 10px -6px rgba(255, 236, 214, 0.06);
}

.abacus__layer,
.abacus__rod {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* the beads: lacquered lentils, lit from the top left. Under the colour, a glint, a warm light bounced back from
   the groove below and a shadow on the far side */
.abacus__bead {
  --light: var(--red-light);
  --tone: var(--red);
  --dark: var(--red-dark);
  position: absolute;
  left: 0;
  top: 50%;
  width: var(--bw);
  height: var(--bh);
  margin: calc(var(--bh) / -2) 0 0 calc(var(--bw) / -2);
  border-radius: 50%;
  background:
    radial-gradient(2.5px 3.2px at 0 50%, rgba(18, 6, 2, 0.7), transparent),
    radial-gradient(2.5px 3.2px at 100% 50%, rgba(18, 6, 2, 0.7), transparent),
    radial-gradient(60% 9% at 50% 94%, color-mix(in srgb, var(--light) 45%, transparent), transparent),
    linear-gradient(90deg, transparent 38%, rgba(255, 255, 255, 0.1) 50%, transparent 62%),
    radial-gradient(150% 100% at 28% 22%, var(--light) 0%, var(--tone) 38%, color-mix(in srgb, var(--tone), var(--dark) 55%) 70%, var(--dark) 100%);
  box-shadow:
    inset -1.5px -2px 2px rgba(0, 0, 0, 0.3),
    inset 1px 1px 0.5px rgba(255, 255, 255, 0.22);
  will-change: transform;
}

.abacus__bead.is-ivory {
  --light: var(--ivory-light);
  --tone: var(--ivory);
  --dark: var(--ivory-dark);
}

/* the lacquer's glint: a sharp one and a soft one around it */
.abacus__bead::before {
  content: '';
  position: absolute;
  left: 17%;
  top: 9%;
  width: 40%;
  height: 22%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0.35) 55%, transparent);
  rotate: -14deg;
}

.abacus__bead::after {
  content: '';
  position: absolute;
  left: 30%;
  top: 14%;
  width: 16%;
  height: 7%;
  border-radius: 50%;
  background: #ffffff;
}

@media (hover: hover) and (pointer: fine) {
  .abacus__bead.is-hover {
    filter: brightness(1.08) saturate(1.05);
  }
}

/* the shadow a bead casts on the bottom of the groove */
.abacus__shade {
  position: absolute;
  left: 0;
  top: calc(50% + var(--bh) / 2 - 7px);
  width: calc(var(--bw) * 1.3);
  height: 10px;
  margin-left: calc(var(--bw) * -0.65);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0));
  will-change: transform;
}

/* the rubber washers at the ends of the rod: the beads stop against them */
.abacus__washer {
  position: absolute;
  left: 0;
  top: 50%;
  width: 6px;
  height: 15px;
  margin-top: -7.5px;
  border-radius: 2.5px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--rubber), #ffffff 18%) 0%, var(--rubber) 40%, color-mix(in srgb, var(--rubber), #000 55%) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 2px 3px rgba(0, 0, 0, 0.5);
  transform-origin: 0 50%;
  will-change: transform;
}

@media (max-width: 520px) {
  .guests {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    width: min(440px, 100%);
  }

  /* the reels have no baseline of their own (they clip): the word is lined up with the figures by hand */
  .guests__head {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    width: auto;
    padding-left: 10px;
  }

  .guests__count {
    font-size: 34px;
  }

  .guests__note {
    margin: 0 0 5px;
  }

  .abacus {
    width: 100%;
    height: 62px;
  }

  .abacus__btn {
    width: 50px;
    height: 50px;
  }

  .abacus__groove {
    --bh: 33px;
  }
}
