/* ==========================================================================
   The desk keyboard (`keyboard` in crt-config.js; keyboard.js builds it) — an
   IBM Model M in CSS 3D, lying on the photo's desk in front of the CRT.

   The scene has the photo's box and the photo's camera: its eye level (the
   horizon, where the desk's depth lines meet) and lens (the perspective, as
   a fraction of the photo's width), read off the desk and what lies on it.
   The keyboard's centre sits on the desk at (--kb-x, --kb-y) — fractions of
   the photo — where a key's pitch is --kb-unit of the photo's width, as big
   as the monitor makes it at that depth. Its look matches the light there:
   in the monitor's shadow, lit from the window behind.
   ========================================================================== */

body.crt--keyboard {
  --kb-horizon: 0.3997;
  --kb-focal: 0.953;
  --kb-x: 0.5006;
  --kb-y: 0.7902;
  --kb-unit: 0.01726;
  --kb-yaw: -1.2deg;
  --kb-u: calc(var(--desk-w) * var(--kb-unit));
  /* How far down the photo the view must reach to show all of it: desk.css
     shrinks the glass until it fits. */
  --desk-view-bottom: 0.8603;
}

.desk__scene {
  display: none;
  position: absolute;
  top: var(--desk-y);
  left: var(--desk-x);
  width: var(--desk-w);
  height: var(--desk-h);
  perspective: calc(var(--desk-w) * var(--kb-focal));
  perspective-origin: 50% calc(var(--kb-horizon) * 100%);
}

body.crt--keyboard .desk__scene {
  display: block;
}

/* Laid flat: the layout's top goes to the back, and z points up. */
.kb {
  /* Plastic in the monitor's shadow: the keycaps' tops catch the window's
     light, their fronts face away from it. The grey keys are darker. */
  --kb-cap-top: #774b33;
  --kb-cap-front: #553423;
  --kb-cap-side: #64402b;
  --kb-grey-top: #674330;
  --kb-grey-front: #472d1e;
  --kb-grey-side: #553726;
  --kb-case-top: #724832;
  --kb-case-front: #4f301f;
  --kb-floor: #251208;
  --kb-legend: rgba(35, 17, 9, 0.85);

  position: absolute;
  left: calc(var(--kb-x) * 100%);
  top: calc(var(--kb-y) * 100%);
  width: 0;
  height: 0;
  transform-style: preserve-3d;
  transform: rotateX(90deg) rotateZ(var(--kb-yaw));
}

.kb div,
.kb svg {
  position: absolute;
  box-sizing: border-box;
}

/* Where it touches the desk, and the shadow its sunlit ends cast forward
   over the desk (keyboard.js maps where the sun is: --sun-map). */
.kb__shadow {
  background: rgba(12, 6, 2, 0.55);
  border-radius: calc(var(--kb-u) * 0.4);
  box-shadow: 0 0 calc(var(--kb-u) * 0.6) calc(var(--kb-u) * 0.3) rgba(12, 6, 2, 0.55);
}

.kb__cast {
  --sun-color: rgba(20, 9, 2, 0.63);
  background: var(--sun-map, none);
  -webkit-mask-image: linear-gradient(to bottom, #000 10%, transparent);
  mask-image: linear-gradient(to bottom, #000 10%, transparent);
}

/* The case's front, stood up from the desk. Its top edge rounds over into
   the rim and catches the light; lower down, the seam between the case's two
   halves. */
.kb__front {
  --sun-color: rgba(255, 188, 143, 0.26);
  transform-origin: 50% 100%;
  transform: rotateX(-90deg);
  background:
    linear-gradient(to bottom, rgba(255, 201, 167, 0.2), rgba(255, 201, 167, 0) 30%),
    linear-gradient(to bottom, transparent 58%, rgba(0, 0, 0, 0.45) 58% 62%, rgba(255, 201, 167, 0.06) 62% 66%, transparent 66%),
    linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 45%),
    var(--sun-map, none),
    var(--kb-case-front);
  border-radius: calc(var(--kb-u) * 0.5) calc(var(--kb-u) * 0.5) calc(var(--kb-u) * 0.15) calc(var(--kb-u) * 0.15) / calc(var(--kb-u) * 0.3) calc(var(--kb-u) * 0.3) calc(var(--kb-u) * 0.1) calc(var(--kb-u) * 0.1);
}

/* The deck: hinged at its front edge and tilted up toward the back. */
.kb__deck {
  transform-style: preserve-3d;
  transform-origin: 50% 100%;
  transform: translateZ(var(--deck-z)) rotateX(calc(-1 * var(--deck-tilt)));
}

.kb__floor {
  --sun-color: rgba(255, 183, 135, 0.26);
  background: var(--sun-map, none), var(--kb-floor);
}

/* In the sun, top surfaces light up warm. */
.kb__rim {
  --sun-color: rgba(255, 193, 148, 0.69);
  transform: translateZ(var(--rim));
  background:
    linear-gradient(to bottom, rgba(255, 205, 171, 0.1), rgba(255, 205, 171, 0)),
    var(--sun-map, none),
    var(--kb-case-top);
}

/* Rounded corners, and the front edge rounding over (lit). */
.kb__rim--back {
  border-radius: calc(var(--kb-u) * 0.5) calc(var(--kb-u) * 0.5) 0 0;
}

.kb__rim--front {
  border-radius: 0 0 calc(var(--kb-u) * 0.5) calc(var(--kb-u) * 0.5);
  background:
    linear-gradient(to top, rgba(255, 201, 167, 0.18), rgba(255, 201, 167, 0) 35%),
    var(--sun-map, none),
    var(--kb-case-top);
}

/* The walls of the opening the keys sit in, stood up from its floor: the
   back one faces the front, the sides face each other. */
.kb__wall {
  backface-visibility: hidden;
  background:
    linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 70%),
    var(--kb-case-front);
}

.kb__wall--to-front {
  transform-origin: 50% 100%;
  transform: rotateX(-90deg);
}

.kb__wall--to-right {
  transform-origin: 100% 50%;
  transform: rotateY(90deg);
  background:
    linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 70%),
    var(--kb-case-front);
}

.kb__wall--to-left {
  transform-origin: 0 50%;
  transform: rotateY(-90deg);
  background:
    linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 70%),
    var(--kb-case-front);
}

/* The lock lights, just above the rim. */
.kb__leds {
  transform: translateZ(calc(var(--rim) + 1px));
}

.kb__leds {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.kb__leds .kb__led {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--kb-u) * 0.06);
}

.kb__leds .kb__led-light {
  position: relative;
  width: calc(var(--kb-u) * 0.16);
  height: calc(var(--kb-u) * 0.16);
  border-radius: 50%;
  background: #2a3121;
  box-shadow: inset 0 calc(var(--kb-u) * 0.02) calc(var(--kb-u) * 0.03) rgba(0, 0, 0, 0.6);
}

.kb__led.is-on .kb__led-light {
  background: #a6ff7a;
  box-shadow:
    0 0 calc(var(--kb-u) * 0.12) #74ff4c,
    0 0 calc(var(--kb-u) * 0.35) rgba(90, 255, 60, 0.55);
}

.kb__leds .kb__led-label {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* -- Keys ------------------------------------------------------------------
   A keycap rides above the deck (--lift) and goes down by its travel. Its
   faces slope in from the footprint (--t, the taper) up to its top (--h):
   --a is that slope and --l its length. --sun is how much sun it's in.
   The sloping faces are trapezoids drawn in SVG (a fill, and a shading
   gradient over it) rather than clipped boxes: hundreds of clip-paths would
   each cost the compositor a mask, every frame. */
.kb-key {
  transform-style: preserve-3d;
  transform: translateZ(var(--lift));
  transition: transform 70ms ease-out;
}

.kb-key.is-down {
  transform: translateZ(calc(var(--lift) - var(--travel)));
  transition-duration: 22ms;
}

.kb-key--dark {
  --kb-cap-top: var(--kb-grey-top);
  --kb-cap-front: var(--kb-grey-front);
  --kb-cap-side: var(--kb-grey-side);
}

.kb-key > * {
  backface-visibility: hidden;
}

.kb-key__top {
  inset: var(--t);
  transform: translateZ(var(--h));
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: calc(var(--kb-u) * 0.05) calc(var(--kb-u) * 0.07);
  border-radius: calc(var(--kb-u) * 0.05);
  overflow: hidden;
  --sun-light: rgba(255, 195, 151, calc(var(--sun) * 0.7));
  background:
    linear-gradient(to bottom, rgba(255, 207, 175, 0.16), rgba(255, 207, 175, 0) 50%),
    radial-gradient(ellipse at 50% 60%, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0) 70%),
    linear-gradient(var(--sun-light), var(--sun-light)),
    var(--kb-cap-top);
}

.kb-key__front {
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--l);
  overflow: visible;
  transform-origin: 50% 100%;
  transform: rotateX(calc(-1 * var(--a)));
}

.kb-key__front .kb-face__fill {
  fill: color-mix(in srgb, var(--kb-cap-front), rgb(255 188 143) calc(var(--sun) * 24%));
}

.kb-key__front .kb-face__shade {
  fill: url(#kb-shade-front);
}

.kb-key__left,
.kb-key__right {
  top: 0;
  width: var(--l);
  height: 100%;
  overflow: visible;
}

.kb-key__left .kb-face__fill,
.kb-key__right .kb-face__fill {
  fill: color-mix(in srgb, var(--kb-cap-side), rgb(255 189 146) calc(var(--sun) * 35%));
}

.kb-key__left {
  left: 0;
  transform-origin: 0 50%;
  transform: rotateY(calc(-1 * var(--a)));
}

.kb-key__left .kb-face__shade {
  fill: url(#kb-shade-left);
}

.kb-key__right {
  right: 0;
  transform-origin: 100% 50%;
  transform: rotateY(var(--a));
}

.kb-key__right .kb-face__shade {
  fill: url(#kb-shade-right);
}

/* Browsers without color-mix() (Safari before 16.2, Firefox before 113) would
   leave the keys' sides unfilled, black: plain plastic there, no sun. */
@supports not (color: color-mix(in srgb, red, blue)) {
  .kb-key__front .kb-face__fill {
    fill: var(--kb-cap-front);
  }

  .kb-key__left .kb-face__fill,
  .kb-key__right .kb-face__fill {
    fill: var(--kb-cap-side);
  }
}

/* The shading gradients' definitions: in the page, never seen. */
.kb__defs {
  position: absolute;
  width: 0;
  height: 0;
}

.kb-legend {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: calc(var(--kb-u) * 0.2);
  line-height: 1.05;
  color: var(--kb-legend);
  white-space: nowrap;
}

.kb-legend--word {
  font-size: calc(var(--kb-u) * 0.12);
}

.kb__led-label .kb-legend {
  font-size: calc(var(--kb-u) * 0.1);
}
