/* ==========================================================================
   Device screens (views/partials/device-screens/*.ejs)

   The v4 app drawn at 0.6 of its point size: every px below is a canvas
   px, so literal sizes are allowed here and nowhere else. The screens are
   the app's dark UI in both site themes; the accent follows the visitor's
   palette through the site's washes and roles. Glass is painted (tint,
   wash, rim), never backdrop-filter: the canvases are scaled artwork.
   ========================================================================== */

/* A bare screen on the field, no frame: the iPhone screen's own shape. */
.feature-card {
  position: relative;
  width: 280px;
  aspect-ratio: 241 / 524;
  margin-inline: auto;
  overflow: hidden;
  container-type: inline-size;
  border-radius: 13.7% / 6.3%;
  background: #0a0b11;
  box-shadow: 0 0 0 1px rgb(255 255 255 / .10), var(--shadow-pop);
}
.feature-card > .app-shot {
  --app-safe: 37px;
  inset: 0 auto auto 0;
  width: 241px;
  height: 524px;
  transform-origin: 0 0;
  transform: scale(calc(280 / 241));
}
@media (max-width: 559.98px) {
  .feature-card { width: 240px; }
  .feature-card > .app-shot { transform: scale(calc(240 / 241)); }
}
/* The island and the status row, in cqw of the screen (402 pt wide). */
.feature-card::before {
  content: '';
  position: absolute;
  z-index: 2;
  top: 2.74cqw;
  left: 34.33cqw;
  width: 31.34cqw;
  height: 9.2cqw;
  border-radius: 4.6cqw;
  background: #000;
}
.feature-card::after {
  content: '9:41';
  position: absolute;
  z-index: 2;
  top: 2.74cqw;
  left: 0;
  right: 0;
  height: 9.2cqw;
  display: flex;
  align-items: center;
  padding: 0 10.8cqw;
  font: 600 4.15cqw/1 var(--font);
  letter-spacing: -0.01em;
  color: #e9ebf5;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 13' fill='%23e9ebf5'%3E%3Crect x='0' y='8' width='3' height='4.5' rx='1'/%3E%3Crect x='5' y='5.5' width='3' height='7' rx='1'/%3E%3Crect x='10' y='3' width='3' height='9.5' rx='1'/%3E%3Crect x='15' y='.5' width='3' height='12' rx='1'/%3E%3Cpath d='M22.3 6.2a9.2 9.2 0 0 1 13.4 0M24.7 8.5a5.9 5.9 0 0 1 8.6 0' fill='none' stroke='%23e9ebf5' stroke-width='1.9' stroke-linecap='round'/%3E%3Ccircle cx='29' cy='11' r='1.5'/%3E%3Crect x='33.6' y='.6' width='23' height='11.8' rx='3.4' fill='none' stroke='%23e9ebf5' stroke-width='1.2' opacity='.38'/%3E%3Crect x='58.1' y='4.4' width='1.6' height='4.2' rx='.8' opacity='.38'/%3E%3Crect x='35.3' y='2.3' width='19.6' height='8.4' rx='2'/%3E%3C/svg%3E") no-repeat right 10.8cqw center / 14.5cqw auto;
}
/* The reader's page is cream, so its status row takes the page's ink. */
.feature-card:has(.app-reader)::after {
  color: #2b2118;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 13' fill='%232b2118'%3E%3Crect x='0' y='8' width='3' height='4.5' rx='1'/%3E%3Crect x='5' y='5.5' width='3' height='7' rx='1'/%3E%3Crect x='10' y='3' width='3' height='9.5' rx='1'/%3E%3Crect x='15' y='.5' width='3' height='12' rx='1'/%3E%3Cpath d='M22.3 6.2a9.2 9.2 0 0 1 13.4 0M24.7 8.5a5.9 5.9 0 0 1 8.6 0' fill='none' stroke='%232b2118' stroke-width='1.9' stroke-linecap='round'/%3E%3Ccircle cx='29' cy='11' r='1.5'/%3E%3Crect x='33.6' y='.6' width='23' height='11.8' rx='3.4' fill='none' stroke='%232b2118' stroke-width='1.2' opacity='.38'/%3E%3Crect x='58.1' y='4.4' width='1.6' height='4.2' rx='.8' opacity='.38'/%3E%3Crect x='35.3' y='2.3' width='19.6' height='8.4' rx='2'/%3E%3C/svg%3E");
}

/* Pictures of the app: keep their own colours under forced colours. */
@media (forced-colors: active) {
  .feature-card, .device { forced-color-adjust: none; }
}

/* Shared: community.css animates with it. */
@keyframes settle {
  from { transform: translateY(16px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

/* --------------------------------------------------------------------------
   Local tokens. Declared on the canvas too, so a frame's status row and the
   Mac desktop around the window read the same dark values.
   -------------------------------------------------------------------------- */
.app-shot,
.device-canvas {
  --app-ground: radial-gradient(120% 60% at 50% 45%, color-mix(in srgb, var(--blue) 6%, transparent), transparent), linear-gradient(#0a0b11, #0a0b11);
  --app-text: #e9ebf5;
  --app-muted: #868da5;
  --app-ink-2: #9ea4b8;
  --app-ink-2-strong: #cfd3e0;
  --app-text-soft: #b6bccf;
  /* Secondary text on glass is ink-2, not muted: #868da5 measures 3.77 to
     4.45 on the painted glass across the ten palettes, ink-2 5.01 or more. */
  --app-link: color-mix(in srgb, var(--tint) 40%, #fff);
  --app-eyebrow: color-mix(in srgb, var(--tint) 68%, #e9ebf5);
  --app-tint-layer: linear-gradient(rgb(255 255 255 / .07), rgb(255 255 255 / .07));
  --app-glass: var(--wash-10), var(--app-tint-layer);
  --app-glass-card: var(--wash-26), var(--app-tint-layer);
  --app-glass-accent: var(--wash-34), var(--app-tint-layer);
  --app-bubble: var(--wash-62), var(--app-tint-layer);
  --app-select: linear-gradient(var(--select-scrim), var(--select-scrim)), var(--grad-select);
  --app-rim: inset 0 1px 0 color-mix(in srgb, var(--rim-ink) 36%, transparent), inset 1px 0 0 color-mix(in srgb, var(--rim-ink) 20%, transparent),
             inset 0 -1px 0 color-mix(in srgb, var(--rim-ink) 48%, transparent), inset -1px 0 0 color-mix(in srgb, var(--rim-ink) 38%, transparent);
  --app-etch: rgb(255 255 255 / .07);
  --app-etch-line: rgb(255 255 255 / .14);
  --app-hairline: rgb(255 255 255 / .10);
  --app-shadow-float: 0 5px 16px -7px rgb(0 0 0 / .45);
  --app-shadow-cover: 0 3.6px 10px rgb(0 0 0 / .45);
  /* Painted frost for floating chrome: the ground at high alpha under the
     glass hides what scrolls beneath it, the way the app's blur does. */
  --app-frost: linear-gradient(rgb(10 11 17 / .97), rgb(10 11 17 / .97));
  /* MangaStatus.completed's dot (lib/models/manga_status.dart). */
  --app-status-done: #4a90e2;
  --app-status-on: #3dbe6c;
}

.app-shot {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  container-type: inline-size;
  padding-top: var(--app-safe, 0px);
  color-scheme: dark;
  background: var(--app-ground);
  color: var(--app-text);
  font: 400 9px/1.35 var(--font);
  letter-spacing: 0;
  text-align: left;
  text-transform: none;
  -webkit-font-smoothing: antialiased;
}
.app-shot p { margin: 0; }
.app-shot b { font-weight: 700; }
.app-shot svg { display: block; flex: none; }
.app-ico {
  width: 12px;
  height: 12px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.app-ico .f { fill: currentColor; stroke: none; }
/* The lemniscate: the app's in-UI mark, stroked on a 64 box. */
.app-logo svg path,
.app-hub-mark svg path,
.app-icon-tile svg path { fill: none; stroke: #fff; stroke-width: 6; }

/* --------------------------------------------------------------------------
   Header rows, toolbars, the pinned band
   -------------------------------------------------------------------------- */
.app-top {
  flex: none;
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 24px;
  padding: 4px 12px 0;
}
.app-top.is-sub { gap: 8px; }
.app-top.is-sub > .app-ico { width: 12px; height: 12px; color: var(--app-text); }
.app-title { font: 700 12px/1.2 var(--font); letter-spacing: -0.2px; white-space: nowrap; }
.app-title.is-lg { font-size: 15px; letter-spacing: -0.24px; }
.app-logo {
  flex: none;
  display: grid;
  place-items: center;
  width: 16.8px;
  height: 16.8px;
  border-radius: 5px;
  background: var(--grad-icon);
}
.app-logo svg { width: 13px; height: 13px; }
.app-tools {
  margin-left: auto;
  display: flex;
  gap: 16.8px;
  padding-right: 4px;
  color: var(--app-muted);
}
.app-band {
  flex: none;
  margin-top: calc(-1 * var(--app-safe, 0px));
  padding: var(--app-safe, 0px) 0 8px;
  background: var(--app-glass), linear-gradient(#0a0b11, #0a0b11);
  box-shadow: inset 0 -1px 0 var(--app-hairline);
}
.app-band .app-chips { margin-top: 8px; }

/* Filter chips: capsules that run off the right edge, no fade. */
.app-chips {
  flex: none;
  display: flex;
  gap: 4.8px;
  margin-top: 12px;
  padding: 0 12px;
  overflow: hidden;
}
.app-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 3.6px;
  height: 20.4px;
  padding: 0 8.4px;
  border-radius: 10.2px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
  font: 600 7.5px/1 var(--font);
  color: var(--app-ink-2);
  white-space: nowrap;
}
.app-chip.is-on {
  background: var(--app-glass-accent);
  color: #fff;
  font-weight: 700;
  text-shadow: var(--label-shadow);
}
.app-chip .app-ico { width: 9px; height: 9px; }
/* A source's own icon is fetched at runtime; this is the app's fallback. */
.app-chip-av {
  display: grid;
  place-items: center;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: rgb(255 255 255 / .14);
  color: var(--app-ink-2);
}
.app-chip-av .app-ico { width: 7px; height: 7px; }

.app-body {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  padding: 0 12px;
}

.app-eyebrow {
  display: block;
  margin: 14px 2.4px 6px;
  font: 700 7.2px/1.2 var(--font);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--app-eyebrow);
}
.app-eyebrow.is-muted { color: var(--app-muted); }

/* --------------------------------------------------------------------------
   Covers and the grid. Columns follow the app's Medium density: tiles up
   to 190 pt (114 px) plus a 12 pt gutter, so 2 on a phone, 5 on an iPad,
   6 in the Mac window.
   -------------------------------------------------------------------------- */
.app-grid {
  --cols: 2;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: 7.2px;
  row-gap: 12px;
  margin-top: 8px;
}
@container (min-width: 560px) { .app-grid { --cols: 5; } }
@container (min-width: 640px) { .app-grid { --cols: 6; } }
@container (min-width: 780px) { .app-grid { --cols: 7; } }
@container (min-width: 860px) { .app-grid { --cols: 8; } }
.app-cell { display: flex; flex-direction: column; min-width: 0; }
.app-cell-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 5.4px;
  font: 600 9.6px/1.25 var(--font);
  letter-spacing: -0.1px;
  color: var(--app-text);
}
.app-cell-meta {
  display: flex;
  align-items: center;
  gap: 3.6px;
  margin-top: 3px;
  font: 700 6.3px/1.2 var(--font);
  letter-spacing: .42px;
  text-transform: uppercase;
  color: var(--app-muted);
  white-space: nowrap;
}
.app-dot { flex: none; width: 3.6px; height: 3.6px; border-radius: 50%; background: var(--app-status-on); }
.app-dot.is-done { background: var(--app-status-done); }

/* Gutenberg ships a generated title-page cover, so the covers are drawn:
   title and author over one of six ramps of the visitor's palette. Sizes
   are px, not cqw: a cover's container width resolved to about 2px inside
   grids whose columns come from a container query, and the type vanished. */
.bk {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 4.5px;
  aspect-ratio: 2 / 3;
  padding: 10px 9px;
  overflow: hidden;
  border-radius: 9.6px;
  outline: 1px solid rgb(255 255 255 / .13);
  outline-offset: -1px;
  box-shadow: var(--app-shadow-cover);
  text-align: center;
  color: #fff;
  background-image: linear-gradient(rgb(0 0 0 / .4), rgb(0 0 0 / .4)), var(--bk-art);
  text-shadow: 0 1px 6px rgb(0 0 0 / .35);
}
.bk::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 7px;
  background: linear-gradient(90deg, rgb(0 0 0 / .42), rgb(0 0 0 / .06));
}
.bk::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(148deg, rgb(255 255 255 / .13), rgb(255 255 255 / .02) 46%, transparent 62%);
}
.bk > * { position: relative; z-index: 1; }
/* A real cover photo (public/img/covers/*.jpg, fetched from Project
   Gutenberg's own generated title-page art) replaces the drawn title and
   author below: the photo already carries its own typography, so drawing a
   second title over it would double up. The bk-N gradient stays as the
   background either way, a fallback behind the image's own edges and the
   full art for any cell with no photo yet. z-index:1 from the .bk > * rule
   above is kept, not overridden: painted in document order at that level,
   so ::before's edge shadow (painted as if the first child) still sits
   under the photo and ::after's gloss (the last child) still sits over it,
   the same depth the drawn covers already have. */
.bk-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.bk-title {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font: 600 12px/1.12 var(--font);
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.bk-rule { width: 16px; height: 1px; background: rgb(255 255 255 / .5); }
.bk-author {
  font: 700 6.6px/1 var(--font);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .72);
}
.bk-1 { --bk-art: linear-gradient(155deg, var(--indigo), var(--violet)); }
.bk-2 { --bk-art: linear-gradient(155deg, var(--indigo), var(--blue) 70%, var(--teal)); }
.bk-3 { --bk-art: linear-gradient(200deg, var(--violet), var(--indigo) 80%); }
.bk-4 { --bk-art: linear-gradient(135deg, var(--blue), var(--teal)); }
.bk-5 { --bk-art: linear-gradient(165deg, var(--teal), var(--indigo)); }
.bk-6 { --bk-art: linear-gradient(145deg, var(--violet), var(--teal)); }
/* Marks on art are not glass: a dark capsule. */
.bk-count {
  position: absolute;
  z-index: 2;
  right: 4px;
  bottom: 4px;
  padding: 2.4px 4.2px;
  border-radius: 999px;
  background: rgb(0 0 0 / .62);
  font: 700 6px/1 var(--font);
  letter-spacing: 0;
  text-transform: none;
  color: #fff;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   The tab bar: a fixed 204 px capsule of five 40.8 px slots, 6 px above
   the bottom edge. The lifted bubble sits over slot --slot.
   -------------------------------------------------------------------------- */
.app-tabbar {
  position: absolute;
  z-index: 5;
  left: 50%;
  bottom: 6px;
  width: 204px;
  height: 33.6px;
  margin-left: -102px;
}
.app-tabbar-bar {
  position: absolute;
  inset: 0;
  display: flex;
  border-radius: 16.8px;
  background: var(--app-glass), var(--app-frost);
  box-shadow: var(--app-rim), var(--app-shadow-float);
}
.app-tab {
  flex: 1 1 0;
  display: grid;
  place-items: center;
  min-width: 0;
}
.app-tab-halo {
  display: grid;
  place-items: center;
  width: 20.4px;
  height: 20.4px;
  border-radius: 50%;
  background: rgb(0 0 0 / .24);
  color: rgb(255 255 255 / .92);
}
.app-tab-halo .app-ico { width: 13.2px; height: 13.2px; }
.app-tab.is-on { align-content: end; padding-bottom: 5.4px; }
.app-tab-label {
  font: 700 6.9px/1 var(--font);
  color: #fff;
  text-shadow: 0 0 4px rgb(0 0 0 / .45);
  white-space: nowrap;
}
/* The bubble's bottom overlaps the bar by 12 px. No text on this wash. */
.app-tab-bubble {
  position: absolute;
  top: -21.6px;
  left: calc(var(--slot, 0) * 40.8px + 3.6px);
  display: grid;
  place-items: center;
  width: 33.6px;
  height: 33.6px;
  border-radius: 50%;
  background: var(--app-bubble), linear-gradient(rgb(10 11 17 / .6), rgb(10 11 17 / .6));
  box-shadow: var(--app-rim), 0 3.6px 11.7px rgb(0 0 0 / .4);
  color: #fff;
}
.app-tab-bubble .app-ico { width: 18px; height: 18px; }

/* --------------------------------------------------------------------------
   Groups, rows, cards, controls
   -------------------------------------------------------------------------- */
.app-group {
  overflow: hidden;
  border-radius: 15.6px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
}
.app-body > * + .app-group { margin-top: 7.2px; }
.app-body > .app-eyebrow + .app-group { margin-top: 0; }
.app-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 7.8px;
  min-height: 34px;
  padding: 7.8px 9.6px;
}
.app-row + .app-row::before {
  content: '';
  position: absolute;
  top: 0;
  left: 9.6px;
  right: 0;
  height: 1px;
  background: var(--app-hairline);
}
.app-group.has-marks .app-row + .app-row::before { left: 35.4px; }
.app-row > .app-ico { width: 12px; height: 12px; color: var(--app-muted); }
.app-row > .app-ico:last-child { color: rgb(255 255 255 / .5); }
.app-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.app-row-label {
  font: 500 9px/1.3 var(--font);
  letter-spacing: -0.1px;
  color: var(--app-text);
}
.app-row-label.is-strong { font-weight: 700; }
.app-row-sub { font: 400 7.5px/1.35 var(--font); color: var(--app-ink-2); }
.app-row-caps,
.app-row-state {
  font: 700 6.3px/1.2 var(--font);
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--app-ink-2);
  white-space: nowrap;
}
.app-row-state { display: flex; align-items: center; gap: 2.4px; }
.app-row-state .app-ico { width: 9px; height: 9px; }
.app-row.is-tall .app-row-text { gap: 2.4px; }
.app-danger { display: grid; color: var(--status-danger); }

/* The 30 px icon mark at 18 px. */
.app-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border: .6px solid transparent;
  border-radius: 6px;
  background:
    radial-gradient(95% 95% at 50% 62.5%, color-mix(in srgb, var(--tint) 26%, transparent), rgb(0 0 0 / .32)) padding-box,
    linear-gradient(rgb(0 0 0 / .55), rgb(255 255 255 / .16)) border-box;
  color: color-mix(in srgb, var(--tint) 58%, white);
}
.app-mark .app-ico { width: 9.6px; height: 9.6px; }

.app-switch {
  flex: none;
  position: relative;
  width: 27.6px;
  height: 16.2px;
  border-radius: 8.1px;
  background: rgb(255 255 255 / .16);
}
.app-switch::after {
  content: '';
  position: absolute;
  top: 1.2px;
  left: 1.2px;
  width: 13.8px;
  height: 13.8px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgb(0 0 0 / .3);
}
.app-switch.is-on { background: var(--app-select); }
.app-switch.is-on::after { left: auto; right: 1.2px; }

.app-card {
  border-radius: 19.2px;
  padding: 12px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
}
.app-card + .app-card { margin-top: 5.4px; }
.app-card.is-feature { background: var(--app-glass-card); }
.app-card-label {
  display: block;
  margin-bottom: 9px;
  font: 700 6.6px/1.2 var(--font);
  letter-spacing: .9px;
  text-transform: uppercase;
  color: var(--app-ink-2);
}
.app-card-row {
  display: flex;
  align-items: center;
  gap: 7.8px;
  margin: 10px -12px 0;
  padding: 9px 12px 0;
  border-top: 1px solid var(--app-hairline);
}
.app-shot .app-card-note { margin-top: 8px; font: 400 7.5px/1.45 var(--font); color: var(--app-ink-2); }

/* Segmented: an etched track inside cards, a glass one on the ground. */
.app-seg {
  display: flex;
  padding: 1.8px;
  border-radius: 12px;
  background: var(--app-etch);
  box-shadow: inset 0 0 0 1px var(--app-etch-line);
}
.app-body > .app-seg { margin-top: 6px; background: var(--app-glass); box-shadow: var(--app-rim); }
.app-seg > span {
  flex: 1 1 0;
  padding: 5.4px 0;
  border-radius: 10.2px;
  font: 600 7.5px/1.2 var(--font);
  text-align: center;
  color: var(--app-text-soft);
  white-space: nowrap;
}
.app-seg > .is-on {
  background: var(--app-select);
  box-shadow: inset 0 0 0 .5px rgb(255 255 255 / .22), 0 2px 9px color-mix(in srgb, var(--tint) 30%, transparent);
  font-weight: 700;
  color: var(--on-select);
  text-shadow: var(--on-select-shadow);
}

.app-circle {
  flex: none;
  display: grid;
  place-items: center;
  width: 25.8px;
  height: 25.8px;
  border-radius: 50%;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
  color: #fff;
}

/* --------------------------------------------------------------------------
   Browse: the Boundless hub, and Search
   -------------------------------------------------------------------------- */
.app-hub {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px 0 17px;
  text-align: center;
}
.app-hub-mark {
  display: grid;
  place-items: center;
  width: 38.4px;
  height: 38.4px;
  border-radius: 50%;
  background: var(--brand-gradient);
  box-shadow: 0 0 12px -3.6px color-mix(in srgb, var(--tint) 40%, transparent), inset 0 0 0 .6px rgb(255 255 255 / .2);
}
.app-hub-mark svg { width: 25px; height: 25px; }
.app-hub-name { margin-top: 8.4px; font: 700 16.2px/1.1 var(--font); letter-spacing: -0.24px; }
.app-hub-tag { margin-top: 2.4px; font: 400 9.6px/1.3 var(--font); color: var(--app-muted); }
.app-info {
  padding: 11px 12px 12px;
  border-radius: 19.2px;
  background: var(--app-glass-card);
  box-shadow: var(--app-rim);
}
.app-info + .app-info { margin-top: 9.6px; }
.app-info-head { display: flex; align-items: center; gap: 7.2px; font: 700 9.6px/1.2 var(--font); letter-spacing: -0.1px; }
.app-info-badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 20.4px;
  height: 20.4px;
  border-radius: 50%;
  background: rgb(255 255 255 / .14);
  box-shadow: inset 0 0 0 .6px rgb(255 255 255 / .16);
  color: #fff;
}
.app-info-badge .app-ico { width: 11px; height: 11px; }
.app-info p { margin-top: 7px; font: 400 8.1px/1.5 var(--font); color: var(--app-ink-2-strong); }

.app-search {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 28.8px;
  margin: 8px 12px 0;
  padding: 0 12px;
  border-radius: 14.4px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
  color: var(--app-muted);
}
.app-search-text { font: 400 9.6px/1 var(--font); color: var(--app-text); }

/* --------------------------------------------------------------------------
   Series page: the blurred cover behind everything, floating circles, the
   floating Info / Read / Comments dock
   -------------------------------------------------------------------------- */
.app-series { background: #0a0b11; }
.app-backdrop {
  position: absolute;
  inset: -8% -30%;
  overflow: hidden;
}
.app-backdrop > .bk {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border-radius: 0;
  outline: 0;
  box-shadow: none;
  filter: blur(6px) saturate(1.2);
}
.app-backdrop > .bk > * { visibility: hidden; }
.app-backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(rgb(10 11 17 / .30), rgb(10 11 17 / .62));
}
.app-series > :not(.app-backdrop) { position: relative; z-index: 1; }
.app-series > .app-dock { position: absolute; z-index: 3; }
.app-series-top {
  flex: none;
  display: flex;
  justify-content: space-between;
  padding: 4px 7.2px 0;
}
.app-series-top .app-circle { background: var(--app-glass-accent); }
.app-series-acts { display: flex; gap: 4.8px; }
.app-series-hero { display: flex; align-items: flex-end; gap: 9.6px; margin-top: 22px; }
.app-series-hero > .bk { flex: none; width: 71.4px; gap: 3px; padding: 7px 6px; }
.app-series-hero .bk-title { font-size: 8.4px; }
.app-series-hero .bk-rule { width: 11px; }
.app-series-hero .bk-author { font-size: 4.8px; }
.app-series-name { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.app-series-name b { font: 700 15px/1.12 var(--font); letter-spacing: -0.2px; }
.app-series-meta {
  font: 700 7.2px/1.2 var(--font);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgb(255 255 255 / .8);
}
.app-series-info { margin-top: 12px; }
.app-genres { display: flex; flex-wrap: wrap; gap: 4.8px; }
.app-genre {
  display: inline-flex;
  align-items: center;
  height: 16.8px;
  padding: 0 7.2px;
  border-radius: 8.4px;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .22);
  font: 600 7.2px/1 var(--font);
  color: #fff;
}
.app-shot .app-synopsis { margin-top: 9px; font: 400 9.6px/1.5 var(--font); color: rgb(255 255 255 / .85); }
.app-more-link { display: block; margin-top: 4px; font: 600 8.4px/1.2 var(--font); color: var(--app-link); }
.app-start {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 37.2px;
  margin-top: 8px;
  border-radius: 19.2px;
  background: var(--app-glass-card);
  box-shadow: var(--app-rim);
}
.app-start > .app-ico { width: 10px; height: 10px; color: #fff; }
.app-start > span { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.app-start b { font: 700 10.8px/1.1 var(--font); }
.app-start b + span { font: 400 8.4px/1.1 var(--font); color: rgb(255 255 255 / .72); }
.app-series-compact { display: flex; align-items: center; gap: 9.6px; margin-top: 10px; }
.app-series-compact > .bk { flex: none; width: 27.6px; padding: 0; gap: 0; }
.app-series-compact > .bk > * { display: none; }
.app-series-compact b { font: 700 12px/1.15 var(--font); letter-spacing: -0.2px; }
.app-series-compact .app-series-name span { font: 400 8.4px/1.2 var(--font); color: var(--app-ink-2); }
.app-listhead { display: flex; align-items: center; justify-content: space-between; margin: 14px 2px 7px 0; color: var(--app-muted); }
.app-listhead b { font: 700 12px/1.2 var(--font); letter-spacing: -0.2px; color: var(--app-text); }
.app-chaps { display: flex; flex-direction: column; gap: 5.4px; }
.app-chap {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 39px;
  padding: 0 9.6px;
  border-radius: 15.6px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
}
.app-chap-num {
  flex: none;
  width: 26px;
  font: 700 13.2px/1 var(--font);
  letter-spacing: -0.3px;
  color: color-mix(in srgb, var(--app-eyebrow) 30%, transparent);
  font-variant-numeric: tabular-nums;
}
.app-chap-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font: 500 9.6px/1.2 var(--font);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.app-chap > .app-ico { width: 11px; height: 11px; color: var(--app-muted); }
.app-chap > .app-ico:last-child { color: rgb(255 255 255 / .5); }
.app-dock {
  left: 50%;
  bottom: 27.6px;
  display: flex;
  width: 186px;
  height: 34.8px;
  margin-left: -93px;
  padding: 3px;
  border-radius: 17.4px;
  background: var(--wash-10), linear-gradient(rgb(0 0 0 / .28), rgb(0 0 0 / .28)), var(--app-tint-layer), var(--app-frost);
  box-shadow: var(--app-rim), var(--app-shadow-float);
}
.app-dock-lens {
  position: absolute;
  top: 3px;
  left: calc(3px + var(--slot, 0) * 60px);
  width: 60px;
  height: 28.8px;
  border-radius: 14.4px;
  background: var(--app-glass-accent);
  box-shadow: var(--app-rim);
}
.app-dock-item {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.4px;
  font: 700 6.6px/1 var(--font);
  color: rgb(255 255 255 / .82);
}
.app-dock-item.is-on { color: #fff; }
.app-dock-item .app-ico { width: 12px; height: 12px; }

/* --------------------------------------------------------------------------
   Novel reader. The page is the reader's own Paper colour, not the theme,
   and the chrome over it is pale glass with dark ink to suit it.
   -------------------------------------------------------------------------- */
.app-reader { background: #f5eedc; color: #2b2118; }
.app-rd-page {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  padding: 38px 10.8px 0;
}
.app-reader.is-bare .app-rd-page { padding-top: 6px; }
.app-rd-page p {
  max-width: 440px;
  margin: 0 auto 8px;
  font: 400 10.8px/1.6 var(--font);
  letter-spacing: 0;
}
.app-rd-close,
.app-rd-tools {
  position: absolute;
  top: calc(var(--app-safe, 0px) + 4px);
  display: flex;
  align-items: center;
  height: 27.6px;
  border-radius: 13.8px;
  background: rgb(236 232 223 / .82);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .55), 0 2px 8px rgb(43 33 24 / .12);
  color: #15151a;
}
.app-rd-close { left: 9px; justify-content: center; width: 27.6px; }
.app-rd-tools { right: 7.2px; justify-content: space-around; width: 77px; padding: 0 4px; }
.app-rd-aa { font: 600 9.6px/1 var(--font); }
.app-rd-dock {
  position: absolute;
  left: 7.2px;
  right: 7.2px;
  bottom: 27.6px;
  padding: 10px 12px 10px 13px;
  border-radius: 18px;
  background: linear-gradient(#ece8df, #e5e1d7);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .55), 0 6px 18px rgb(43 33 24 / .16);
  color: #15151a;
}
.app-rd-now { display: flex; align-items: center; gap: 8px; }
.app-rd-meta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.app-rd-meta b { overflow: hidden; font: 700 9px/1.2 var(--font); text-overflow: ellipsis; white-space: nowrap; }
.app-rd-meta span {
  display: flex;
  align-items: center;
  gap: 2px;
  font: 700 6.3px/1.2 var(--font);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgb(21 21 26 / .6);
}
.app-rd-meta .app-ico { width: 7px; height: 7px; }
.app-rd-play {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #15151a;
  color: #fff;
}
.app-rd-play .app-ico { width: 10px; height: 10px; }
.app-rd-scrub { display: flex; align-items: center; gap: 7px; margin-top: 9px; }
.app-rd-scrub > .app-ico { width: 10px; height: 10px; }
.app-rd-pct { font: 700 7.5px/1 var(--font); color: rgb(21 21 26 / .7); font-variant-numeric: tabular-nums; }
.app-rd-track { position: relative; flex: 1 1 auto; height: 2.4px; border-radius: 1.2px; background: rgb(21 21 26 / .16); }
.app-rd-track i {
  position: absolute;
  top: 50%;
  left: 0;
  width: 9px;
  height: 9px;
  margin-top: -4.5px;
  border-radius: 50%;
  background: radial-gradient(circle, #15151a 0 1.4px, #fff 1.6px);
  box-shadow: 0 1px 3px rgb(43 33 24 / .35);
}

/* --------------------------------------------------------------------------
   Sources and Appearance
   -------------------------------------------------------------------------- */
.app-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 6px 0 4px;
  text-align: center;
}
.app-empty-tile {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-bottom: 5px;
  border-radius: 10px;
  background: var(--app-etch);
  box-shadow: inset 0 0 0 1px var(--app-etch-line);
  color: var(--app-muted);
}
.app-empty-tile .app-ico { width: 14px; height: 14px; }
.app-empty b { font: 600 10.8px/1.2 var(--font); }
.app-empty > span:last-child { max-width: 180px; font: 400 8.4px/1.4 var(--font); color: var(--app-muted); }
.app-addrow { display: flex; align-items: center; gap: 6px; }
.app-field {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  height: 27px;
  padding: 0 9.6px;
  overflow: hidden;
  border-radius: 12px;
  background: var(--app-glass);
  box-shadow: var(--app-rim);
  font: 400 8.4px/1 var(--font);
  color: var(--app-text);
  white-space: nowrap;
}
.app-field.is-empty { color: var(--app-ink-2); }
.app-btn {
  flex: none;
  display: grid;
  place-items: center;
  height: 27px;
  padding: 0 13px;
  border-radius: 13.5px;
  background: var(--app-select);
  box-shadow: inset 0 0 0 .5px rgb(255 255 255 / .22), 0 2px 9px color-mix(in srgb, var(--tint) 30%, transparent);
  font: 700 8.4px/1 var(--font);
  color: var(--on-select);
  text-shadow: var(--on-select-shadow);
}
.app-addrow + .app-group { margin-top: 9px; }

.app-picks { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); row-gap: 9px; }
.app-pick { display: flex; flex-direction: column; align-items: center; gap: 4.8px; min-width: 0; }
.app-pick-cap { font: 500 6.9px/1 var(--font); color: var(--app-ink-2); white-space: nowrap; }
.app-pick.is-on .app-pick-cap { font-weight: 700; color: #fff; }
.app-swatch-dot,
.app-icon-tile,
.app-effect-tile { display: grid; place-items: center; }
.app-swatch-dot {
  width: 22.2px;
  height: 22.2px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 .6px rgb(255 255 255 / .18);
}
.app-swatch-dot .app-ico { width: 10px; height: 10px; color: #fff; stroke-width: 2.6; opacity: 0; }
/* The ringed swatch is the visitor's own palette (the app has no Ink). */
:root:not([data-palette]) .app-swatch[data-key='boundless'],
:root[data-palette='boundless'] .app-swatch[data-key='boundless'],
:root[data-palette='nova'] .app-swatch[data-key='nova'],
:root[data-palette='mono'] .app-swatch[data-key='mono'],
:root[data-palette='reverse'] .app-swatch[data-key='reverse'],
:root[data-palette='blossom'] .app-swatch[data-key='blossom'],
:root[data-palette='ember'] .app-swatch[data-key='ember'],
:root[data-palette='mint'] .app-swatch[data-key='mint'],
:root[data-palette='royal'] .app-swatch[data-key='royal'],
:root[data-palette='void'] .app-swatch[data-key='void'] {
  --swatch-on: 1;
}
.app-swatch { --swatch-on: 0; }
.app-swatch-dot { outline: calc(var(--swatch-on) * .9px) solid var(--app-text); outline-offset: 2.4px; }
.app-swatch-dot .app-ico { opacity: var(--swatch-on); }
.app-swatch .app-pick-cap { font-weight: calc(500 + var(--swatch-on) * 200); color: color-mix(in srgb, #fff calc(var(--swatch-on) * 100%), var(--app-ink-2)); }
.app-icon-tile { width: 22.2px; height: 22.2px; border-radius: 7.2px; }
.app-icon-tile svg { width: 15px; height: 15px; }
.app-icon-tile.is-ink svg path { stroke: #241d57; }
.app-pick.is-on .app-icon-tile { outline: .9px solid var(--app-text); outline-offset: 2.4px; }
.app-effect-tile {
  width: 24px;
  height: 24px;
  border-radius: 7.8px;
  background: var(--app-etch);
  box-shadow: inset 0 0 0 1px var(--app-etch-line);
  color: var(--app-ink-2);
}
.app-effect-tile .app-ico { width: 12px; height: 12px; }
.app-pick.is-on .app-effect-tile {
  background: var(--app-select);
  box-shadow: inset 0 0 0 .5px rgb(255 255 255 / .22), 0 2px 9px color-mix(in srgb, var(--tint) 30%, transparent);
  color: var(--on-select);
}

/* Screens framed in hardware: each device's top safe area. */
.device-iphone .device-canvas > .app-shot { --app-safe: 37px; }
.device-ipad .device-canvas > .app-shot { --app-safe: 14px; }

/* ==========================================================================
   Device frames: iPhone, iPad, MacBook Pro (views/partials/devices/*.ejs)
   ========================================================================== */

/* ==========================================================================
   Device frames: the shared canvas.

   Every frame (iphone, ipad, macbook) draws its hardware around one
   .device-screen, and the app screen inside is one of the existing
   views/partials/device-screens partials, drawn at 0.6 of the device's
   point size (a 402 by 874 point iPhone is a 241 by 524 canvas). The
   canvas keeps that fixed size so the drawing never reflows, and is
   scaled to whatever width the frame is rendered at: tan(atan2(a, b)) is
   the one way CSS can divide two lengths into a plain number, so the
   scale factor is the screen's own width over the canvas width, exact at
   any size and any device pixel ratio, with no script.
   ========================================================================== */
.device {
  position: relative;
  display: block;
  width: 100%;
  --canvas-w: 241;
  --canvas-h: 524;
  /* Artwork, and nothing inside it uses backdrop-filter. */
  filter: var(--drop-device);
}
.device-screen {
  position: relative;
  overflow: hidden;
  container-type: inline-size;
  aspect-ratio: var(--canvas-w) / var(--canvas-h);
  background: #0a0b11;
}
.device-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--canvas-w) * 1px);
  height: calc(var(--canvas-h) * 1px);
  /* Its own container too, so the screen partials' container queries
     measure the canvas (the device's point size) and not the frame, while
     the 100cqw in the scale below still reads the .device-screen ancestor:
     a property on the container itself never queries the same box. */
  container-type: inline-size;
  transform-origin: 0 0;
  transform: scale(tan(atan2(100cqw, calc(var(--canvas-w) * 1px))));
}
/* site.js's initDeviceFrameScale rewrites this scale inline, a safety net
   for a browser that once rendered the canvas unscaled; the rule above is
   what paints before the script and without it. */

/* ==========================================================================
   Device frame: iPhone 17 Pro, front, portrait.

   Markup in views/partials/devices/iphone.ejs. Sits on the shared canvas
   rules above (.device, .device-screen, .device-canvas): the screen is the
   402 by 874 point display drawn at 0.6, a 241 by 524 canvas.

   Every size is a share of the frame's own width, in cqw against the root
   (which is the container), so one set of rules draws the same phone at
   180px and at 900px with no media queries. The body is 71.9 by 150.0 mm,
   and its ratio is never written down: the root's height falls out of the
   screen's aspect ratio plus a uniform 3.75 percent margin on every side.
   That margin is what the real phone has between the glass edge and the
   lit pixels, about 2.7 mm, and it splits into the aluminium band seen
   face-on (2.15 percent, about 1.55 mm) and the black bezel inside it
   (1.6 percent, Apple's 1.15 mm). Solve 100 minus 2m over 0.4599 equals
   208.62 minus 2m and m comes out at 3.75, so the outer box lands on
   71.9 over 150.0 exactly, 0.4793.

   Corner radii are concentric so the band and bezel stay one thickness
   round the corner: display 14.25 (62 of 402 pt on a 92.5-wide screen),
   bezel 15.85, body 18.0, all in cqw of the body width.
   ========================================================================== */
.device-iphone {
  /* Position, width and the canvas size come from .device above and from
     the inline style the partial writes; only the container and the
     tokens live here, so there is one place each number is set. */
  container-type: inline-size;
  isolation: isolate;

  /* The 'black' finish. Not pure black: a charcoal metal that keeps a
     lighter top edge and a polished rim, otherwise the band reads as a
     hole in the page under the light theme. Fixed greys on purpose, a
     space-black chassis is the same colour in every palette. */
  --ip-metal-top: #4a4b53;
  --ip-metal: #2c2d34;
  --ip-metal-low: #1c1d22;
  --ip-antenna: rgba(255, 255, 255, 0.16);
  --ip-rim: inset 0 0 0 1px rgba(255, 255, 255, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.14);
  --ip-seam: rgba(0, 0, 0, 0.6);
  --ip-btn-rim: rgba(255, 255, 255, 0.2);
  /* The Camera Control's sapphire cover is the band's own tone with a
     faint gloss, found on a second look rather than the first: peak ten
     percent white over the charcoal, against the side button's twenty. */
  --ip-camctl: linear-gradient(to bottom, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.04) 50%, rgba(255, 255, 255, 0.08));

  /* Ground shadow, in cqw so it scales with the phone: at a 320px frame
     these are 0 32px 64px -22px and 0 10px 22px -10px. */
  --ip-ground: 0 10cqw 20cqw -7cqw rgba(0, 0, 0, 0.55), 0 3cqw 7cqw -3cqw rgba(0, 0, 0, 0.4);
}

/* Silver: a light warm grey with darker edges, so it separates from a
   white page by its rim rather than its fill. */
.device-iphone.is-silver {
  --ip-metal-top: #f6f4f0;
  --ip-metal: #dedbd5;
  --ip-metal-low: #c4c0b9;
  --ip-antenna: rgba(0, 0, 0, 0.16);
  --ip-rim: inset 0 0 0 1px rgba(0, 0, 0, 0.26), inset 0 0 0 2px rgba(255, 255, 255, 0.55);
  --ip-seam: rgba(0, 0, 0, 0.42);
  --ip-btn-rim: rgba(0, 0, 0, 0.28);
  --ip-camctl: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.2) 50%, rgba(0, 0, 0, 0.12));
}

/* Light page: a lighter ground shadow, tinted with the page's own ink like
   --shadow above, so the phone rests on the page instead of burning a
   black pool into it. */
:root[data-theme='light'] .device-iphone {
  --ip-ground: 0 10cqw 20cqw -7cqw rgba(20, 22, 40, 0.3), 0 3cqw 7cqw -3cqw rgba(20, 22, 40, 0.2);
}
/* shadow: false. Written twice so it outranks the light-theme rule above
   (0,3,0) on both pages; a bare .device-iphone.no-shadow (0,2,0) would
   lose to it and the option would silently do nothing under light. */
.device-iphone.no-shadow,
:root[data-theme='light'] .device-iphone.no-shadow { --ip-ground: 0 0 0 0 transparent; }

/* --------------------------------------------------------------------------
   The body: the aluminium band seen face-on.

   Three background layers, top to bottom in paint order: two pairs of
   antenna breaks (1px lines, lighter on the black finish and darker on
   silver, at 8 and 92 percent of the height and at 25 and 75 percent of
   the width; they cross the whole body but the black bezel covers all of
   them except the sliver in the band) and the metal gradient, lighter
   along the top edge and darkest along the bottom. The rim is a 1px
   inset highlight with an extra catch of light along the top.

   No brushed grain. The real band is matte anodised aluminium with no
   visible texture, and a 1px line pattern on a band this narrow runs
   across the side bands rather than along them, so it read as ribbed
   metal at every size. The gradient and the rim carry the material.
   -------------------------------------------------------------------------- */
.device-iphone-body {
  position: relative;
  z-index: 1;
  padding: 2.15cqw;
  border-radius: 18cqw;
  background:
    linear-gradient(to bottom,
      transparent calc(8% - 0.5px), var(--ip-antenna) calc(8% - 0.5px), var(--ip-antenna) calc(8% + 0.5px), transparent calc(8% + 0.5px),
      transparent calc(92% - 0.5px), var(--ip-antenna) calc(92% - 0.5px), var(--ip-antenna) calc(92% + 0.5px), transparent calc(92% + 0.5px)),
    linear-gradient(to right,
      transparent calc(25% - 0.5px), var(--ip-antenna) calc(25% - 0.5px), var(--ip-antenna) calc(25% + 0.5px), transparent calc(25% + 0.5px),
      transparent calc(75% - 0.5px), var(--ip-antenna) calc(75% - 0.5px), var(--ip-antenna) calc(75% + 0.5px), transparent calc(75% + 0.5px)),
    linear-gradient(to bottom, var(--ip-metal-top) 0, var(--ip-metal) 1.4%, var(--ip-metal) 60%, var(--ip-metal-low) 100%);
  box-shadow: var(--ip-rim), var(--ip-ground);
}

/* The bezel: pure black, with a 1px darker seam where it meets the metal
   so the two materials do not merge into one grey edge. */
.device-iphone-bezel {
  position: relative;
  padding: 1.6cqw;
  border-radius: 15.85cqw;
  background: #000;
  box-shadow: 0 0 0 1px var(--ip-seam);
}

/* The display. The shared rule gives it its aspect ratio and clips the
   canvas; here it only gets the 62pt corner and a black ground, so any
   sub-pixel seam between canvas and bezel is black rather than page. */
.device-iphone .device-screen {
  border-radius: 14.25cqw;
  background: #000;
}

/* The glass. A diagonal reflection across the top third, transparent to
   five percent white and back, and a 2px inset shadow at the very edge so
   the picture sits a hair below the surface. Lives on top of the island
   too: the island is under the same glass. */
.device-iphone .device-screen::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(118deg, transparent 8%, rgba(255, 255, 255, 0.05) 22%, transparent 36%);
  box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.6);
}

/* --------------------------------------------------------------------------
   The Dynamic Island: 126 by 37 pt on a 402 pt screen, its top edge 11 pt
   down. In cqw of the screen (the nearest container) that is 31.34 by
   9.2, 2.74 from the top, fully rounded. Pure black, with a faint 1px
   lighter ring so it still reads as a thing on a dark app header.
   -------------------------------------------------------------------------- */
.device-iphone-island {
  position: absolute;
  z-index: 2;
  top: 2.74cqw;
  left: 0;
  right: 0;
  margin: 0 auto;
  width: 31.34cqw;
  height: 9.2cqw;
  border-radius: 4.6cqw;
  background: #000;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08);
}

/* --------------------------------------------------------------------------
   Side controls. Slim bars behind the body, so only the 1.2 percent that
   protrudes past the edge is visible. Positions are shares of the body
   height, read off the real phone: left edge, Action 17 to 22, volume up
   26 to 34, volume down 37 to 45; right edge, side button 30 to 42.
   -------------------------------------------------------------------------- */
.device-iphone-btn {
  position: absolute;
  z-index: 0;
  width: 3cqw;
  border-radius: 0.7cqw;
  background: linear-gradient(to bottom, var(--ip-metal-top), var(--ip-metal) 18%, var(--ip-metal-low));
}
.device-iphone-btn.is-action,
.device-iphone-btn.is-vol-up,
.device-iphone-btn.is-vol-down {
  left: -1.2cqw;
  box-shadow: inset 1px 0 0 var(--ip-btn-rim), inset 0 1px 0 var(--ip-btn-rim);
}
.device-iphone-btn.is-side {
  right: -1.2cqw;
  box-shadow: inset -1px 0 0 var(--ip-btn-rim), inset 0 1px 0 var(--ip-btn-rim);
}
.device-iphone-btn.is-action   { top: 17%; height: 5%; }
.device-iphone-btn.is-vol-up   { top: 26%; height: 8%; }
.device-iphone-btn.is-vol-down { top: 37%; height: 8%; }
.device-iphone-btn.is-side     { top: 30%; height: 12%; }

/* The Camera Control, 60 to 67 percent down the right edge. Flush with
   the band rather than protruding, so it is drawn inside it: a strip the
   band's own width of slightly different tone (lighter on black, darker
   on silver, the sapphire cover glass either way) with a dark hairline
   above and below where the glass meets the metal. */
.device-iphone-camctl {
  position: absolute;
  right: 0;
  top: 60%;
  height: 7%;
  width: 2.15cqw;
  border-radius: 0.5cqw 0 0 0.5cqw;
  background: var(--ip-camctl);
  box-shadow: 0 -1px 0 var(--ip-seam), 0 1px 0 var(--ip-seam);
}

/* --------------------------------------------------------------------------
   The iOS status bar, drawn by the frame because the screen partials do
   not carry one. It sits in the canvas as a
   sibling of the app screen, in canvas pixels, so it scales with the
   screen and the app's own layout is untouched.

   iOS centres the time and the status glyphs on the Dynamic Island, so
   the row is the island's own box: top 11 pt, height 37 pt, which at 0.6
   is 6.6 and 22.2 px. The time is 17 pt semibold, 10 px here; the glyphs
   sit at the island's centre line, 12 pt tall (7 px), and both ears keep
   Apple's 43 pt margin from the glass edge, 26 px. The row is drawn in
   the app screen's own light ink, and the reader's fixed paper ink where
   the canvas holds the reader, whose page is cream.
   -------------------------------------------------------------------------- */
.device-iphone-status {
  position: absolute;
  top: 6.6px;
  left: 0;
  right: 0;
  height: 22.2px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 26px;
  pointer-events: none;
  font-family: var(--font);
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--app-text);
  -webkit-font-smoothing: antialiased;
}
.device-iphone .device-canvas:has(.app-reader) .device-iphone-status { color: #2b2118; }
.device-iphone-status-time { display: block; }
.device-iphone-status-glyphs {
  display: flex;
  align-items: center;
  gap: 3.5px;
}
.device-iphone-status-glyphs svg { display: block; height: 7px; fill: currentColor; }
.device-iphone-status-glyphs .is-signal { width: 10.5px; }
.device-iphone-status-glyphs .is-wifi { width: 10px; }
/* The battery is a hair taller than the other two, as Apple draws it, and
   its case is drawn at a third of the ink so the solid charge inside it
   reads as the level rather than the outline doing so. */
.device-iphone-status-glyphs .is-battery { width: 16px; height: 8px; }

/* ==========================================================================
   Device frames: iPad Pro 13" (M4), front view.

   Markup is views/partials/devices/ipad.ejs. The frame root is a query
   container, so every piece of hardware below is sized in cqw of the
   frame's own width and the one partial renders correctly at any width
   with no media queries. Because the same slab is drawn in both
   orientations, measurements are written in --u, one percent of the
   body's SHORT side (215.5 mm, so 1u is 2.155 mm): in portrait that is
   1cqw, in landscape 0.76527cqw, and a bezel or button stays the same
   physical size whichever way the slab is turned.

   The real body is 281.6 by 215.5 mm, so the outer box is 2155 / 2816
   (0.7653) in portrait and its inverse (1.3067) in landscape. The
   display is 1032 by 1376 pt, drawn on a 619 by 826 canvas (0.6 of the
   point size, the same factor every frame uses). Holding both of those
   ratios with a UNIFORM bezel fixes the bezel at 4.14u: any thinner and
   the top and bottom bezels would have to differ from the sides. The
   4.14u is the real 8.5 mm from body edge to display edge, and it splits
   into 0.9u of aluminium rim (the slab is 5.1 mm thick and flat-sided, so
   the band is a quarter of the iPhone's) and 3.24u of black glass bezel.
   ========================================================================== */

.device-ipad {
  container-type: inline-size;
  /* The shadow, buttons and slab stack on z-index 0, 1 and 2 inside the
     frame. Isolating the root keeps those numbers local, so a frame set
     beside a page element with its own z-index never paints over it. */
  isolation: isolate;
  aspect-ratio: 2155 / 2816;
  --canvas-w: 619;
  --canvas-h: 826;
  --u: 1cqw;

  /* Rim, bezel and corners. The display corner is 18 pt of a 1032 pt
     wide display, which on a 91.72u wide screen is 1.6u: tight, nothing
     like the iPhone's. The body corner is 5u (10.8 mm); a concentric
     corner would be 5.74u, but Apple's body corners run a little tighter
     than concentric and 5u is what the photographs measure. The glass
     sits inside the rim, so its corner is the body's less the band. */
  --ipad-band: calc(0.9 * var(--u));
  --ipad-bezel: calc(4.14 * var(--u));
  --ipad-r: calc(5 * var(--u));
  --ipad-glass-r: calc(var(--ipad-r) - var(--ipad-band));
  --ipad-screen-r: calc(1.6 * var(--u));

  /* Space Black, the default. A dark charcoal aluminium, read from the
     front as a machined flat edge: nearly uniform, a touch of light on the
     top run and shadow on the bottom. It is a few steps lighter than the
     iPhone's band because the wider slab shows more of its face to the
     light. Fixed greys on purpose: a space black chassis is the same
     colour in every palette. */
  --ipad-chassis: linear-gradient(180deg, #45464d 0%, #313238 7%, #2a2b31 50%, #26272d 93%, #1a1b1f 100%);
  --ipad-chassis-hi: rgba(255, 255, 255, 0.16);
  --ipad-chassis-lo: rgba(0, 0, 0, 0.38);
  --ipad-outline: rgba(0, 0, 0, 0);
  --ipad-button: #232429;
  --ipad-button-hi: rgba(255, 255, 255, 0.14);

  /* The one place the frame picks up the palette: the sheen on the glass
     leans a little toward the palette's teal, so the reflection reads as
     the same light that sweeps the site's panels. Mono's teal is white
     and void's is a dark violet, and both still read as a reflection
     because the mix is 20 percent and the whole layer sits at 8 percent
     alpha. */
  --ipad-sheen: color-mix(in srgb, var(--teal) 20%, white);

  /* Ground shadow. A thin slab throws a short shadow, so the ellipse sits
     tight under the bottom edge rather than pooling out around it. */
  --ipad-ground-a: 0.55;
  --ipad-lift: 0 calc(0.55 * var(--u)) calc(1.6 * var(--u)) calc(-0.3 * var(--u)) rgba(0, 0, 0, 0.5);
}

.device-ipad.is-landscape {
  aspect-ratio: 2816 / 2155;
  --canvas-w: 826;
  --canvas-h: 619;
  --u: 0.76527cqw;
}

/* Silver aluminium. White light on the top run, cool grey on the face,
   darker at the bottom, and a slightly darker grey for the buttons so they
   read as separate parts. */
.device-ipad.is-silver {
  --ipad-chassis: linear-gradient(180deg, #ffffff 0%, #e4e6eb 7%, #cfd2d9 50%, #c3c7ce 93%, #a3a7af 100%);
  --ipad-chassis-hi: rgba(255, 255, 255, 0.85);
  --ipad-chassis-lo: rgba(0, 0, 0, 0.22);
  --ipad-button: #b9bdc5;
  --ipad-button-hi: rgba(255, 255, 255, 0.7);
}

/* Light theme. The shadow lightens to match the paler ground, and Space
   Black lifts a few steps with a stronger edge highlight so the slab reads
   as an object sitting on the page rather than a hole cut in it. Silver
   gains a hairline outline, since #c3c7ce against #f6f7fc has almost no
   edge of its own. */
:root[data-theme='light'] .device-ipad {
  --ipad-ground-a: 0.24;
  --ipad-lift: 0 calc(0.55 * var(--u)) calc(1.6 * var(--u)) calc(-0.3 * var(--u)) rgba(20, 22, 40, 0.28);
  --ipad-chassis: linear-gradient(180deg, #5a5b63 0%, #3f4047 7%, #363740 50%, #31323a 93%, #24252b 100%);
  --ipad-chassis-hi: rgba(255, 255, 255, 0.3);
  --ipad-button: #2f3037;
  --ipad-button-hi: rgba(255, 255, 255, 0.22);
}
:root[data-theme='light'] .device-ipad.is-silver {
  --ipad-chassis: linear-gradient(180deg, #ffffff 0%, #e0e2e7 7%, #c9cdd4 50%, #bcc0c8 93%, #9a9ea6 100%);
  --ipad-outline: rgba(20, 22, 40, 0.16);
  --ipad-button: #aeb2ba;
}

/* --------------------------------------------------------------------------
   Ground shadow. An ellipse straddling the bottom edge, 90 percent of the
   width and 7u tall, fading to nothing at its own boundary. A pseudo on the
   root rather than a box-shadow so it can be softer and wider than the
   contact shadow the slab itself carries, and so it stays behind the
   buttons. cqw on a pseudo-element resolves against its originating
   element when that element is the container, which is the case here.
   -------------------------------------------------------------------------- */
.device-ipad::before {
  content: '';
  position: absolute;
  z-index: 0;
  left: 5%;
  right: 5%;
  bottom: calc(-3.6 * var(--u));
  height: calc(7 * var(--u));
  background: radial-gradient(ellipse 50% 50% at 50% 45%, rgba(0, 0, 0, var(--ipad-ground-a)) 0%, rgba(0, 0, 0, calc(var(--ipad-ground-a) * 0.45)) 40%, rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   The slab. The aluminium fills the whole frame box; the 1px inset
   highlight on the top edge and the 1px shadow on the bottom are what make
   it read as a machined edge rather than a flat grey border. The outline
   is a hairline that only light theme's silver switches on.
   -------------------------------------------------------------------------- */
.device-ipad-body {
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: var(--ipad-r);
  background: var(--ipad-chassis);
  box-shadow:
    inset 0 1px 0 var(--ipad-chassis-hi),
    inset 0 -1px 0 var(--ipad-chassis-lo),
    0 0 0 1px var(--ipad-outline),
    var(--ipad-lift);
}

/* The front glass: pure black bezel, edge to edge, with a 1px catch of
   light along its top edge where the glass meets the rim. The display sits
   inside it at the full 4.14u inset from the body edge. */
.device-ipad-front {
  position: absolute;
  inset: var(--ipad-band);
  border-radius: var(--ipad-glass-r);
  background: #000;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07);
  overflow: hidden;
}

/* The sheen across the glass: one diagonal wash from the top left corner,
   gone by 44 percent of the way across, so it catches the bezel and the
   first corner of the screen without dimming the app. No blur, no
   backdrop-filter, one gradient. */
.device-ipad-front::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  background: linear-gradient(
    112deg,
    color-mix(in srgb, var(--ipad-sheen) 8%, transparent) 0%,
    color-mix(in srgb, var(--ipad-sheen) 3%, transparent) 26%,
    rgba(255, 255, 255, 0) 44%
  );
  pointer-events: none;
}

/* The display. base.css gives .device-screen its canvas aspect ratio and
   the container-type the scaled canvas needs; the frame only places it.
   All four insets are set, so the box is 91.72u by 122.39u, which is the
   619 by 826 canvas ratio to four decimal places. */
.device-ipad .device-screen {
  position: absolute;
  z-index: 1;
  inset: calc(var(--ipad-bezel) - var(--ipad-band));
  border-radius: var(--ipad-screen-r);
}

/* --------------------------------------------------------------------------
   Front camera. A 1.6 mm lens is 0.75u, drawn as a near-black disc with a
   cooler highlight off centre and a 1px ring a shade lighter than the
   bezel. The bezel runs from 0.9u to 4.14u in from the body edge, so the
   lens is centred 2.52u in and its edge lands 2.145u in. The disc is
   positioned inside the glass, whose edge is already 0.9u in, so the
   offset written below is 1.245u. Portrait puts it in the right bezel,
   vertically centred; landscape puts it in the top bezel, horizontally
   centred.
   -------------------------------------------------------------------------- */
.device-ipad-cam {
  position: absolute;
  z-index: 1;
  width: calc(0.75 * var(--u));
  height: calc(0.75 * var(--u));
  top: calc(50% - 0.375 * var(--u));
  right: calc(1.245 * var(--u));
  border-radius: 50%;
  background: radial-gradient(circle at 38% 34%, #232a3a 0%, #0b0d14 55%, #04050a 100%);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.11);
}
.device-ipad.is-landscape .device-ipad-cam {
  top: calc(1.245 * var(--u));
  right: auto;
  left: calc(50% - 0.375 * var(--u));
}

/* --------------------------------------------------------------------------
   Buttons. Each is a 1u thick bar drawn behind the slab, so only the outer
   0.5u (1 mm) shows past the silhouette, which is how the flat-sided M4
   reads from the front. The top button is 5u long (10.8 mm) and starts 6u
   from its corner; the volume buttons are 3.8u each with a 1.2u gap,
   starting 9u from the same corner. Portrait: top button on the top edge
   at the right, volume on the right edge at the top. Landscape is that
   cluster turned a quarter anticlockwise: top button at the top of the
   left edge, volume on the top edge at the left.
   -------------------------------------------------------------------------- */
.device-ipad-btn {
  position: absolute;
  z-index: 1;
  display: block;
  background: var(--ipad-button);
  box-shadow: inset 0 1px 0 var(--ipad-button-hi);
  border-radius: calc(0.3 * var(--u));
}
.device-ipad-btn-top {
  top: calc(-0.5 * var(--u));
  right: calc(6 * var(--u));
  width: calc(5 * var(--u));
  height: var(--u);
}
.device-ipad-btn-vol-up,
.device-ipad-btn-vol-down {
  right: calc(-0.5 * var(--u));
  width: var(--u);
  height: calc(3.8 * var(--u));
}
.device-ipad-btn-vol-up { top: calc(9 * var(--u)); }
.device-ipad-btn-vol-down { top: calc(14 * var(--u)); }

.device-ipad.is-landscape .device-ipad-btn-top {
  top: calc(6 * var(--u));
  right: auto;
  left: calc(-0.5 * var(--u));
  width: var(--u);
  height: calc(5 * var(--u));
}
.device-ipad.is-landscape .device-ipad-btn-vol-up,
.device-ipad.is-landscape .device-ipad-btn-vol-down {
  top: calc(-0.5 * var(--u));
  right: auto;
  width: calc(3.8 * var(--u));
  height: var(--u);
}
.device-ipad.is-landscape .device-ipad-btn-vol-up { left: calc(9 * var(--u)); }
.device-ipad.is-landscape .device-ipad-btn-vol-down { left: calc(14 * var(--u)); }

/* ==========================================================================
   Device frame: MacBook Pro 14", seen from above and a little in front.

   The composition is a product render, not a side view: the deck is drawn
   exactly top-down and the lid leans back from the hinge in real 3D, so
   its top edge, being nearer the camera, comes out wider than its bottom
   edge and the screen content foreshortens with it. Every hardware length
   is in cqw against the frame root, so one partial draws correctly from
   about 180px to 1000px wide with no media queries.

   Real proportions used throughout: body 312.6 x 221.2 mm, so the deck is
   0.7076 as deep as it is wide; display 1512 x 982 pt, canvas 907 x 589 at
   0.6; key pitch 19 mm and a 14.5 unit wide alphanumeric block, which is
   about 91 percent of the body width; trackpad 130 x 80 mm; hinge cover
   about 8 mm; body corner radius about 8.5 mm.

   Colours: the chassis is hardware, so its greys are fixed (space black is
   black in every palette). The screen is macOS in dark mode in both site
   themes, like the app inside it; only its wallpaper takes the palette.
   ========================================================================== */

.device.device-macbook {
  --canvas-w: 907;
  --canvas-h: 589;
  /* The root is the container every cqw below measures. Its own box is
     sized by its children, all of which are in cqw, so its height follows
     its width deterministically: 29.15 (projected lid) + 44.58 (base)
     - 0.75 (the base rising into the lid's chin) + 4.5 (shadow room),
     77.5 in all, so the frame is about 1.29 : 1. */
  container-type: inline-size;

  /* Geometry, unitless cqw so the lid maths can multiply and divide. The
     base is 63 percent of the frame, leaving room for the lid's wider top
     edge (about 78 percent after perspective) and the ground shadow. */
  --mb-base-w: 63;
  --mb-base-h: calc(var(--mb-base-w) * 0.7076);
  /* The lid block before it is tilted: 63 wide by 44.6 deep, the same
     221.2 mm as the base because a closed lid covers it. Inside that, a
     0.55 top edge, a 0.76 bezel (1.2 percent of the lid), the 39.93 tall
     display, and what is left is the chin: 3.36cqw, about 16.7 mm, the
     black band under the display that carries the wordmark. */
  --mb-lid-h: 44.6;
  /* Tilt and camera distance. rotateX by a negative angle about the hinge
     brings the top edge toward the viewer, so perspective widens it. The
     scale of the top edge is P / (P - h sin t); with these values it is
     1.233, so the top edge spans 77.7 percent of the frame against the
     base's 63, and the lid's projected height, h cos t times that scale,
     is 29.15, about 0.65 of its true depth, which puts the lid at 40
     percent of the hardware's height against the reference's 37. */
  --mb-tilt: 58deg;
  --mb-persp: 200;
  --mb-lid-scale: calc(var(--mb-persp) / (var(--mb-persp) - var(--mb-lid-h) * sin(var(--mb-tilt))));
  /* How far the base rises into the lid's chin so the hinge cover overlaps
     the lid instead of butting against it. The chin is foreshortened to
     0.53 of its depth by the tilt, so of its 3.36cqw about 1.8 projects
     and 1.05 stays visible above the hinge once this is taken off. */
  --mb-tuck: 0.75;

  /* The keyboard. 14.5 units of 19 mm pitch is 91 percent of the deck, a
     keycap is 86 percent of the pitch and the gap the other 14, which is
     the 16 percent of a key the real board shows between caps. */
  --mb-pitch: calc(var(--mb-base-w) * 0.91cqw / 14.5);
  --mb-gap: calc(var(--mb-pitch) * 0.14);
  --mb-key: calc(var(--mb-pitch) - var(--mb-gap));
  --mb-kbd-w: calc(var(--mb-pitch) * 14.5 - var(--mb-gap));
  /* fn row at 0.55 of a key, five full rows, five row gaps. */
  --mb-kbd-h: calc(var(--mb-key) * 5.55 + var(--mb-gap) * 5);
  --mb-well-pad: 0.55cqw;
  /* Hinge cover about 8 mm, then the well begins about 4 mm behind it. */
  --mb-hinge-h: 2cqw;
  --mb-well-top: 3cqw;

  /* Space black. The deck is anodised aluminium, dark but not black, so
     the black keyboard well and the black bezel read as recesses against
     it. */
  --mb-body: #2b2b2f;
  --mb-body-deep: #1b1b1f;
  --mb-body-rim: rgba(255, 255, 255, 0.12);
  --mb-lid: #262629;
  --mb-lid-edge: #6a6a71;
  --mb-hinge: #121214;
  --mb-hinge-hi: rgba(255, 255, 255, 0.1);
  --mb-well: #08080a;
  --mb-keycap: #1d1d20;
  --mb-keycap-hi: rgba(255, 255, 255, 0.07);
  --mb-legend: #e6e6ea;
  --mb-grille: rgba(0, 0, 0, 0.6);
  --mb-trackpad: rgba(255, 255, 255, 0.06);
  /* How much the lid shades the rear of the deck and the front lip falls
     off, and the ground shadow colour. */
  --mb-shade-rear: rgba(0, 0, 0, 0.42);
  --mb-shade-front: rgba(0, 0, 0, 0.32);
  --mb-ground: rgb(0 0 0 / .75);
}
/* Silver. The strip seen between deck and display from above is the lid's
   own aluminium curving away over the hinge, so it stays light here, with
   only the dark slot at its top edge (the 60 percent black in the hinge
   gradient) and a bright front lip. */
.device.device-macbook.is-silver {
  --mb-body: #d2d3d8;
  --mb-body-deep: #b4b5bb;
  --mb-body-rim: rgba(255, 255, 255, 0.85);
  --mb-lid: #cbccd1;
  --mb-lid-edge: #f2f2f5;
  --mb-hinge: #9a9ba1;
  --mb-hinge-hi: rgba(255, 255, 255, 0.7);
  --mb-grille: rgba(0, 0, 0, 0.3);
  --mb-trackpad: rgba(0, 0, 0, 0.09);
  --mb-shade-rear: rgba(0, 0, 0, 0.22);
  --mb-shade-front: rgba(0, 0, 0, 0.14);
}
/* On the light page a space black chassis needs its rim to carry it, or
   it sits on the white like a hole cut out of the page. The body also
   lifts a shade, the way dark anodising does in a bright room. Scoped to
   the black finish: at four compound selectors this rule outranks the
   silver block above, and without the :not() it would hand silver the
   black chassis's faint rim. */
:root[data-theme='light'] .device.device-macbook:not(.is-silver) {
  --mb-body: #34343a;
  --mb-body-deep: #232327;
  --mb-body-rim: rgba(255, 255, 255, 0.34);
  --mb-lid: #2e2e33;
  --mb-hinge-hi: rgba(255, 255, 255, 0.22);
}
/* A paler ground on the light page, tinted with the page's own ink. */
:root[data-theme='light'] .device.device-macbook {
  --mb-ground: rgb(20 22 40 / .42);
}
:root[data-theme='light'] .device.device-macbook.is-silver {
  --mb-body: #dcdde2;
  --mb-body-deep: #bfc0c6;
  --mb-lid: #d3d4d9;
}

/* --------------------------------------------------------------------------
   The lid. Its layout box stays the full unforeshortened 44.6cqw tall,
   anchored to the bottom of a wrapper whose height is the projected
   height, so the drawn lid lands exactly in the space reserved for it and
   the base sits right at the hinge. The wrapper is deliberately not
   overflow hidden: the widened top edge reaches past the base on both
   sides, and that overhang is the whole point of the angle.
   -------------------------------------------------------------------------- */
.device-macbook-lid-space {
  position: relative;
  height: calc(var(--mb-lid-h) * 1cqw * cos(var(--mb-tilt)) * var(--mb-lid-scale));
}
.device-macbook-lid {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: calc(var(--mb-base-w) * 1cqw);
  height: calc(var(--mb-lid-h) * 1cqw);
  margin-left: calc(var(--mb-base-w) * -0.5cqw);
  border-radius: 1.9cqw 1.9cqw 1.4cqw 1.4cqw;
  background: linear-gradient(180deg, var(--mb-lid-edge), var(--mb-lid) 0.55cqw, var(--mb-lid));
  transform-origin: 50% 100%;
  transform: perspective(calc(var(--mb-persp) * 1cqw)) rotateX(calc(-1 * var(--mb-tilt)));
}
/* The aluminium rim is a hair wide at the sides and bottom and 0.55cqw at
   the top, where the lid's actual top edge faces the camera and catches
   the light; that gradient on the lid paints it. */
.device-macbook-bezel {
  position: absolute;
  inset: 0.55cqw 0.18cqw 0.18cqw;
  border-radius: 1.75cqw 1.75cqw 1.25cqw 1.25cqw;
  background: #040405;
}
.device-macbook-lid .device-screen {
  position: absolute;
  left: 0.76cqw;
  top: 1.31cqw;
  width: calc((var(--mb-base-w) - 1.52) * 1cqw);
  border-radius: 0.55cqw 0.55cqw 0 0;
  background: #0a0b11;
}
.device-macbook-notch {
  position: absolute;
  top: 0;
  left: 50%;
  width: 11%;
  height: 3.3%;
  transform: translateX(-50%);
  /* cqw in here measures .device-screen, itself an inline-size container
     at 61.48 percent of the frame, so 0.73 of it is 0.45 frame cqw: the
     real notch's 10pt bottom corners at this scale. */
  border-radius: 0 0 0.73cqw 0.73cqw;
  background: #040405;
  z-index: 3;
}
/* The wordmark on the chin, as the 2021 onward machines carry it. It is
   placed in the lid's own unforeshortened space: the base covers the lid
   up to 1.41cqw above the hinge line and the display starts at 3.36, so
   the text is centred between them at 2.39 and the tilt flattens it to
   roughly half its height, which is how small the real one looks from
   this angle. */
.device-macbook-wordmark {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2.05cqw;
  text-align: center;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: 0.68cqw;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.03em;
  color: rgba(255, 255, 255, 0.34);
  -webkit-font-smoothing: antialiased;
}
/* One diagonal sheen across the glass, faint enough to leave the window
   legible but present enough that the display reads as a surface. */
.device-macbook-glass {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(112deg, rgba(255, 255, 255, 0.09) 0%, rgba(255, 255, 255, 0.03) 26%, transparent 40%, transparent 72%, rgba(255, 255, 255, 0.035) 100%);
}

/* --------------------------------------------------------------------------
   The base, top-down. A rounded slab of the body colour, a shade darker
   toward the front lip, a 1px rim highlight so its edge reads on both
   themes, the lid's shadow across its rear, and the ground shadow under
   it in the site's own shadow colour. It rises --mb-tuck into the lid's
   chin so the hinge overlaps the lid rather than butting against it.
   -------------------------------------------------------------------------- */
.device-macbook-base {
  position: relative;
  z-index: 2;
  width: calc(var(--mb-base-w) * 1cqw);
  height: calc(var(--mb-base-h) * 1cqw);
  margin: calc(var(--mb-tuck) * -1cqw) auto 4.5cqw;
  border-radius: 1.2cqw 1.2cqw 1.7cqw 1.7cqw;
  background:
    linear-gradient(180deg, var(--mb-shade-rear), color-mix(in srgb, var(--mb-shade-rear) 30%, transparent) 5cqw, transparent 9cqw),
    linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--mb-shade-front) 50%, transparent) 88%, var(--mb-shade-front) 100%),
    radial-gradient(ellipse 70% 50% at 28% 0%, rgba(255, 255, 255, 0.05), transparent 70%),
    linear-gradient(180deg, var(--mb-body), var(--mb-body) 70%, var(--mb-body-deep));
  box-shadow:
    inset 0 0 0 1px var(--mb-body-rim),
    inset 0 -1px 0 rgba(255, 255, 255, 0.05),
    0 3.4cqw 6cqw -1cqw var(--mb-ground),
    0 1cqw 2cqw color-mix(in srgb, var(--mb-ground) 70%, transparent);
}
/* The hinge cover: a dark strip between the two rear corners, lit along
   its front edge. It sits above the lid in the stack so the lid's chin
   tucks under it. */
.device-macbook-hinge {
  position: absolute;
  top: 0;
  left: 1.5cqw;
  right: 1.5cqw;
  height: var(--mb-hinge-h);
  border-radius: 0 0 0.5cqw 0.5cqw;
  background: linear-gradient(180deg, color-mix(in srgb, var(--mb-hinge) 60%, black) 0, var(--mb-hinge) 45%, color-mix(in srgb, var(--mb-hinge) 92%, white) 100%);
  box-shadow: 0 1px 0 var(--mb-hinge-hi);
}

/* --------------------------------------------------------------------------
   The keyboard. A black well, and in it six rows, each a 58 track grid
   with a gap of --mb-gap: a track is a quarter unit, so a 1.5u tab spans 6
   tracks, a 1.75u caps lock 7, a 2.25u shift 9, the 5u space bar 20, and
   every row totals 58. Spanned tracks swallow their internal gaps, so a
   key of n quarters is exactly n/4 of the pitch minus one gap, the way a
   real keycap sits in its pitch.
   -------------------------------------------------------------------------- */
.device-macbook-well {
  position: absolute;
  top: var(--mb-well-top);
  left: 50%;
  width: calc(var(--mb-kbd-w) + var(--mb-well-pad) * 2);
  padding: var(--mb-well-pad);
  transform: translateX(-50%);
  border-radius: 0.6cqw;
  /* The backlight's floor. The keys are opaque, so what the eye gets is
     light in the gaps, and a backlit board is lit in every gap, esc and
     the arrows included, so the well itself glows: white over the black
     at 0.15 along the fn row rising to 0.22 by the bottom rows. */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.22) 72%, rgba(255, 255, 255, 0.2)),
    var(--mb-well);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.5);
}
/* The bloom on top of that floor, behind the keys, in a box 3.5cqw wider
   than the well each side, 2.5 taller and 5 deeper. Two ellipses, both
   sized in cqw so they reach transparent inside the box and never leave a
   clipped edge on the deck: a bright one, 27 by 9.5 radius, centred on the
   shift row (64 percent of the box height) so the light is strongest
   under the bottom rows and spills about 3.5cqw below the well onto the
   deck, and a wide faint one, 36 by 13, that carries a little light past
   the well's sides over the grilles. Peak alpha over the floor comes to
   about 0.5 white in the gaps under B and N. */
.device-macbook-well::before {
  content: '';
  position: absolute;
  inset: -2.5cqw -3.5cqw -5cqw;
  background:
    radial-gradient(27cqw 9.5cqw at 50% 64%, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.16) 50%, rgba(255, 255, 255, 0.04) 82%, transparent 100%),
    radial-gradient(36cqw 13cqw at 50% 60%, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.08) 50%, rgba(255, 255, 255, 0.03) 85%, transparent 100%);
  pointer-events: none;
}
.device-macbook-keyboard {
  position: relative;
  z-index: 1;
  display: grid;
  row-gap: var(--mb-gap);
  width: var(--mb-kbd-w);
}
.device-macbook-row {
  display: grid;
  grid-template-columns: repeat(58, 1fr);
  gap: var(--mb-gap);
  grid-auto-rows: var(--mb-key);
}
.device-macbook-row.is-fn { grid-auto-rows: calc(var(--mb-key) * 0.55); }

.device-macbook-key {
  position: relative;
  display: grid;
  place-items: center;
  grid-column: span var(--w, 4);
  border-radius: calc(var(--mb-key) * 0.12);
  background: var(--mb-keycap);
  box-shadow: inset 0 1px 0 var(--mb-keycap-hi), 0 1px 1px rgba(0, 0, 0, 0.5);
  color: var(--mb-legend);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  text-shadow: 0 0 0.3cqw rgba(255, 255, 255, 0.35);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
/* Legends. A letter is centred at a font-size of 0.4 of the key, which
   puts its cap height near 0.3, a 5 mm letter on a 16 mm cap. A number
   row cap stacks its shifted symbol over its number. A
   modifier's word sits along the bottom at 0.21 of the key with its
   glyph in a top corner. Left hand modifiers align left, right hand ones
   align right, and the bottom row centres its words, exactly as the real
   board is printed. */
.device-macbook-kl { font-size: calc(var(--mb-key) * 0.4); }
.device-macbook-ks {
  display: grid;
  gap: calc(var(--mb-key) * 0.12);
  text-align: center;
  font-size: calc(var(--mb-key) * 0.29);
}
.device-macbook-kw {
  position: absolute;
  left: 11%;
  right: 11%;
  bottom: 11%;
  text-align: center;
  font-size: calc(var(--mb-key) * 0.21);
  white-space: nowrap;
}
.device-macbook-key.is-left .device-macbook-kw { text-align: left; }
.device-macbook-key.is-right .device-macbook-kw { text-align: right; }
.device-macbook-kg {
  position: absolute;
  top: 9%;
  right: 11%;
  font-size: calc(var(--mb-key) * 0.3);
}
.device-macbook-key.is-left .device-macbook-kg { right: auto; left: 11%; }
/* The caps lock indicator: an unlit dot at the left edge. */
.device-macbook-kled {
  position: absolute;
  left: 9%;
  top: 50%;
  width: calc(var(--mb-key) * 0.08);
  height: calc(var(--mb-key) * 0.08);
  margin-top: calc(var(--mb-key) * -0.04);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
}
/* fn row: the glyph centred in the upper part, the F number in tiny type
   along the bottom. The glyphs are 24 unit stroke SVGs at 0.3 of a key. */
.device-macbook-kf {
  display: grid;
  place-items: center;
  width: calc(var(--mb-key) * 0.3);
  height: calc(var(--mb-key) * 0.3);
  margin-top: calc(var(--mb-key) * -0.09);
}
.device-macbook-kf svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.device-macbook-kf svg .f { fill: currentColor; stroke: none; }
.device-macbook-kn {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 7%;
  text-align: center;
  font-size: calc(var(--mb-key) * 0.15);
  opacity: 0.85;
}
/* Touch ID: a sapphire square, blank but for a faint ring. */
.device-macbook-key.is-touchid { background: #0c0c0e; }
.device-macbook-key.is-touchid::after {
  content: '';
  width: 62%;
  aspect-ratio: 1;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09);
}
/* The inverted T: left and right arrows are half height keys sitting on
   the bottom of the row, up and down a stacked pair in the middle. */
.device-macbook-key.is-half {
  align-self: end;
  height: calc((var(--mb-key) - var(--mb-gap)) / 2);
  font-size: calc(var(--mb-key) * 0.24);
}
.device-macbook-updown {
  grid-column: span 4;
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: var(--mb-gap);
}
.device-macbook-updown .device-macbook-key { grid-column: auto; height: auto; font-size: calc(var(--mb-key) * 0.24); }

/* Speaker grilles: two columns of fine dots flanking the well, the height
   of the well. Two offset layers of the same tiny radial gradient give a
   staggered pattern at a pitch of 0.42cqw, which is what survives from a
   1 mm hole pitch at these sizes. */
.device-macbook-grille {
  position: absolute;
  top: var(--mb-well-top);
  width: 1.5cqw;
  height: calc(var(--mb-kbd-h) + var(--mb-well-pad) * 2);
  border-radius: 0.3cqw;
  background:
    radial-gradient(circle, var(--mb-grille) 26%, transparent 34%) 0 0 / 0.42cqw 0.42cqw,
    radial-gradient(circle, var(--mb-grille) 26%, transparent 34%) 0.21cqw 0.21cqw / 0.42cqw 0.42cqw;
}
.device-macbook-grille.is-left { left: 0.42cqw; }
.device-macbook-grille.is-right { right: 0.42cqw; }

/* The trackpad: 130 x 80 mm, so 41.6 percent of the deck wide, below the
   well with a gap the size of the hinge, leaving a 1.3cqw lip at the
   front. Only a 1px outline, because that is all a real one shows. */
.device-macbook-trackpad {
  position: absolute;
  left: 50%;
  top: calc(var(--mb-well-top) + var(--mb-kbd-h) + var(--mb-well-pad) * 2 + 1.35cqw);
  bottom: 1.3cqw;
  width: calc(var(--mb-base-w) * 0.416cqw);
  transform: translateX(-50%);
  border-radius: 0.55cqw;
  box-shadow: inset 0 0 0 1px var(--mb-trackpad);
}

/* --------------------------------------------------------------------------
   The desktop, drawn at 0.6 scale in canvas pixels inside the 907 x 589
   display, dark in both site themes; the wallpaper takes the palette.
   -------------------------------------------------------------------------- */
.device-macbook-desktop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  color: var(--app-text);
  -webkit-font-smoothing: antialiased;
  /* Soft pools of the palette over a ground lifted 8 percent toward the
     ink, plus 3 percent white: under mono and void the pools are near
     black, and a lit panel must still read against the #040405 bezel. */
  background:
    linear-gradient(rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.03)),
    radial-gradient(ellipse 70% 80% at 12% 8%, color-mix(in srgb, var(--violet) 48%, #0a0b11), transparent 70%),
    radial-gradient(ellipse 62% 72% at 92% 100%, color-mix(in srgb, var(--teal) 34%, #0a0b11), transparent 70%),
    radial-gradient(ellipse 60% 50% at 30% 100%, color-mix(in srgb, var(--blue) 26%, #0a0b11), transparent 70%),
    radial-gradient(ellipse 90% 70% at 55% 50%, color-mix(in srgb, var(--indigo) 70%, #0a0b11), transparent 75%),
    color-mix(in srgb, var(--app-text) 8%, #0a0b11);
}
/* The menu bar is the notch's height, 32pt, as it is on the real 14";
   translucent over the wallpaper with a hairline under it. */
.device-macbook-menubar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 20px;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 10px 0 11px;
  font-size: 7.8px;
  font-weight: 500;
  color: var(--app-muted);
  background: color-mix(in srgb, #0f111a 55%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--app-text) 8%, transparent);
}
.device-macbook-apple { display: block; width: 8px; height: 8px; color: var(--app-text); margin-right: 1px; }
.device-macbook-apple svg { display: block; width: 100%; height: 100%; fill: currentColor; }
.device-macbook-menu.is-app { color: var(--app-text); font-weight: 600; }
.device-macbook-status {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--app-text);
  font-weight: 500;
}
.device-macbook-status svg { display: block; height: 8px; width: auto; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.device-macbook-status svg .f { fill: currentColor; stroke: none; }

/* The app window: 1100 x 783 pt, the size the iPad app opens at on a Mac,
   so 660 x 470 here, centred on the desktop below the menu bar. A 28pt
   title bar, 12pt traffic lights, 12pt corners, a hairline edge and a
   shadow deep enough to lift it off the wallpaper. */
.device-macbook-window {
  position: absolute;
  left: 50%;
  top: 20px;
  bottom: 0;
  width: 660px;
  height: 470px;
  margin: auto 0 auto -330px;
  display: flex;
  flex-direction: column;
  border-radius: 7px;
  overflow: hidden;
  background: #0f111a;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.35),
    0 22px 48px -8px rgba(0, 0, 0, 0.6),
    0 4px 12px rgba(0, 0, 0, 0.3);
}
/* The light inner hairline that makes a macOS window read as lifted. It
   is an overlay rather than an inset shadow on the window because an
   inset shadow paints under the children, and the title bar and the app
   fill the box edge to edge, so it never showed. */
.device-macbook-window::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--app-text) 14%, transparent);
  pointer-events: none;
}
.device-macbook-titlebar {
  position: relative;
  flex: none;
  height: 17px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 8px;
  background: color-mix(in srgb, var(--app-text) 7%, #0f111a);
  border-bottom: 1px solid color-mix(in srgb, var(--app-text) 10%, transparent);
}
.device-macbook-light {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.18);
}
/* The one place fixed colour is right on the screen: macOS paints these
   the same in every appearance. */
.device-macbook-light.is-close { background: #ff5f57; }
.device-macbook-light.is-min { background: #febc2e; }
.device-macbook-light.is-zoom { background: #28c840; }
.device-macbook-title {
  position: absolute;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 7.8px;
  font-weight: 600;
  color: var(--app-text);
  pointer-events: none;
}
/* The window body is its own inline-size container so the app screen's
   container queries measure the 660px window, not the 907px display. */
.device-macbook-window-body {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  container-type: inline-size;
}

/* window: false. The app fills the display with no desktop, the way a
   full-screen Mac app does, and macOS reserves the notch's band for it:
   the top 32pt is black either side of the notch and content starts
   below. That band is 20 canvas px, the same height the menu bar has in
   the windowed mode, and the notch's 3.3 percent (19.4px) sits inside it. */
.device-macbook.is-fullscreen .device-screen { background: #040405; }
.device-macbook.is-fullscreen .device-canvas > .app-shot { top: 20px; }


/* --------------------------------------------------------------------------
   Device figures on the page: frames stand directly on the ambient field
   with a plain caption under each. Markup: .device-page > .device-page-grid
   > figure (display: contents) > .device-stage > .device-stage-mount >
   .device, then figcaption.device-plate.
   -------------------------------------------------------------------------- */
.device-page {
  position: relative;
  container-type: inline-size;
}
/* The grid is one box in from the page, because a container query never
   answers for the element that carries the container. */
.device-page-grid {
  display: grid;
  column-gap: clamp(16px, 3.4cqw, 40px);
  row-gap: 18px;
}
.device-page-grid > figure { display: contents; }
.device-stage {
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
/* Devices in a row share one baseline: each mount aligns its device to
   the end of the row, and the room under it is the drop shadow's. */
.device-stage-mount {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  min-height: 0;
  padding-bottom: 6px;
}
.device-stage-mount > .device { width: min(100%, var(--stage-device, 100%)); }
/* The MacBook frame keeps 4.5 percent of its width as shadow room under
   its base; pulling it down by the same share puts the base, not the
   frame, on the row's baseline. */
.device-stage-mount > .device-macbook { margin-bottom: calc(min(100%, var(--stage-device, 100%)) * -0.045); }
.device-plate {
  min-width: 0;
  max-width: 32ch;
  margin: 0 auto;
  text-align: center;
  font: 400 var(--step--1)/1.45 var(--font);
  color: var(--ink-2);
}
.device-plate .card-label,
.device-plate .eyebrow { display: block; }
.device-plate strong {
  display: block;
  margin-bottom: 2px;
  font: 700 var(--step-0s)/1.3 var(--font);
  letter-spacing: -0.01em;
  color: var(--text);
}
.device-plate p { margin: 0; text-wrap: pretty; }

/* Solo: one device and its caption. */
.device-page-solo {
  width: min(640px, 100%);
  margin-inline: auto;
}
.device-page-solo .device-page-grid {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: 'stage' 'plate';
}
.device-page-solo .device-stage { grid-area: stage; }
.device-page-solo .device-plate { grid-area: plate; }

/* Trio: phone, iPad, Mac on column shares 1 : 1.6 : 2.4, each device
   capped so the three hold a believable scale against each other. Between
   600 and 900 px the laptop takes its own row; under 600 all three stack.
   Extra row-gap (the shared 18px base plus 30px more) keeps the caption
   clear of --drop-device's light-theme falloff, which reaches well past
   the shared gap's 24px total (18px row-gap + the stage mount's 6px
   padding-bottom) and was washing out the card-label contrast. */
.device-page-trio .device-page-grid {
  grid-template-columns: 1fr 1.6fr 2.4fr;
  grid-template-areas:
    'phone ipad mac'
    'phone-cap ipad-cap mac-cap';
  row-gap: 48px;
}
.device-page-trio .is-phone { grid-area: phone; --stage-device: 140px; }
.device-page-trio .is-ipad { grid-area: ipad; --stage-device: 380px; }
.device-page-trio .is-mac { grid-area: mac; --stage-device: 640px; }
.device-page-trio .is-phone-cap { grid-area: phone-cap; }
.device-page-trio .is-ipad-cap { grid-area: ipad-cap; }
.device-page-trio .is-mac-cap { grid-area: mac-cap; }
@container (max-width: 899.98px) {
  .device-page-trio .device-page-grid {
    grid-template-columns: 1fr 1.6fr;
    grid-template-areas:
      'phone ipad'
      'phone-cap ipad-cap'
      'mac mac'
      'mac-cap mac-cap';
  }
  .device-page-trio .is-phone { --stage-device: 150px; }
  .device-page-trio .is-mac { --stage-device: 560px; }
  .device-page-trio :is(.is-phone-cap, .is-ipad-cap) { margin-bottom: 22px; }
}
@container (max-width: 599.98px) {
  .device-page-trio .device-page-grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'phone' 'phone-cap' 'ipad' 'ipad-cap' 'mac' 'mac-cap';
  }
  .device-page-trio .is-phone { --stage-device: 160px; }
  .device-page-trio .is-ipad { --stage-device: 320px; }
}
