/* The typewriter field: a black enamel carriage on a white page, with a strip of paper on its rubber platen, the
   knurled knob and the return lever at its left end, a chrome guide at the strike point and an ivory key. */
:root {
  --page: #ffffff;          /* the page */
  --body: #121214;          /* the enamel of the carriage */
  --platen: #19191b;        /* the rubber platen */
  --paper: #fbf8f1;         /* the paper */
  --ink: #1c1a17;           /* the black half of the ribbon */
  --red: #b3241d;           /* the red half of the ribbon */
  --pencil: #b4ada2;        /* the address pencilled on the paper while the field is empty */
  --muted: #77726a;         /* the line under the field */
  --key: #efe7d6;           /* the ivory of the key */
}

* {
  box-sizing: border-box;
}

html {
  touch-action: manipulation;
}

html,
body {
  margin: 0;
  overflow-x: clip;
}

body {
  min-height: 100svh;
  background: var(--page);
  color: var(--ink);
  font-family: 'Courier Prime', 'Courier New', monospace;
  -webkit-font-smoothing: antialiased;
}

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

.tw {
  --type: 19px;             /* the size of the letters on the paper */
  --key-w: 104px;
  --knob-w: 28px;
  position: relative;
  width: min(440px, 100%);
  margin: 0;
}

/* ---------------------------------------------------------------- the label, and the bell above the strike point */
.tw__top {
  display: flex;
  align-items: flex-end;
  height: 20px;
  margin: 0 0 10px;
  padding-left: 34px;
}

.tw__label {
  font-size: 14px;
  font-weight: 700;
  line-height: 20px;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.tw__bell {
  position: absolute;
  left: 0;
  top: -3px;
  width: 28px;
  height: 22px;
  margin-left: -14px;
  overflow: visible;
  opacity: 0;
  pointer-events: none;
}

.bell__dome {
  fill: #dfe1e4;
  stroke: var(--ink);
  stroke-width: 1.4;
  stroke-linejoin: round;
}

.bell__base,
.bell__stem,
.bell__ring {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.5;
  stroke-linecap: round;
}

.bell__knob {
  fill: var(--ink);
}

.bell__ring {
  stroke-width: 1.3;
  opacity: 0;
}

/* ---------------------------------------------------------------- the carriage */
.tw__field {
  position: relative;
  height: 60px;
  border-radius: 16px;
  background: linear-gradient(180deg, #2a2a2d 0%, var(--body) 22%, #0b0b0c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.7),
    0 1px 2px rgba(0, 0, 0, 0.22),
    0 14px 26px -16px rgba(0, 0, 0, 0.6),
    0 0 0 0 var(--page),
    0 0 0 0 transparent;
  transition: box-shadow 0.25s ease;
  cursor: text;
}

/* the focus: a ring of ink round the carriage, clear of it */
.tw__field.is-on {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.7),
    0 1px 2px rgba(0, 0, 0, 0.22),
    0 14px 26px -16px rgba(0, 0, 0, 0.6),
    0 0 0 3px var(--page),
    0 0 0 5px var(--ink);
}

.tw__field.is-on.is-wrong {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.7),
    0 1px 2px rgba(0, 0, 0, 0.22),
    0 14px 26px -16px rgba(0, 0, 0, 0.6),
    0 0 0 3px var(--page),
    0 0 0 5px var(--red);
}

/* the return lever, sticking out above the carriage's left end */
.tw__lever {
  position: absolute;
  left: 0;
  top: -30px;
  width: 34px;
  height: 40px;
  overflow: visible;
  pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
}

.lever__arm,
.lever__blade,
.lever__boss {
  fill: url(#tw-chrome);
  stroke: #4f535a;
  stroke-width: 0.7;
  stroke-linejoin: round;
}

.lever__shine {
  fill: none;
  stroke: rgba(255, 255, 255, 0.95);
  stroke-width: 0.9;
  stroke-linecap: round;
}

.lever__screw {
  fill: #3c3f45;
}

/* the knurled knob at the platen's end */
.tw__knob {
  position: absolute;
  left: 7px;
  top: 5px;
  width: 16px;
  height: 50px;
  pointer-events: none;
}

.knob__body {
  fill: #1d1d20;
}

.knob__grooves {
  fill: none;
  stroke: #000000;
  stroke-width: 1;
}

.knob__ridges {
  fill: none;
  stroke: rgba(255, 255, 255, 0.2);
  stroke-width: 0.7;
}

/* ---------------------------------------------------------------- the platen and the paper */
.tw__window {
  position: absolute;
  left: var(--knob-w);
  right: calc(var(--key-w) + 16px);
  top: 0;
  bottom: 0;
  overflow: hidden;
  overflow: clip;
  /* the rubber: a cylinder, with a soft light along its top */
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0) 10px, rgba(0, 0, 0, 0) calc(100% - 8px), rgba(0, 0, 0, 0.55)),
    linear-gradient(180deg, #030304 0%, #141416 4%, #2b2b2f 9%, #48484d 13.5%, #333337 16.7%, var(--platen) 50%, #202023 83.3%, #19191c 88%, #0c0c0d 95%, #030304 100%);
}

/* the paper moves with the carriage; everything on it is in the paper's own pixels */
.tw__sheet {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
}

.tw__paper {
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: -260px;
  width: 6400px;
  background-color: var(--paper);
  background-image: var(--fibre, none);
  background-size: 96px 96px;
  /* its edges: the top catches the light, the bottom turns away, the left casts a shadow on the rubber */
  box-shadow: -2px 0 3px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(60, 46, 30, 0.22);
}

/* the lines of type: cut to the paper above and below, never at the sides */
.tw__lines {
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: 0;
  width: 0;
  clip-path: inset(0 -7000px);
}

.tw__line {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 100%;
}

/* a letter, struck */
.g {
  position: absolute;
  left: 0;
  top: 50%;
  font: 400 var(--type) / normal 'Courier Prime', 'Courier New', monospace;
  color: var(--ink);
  white-space: pre;
  opacity: 0;
  text-shadow: 0 0 0.8px rgba(28, 26, 23, 0.6);
  -webkit-mask-image: linear-gradient(#000, #000), var(--grain, linear-gradient(#000, #000));
  mask-image: linear-gradient(#000, #000), var(--grain, linear-gradient(#000, #000));
  -webkit-mask-size: 100% 100%, 64px 64px;
  mask-size: 100% 100%, 64px 64px;
  -webkit-mask-repeat: no-repeat, repeat;
  mask-repeat: no-repeat, repeat;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* now and then the typebar hits twice */
.g.is-twice {
  text-shadow: 0 0 0.8px rgba(28, 26, 23, 0.6), 0.6px -0.35px 0 rgba(28, 26, 23, 0.32);
}

/* the address pencilled on the paper while the field is empty, ending at the strike point */
.tw__ph {
  position: absolute;
  right: 0;
  top: 50%;
  padding-right: 4px;
  font: italic 400 var(--type) / normal 'Courier Prime', 'Courier New', monospace;
  color: var(--pencil);
  white-space: pre;
  transform: translateY(-50%);
  transition: color 0.3s ease;
}

.tw__field.is-on .tw__ph {
  color: #cdc7bc;
  color: color-mix(in srgb, var(--pencil) 62%, var(--paper));
}

/* the real input, riding in the sheet: its letters lie exactly under the drawn ones and stay transparent, so its
   caret and its selection show where they belong */
.tw__input {
  position: absolute;
  left: -900px;
  top: 0;
  width: 7200px;
  height: 100%;
  margin: 0;
  padding: 0 0 0 900px;
  border: 0;
  border-radius: 0;
  outline: none;
  background: transparent;
  color: transparent;
  -webkit-text-fill-color: transparent;
  caret-color: var(--ink);
  font: 400 var(--type) / normal 'Courier Prime', 'Courier New', monospace;
  font-kerning: none;
  font-variant-ligatures: none;
  letter-spacing: 0;
  -webkit-tap-highlight-color: transparent;
  -webkit-appearance: none;
  appearance: none;
}

.tw__input::placeholder {
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.tw__input::selection {
  background: rgba(28, 26, 23, 0.16);
  color: transparent;
}

/* the browser's autofill paints the field: it waits a very long time instead */
.tw__input:-webkit-autofill,
.tw__input:-webkit-autofill:focus {
  -webkit-text-fill-color: transparent;
  transition: background-color 600000s 0s, color 600000s 0s;
}

/* while the machine catches up, and once the address has gone, no caret */
.tw__field.is-busy .tw__input,
.tw__field.is-sent .tw__input {
  caret-color: transparent;
}

/* the curve of the platen over the paper: darker where it turns away, and darker where it goes under the carriage */
.tw__shade {
  position: absolute;
  left: 0;
  right: 0;
  top: 10px;
  bottom: 10px;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(60, 46, 30, 0.2) 0, rgba(60, 46, 30, 0.05) 16%, rgba(255, 255, 255, 0) 32%, rgba(255, 255, 255, 0) 64%, rgba(60, 46, 30, 0.06) 82%, rgba(60, 46, 30, 0.24) 100%),
    linear-gradient(90deg, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0) 12px, rgba(0, 0, 0, 0) calc(100% - 10px), rgba(0, 0, 0, 0.45) 100%);
}

/* ---------------------------------------------------------------- the guide, the typebar and the correction tape */
.tw__guide {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  pointer-events: none;
}

.guide__plate {
  position: absolute;
  left: -32px;
  top: 0;
  width: 64px;
  height: 60px;
  overflow: visible;
}

.guide__body {
  fill: url(#tw-plate);
  stroke: #50545b;
  stroke-width: 0.6;
  filter: drop-shadow(0 -0.5px 0.6px rgba(0, 0, 0, 0.25));
}

.guide__lip {
  fill: none;
  stroke: rgba(255, 255, 255, 0.9);
  stroke-width: 0.8;
}

.guide__slots {
  fill: none;
  stroke: #4a4e55;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.guide__index {
  fill: url(#tw-plate);
  stroke: #50545b;
  stroke-width: 0.5;
  transition: fill 0.3s ease;
}

/* the red half of the ribbon is in: the index turns red */
.tw__field.is-wrong .guide__index {
  fill: var(--red);
  stroke: var(--red);
}

/* the typebar: its slug flies up from below for an instant and hits the paper through the ribbon */
.tw__bar {
  position: absolute;
  left: calc(var(--cw, 11px) / -2);
  top: 18px;
  width: var(--cw, 11px);
  height: 25px;
  border-radius: 2px 2px 1px 1px;
  background: linear-gradient(90deg, #6b6f76, #2a2c31 30%, #17181b 70%, #3b3e44);
  box-shadow: 0 0 0 0.6px rgba(0, 0, 0, 0.6), 0 2px 3px rgba(0, 0, 0, 0.35);
  transform: translateY(48px);
  transform-origin: 50% 320%;
}

.tw__bar::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 4px;
  height: 13px;
  border-radius: 1px;
  background: #0d0d0e;
  background: repeating-linear-gradient(135deg, #0b0b0c 0 1.2px, #1f1f22 1.2px 2.2px);
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.7);
}

.tw__bar::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 4px;
  height: 40px;
  margin-left: -2px;
  background: linear-gradient(90deg, #6b6f76, #22242a 60%, #44474d);
}

/* the lift-off tape: a white strip that comes up and takes the letter away */
.tw__tape {
  position: absolute;
  left: calc(var(--cw, 11px) * -0.85);
  top: 20px;
  width: calc(var(--cw, 11px) * 1.7);
  height: 19px;
  border-radius: 1.5px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(240, 238, 232, 0.92));
  box-shadow: 0 0 0 0.6px rgba(0, 0, 0, 0.18), 0 2px 4px rgba(0, 0, 0, 0.18);
  transform: translateY(46px);
  opacity: 0;
}

/* ---------------------------------------------------------------- the key */
.tw__key {
  position: absolute;
  top: 7px;
  right: 8px;
  bottom: 7px;
  width: var(--key-w);
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 13px;
  background: transparent;
  color: var(--ink);
  font: 700 15px/1 'Courier Prime', 'Courier New', monospace;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* the chrome rim and the ivory top, on a dark skirt: the key travels down into it */
.key__top {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 3px;
  padding: 2px;
  border-radius: 13px;
  background: linear-gradient(180deg, #ffffff 0%, #b7bbc2 40%, #eef0f2 58%, #7e828a 100%);
  box-shadow: 0 3px 0 #000000, 0 4px 7px rgba(0, 0, 0, 0.55);
  transition: transform 0.14s cubic-bezier(0.3, 1.6, 0.5, 1), box-shadow 0.14s ease;
}

.key__cap {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  height: 100%;
  border-radius: 11px;
  background: radial-gradient(130% 100% at 50% 12%, #fffdf7 0%, var(--key) 55%, #d8cfba 100%);
  box-shadow: inset 0 -2px 3px rgba(80, 60, 30, 0.2), inset 0 1px 0 #ffffff;
  overflow: hidden;
}

.key__cap > * {
  grid-area: 1 / 1;
}

.key__word {
  display: block;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.key__tick {
  width: 24px;
  height: 24px;
  overflow: visible;
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}

@media (hover: hover) and (pointer: fine) {
  .tw__key:not([aria-disabled='true']):hover .key__top {
    transform: translateY(-1.5px);
    box-shadow: 0 4.5px 0 #000000, 0 7px 10px rgba(0, 0, 0, 0.5);
  }

  .tw__key:not([aria-disabled='true']):hover .key__cap {
    background: radial-gradient(130% 100% at 50% 12%, #ffffff 0%, #f6f0e2 55%, #ded6c2 100%);
  }
}

.tw__key:not([aria-disabled='true']):active .key__top,
.tw__key.is-down .key__top {
  transform: translateY(2.5px);
  box-shadow: 0 0.5px 0 #000000, 0 1px 2px rgba(0, 0, 0, 0.5);
  transition-duration: 0.06s;
}

.tw__key[aria-disabled='true'] {
  cursor: default;
}

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

.tw__key:focus-visible .key__top {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------- the line under the field */
.tw__help {
  position: relative;
  height: 20px;
  margin: 12px 0 0;
  padding-left: 34px;
  font-size: 13.5px;
  line-height: 20px;
  white-space: nowrap;
}

.help__line {
  display: block;
  color: var(--muted);
}

.help__line.is-going {
  position: absolute;
  left: 34px;
  top: 0;
}

/* small type: the red a touch deeper, to read well */
.help__line.is-wrong {
  color: #9c1f19;
  color: color-mix(in srgb, var(--red) 82%, #000000);
}

.help__line.is-done {
  color: var(--ink);
}

/* a letter typed under the field, in one half of the ribbon or the other */
.hg {
  display: inline-block;
  white-space: pre;
  text-shadow: 0 0 0.6px currentColor;
  -webkit-mask-image: linear-gradient(#000, #000), var(--grain, linear-gradient(#000, #000));
  mask-image: linear-gradient(#000, #000), var(--grain, linear-gradient(#000, #000));
  -webkit-mask-size: 100% 100%, 56px 56px;
  mask-size: 100% 100%, 56px 56px;
  -webkit-mask-repeat: no-repeat, repeat;
  mask-repeat: no-repeat, repeat;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* for screen readers only */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (max-width: 440px) {
  .tw {
    --type: 16px;
    --key-w: 86px;
    --knob-w: 26px;
  }

  .tw__key {
    font-size: 14px;
  }

  .tw__help {
    font-size: 12.5px;
  }
}
