/* The reset, the font, and the page. The desk layout is in pf-desk.js; the catalog layout is in src/pages/components.js. */
@font-face {
  font-family: 'Geist';
  src: url('../assets/fonts/Geist.woff2') format('woff2');
  font-weight: 100 900;
  font-display: block;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--desk);
  color: var(--ink);
  font-family: var(--font);
  font-feature-settings: 'ss01', 'tnum';
  -webkit-font-smoothing: antialiased;
}
/* The grain of the desk: white noise on whole pixels, under all parts. --grain: 0 turns it off. The flat ui has none. */
body:not(.ui)::before {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: url('../assets/grain.png') 0 0 / 256px 256px; image-rendering: pixelated;
  mix-blend-mode: overlay; opacity: calc(.22 * var(--grain));
}

/* The header of each page: the name, and the nav to each page. It has the same size on each page, and the side space of
   the pages (--edge). On the desk it lies over the desk, and only its links take a click. */
.pf-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: calc(48px + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) var(--edge) 0; font: 600 13px / 1 var(--font); }
/* The logo: large and light, as the name of teenage engineering on its site, with a small ™ at the top. */
.pf-header > b { font: 300 clamp(20px, 5.5vw, 26px) / 1 var(--font); letter-spacing: -.02em; white-space: nowrap; }
.pf-header > b a { color: inherit; text-decoration: none; }
.pf-header > b sup { margin-left: .1em; font-size: .45em; line-height: 0; vertical-align: .9em; }
/* The header stays at the top as the page scrolls, on the color and the grain of the page (body::before). */
.pf-header { position: sticky; top: 0; z-index: 50; background: var(--desk); }
body:not(.ui, .desk) .pf-header::before { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: url('../assets/grain.png') 0 0 / 256px 256px fixed; image-rendering: pixelated; mix-blend-mode: overlay; opacity: calc(.22 * var(--grain)); }
body.desk .pf-header { position: fixed; z-index: 5; inset: 0 0 auto; pointer-events: none; background: none; }
body.desk .pf-header a { pointer-events: auto; }
.pf-nav { display: flex; gap: 16px; font: 500 13px / 1 var(--font); }
.pf-nav a { padding: 8px 0; color: var(--ink-soft); text-decoration: none; }
.pf-nav a[aria-current] { color: var(--accent); }
/* On a phone the nav is a dial (Nav in page.js): one row that a swipe turns. It snaps each page to the middle, fades out
   to the sides and marks the page in the middle. The space at each end lets the first and the last page come to the middle. */
@media (max-width: 720px) {
  .pf-nav { flex: 1; min-width: 0; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; pointer-events: auto;
    mask-image: linear-gradient(90deg, transparent, #000 25% 75%, transparent); }
  .pf-nav::-webkit-scrollbar { display: none; }
  .pf-nav::before, .pf-nav::after { content: ''; flex: none; width: 50%; }
  .pf-nav a { flex: none; scroll-snap-align: center; }
  .pf-nav a[aria-current] { color: var(--ink-soft); }
  .pf-nav a[data-at] { color: var(--accent); }
}
.pf-nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Print on a device: its name with its icon, its code, the labels of its parts, and small specs. */
.pf-name, .pf-code, .pf-label, .pf-spec { color: var(--ink); white-space: nowrap; pointer-events: none; }
.pf-name { display: flex; align-items: center; gap: calc(.4 * var(--u)); font: 600 calc(1 * var(--u)) / 1 var(--font); letter-spacing: -.01em; }
.pf-name .pf-icon { width: calc(1.15 * var(--u)); height: calc(1.15 * var(--u)); fill: currentColor; }
.pf-code { font: 500 calc(.6 * var(--u)) / 1 var(--font); letter-spacing: .08em; color: var(--ink-soft); }
.pf-label { font: 500 calc(var(--label-size) * var(--u)) / 1 var(--font); letter-spacing: .02em; width: fit-content; }   /* the width of its text, so place=center centers it */
.pf-spec { font: 400 calc(.58 * var(--u)) / 1.35 var(--font); letter-spacing: .03em; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

/* ---------- the desk ----------
   On a desktop, the devices are in a row and the cables lie in the bay under them.
   On a phone in portrait, the devices are in two columns, with a bay under each row.
   The jacks are on the sides of the devices, so a column gap holds two plugs and the bend of a cable. */
body.desk { overflow: hidden; overscroll-behavior: none; }
pf-desk {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; height: 100vh; height: 100dvh;
  grid-template:
    "bat  dial pad  lamp" auto
    "bay  bay  bay  bay " calc(15 * var(--u))
    / auto auto auto auto;
  place-content: center;
  gap: calc(3 * var(--u)) calc(8 * var(--u));
  align-items: start;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
}
pf-desk > .pf-bay { grid-area: bay; align-self: stretch; }
pf-desk > .pf-bay + .pf-bay { display: none; }
pf-desk > [area=bat] { grid-area: bat; }
pf-desk > [area=dial] { grid-area: dial; }
pf-desk > [area=pad] { grid-area: pad; }
pf-desk > [area=lamp] { grid-area: lamp; }
@media (max-width: 720px) and (orientation: portrait) {
  pf-desk {
    grid-template:
      "bat  lamp" auto
      "bay  bay " calc(13 * var(--u))
      "dial pad " auto
      "bay2 bay2" calc(11 * var(--u))
      / auto auto;
    gap: calc(2 * var(--u)) calc(8 * var(--u));
  }
  pf-desk > .pf-bay + .pf-bay { display: block; grid-area: bay2; }
}

/* The canvas of the cables lies above the devices; the buttons of the plugs lie above it. */
.pf-cables { position: absolute; inset: 0; z-index: 3; width: 100%; height: 100%; pointer-events: none; }
pf-cable { position: absolute; inset: 0; pointer-events: none; }
/* A desk in a page that scrolls (pf-desk.js): its canvas covers the screen and scrolls with the page, and the desk lies
   above the other parts of the page, so a cable can go anywhere on it. */
pf-desk[page] { display: block; height: auto; overflow: visible; padding: 0; z-index: 5; touch-action: auto; }
/* A desk that zooms (zoom.js) is --zoom times the screen, and it and its canvas are fixed on the screen. A desk in the
   flow makes the page as large as the desk, and a phone then puts the fixed parts, such as the header, off the screen. */
pf-desk[zoom] { position: fixed; width: calc(var(--zoom, 1) * 100%); height: calc(var(--zoom, 1) * 100dvh); overflow: visible; }   /* no edge: zoomed out, the desk is smaller than the screen, and a shadow past its box still shows */
pf-desk[zoom] > .pf-cables { position: fixed; }
/* Space is down, and a drag pans the desk (zoom.js). */
.pf-hand, .pf-hand * { cursor: grab !important; }
.pf-pan, .pf-pan * { cursor: grabbing !important; }
.pf-plug, .pf-tie { position: absolute; z-index: 4; margin: 0; padding: 0; border: 0; border-radius: 999px; background: none; pointer-events: auto;
  cursor: grab; touch-action: none; -webkit-tap-highlight-color: transparent; }
.pf-plug:active, .pf-tie:active { cursor: grabbing; }
.pf-plug:focus-visible, .pf-tie:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
/* The plug in its button, and the ghost of a plug in a port (pf-cable.js): a pf-plug in the middle of its box. */
.pf-plug > pf-plug, .pf-ghost > pf-plug { position: absolute; inset: 0; margin: auto; }
/* The clip of a tie (ties.js), in the middle of its button. It is wider than the button, so it is not put there with margin: auto.
   Its unit makes its cables as wide as the widest cable of the tie (--tie-cable), so it is the clip of the components page to scale.
   A strap holds its cables snug, with no gap between them. */
.pf-tie > pf-clip { position: absolute; left: 50%; top: 50%; translate: -50% -50%; pointer-events: none; --u: calc(var(--tie-cable) / var(--cable-width)); --clip-gap: 0; }
.pf-ghost { position: absolute; z-index: 4; pointer-events: none; opacity: .6; }
/* The node of a free port on a desk with patch: a small gray dot --port-node-offset out of the mouth of a jack. It pops up
   while the pointer is on its device or near it (patch.js), and grows while the pointer is on the port or the node, so
   a drag from it pulls out a cable. A taken port and a magsafe port start no cable, so they show no node. A face-on
   port has its node in the middle of its mouth. */
pf-desk[patch] pf-port::after { content: ''; position: absolute; z-index: 3; left: calc(100% + var(--port-node-offset) * var(--u)); top: 50%;
  width: calc(var(--port-node) * var(--u)); aspect-ratio: 1; border-radius: 50%;
  background: var(--ink-soft); pointer-events: none; translate: -50% -50%; scale: .3; opacity: 0; transition: scale .15s, opacity .15s; }
pf-desk[patch] pf-port[side=left]::after { left: calc(-1 * var(--port-node-offset) * var(--u)); }
pf-desk[patch] pf-port[side=top]::after { left: 50%; top: calc(-1 * var(--port-node-offset) * var(--u)); }
pf-desk[patch] pf-port[side=bottom]::after { left: 50%; top: calc(100% + var(--port-node-offset) * var(--u)); }
pf-desk[patch] pf-port:is([variant=aux], [variant=usb-c], [variant=lightning])::after { left: 50%; top: 50%; }
pf-desk[patch] > [near] pf-port:not([connected], [variant=magsafe])::after { scale: 1; opacity: .5; pointer-events: auto; }
pf-desk[patch] > [near] pf-port:hover:not([connected], [variant=magsafe])::after { scale: 1.25; opacity: .75; }
.pf-plug.held { z-index: 5; }
