/* ==========================================================================
   Project previews
   Every project card opens with a small, live recreation of the project: the
   window it ran in, drawn in HTML and SVG. Everything inside a preview is sized
   in cqw (1% of the preview's width), so it scales like a screenshot, from a
   phone card up to the dialog. Animations only run while a preview is on
   screen (js/previews.js toggles .is-live).
   ========================================================================== */

.pv {
  --pv-shadow: 0 1.8cqw 4.5cqw -1.4cqw rgb(0 0 0 / 0.6), 0 0 0 1px rgb(0 0 0 / 0.35);
  --f-ui: "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  --f-plot: Helvetica, Arial, "Liberation Sans", sans-serif;
  position: relative;
  display: block;
  container-type: inline-size;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  isolation: isolate;
  background-color: color-mix(in srgb, var(--surface-2) 70%, var(--bg-raised));
  background-image:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--text) 4%, transparent), transparent 70%),
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: auto, 16px 16px, 16px 16px;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

:root[data-theme="light"] .pv {
  --pv-shadow: 0 1.8cqw 4.5cqw -1.6cqw rgb(24 22 18 / 0.38), 0 0 0 1px rgb(24 22 18 / 0.14);
}

.pv svg {
  display: block;
  overflow: visible;
}

.pv svg path {
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Grid and featured cards: the preview runs edge to edge across the top */
.project > .pv {
  margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-2);
  border-bottom: 1px solid var(--line);
  border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0;
}

.project--featured > .pv {
  margin-top: calc(var(--space-6) * -1);
  aspect-ratio: 16 / 9.4;
}

/* ---------- Window chrome ---------- */

.win {
  position: absolute;
  inset: 7cqw 6cqw auto;
  height: 60cqw;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 1.4cqw;
  background: #fff;
  box-shadow: var(--pv-shadow);
  font: 400 2.4cqw/1.35 var(--f-ui);
  color: #1b1b1b;
  transition: transform 0.7s var(--ease-out), box-shadow 0.7s var(--ease-out);
}

.project--featured .win {
  height: 58cqw;
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .project:hover .pv .win,
  .project:hover .pv .dev {
    transform: translateY(-1.4cqw);
  }
}

/* Windows 11 title bar */
.bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.3cqw;
  height: 5.6cqw;
  padding-left: 2cqw;
  background: #f3f3f3;
  color: #1b1b1b;
  font: 400 2.2cqw/1 var(--f-ui);
  white-space: nowrap;
}

.bar > span {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.4;
}

.bar--dark {
  background: #202020;
  color: #e8e8e8;
}

/* Minimise, maximise, close */
.bar__ctl {
  flex: none;
  align-self: stretch;
  width: 17cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 102 34' fill='none' stroke='%23333' stroke-width='1.1'%3E%3Cpath d='M12 17h10'/%3E%3Crect x='46' y='12' width='10' height='10' rx='1.5'/%3E%3Cpath d='M80 12l10 10M90 12 80 22'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}

.bar--dark .bar__ctl {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 102 34' fill='none' stroke='%23ddd' stroke-width='1.1'%3E%3Cpath d='M12 17h10'/%3E%3Crect x='46' y='12' width='10' height='10' rx='1.5'/%3E%3Cpath d='M80 12l10 10M90 12 80 22'/%3E%3C/svg%3E");
}

/* The app's own icon in the title bar, drawn small the way Windows shows it */
.bar__app {
  flex: none;
  width: 2.6cqw;
  height: 2.6cqw;
  background: var(--ico) center / contain no-repeat;
}

/* MATLAB's membrane: Simulink scopes and App Designer apps carry it too */
.bar__app--ml { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M.8 10.3 4.9 7.7l2.2 1.6-3.4 3.3z' fill='%234b92d6'/%3E%3Cpath d='M4.9 7.7 8.7 1.2l1.9 4.9 1.7 3.4 3 3.6-4.2-2.1-4-1.7z' fill='%23f5922d'/%3E%3Cpath d='M8.7 1.2l1.9 4.9 1.7 3.4 3 3.6-1.6.2-2.5-3.3-1.7-4.4z' fill='%23c4401b'/%3E%3C/svg%3E"); }
/* python.exe's icon, which a PyQt window gets when nobody sets one */
.bar__app--py { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.2c-2.6 0-2.9 1.1-2.9 1.9v1.5h3v.6H3.4C2.2 5.2 1.2 6 1.2 8.1s.9 2.9 2 2.9h1.2V9.3c0-1.2 1-2 2.1-2h3c1 0 1.7-.8 1.7-1.7V3.1c0-1-.9-1.9-3.2-1.9z' fill='%233776ab'/%3E%3Cpath d='M8 14.8c2.6 0 2.9-1.1 2.9-1.9v-1.5h-3v-.6h4.7c1.2 0 2.2-.8 2.2-2.9s-.9-2.9-2-2.9h-1.2v1.7c0 1.2-1 2-2.1 2h-3c-1 0-1.7.8-1.7 1.7v2.5c0 1 .9 1.9 3.2 1.9z' fill='%23ffd43b'/%3E%3Ccircle cx='6.3' cy='2.8' r='.6' fill='%23fff'/%3E%3Ccircle cx='9.7' cy='13.2' r='.6' fill='%23fff'/%3E%3C/svg%3E"); }
/* pygame's default window icon: its little snake */
.bar__app--pg { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.2 13.4c2.6.4 3.4-1.4 4.6-3.3 1.1-1.8 2.5-3.2 5.6-2.9' fill='none' stroke='%232f7d32' stroke-width='2.6' stroke-linecap='round'/%3E%3Cpath d='M2.4 13.2c2.4.2 3.1-1.3 4.2-3' fill='none' stroke='%23f2d23c' stroke-width='.9' stroke-linecap='round'/%3E%3Cellipse cx='12.6' cy='6.3' rx='2.7' ry='2.2' fill='%232f7d32'/%3E%3Ccircle cx='13.4' cy='5.6' r='.65' fill='%23fff'/%3E%3Cpath d='M15.2 6.6h.8' stroke='%23d33' stroke-width='.6'/%3E%3C/svg%3E"); }
.bar__app--etap { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1' y='1' width='14' height='14' rx='2.5' fill='%231b6fb5'/%3E%3Cpath d='M4.6 8.3h6.6c0-2-1.3-3.4-3.2-3.4S4.6 6.4 4.6 8.2 6 11.5 8 11.5c1.3 0 2.2-.5 2.8-1.4' fill='none' stroke='%23fff' stroke-width='1.5'/%3E%3C/svg%3E"); }
.bar__app--cds { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1' y='1' width='14' height='14' rx='2.5' fill='%23d52b1e'/%3E%3Cpath d='M11.2 5.2a4 4 0 1 0 0 5.6' fill='none' stroke='%23fff' stroke-width='1.9'/%3E%3C/svg%3E"); }
/* PuTTY: a terminal with a lightning bolt through it */
.bar__app--putty { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1.5' y='2' width='11' height='9' rx='.8' fill='%23c9c9c9' stroke='%23777' stroke-width='.5'/%3E%3Crect x='2.7' y='3.2' width='8.6' height='6.4' fill='%23121212'/%3E%3Cpath d='M4.3 12.4h5.4v1.4H4.3z' fill='%23999'/%3E%3Cpath d='M11 1 7.4 7.6h2.4L7.9 15l6-9h-2.6L13.5 1z' fill='%23ffd21f' stroke='%238a6d00' stroke-width='.5'/%3E%3C/svg%3E"); }
/* Matplotlib's logo, which Tk figure windows use */
.bar__app--mpl { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='7' fill='%23fff' stroke='%23999' stroke-width='.6'/%3E%3Cpath d='M8 8V1.8a6.2 6.2 0 0 1 5.4 3.1z' fill='%2311557c'/%3E%3Cpath d='M8 8l3.8-2.2a4.4 4.4 0 0 1 .3 3.6z' fill='%23ffa500'/%3E%3Cpath d='M8 8l2.9 3.5a4.5 4.5 0 0 1-5.1.5z' fill='%234c9d4c'/%3E%3Cpath d='M8 8 3.1 10.1a5.3 5.3 0 0 1 .8-5.6z' fill='%232b83ba'/%3E%3C/svg%3E"); }
/* KiCad's PCB Editor */
.bar__app--kicad { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1' y='2' width='14' height='12' rx='1.2' fill='%23156b3a'/%3E%3Cpath d='M3.5 5h3.2l2.2 2.2h3.6M3.5 11h4.3l1.6-1.6h3.1' fill='none' stroke='%23e8a948' stroke-width='1.1'/%3E%3Ccircle cx='3.5' cy='5' r='1.1' fill='%23f1d28a'/%3E%3Ccircle cx='3.5' cy='11' r='1.1' fill='%23f1d28a'/%3E%3Ccircle cx='12.5' cy='7.2' r='1.1' fill='%23f1d28a'/%3E%3Ccircle cx='12.5' cy='9.4' r='1.1' fill='%23f1d28a'/%3E%3C/svg%3E"); }

/* The menu bar, where the real window has one */
.mnu {
  flex: none;
  display: flex;
  align-items: center;
  gap: 2.1cqw;
  height: 3.9cqw;
  padding: 0 1.9cqw;
  background: #fff;
  font: 400 1.95cqw/1 var(--f-ui);
  color: #1b1b1b;
  white-space: nowrap;
  overflow: hidden;
}

.mnu b {
  font-weight: 400;
}

/* ---------- Chrome on Windows ---------- */
.br__tabs {
  flex: none;
  display: flex;
  align-items: flex-end;
  height: 6.2cqw;
  padding-left: 2cqw;
  background: #dfe3ea;
}

.br__tab {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1.2cqw;
  align-self: stretch;
  width: 32cqw;
  margin-top: 1.2cqw;
  padding: 0 1.3cqw 0 2cqw;
  border-radius: 1.4cqw 1.4cqw 0 0;
  background: #fff;
  font: 400 1.95cqw/1 var(--f-ui);
  color: #1f1f1f;
}

.br__tab > span {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
}

/* The curves where the open tab flows into the toolbar */
.br__tab::before,
.br__tab::after {
  content: "";
  position: absolute;
  bottom: 0;
  width: 1.4cqw;
  height: 1.4cqw;
}

.br__tab::before {
  right: 100%;
  background: radial-gradient(1.4cqw at 0 0, transparent 97%, #fff);
}

.br__tab::after {
  left: 100%;
  background: radial-gradient(1.4cqw at 100% 0, transparent 97%, #fff);
}

/* Flask serves no favicon, so Chrome shows its plain globe */
.br__fav {
  flex: none;
  width: 2.2cqw;
  height: 2.2cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%235f6368' stroke-width='1.2'%3E%3Ccircle cx='8' cy='8' r='6.3'/%3E%3Cellipse cx='8' cy='8' rx='2.6' ry='6.3'/%3E%3Cpath d='M1.8 8h12.4M2.9 4.9h10.2M2.9 11.1h10.2'/%3E%3C/svg%3E") center / contain no-repeat;
}

.br__x,
.br__new {
  flex: none;
  width: 1.9cqw;
  height: 1.9cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='%23474747' stroke-width='1'%3E%3Cpath d='M2.5 2.5l5 5m0-5-5 5'/%3E%3C/svg%3E") center / contain no-repeat;
}

.br__new {
  align-self: center;
  margin: 0.6cqw 0 0 2cqw;
  width: 2.2cqw;
  height: 2.2cqw;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='%23474747' stroke-width='.9'%3E%3Cpath d='M5 1.5v7M1.5 5h7'/%3E%3C/svg%3E");
}

.br__tabs .bar__ctl {
  margin-left: auto;
}

.br__url {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.8cqw;
  height: 6.2cqw;
  padding: 0 1.6cqw 0 2cqw;
  background: #fff;
  border-bottom: 1px solid #e1e3e6;
}

/* Back, forward (nowhere to go), reload */
.br__nav {
  flex: none;
  width: 11cqw;
  height: 2.3cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 66 14' fill='none' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 7H2.5M7 2.5 2.5 7 7 11.5' stroke='%23474747'/%3E%3Cpath d='M26 7h9.5M31 2.5 35.5 7 31 11.5' stroke='%23bdbdbd'/%3E%3Cpath d='M62 7a5.2 5.2 0 1 1-1.6-3.8M61 1.6v2.8h-2.8' stroke='%23474747'/%3E%3C/svg%3E") left center / contain no-repeat;
}

.br__addr {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 1cqw;
  height: 4.3cqw;
  padding: 0 1.6cqw 0 1.2cqw;
  border-radius: 2.2cqw;
  background: #edf1f7;
  font: 400 2cqw/1 var(--f-ui);
  color: #1f1f1f;
  white-space: nowrap;
}

/* Plain http, so Chrome says so before the address */
.br__ns {
  display: flex;
  align-items: center;
  gap: 0.7cqw;
  padding: 0.7cqw 1.2cqw 0.7cqw 0.8cqw;
  border-radius: 1.6cqw;
  color: #474747;
}

.br__ns::before {
  content: "";
  width: 2cqw;
  height: 2cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23474747' stroke-width='1.3'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M8 7v4.4'/%3E%3Ccircle cx='8' cy='4.7' r='.4' fill='%23474747'/%3E%3C/svg%3E") center / contain no-repeat;
}

.br__star {
  margin-left: auto;
  width: 2.1cqw;
  height: 2.1cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23474747' stroke-width='1.2' stroke-linejoin='round'%3E%3Cpath d='M8 1.8l1.9 4 4.3.5-3.2 3 .9 4.3L8 11.5l-3.9 2.1.9-4.3-3.2-3 4.3-.5z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Profile picture and the three-dot menu */
.br__me {
  flex: none;
  width: 7cqw;
  height: 2.6cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 16'%3E%3Ccircle cx='10' cy='8' r='7' fill='%23b6572f'/%3E%3Ctext x='10' y='11.2' font-family='Segoe UI,Arial' font-size='9' fill='%23fff' text-anchor='middle'%3EM%3C/text%3E%3Cg fill='%23474747'%3E%3Ccircle cx='35' cy='3.5' r='1.3'/%3E%3Ccircle cx='35' cy='8' r='1.3'/%3E%3Ccircle cx='35' cy='12.5' r='1.3'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
}

/* The Windows arrow pointer, with the system's soft cursor shadow. It's sized against
   the 9 pt UI font the way it is on a 100 % display (js/previews/pointer.js moves it). */
.ptr {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 40;
  width: 1.92cqw;
  height: 3.1cqw;
  margin: -0.07cqw 0 0 -0.07cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 21'%3E%3Cpath d='M.5.5v16.4l3.8-3.7 2.6 6.1 2.4-1-2.6-6h5.4z' fill='%23fff' stroke='%23000' stroke-width='1'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
  filter: drop-shadow(0.12cqw 0.22cqw 0.14cqw rgb(0 0 0 / 0.32));
  pointer-events: none;
  will-change: transform;
}

/* A plain Windows tooltip, which shows up under the pointer after a short hover */
.ptr__tip {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 39;
  padding: 0.35cqw 0.9cqw 0.45cqw;
  border: 1px solid #767676;
  background: #fff;
  box-shadow: 0.2cqw 0.2cqw 0.5cqw rgb(0 0 0 / 0.18);
  font: 400 1.85cqw/1.2 var(--f-ui);
  color: #1b1b1b;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.12s;
  pointer-events: none;
}

.ptr__tip.is-on {
  opacity: 1;
}

/* ---------- Entrance, pausing, reduced motion ---------- */

/* The window rises onto the page a beat after its card appears */
@media (prefers-reduced-motion: no-preference) {
  .js .project[data-reveal] .pv > * {
    opacity: 0;
    translate: 0 4cqw;
    transition: opacity 0.6s 0.25s, translate 0.9s 0.2s var(--ease-out), transform 0.7s var(--ease-out);
  }

  .js .project.is-visible .pv > * {
    opacity: 1;
    translate: 0 0;
  }
}

/* Nothing loops while it's off screen */
.js .pv:not(.is-live) *,
.js .pv:not(.is-live) *::before,
.js .pv:not(.is-live) *::after {
  animation-play-state: paused !important;
}

@media (prefers-reduced-motion: reduce) {
  .pv *,
  .pv *::before,
  .pv *::after {
    animation: none !important;
  }
}

/* ==========================================================================
   Boost converter: a Simulink Scope, as it looks while the model runs
   ========================================================================== */

.sl {
  background: #f0f0f0;
  --sl-bg: #141414;
  --i-cfg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='none' stroke='%235a5a5a'%3E%3Ccircle cx='8' cy='8' r='2.3' stroke-width='1.4'/%3E%3Cpath d='M8 1.6v2.2M8 12.2v2.2M1.6 8h2.2M12.2 8h2.2M3.5 3.5 5 5M11 11l1.5 1.5M3.5 12.5 5 11M11 5l1.5-1.5' stroke-width='1.8'/%3E%3C/g%3E%3C/svg%3E");
  --i-style: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 13.5c0-2.2 1.2-3.4 2.8-3.4 1.4 0 2.3 1 1.6 2.4-.8 1.6-3.2 1.6-4.4 1z' fill='%23d8452c'/%3E%3Cpath d='M6.4 10.2 13 3.1' stroke='%238a6a3c' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  --i-run: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 2.4 13.2 8 4 13.6z' fill='%2323a034' stroke='%2315701f' stroke-width='.6' stroke-linejoin='round'/%3E%3C/svg%3E");
  --i-pause: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 3h3v10H4zM9 3h3v10H9z' fill='%232f7fd1'/%3E%3C/svg%3E");
  --i-stepf: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3 10 8l-7 5z' fill='%2323a034'/%3E%3Cpath d='M11 3h2v10h-2z' fill='%2323a034'/%3E%3C/svg%3E");
  --i-stop: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='3.5' y='3.5' width='9' height='9' fill='%234f4f4f'/%3E%3C/svg%3E");
  --i-stopoff: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='3.5' y='3.5' width='9' height='9' fill='%23c9c9c9'/%3E%3C/svg%3E");
  --i-zoom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='6.6' cy='6.6' r='4.3' fill='%23e3f0fc' stroke='%233c3c3c' stroke-width='1.3'/%3E%3Cpath d='M9.8 9.8 14 14' stroke='%233c3c3c' stroke-width='2.1' stroke-linecap='round'/%3E%3C/svg%3E");
  --i-scale: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='4.5' y='4.5' width='7' height='7' fill='%23fff' stroke='%235a5a5a'/%3E%3Cpath d='M1.5 1.5l2.5 2.5M14.5 1.5 12 4M1.5 14.5 4 12M14.5 14.5 12 12' stroke='%232f7fd1' stroke-width='1.3'/%3E%3Cpath d='M1.5 1.5h2.2M1.5 1.5v2.2M14.5 1.5h-2.2M14.5 1.5v2.2M1.5 14.5h2.2M1.5 14.5v-2.2M14.5 14.5h-2.2M14.5 14.5v-2.2' stroke='%232f7fd1' stroke-width='1.1'/%3E%3C/svg%3E");
  --i-trig: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M1.5 11.5h3l2-7h3l2 7h3' fill='none' stroke='%233c3c3c' stroke-width='1.2'/%3E%3Cpath d='M8 1.5v13' stroke='%23d8452c' stroke-width='1' stroke-dasharray='1.6 1.2'/%3E%3C/svg%3E");
  --i-cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M5 1.5v13M11 1.5v13' stroke='%233c3c3c' stroke-width='1.1'/%3E%3Cpath d='M5 8h6' stroke='%232f7fd1' stroke-width='1.2'/%3E%3Cpath d='M6.6 6.6 5 8l1.6 1.4M9.4 6.6 11 8 9.4 9.4' fill='none' stroke='%232f7fd1' stroke-width='1.1'/%3E%3C/svg%3E");
  --i-stats: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 14h12' stroke='%233c3c3c'/%3E%3Cpath d='M3.5 13V8M6.5 13V4M9.5 13V6M12.5 13V9.5' stroke='%232f7fd1' stroke-width='2'/%3E%3C/svg%3E");
  --i-block: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='7.5' y='6.5' width='7' height='6' fill='%23fff' stroke='%233c3c3c'/%3E%3Cpath d='M1.5 3.5c3 0 5 1.5 5.2 4.6' fill='none' stroke='%23e89a1c' stroke-width='1.3'/%3E%3Cpath d='M4.8 7.3 6.8 9.4l1.6-2.4' fill='none' stroke='%23e89a1c' stroke-width='1.3'/%3E%3C/svg%3E");
}

.sl .mnu {
  background: #f0f0f0;
}

/* Settings, style | run, step, stop | zoom, scale | triggers, cursors, stats | find block */
.sl__tools {
  flex: none;
  display: flex;
  gap: 1.05cqw;
  align-items: center;
  height: 4.4cqw;
  padding: 0 1.8cqw;
  border-bottom: 1px solid #d4d4d4;
}

.sl__tools i {
  flex: none;
  width: 2.3cqw;
  height: 2.3cqw;
  background: var(--g) center / contain no-repeat;
}

.sl__tools i:nth-child(1) { --g: var(--i-cfg); }
.sl__tools i:nth-child(2) { --g: var(--i-style); margin-right: 1.4cqw; }
.sl__tools i:nth-child(3) { --g: var(--i-run); }
.sl__tools i:nth-child(4) { --g: var(--i-stepf); }
.sl__tools i:nth-child(5) { --g: var(--i-stopoff); margin-right: 1.4cqw; }
.sl__tools i:nth-child(6) { --g: var(--i-zoom); }
.sl__tools i:nth-child(7) { --g: var(--i-scale); margin-right: 1.4cqw; }
.sl__tools i:nth-child(8) { --g: var(--i-trig); }
.sl__tools i:nth-child(9) { --g: var(--i-cursor); }
.sl__tools i:nth-child(10) { --g: var(--i-stats); margin-right: 1.4cqw; }
.sl__tools i:nth-child(11) { --g: var(--i-block); }
.sl__tools i:nth-child(12) { display: none; }

/* Toolbar hot-tracking under the pointer, and the pressed state */
.sl__tools i.is-hover {
  background-color: #e5f3ff;
  box-shadow: 0 0 0 0.45cqw #e5f3ff, 0 0 0 calc(0.45cqw + 1px) #cce8ff;
}

.sl__tools i.is-down {
  background-color: #cce8ff;
  box-shadow: 0 0 0 0.45cqw #cce8ff, 0 0 0 calc(0.45cqw + 1px) #99d1ff;
}

.sl__plots {
  position: relative;
  flex: 1;
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 2.2cqw;
  padding: 1.8cqw 2.4cqw 4.6cqw 5.8cqw;
  background: var(--sl-bg);
}

.sl__ax {
  position: relative;
  border: 1px solid #6e6e6e;
  background: #000;
}

.sl__ax > svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* Grid lines on the ticks: every 5 ms across, four rows down */
.sl__ax::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background-image:
    linear-gradient(90deg, rgb(255 255 255 / 0.17) 1px, transparent 1px),
    linear-gradient(rgb(255 255 255 / 0.17) 1px, transparent 1px);
  background-size: 12.5% 100%, 100% 25%;
  pointer-events: none;
}

/* The black wipe that uncovers the traces as the sim runs */
.sl__ax::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #000;
  transform: scaleX(0);
  transform-origin: 100% 50%;
}

/* At 100 kHz the switching ripple is too fast to resolve, so each trace is a solid band */
.sl__v,
.sl__i {
  stroke-width: 1.3;
}

.sl__v { fill: #ffff11; stroke: #ffff11; }
.sl__i { fill: #1aa3ff; stroke: #1aa3ff; }

/* The whole scope fits, down to its status bar */
.pv .sl {
  top: 5.2cqw;
  height: 54cqw;
}

.sl__y,
.sl__x {
  position: absolute;
  display: flex;
  justify-content: space-between;
  font: 400 1.7cqw/1 var(--f-plot);
  color: #d0d0d0;
}

.sl__y {
  top: -0.85cqw;
  bottom: -0.85cqw;
  right: calc(100% + 0.9cqw);
  flex-direction: column;
  align-items: flex-end;
}

.sl__x {
  top: calc(100% + 0.8cqw);
  left: 0;
  right: 0;
}

.sl__x b {
  width: 0;
  display: flex;
  justify-content: center;
}

.sl__y b,
.sl__x b {
  font-weight: 400;
}

.sl__off {
  position: absolute;
  left: 1.2cqw;
  bottom: 0.9cqw;
  font: 400 1.6cqw/1 var(--f-plot);
  color: #d0d0d0;
}

.sl__lg {
  position: absolute;
  z-index: 4;
  top: 0.9cqw;
  right: 0.9cqw;
  display: flex;
  align-items: center;
  gap: 0.8cqw;
  padding: 0.35cqw 0.9cqw;
  border: 1px solid #8a8a8a;
  background: #000;
  font: 400 1.7cqw/1 var(--f-plot);
  color: #e6e6e6;
}

.sl__lg i {
  width: 2.6cqw;
  height: 0.3cqw;
  background: #ffff11;
}

.sl__lg sub {
  font-size: 0.72em;
  vertical-align: -0.25em;
  line-height: 0;
}

.sl__lg--i i {
  background: #1aa3ff;
}

.sl__status {
  flex: none;
  display: flex;
  align-items: center;
  gap: 2cqw;
  height: 4.2cqw;
  padding: 0 2cqw;
  border-top: 1px solid #d4d4d4;
  font: 400 1.8cqw/1 var(--f-ui);
  color: #444;
}

.sl__state {
  display: grid;
}

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

.sl__busy {
  opacity: 0;
}

.sl__t {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

.sl__t::after {
  content: "0.040";
}

@property --sl-t {
  syntax: "<integer>";
  inherits: false;
  initial-value: 40;
}

/* One run every 9 s: Run turns into Pause and Stop wakes up while the model runs */
@media (prefers-reduced-motion: no-preference) {
  .js .sl__ax::before {
    animation: sl-wipe 9s linear infinite;
  }

  .js .sl__ax svg {
    animation: sl-fade 9s linear infinite;
  }

  .js .sl__tools i:nth-child(3) {
    animation: sl-run 9s steps(1) infinite;
  }

  .js .sl__tools i:nth-child(5) {
    animation: sl-stop 9s steps(1) infinite;
  }

  .js .sl__t {
    counter-reset: t var(--sl-t);
    animation: sl-time 9s linear infinite;
  }

  .js .sl__t::after {
    content: "0.0" counter(t, decimal-leading-zero);
  }

  .js .sl__ready { animation: sl-ready 9s steps(1) infinite; }
  .js .sl__busy { animation: sl-busy 9s steps(1) infinite; }
}

@keyframes sl-wipe {
  0%, 5% { transform: scaleX(1); }
  38%, 100% { transform: scaleX(0); }
}

@keyframes sl-fade {
  0%, 93% { opacity: 1; }
  99%, 100% { opacity: 0; }
}

@keyframes sl-time {
  0%, 5% { --sl-t: 0; }
  38%, 100% { --sl-t: 40; }
}

@keyframes sl-run {
  0% { --g: var(--i-run); }
  5% { --g: var(--i-pause); }
  38% { --g: var(--i-run); }
}

@keyframes sl-stop {
  0% { --g: var(--i-stopoff); }
  5% { --g: var(--i-stop); }
  38% { --g: var(--i-stopoff); }
}

@keyframes sl-ready {
  0% { opacity: 1; }
  5% { opacity: 0; }
  38% { opacity: 1; }
}

@keyframes sl-busy {
  0% { opacity: 0; }
  5% { opacity: 1; }
  38% { opacity: 0; }
}

/* ==========================================================================
   PID motor: the firmware's UART log in PuTTY, and a live matplotlib plot
   ========================================================================== */

/* PuTTY with its defaults: Courier New, grey on black, a green block cursor */
.pv .tty {
  inset: 4.6cqw auto auto 3.5cqw;
  width: 52cqw;
  height: 40cqw;
  background: #000;
}

.tty__scr {
  position: relative;
  flex: 1;
  overflow: hidden;
  border-right: 1.5cqw solid #f0f0f0;
}

/* The scrollbar's thumb, down at the bottom where new lines come in */
.tty__scr::after {
  content: "";
  position: absolute;
  right: -1.15cqw;
  bottom: 0.4cqw;
  width: 0.8cqw;
  height: 5.5cqw;
  border-radius: 0.4cqw;
  background: #8a8a8a;
}

.tty__out {
  position: absolute;
  left: 0.5cqw;
  bottom: 0;
  margin: 0;
  font: 400 1.75cqw/1.2 "Courier New", Courier, monospace;
  color: #bbb;
  white-space: pre;
}

.tty__out::after {
  content: "";
  display: inline-block;
  width: 0.6em;
  height: 1.12em;
  vertical-align: -0.2em;
  background: #0f0;
}

/* Matplotlib's Tk window: white canvas, toolbar along the bottom */
.pv .mpl {
  inset: 10.4cqw auto auto 34cqw;
  width: 62.5cqw;
  height: 46.6cqw;
  z-index: 1;
  --mpl-tools: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 174 16'%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M2.2 8.2 8 2.6l5.8 5.6M4 6.8v6.9h8V6.8' fill='none' stroke='%23000' stroke-width='1.1' stroke-linejoin='round'/%3E%3Cpath d='M6.8 13.7V10h2.4v3.7' fill='none' stroke='%23000'/%3E%3C/g%3E%3Cg transform='translate(22 0)'%3E%3Cpath d='M13.5 8H3M7.2 3.8 3 8l4.2 4.2' fill='none' stroke='%23000' stroke-width='1.3' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(44 0)'%3E%3Cpath d='M2.5 8H13M8.8 3.8 13 8l-4.2 4.2' fill='none' stroke='%23000' stroke-width='1.3' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(76 0)'%3E%3Cpath d='M8 1.5v13M1.5 8h13' stroke='%23000' stroke-width='1.1'/%3E%3Cpath d='M6 3.5 8 1.5l2 2M6 12.5l2 2 2-2M3.5 6 1.5 8l2 2M12.5 6l2 2-2 2' fill='none' stroke='%23000' stroke-width='1.1'/%3E%3C/g%3E%3Cg transform='translate(98 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.4' fill='none' stroke='%23000' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14.2 14.2' stroke='%23000' stroke-width='1.7'/%3E%3Crect x='4.6' y='4.6' width='4' height='4' fill='none' stroke='%23000' stroke-width='.8' stroke-dasharray='1 .8'/%3E%3C/g%3E%3Cg transform='translate(120 0)'%3E%3Cpath d='M1.8 4h12.4M1.8 8h12.4M1.8 12h12.4' stroke='%23000' stroke-width='1'/%3E%3Crect x='4' y='2.5' width='2.2' height='3' fill='%23fff' stroke='%23000' stroke-width='.9'/%3E%3Crect x='9.6' y='6.5' width='2.2' height='3' fill='%23fff' stroke='%23000' stroke-width='.9'/%3E%3Crect x='6' y='10.5' width='2.2' height='3' fill='%23fff' stroke='%23000' stroke-width='.9'/%3E%3C/g%3E%3Cg transform='translate(152 0)'%3E%3Cpath d='M2.5 2.5h9l2 2v9h-11z' fill='none' stroke='%23000' stroke-width='1.1' stroke-linejoin='round'/%3E%3Cpath d='M5 2.5V6h5.2V2.5M4.6 13.5V9.6h6.8v3.9' fill='none' stroke='%23000'/%3E%3C/g%3E%3C/svg%3E");
}

.mpl__canvas {
  position: relative;
  flex: 1;
  background: #fff;
  font: 400 1.6cqw/1 "DejaVu Sans", Verdana, sans-serif;
  color: #000;
}

.mpl__tb {
  flex: none;
  height: 4.2cqw;
  border-top: 1px solid #dcdcdc;
  background: #f0f0f0 var(--mpl-tools) 1.6cqw 50% / auto 2.3cqw no-repeat;
}

.mpl__ax {
  position: absolute;
  inset: 2.2cqw 2.4cqw 6.6cqw 10.4cqw;
  border: 1px solid #000;
}

.mpl__ax > svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.mpl__grid {
  fill: none;
  stroke: #b0b0b0;
  stroke-width: 0.8;
}

/* C0 for the speed, C1 dashed for the setpoint */
.mpl__w,
.mpl__set {
  fill: none;
  stroke-width: 1.5;
}

.mpl__w { stroke: #1f77b4; }
.mpl__set { stroke: #ff7f0e; stroke-dasharray: 5.5 2.4; stroke-linecap: butt; }

.mpl__legend {
  position: absolute;
  z-index: 2;
  top: 0.9cqw;
  right: 0.9cqw;
  display: grid;
  gap: 0.5cqw;
  padding: 0.6cqw 0.9cqw;
  border: 1px solid #ccc;
  border-radius: 0.5cqw;
  background: rgb(255 255 255 / 0.8);
  white-space: nowrap;
}

.mpl__legend span {
  display: flex;
  align-items: center;
  gap: 0.9cqw;
}

.mpl__legend i {
  width: 3.2cqw;
  border-top: 0.3cqw solid #1f77b4;
}

.mpl__legend i.d {
  border-top: 0.3cqw dashed #ff7f0e;
}

.mpl__xt,
.mpl__yt {
  position: absolute;
  inset: 0;
}

.mpl__xt b,
.mpl__yt b {
  position: absolute;
  font-weight: 400;
  white-space: nowrap;
}

/* Ticks point outwards */
.mpl__xt b {
  top: calc(100% + 1.2cqw);
  left: calc(var(--x) * 1%);
  translate: -50% 0;
}

.mpl__xt b::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -1.2cqw;
  height: 0.75cqw;
  border-left: 1px solid #000;
}

.mpl__yt b {
  right: calc(100% + 1.2cqw);
  top: calc(var(--y) * 1%);
  translate: 0 -50%;
}

.mpl__yt b::after {
  content: "";
  position: absolute;
  right: -1.2cqw;
  top: 50%;
  width: 0.75cqw;
  border-top: 1px solid #000;
}

.mpl__xl,
.mpl__yl {
  position: absolute;
  font-size: 1.7cqw;
  white-space: nowrap;
}

.mpl__xl {
  left: 50%;
  top: calc(100% + 3.8cqw);
  translate: -50% 0;
}

.mpl__yl {
  right: calc(100% + 7.6cqw);
  top: 50%;
  translate: 50% -50%;
  rotate: -90deg;
}

/* ==========================================================================
   Smart power meter: the Flask dashboard on the Pi
   ========================================================================== */

/* A Bootstrap page, the way it looks before anyone themes it */
.fl {
  flex: 1;
  background: #f8f9fa;
  font: 400 1.75cqw/1.3 var(--f-ui);
  color: #212529;
}

.fl__nav {
  display: flex;
  align-items: center;
  gap: 2.4cqw;
  height: 5.4cqw;
  padding: 0 2.6cqw;
  background: #212529;
  color: rgb(255 255 255 / 0.55);
  white-space: nowrap;
}

.fl__nav b {
  margin-right: 0.8cqw;
  font-size: 2.3cqw;
  font-weight: 400;
  color: #fff;
}

.fl__nav .on {
  color: #fff;
}

.fl__nav small {
  margin-left: auto;
  font-size: 1.55cqw;
  font-variant-numeric: tabular-nums;
}

.fl__body {
  padding: 1.9cqw 2.6cqw;
}

.fl__tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.6cqw;
}

.fl__tiles > div,
.fl__card {
  border: 1px solid rgb(0 0 0 / 0.175);
  border-radius: 0.8cqw;
  background: #fff;
}

.fl__tiles > div {
  padding: 0.9cqw 1.4cqw 1cqw;
}

.fl__tiles h6 {
  margin: 0 0 0.3cqw;
  font-size: 1.5cqw;
  font-weight: 400;
  color: #6c757d;
}

.fl__tiles b {
  font-size: 2.6cqw;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.fl__card {
  margin-top: 1.6cqw;
}

/* Chart.js with the defaults: grey 12px Helvetica, a bold title, a boxed legend, dots on every point */
.fl__chart {
  padding: 1.1cqw 2.4cqw 4.2cqw 1.6cqw;
  font: 400 1.5cqw/1 "Helvetica Neue", Helvetica, Arial, sans-serif;
  color: #666;
}

.fl__ti {
  margin-bottom: 0.9cqw;
  font-weight: 700;
  text-align: center;
}

.fl__lg {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.9cqw;
  margin-bottom: 1.3cqw;
}

.fl__lg i {
  width: 4cqw;
  height: 1.3cqw;
  border: 0.32cqw solid rgb(75 192 192);
  background: rgb(0 0 0 / 0.1);
}

.fl__plot {
  position: relative;
  height: 12cqw;
  margin-left: 4.6cqw;
  border-left: 1px solid rgb(0 0 0 / 0.25);
  border-bottom: 1px solid rgb(0 0 0 / 0.25);
}

.fl__plot svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.fl__grid {
  fill: none;
  stroke: rgb(0 0 0 / 0.1);
  stroke-width: 1;
}

.fl__line {
  fill: none;
  stroke: rgb(75 192 192);
  stroke-width: 2.4;
}

/* Zero-length round caps: dots that stay round however the SVG stretches */
.fl__pts {
  fill: none;
  stroke: rgb(75 192 192);
  stroke-width: 5.5;
}

.fl__pts--in {
  stroke: #e9f4f4;
  stroke-width: 3.3;
}

/* The hovered point: radius 3 becomes hoverRadius 4, and the fill darkens a touch */
.fl__hov {
  fill: none;
  stroke: rgb(75 192 192);
  stroke-width: 7.5;
}

.fl__hov--in {
  stroke: #d5e8e8;
  stroke-width: 5.3;
}

/* Chart.js's default tooltip: 80 % black, 6 px padding and corners, a 5 px caret
   2 px off the point, bold title, then a colour box and the label (12 px = 1.5cqw) */
.cj__tip {
  --px: 0.125cqw;
  position: absolute;
  z-index: 5;
  margin-left: calc(7 * var(--px));
  padding: calc(6 * var(--px));
  border-radius: calc(6 * var(--px));
  background: rgb(0 0 0 / 0.8);
  color: #fff;
  font: 400 1.5cqw/1 "Helvetica Neue", Helvetica, Arial, sans-serif;
  white-space: nowrap;
  translate: 0 -50%;
  visibility: hidden;
}

.cj__tip:not(.is-right) {
  margin: 0 calc(7 * var(--px)) 0 0;
}

.cj__tip.is-on {
  visibility: visible;
}

.cj__tip::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  border: calc(5 * var(--px)) solid transparent;
  border-right-color: rgb(0 0 0 / 0.8);
  border-left: 0;
  translate: 0 -50%;
}

.cj__tip:not(.is-right)::before {
  right: auto;
  left: 100%;
  border-right: 0;
  border-left: calc(5 * var(--px)) solid rgb(0 0 0 / 0.8);
}

.cj__tip b {
  display: block;
  margin-bottom: calc(6 * var(--px));
  font-weight: 700;
}

.cj__tip span {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--px));
}

.cj__tip i {
  width: 1.5cqw;
  height: 1.5cqw;
  border: 1px solid rgb(75 192 192);
  background: #e6e6e6;
}

.fl__yt,
.fl__xt {
  position: absolute;
  inset: 0;
}

.fl__yt b,
.fl__xt b {
  position: absolute;
  font-weight: 400;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.fl__yt b {
  right: calc(100% + 0.9cqw);
  top: calc(var(--y) * 1%);
  translate: 0 -50%;
}

.fl__xt b {
  top: calc(100% + 1cqw);
  left: calc(var(--x) * 1%);
  translate: -50% 0;
}

/* ==========================================================================
   Phones: the device frame from the app's own site (myjrnl.vercel.app)
   A silver frame, a punch-hole camera and the gesture bar. --u is one pixel
   of that 178 px mockup, so every size below is copied straight from it.
   ========================================================================== */

.dev {
  --u: calc(27.5cqw / 178);
  position: absolute;
  width: 27.5cqw;
  aspect-ratio: 178 / 384;
  overflow: hidden;
  border: calc(4 * var(--u)) solid #c8c8d0;
  border-radius: calc(36 * var(--u));
  background: #f5f5f7;
  box-shadow: 0 2.2cqw 4.4cqw -1.4cqw rgb(0 0 0 / 0.6);
  transition: transform 0.7s var(--ease-out);
}

.dev::before,
.dev::after {
  content: "";
  position: absolute;
  z-index: 3;
  left: 50%;
  translate: -50% 0;
  border-radius: 999px;
}

.dev::before {
  top: calc(9 * var(--u));
  width: calc(9 * var(--u));
  height: calc(9 * var(--u));
  background: #080810;
}

.dev::after {
  bottom: calc(7 * var(--u));
  width: calc(78 * var(--u));
  height: calc(3 * var(--u));
  background: rgb(142 142 147 / 0.55);
}

/* ==========================================================================
   My Journal: the Mood Statistics and Tasks screens, as the app draws them
   ========================================================================== */

.pv--journal .dev--front {
  left: 19.5cqw;
  top: 5cqw;
  z-index: 2;
}

.pv--journal .dev--back {
  left: 51.5cqw;
  top: 9cqw;
  rotate: 3deg;
}

.mj {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: calc(26 * var(--u)) calc(9 * var(--u)) 0;
  color: #1d1d1f;
  font: 400 calc(7 * var(--u)) / 1.3 -apple-system, "Segoe UI", Roboto, sans-serif;
}

.mj__title {
  margin-bottom: calc(9 * var(--u));
  font-size: calc(12 * var(--u));
  font-weight: 700;
  text-align: center;
  color: #1c1c1e;
}

.mj__label {
  margin: 0 0 calc(8 * var(--u));
  font-size: calc(8 * var(--u));
  font-weight: 700;
  color: #1c1c1e;
}

.mj__moods {
  display: grid;
  gap: calc(6.5 * var(--u));
}

.mj__moods li {
  display: flex;
  align-items: center;
  gap: calc(4.5 * var(--u));
  height: calc(17 * var(--u));
}

.mj__moods i {
  flex: none;
  display: grid;
  place-items: center;
  width: calc(17 * var(--u));
  height: calc(17 * var(--u));
  border-radius: calc(6 * var(--u));
  background: var(--t);
  font-style: normal;
  font-size: calc(9 * var(--u));
}

.mj__moods span {
  width: calc(30 * var(--u));
  font-size: calc(6 * var(--u));
  color: #6e6e73;
}

.mj__moods s {
  position: relative;
  flex: 1;
  height: calc(4 * var(--u));
  border-radius: 999px;
  background: #e5e5ea;
  overflow: hidden;
}

.mj__moods s::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--c);
  transform: scaleX(calc(var(--v) / 8));
  transform-origin: left;
}

.mj__moods b {
  width: calc(13 * var(--u));
  font-size: calc(6 * var(--u));
  font-weight: 700;
  text-align: right;
  color: var(--c);
}

.mj__total {
  margin: calc(8 * var(--u)) 0 0;
  padding: calc(8 * var(--u));
  border-radius: calc(12 * var(--u));
  background: #e8f4ee;
}

.mj__total small {
  display: block;
  margin-bottom: calc(2 * var(--u));
  font-size: calc(5.5 * var(--u));
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #16a34a;
}

.mj__total b {
  font-size: calc(20 * var(--u));
  font-weight: 800;
  line-height: 1.6;
  color: #15803d;
}

.mj__search {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--u));
  margin: 0 0 calc(7 * var(--u));
  padding: calc(4 * var(--u)) calc(8 * var(--u));
  border-radius: calc(12 * var(--u));
  background: #f2f2f7;
  font-size: calc(6 * var(--u));
  line-height: calc(10 * var(--u));
  color: #8e8e93;
}

.mj__search::before {
  content: "";
  width: calc(7 * var(--u));
  height: calc(7 * var(--u));
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2.5'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E") center / contain no-repeat;
}

.mj__tasks {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: calc(5 * var(--u));
}

.mj__tasks li {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(29 * var(--u));
  padding: 0 calc(9 * var(--u));
  border: 1px solid rgb(0 0 0 / 0.05);
  border-radius: calc(13 * var(--u));
  background: #fff;
  box-shadow: 0 calc(1 * var(--u)) calc(8 * var(--u)) rgb(0 0 0 / 0.06);
}

/* Done tasks sit a little apart, faded */
.mj__tasks .is-done {
  margin-top: calc(5 * var(--u));
  opacity: 0.6;
}

.mj__tasks li > i {
  flex: none;
  position: relative;
  width: calc(13 * var(--u));
  height: calc(13 * var(--u));
  border: calc(1.3 * var(--u)) solid #e5e5ea;
  border-radius: calc(4 * var(--u));
}

.mj__tasks li > i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='white' stroke-width='.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5.2 4.5 7 7.2 3'/%3E%3C/svg%3E") center / 100% no-repeat;
  opacity: 0;
}

.mj__tasks span {
  flex: 1;
  min-width: 0;
  font-size: calc(7.5 * var(--u));
  font-weight: 600;
  color: #1c1c1e;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mj__tasks em {
  flex: none;
  padding: calc(1.5 * var(--u)) calc(5 * var(--u));
  border-radius: 999px;
  font-style: normal;
  font-size: calc(5.5 * var(--u));
  font-weight: 700;
}

.mj__tasks .hi { background: rgb(255 107 0 / 0.14); color: #e84d00; }
.mj__tasks .med { background: rgb(255 200 0 / 0.16); color: #b87a00; }
.mj__tasks .lo { background: rgb(52 199 89 / 0.14); color: #15803d; }

.mj__tasks .is-done > i {
  border-color: #34c759;
  background: #34c759;
}

.mj__tasks .is-done > i::after {
  opacity: 1;
}

.mj__tasks .is-done span {
  color: #aeaeb2;
  text-decoration: line-through;
}

.mj__fab {
  position: absolute;
  right: calc(9 * var(--u));
  bottom: calc(56 * var(--u));
  width: calc(32 * var(--u));
  height: calc(32 * var(--u));
  border-radius: calc(12 * var(--u));
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' stroke='white' stroke-width='.55' stroke-linecap='round'%3E%3Cpath d='M5 2.6v4.8M2.6 5h4.8'/%3E%3C/svg%3E") center / 100% no-repeat, linear-gradient(140deg, #4ade80, #22c55e);
  box-shadow: 0 calc(4 * var(--u)) calc(20 * var(--u)) rgb(52 199 89 / 0.5);
}

/* Overview, Calendar, Add, Stats, Settings: the app's own tab bar */
.mj__nav {
  display: flex;
  justify-content: space-around;
  align-items: center;
  margin: auto calc(-9 * var(--u)) 0;
  height: calc(52 * var(--u));
  padding-bottom: calc(7 * var(--u));
  border-top: 1px solid rgb(0 0 0 / 0.08);
  background: #fff;
}

.mj__nav span {
  display: grid;
  justify-items: center;
  gap: calc(2 * var(--u));
  font-size: calc(4.3 * var(--u));
  font-weight: 600;
  color: #8e8e93;
}

.mj__nav .is-on {
  color: #34c759;
}

.mj__ic {
  width: calc(16 * var(--u));
  height: calc(16 * var(--u));
  background: currentColor;
  -webkit-mask: var(--m) center / contain no-repeat;
  mask: var(--m) center / contain no-repeat;
}

.mj__ic--home { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'/%3E%3C/svg%3E"); }
.mj__ic--cal { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'%3E%3Crect x='3.5' y='5' width='17' height='15.5' rx='2.5'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E"); }
.mj__ic--add { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 8v8M8 12h8'/%3E%3C/svg%3E"); }
.mj__ic--stats { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='14' width='4.5' height='7' rx='1.5'/%3E%3Crect x='9.75' y='9' width='4.5' height='12' rx='1.5'/%3E%3Crect x='16.5' y='4' width='4.5' height='17' rx='1.5'/%3E%3C/svg%3E"); }
.mj__ic--gear { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z'/%3E%3C/svg%3E"); }

@media (prefers-reduced-motion: no-preference) {
  /* Bars fill once the card is on screen */
  .js .project[data-reveal] .mj__moods s::before {
    transform: scaleX(0);
    transition: transform 1s var(--ease-out);
  }

  .js .project.is-visible .mj__moods s::before {
    transform: scaleX(calc(var(--v) / 8));
  }

  .js .project.is-visible .mj__moods li:nth-child(2) s::before { transition-delay: 0.08s; }
  .js .project.is-visible .mj__moods li:nth-child(3) s::before { transition-delay: 0.16s; }
  .js .project.is-visible .mj__moods li:nth-child(4) s::before { transition-delay: 0.24s; }
  .js .project.is-visible .mj__moods li:nth-child(5) s::before { transition-delay: 0.32s; }
  .js .project.is-visible .mj__moods li:nth-child(6) s::before { transition-delay: 0.4s; }
  .js .project.is-visible .mj__moods li:nth-child(7) s::before { transition-delay: 0.48s; }

  /* Someone ticks a task off, then changes their mind */
  .js .mj__tick {
    animation: mj-row 7s infinite;
  }

  .js .mj__tick > i {
    animation: mj-check 7s infinite;
  }

  .js .mj__tick > i::after {
    animation: mj-mark 7s infinite;
  }

  .js .mj__tick span {
    animation: mj-strike 7s infinite;
  }
}

@keyframes mj-row {
  0%, 38% { opacity: 1; }
  44%, 84% { opacity: 0.6; }
  90%, 100% { opacity: 1; }
}

@keyframes mj-check {
  0%, 36% { background: transparent; border-color: #e5e5ea; }
  38%, 86% { background: #34c759; border-color: #34c759; }
  88%, 100% { background: transparent; border-color: #e5e5ea; }
}

@keyframes mj-mark {
  0%, 36% { opacity: 0; }
  38%, 86% { opacity: 1; }
  88%, 100% { opacity: 0; }
}

@keyframes mj-strike {
  0%, 36% { color: #1c1c1e; text-decoration: none; }
  38%, 86% { color: #aeaeb2; text-decoration: line-through; }
  88%, 100% { color: #1c1c1e; text-decoration: none; }
}

/* ==========================================================================
   MATLAB figure windows (MPPT, inverter, power quality)
   Default figure: grey background, white axes at MATLAB's subplot positions,
   Helvetica, the default colour order, grid on.
   ========================================================================== */

.ml {
  background: #f0f0f0;
  --ml-tools: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 344 16'%3E%3Cdefs%3E%3ClinearGradient id='pa' x1='0' y1='1' x2='0' y2='0'%3E%3Cstop offset='0' stop-color='%23352a87'/%3E%3Cstop offset='.35' stop-color='%230f8bd9'/%3E%3Cstop offset='.65' stop-color='%2358bc82'/%3E%3Cstop offset='1' stop-color='%23f9fb0e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M3.5 1.5h6.5l3 3v10h-9.5z' fill='%23fff' stroke='%236d6d6d'/%3E%3Cpath d='M10 1.5v3h3' fill='none' stroke='%236d6d6d'/%3E%3C/g%3E%3Cg transform='translate(19 0)'%3E%3Cpath d='M1.5 4.5h4.5l1.4 1.4h7.1v7.6h-13z' fill='%23f3c55a' stroke='%23a47c1c'/%3E%3Cpath d='M1.5 7.5h13' stroke='%23d9a93a'/%3E%3C/g%3E%3Cg transform='translate(38 0)'%3E%3Crect x='2' y='2' width='12' height='12' rx='1' fill='%233f6fb2'/%3E%3Crect x='4.5' y='2' width='7' height='4.3' fill='%23e8e8e8'/%3E%3Crect x='9' y='2.7' width='1.4' height='2.8' fill='%233f6fb2'/%3E%3Crect x='4' y='8.8' width='8' height='5.2' fill='%23fff'/%3E%3C/g%3E%3Cg transform='translate(57 0)'%3E%3Crect x='4.5' y='1.5' width='7' height='4.5' fill='%23fff' stroke='%23777'/%3E%3Crect x='1.5' y='5.5' width='13' height='6' rx='1' fill='%238c8c8c'/%3E%3Crect x='4.5' y='9.5' width='7' height='5' fill='%23fff' stroke='%23777'/%3E%3Ccircle cx='12.3' cy='7.3' r='.6' fill='%233c3'/%3E%3C/g%3E%3Cpath d='M79.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(84 0)'%3E%3Cpath d='M4 1.8v11.4l2.9-2.8 2 4.4 1.7-.8-2-4.3h4z' fill='%23fff' stroke='%23222' stroke-width='.9' stroke-linejoin='round'/%3E%3C/g%3E%3Cpath d='M106.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(111 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.4' fill='%23e3f0fc' stroke='%23333' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14.2 14.2' stroke='%23333' stroke-width='2.1' stroke-linecap='round'/%3E%3Cpath d='M4.4 6.6h4.4M6.6 4.4v4.4' stroke='%231f5fa8' stroke-width='1.2'/%3E%3C/g%3E%3Cg transform='translate(130 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.4' fill='%23e3f0fc' stroke='%23333' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14.2 14.2' stroke='%23333' stroke-width='2.1' stroke-linecap='round'/%3E%3Cpath d='M4.4 6.6h4.4' stroke='%231f5fa8' stroke-width='1.2'/%3E%3C/g%3E%3Cg transform='translate(149 0)'%3E%3Cpath d='M4.3 9.3V5.4a.9.9 0 0 1 1.8 0v2.8V3.3a.9.9 0 0 1 1.8 0v4.9V2.6a.9.9 0 0 1 1.8 0v5.6V4a.9.9 0 0 1 1.8 0v6.3c0 2.6-1.5 4.2-3.9 4.2-2 0-3-.9-4-2.5L2 9.6a.95.95 0 0 1 1.5-1.1z' fill='%23f6d6b0' stroke='%236d4c2c' stroke-width='.75' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(168 0)'%3E%3Cpath d='M12.8 6.6A5.2 5.2 0 1 0 12 11.6' fill='none' stroke='%23333' stroke-width='1.3'/%3E%3Cpath d='M13.8 3.2 13 7l-3.6-1.4' fill='none' stroke='%23333' stroke-width='1.3' stroke-linejoin='round'/%3E%3Cellipse cx='8' cy='8' rx='2' ry='1' fill='none' stroke='%231f5fa8' stroke-width='.9'/%3E%3C/g%3E%3Cg transform='translate(187 0)'%3E%3Crect x='1.5' y='1.5' width='9' height='5.6' fill='%23fffbc5' stroke='%238a7b1c' stroke-width='.8'/%3E%3Cpath d='M3 3.6h6M3 5.3h4' stroke='%238a7b1c' stroke-width='.7'/%3E%3Cpath d='M4.5 7.1 6 9' stroke='%23333'/%3E%3Cpath d='M11 9v5.5M8.2 11.8h5.6' stroke='%23333' stroke-width='1.1'/%3E%3C/g%3E%3Cg transform='translate(206 0)'%3E%3Cpath d='M2.5 14c0-2.3 1.3-3.4 2.8-3.4s2.3 1.1 1.6 2.5c-.8 1.5-3 1.4-4.4.9z' fill='%23d8452c'/%3E%3Cpath d='M6.4 10.4 13.2 3' stroke='%238a6a3c' stroke-width='2' stroke-linecap='round'/%3E%3C/g%3E%3Cpath d='M228.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(233 0)'%3E%3Cpath d='M7.2 9.8 6 11a2.1 2.1 0 0 1-3-3l2-2a2.1 2.1 0 0 1 3 0M8.8 6.2 10 5a2.1 2.1 0 0 1 3 3l-2 2a2.1 2.1 0 0 1-3 0' fill='none' stroke='%23555' stroke-width='1.3' stroke-linecap='round'/%3E%3C/g%3E%3Cpath d='M255.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(260 0)'%3E%3Crect x='2' y='2' width='5.5' height='12' fill='%23fff' stroke='%238a8a8a' stroke-width='.8'/%3E%3Crect x='9' y='2' width='4.5' height='12' fill='url(%23pa)' stroke='%23555' stroke-width='.7'/%3E%3C/g%3E%3Cg transform='translate(279 0)'%3E%3Crect x='1.8' y='2.5' width='12.4' height='11' fill='%23fff' stroke='%23555' stroke-width='.8'/%3E%3Cpath d='M3.6 5.5h3.4M3.6 8h3.4M3.6 10.5h3.4' stroke-width='1.3' stroke='%230072bd'/%3E%3Cpath d='M8.2 5.5h4.3M8.2 8h4.3M8.2 10.5h4.3' stroke='%239a9a9a' stroke-width='.8'/%3E%3C/g%3E%3Cpath d='M301.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(306 0)'%3E%3Crect x='1.8' y='2.5' width='12.4' height='11' fill='%23fff' stroke='%23666' stroke-width='.8'/%3E%3Cpath d='M1.8 5h12.4' stroke='%23666'/%3E%3C/g%3E%3Cg transform='translate(325 0)'%3E%3Crect x='1.8' y='2.5' width='12.4' height='11' fill='%23fff' stroke='%23666' stroke-width='.8'/%3E%3Cpath d='M1.8 5h12.4M6 5v8.5M10.2 5v8.5' stroke='%23666' stroke-width='.8'/%3E%3C/g%3E%3C/svg%3E");
}

.ml__tb {
  flex: none;
  height: 4.2cqw;
  border-bottom: 1px solid #d9d9d9;
  background: var(--ml-tools) 1.7cqw 50% / auto 2.25cqw no-repeat;
}

.ml__fig {
  position: relative;
  flex: 1;
  font: 400 1.75cqw/1 var(--f-plot);
  color: #262626;
}

/* Axes placed like MATLAB's Position property: left, bottom, width, height in % of the figure */
.ml__ax {
  position: absolute;
  left: calc(var(--l, 13) * 1%);
  bottom: calc(var(--b, 11) * 1%);
  width: calc(var(--w, 77.5) * 1%);
  height: calc(var(--h, 81.5) * 1%);
  border: 1px solid #262626;
  background: #fff;
}

.ml__ax > svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.ml__grid {
  fill: none;
  stroke: rgb(38 38 38 / 0.15);
  stroke-width: 1;
}

.ml__title {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 0.8cqw);
  font-size: 1.9cqw;
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
}

.ml__title sub {
  font-size: 0.75em;
  line-height: 0;
}

/* Tick labels, placed by --x / --y in percent of the axes */
.ml__xt,
.ml__yt,
.tc__xt,
.tc__yt {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.ml__xt b,
.ml__yt b,
.tc__xt b,
.tc__yt b {
  position: absolute;
  font-weight: 400;
  white-space: nowrap;
}

.ml__xt b,
.tc__xt b {
  top: calc(100% + 0.8cqw);
  left: calc(var(--x) * 1%);
  translate: -50% 0;
}

.ml__yt b,
.tc__yt b {
  right: calc(100% + 0.8cqw);
  top: calc(var(--y) * 1%);
  translate: 0 -50%;
}

.ml__xl,
.ml__yl {
  position: absolute;
  font-size: 1.9cqw;
  white-space: nowrap;
}

.ml__xl {
  left: 50%;
  top: calc(100% + 3.3cqw);
  translate: -50% 0;
}

/* Rotated about its own centre, then centred beside the tick labels */
.ml__yl {
  right: calc(100% + var(--yl, 4.4cqw));
  top: 50%;
  translate: 50% -50%;
  rotate: -90deg;
}

/* Grid cards: MATLAB figures stop just short of the bottom edge */
.ml,
.tc {
  height: 56.5cqw;
}

/* Default colour order: blue, orange, yellow */
.ml__c {
  fill: none;
  stroke: #0072bd;
  stroke-width: 1.5;
}

.ml__c--o { stroke: #d95319; }
.ml__c--y { stroke: #edb120; }
.ml__c--k { stroke: #7f7f7f; stroke-width: 1; }
.ml__c--dash { stroke-dasharray: 6 4; }
.ml__c--thin { stroke-width: 1; }

.ml__legend {
  position: absolute;
  z-index: 2;
  display: grid;
  gap: 0.5cqw;
  padding: 0.7cqw 1.1cqw;
  border: 1px solid #262626;
  background: #fff;
  font-size: 1.65cqw;
  white-space: nowrap;
}

.ml__legend > span {
  display: flex;
  align-items: center;
  gap: 0.8cqw;
}

.ml__legend i {
  width: 3.4cqw;
  border-top: 0.3cqw solid var(--c, #0072bd);
}

.ml__legend i.dash {
  border-top-style: dashed;
}

/* A marker in the legend: plot(v, p, 'ro', 'MarkerFaceColor', 'r') */
.ml__legend i.dot {
  width: 3.4cqw;
  height: 1.3cqw;
  border: 0;
  background: radial-gradient(circle, #f00 0.55cqw, transparent 0.6cqw);
}

/* ---------- MPPT ---------- */

.mp__dot {
  position: absolute;
  z-index: 2;
  width: 1.5cqw;
  height: 1.5cqw;
  margin: -0.75cqw 0 0 -0.75cqw;
  border-radius: 50%;
  background: #f00;
}

/* ---------- Power quality ---------- */

.pq__bars {
  position: absolute;
  inset: 0;
}

/* bar(): the first colour, black edges, 0.8 of the spacing */
.pq__bars i {
  position: absolute;
  bottom: 0;
  left: calc(var(--x) * 1%);
  width: 11.4%;
  height: calc(var(--h) * 1%);
  translate: -50% 0;
  background: #0072bd;
  border: 1px solid #000;
  border-bottom: 0;
}

/* ---------- Inverter ---------- */

.inv__v {
  fill: none;
  stroke: #0072bd;
  stroke-width: 1;
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

/* ==========================================================================
   Relay coordination: an ETAP Star view (time-current curves on log-log paper)
   ========================================================================== */

.tc {
  background: #fff;
  --tc-tools: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 16'%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M3 13 11.5 4.5l1.8 1.8L4.8 14.8H3z' fill='%23f4c542' stroke='%237a5c00' stroke-width='.7'/%3E%3Cpath d='M11.5 4.5l1.3-1.3a1.2 1.2 0 0 1 1.8 1.8l-1.3 1.3' fill='%23e57373' stroke='%237a5c00' stroke-width='.7'/%3E%3C/g%3E%3Cpath d='M24.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(30 0)'%3E%3Cpath d='M2 8h9M8 4.5 11.5 8 8 11.5' fill='none' stroke='%231c7a2c' stroke-width='1.6'/%3E%3Crect x='12' y='3' width='2.5' height='10' fill='%231c7a2c'/%3E%3C/g%3E%3Cg transform='translate(50 0)'%3E%3Cpath d='M9.5 1.5 4 9h3.5L6 14.5 12 6.5H8.5z' fill='%23ffcc00' stroke='%238a6d00' stroke-width='.7'/%3E%3C/g%3E%3Cg transform='translate(70 0)'%3E%3Ccircle cx='8' cy='8' r='6' fill='%23fff' stroke='%23555'/%3E%3Ctext x='8' y='11.3' font-family='Arial' font-size='9' font-weight='bold' text-anchor='middle' fill='%23555'%3EM%3C/text%3E%3C/g%3E%3Cg transform='translate(90 0)'%3E%3Cpath d='M1.5 8c1.2-5 2.3-5 3.5 0s2.3 5 3.5 0 2.3-5 3.5 0 1.2 3 2.5 3' fill='none' stroke='%237b3fb5' stroke-width='1.4'/%3E%3C/g%3E%3Cg transform='translate(110 0)'%3E%3Cpath d='M1.5 11c2-6 4-8 6-4s4 4 7-4' fill='none' stroke='%23d06a00' stroke-width='1.4'/%3E%3Cpath d='M1.5 14.5h13' stroke='%23555'/%3E%3C/g%3E%3Cg transform='translate(130 0)'%3E%3Cpath d='M8 1.8c1 4 2 6 5.5 11.5M8 1.8c-1 4-2 6-5.5 11.5' fill='none' stroke='%23c62828' stroke-width='1.3'/%3E%3Cpath d='M4.5 11.5h7' stroke='%23c62828' stroke-width='1.1'/%3E%3C/g%3E%3Crect x='149.5' y='.5' width='19' height='15' rx='2' fill='%23cfe3f7' stroke='%236a9fd4'/%3E%3Cg transform='translate(151 0)'%3E%3Cpath d='M2.5 1.5v12.5H15' fill='none' stroke='%23333' stroke-width='.9'/%3E%3Cpath d='M4.5 2c.4 5 2 8.5 9.5 10.5' fill='none' stroke='%23e0201b' stroke-width='1.3'/%3E%3Cpath d='M7 2c.4 4 2 6.5 7.5 8' fill='none' stroke='%231c4fd8' stroke-width='1.3'/%3E%3C/g%3E%3C/svg%3E");
}

.tc .mnu {
  background: #f0f0f0;
}

/* Study modes, with Star (protective device coordination) pressed */
.tc__tb {
  flex: none;
  height: 4.2cqw;
  border-bottom: 1px solid #d0d0d0;
  background: #f0f0f0 var(--tc-tools) 1.7cqw 50% / auto 2.3cqw no-repeat;
}

.tc__plot {
  position: relative;
  flex: 1;
  margin: 2.2cqw 2.6cqw 6.4cqw 8.8cqw;
  border: 1px solid #000;
  font: 400 1.3cqw/1 Arial, var(--f-plot);
  color: #000;
}

.tc__plot > svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.tc__minor { fill: none; stroke: #e2e2e2; stroke-width: 1; }
.tc__major { fill: none; stroke: #b4b4b4; stroke-width: 1; }
.tc__r { fill: none; stroke-width: 1.7; }

/* Device settings, the way Star lists them */
.tc__legend {
  position: absolute;
  z-index: 2;
  top: 0.9cqw;
  right: 0.9cqw;
  display: grid;
  gap: 0.55cqw;
  padding: 0.7cqw 0.9cqw;
  border: 1px solid #000;
  background: #fff;
  white-space: nowrap;
}

.tc__legend span {
  display: flex;
  align-items: center;
  gap: 0.7cqw;
}

.tc__legend i {
  width: 2.6cqw;
  border-top: 0.3cqw solid var(--c);
}

.tc__legend b {
  font-weight: 700;
}

/* A fault: its arrow on the current axis, and the time between the primary relay and its backup */
.tc__f {
  position: absolute;
  z-index: 3;
  top: 0;
  bottom: 0;
  left: calc(var(--x) * 1%);
  width: 0;
}

.tc__arrow {
  position: absolute;
  bottom: 0;
  left: -0.7cqw;
  width: 1.4cqw;
  height: 3.4cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 34'%3E%3Cpath d='M7 34V6' stroke='%23000' stroke-width='1.4'/%3E%3Cpath d='M7 0l6 9H1z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}

.tc__fl {
  position: absolute;
  bottom: 0.4cqw;
  left: 1.1cqw;
  white-space: nowrap;
  font-weight: 700;
}

.tc__dt {
  position: absolute;
  left: 0;
  border-left: 1px solid #000;
}

.tc__dt i {
  position: absolute;
  left: -0.75cqw;
  width: 1.5cqw;
  height: 1.5cqw;
  border: 0.3cqw solid var(--c);
  border-radius: 50%;
  background: #fff;
}

.tc__dt i:first-child { top: -0.75cqw; }
.tc__dt i:nth-child(2) { bottom: -0.75cqw; }

.tc__dt b {
  position: absolute;
  left: 1.3cqw;
  top: 50%;
  translate: 0 -50%;
  padding: 0.35cqw 0.6cqw;
  border: 1px solid #000;
  background: #ffffe1;
  font-weight: 400;
  white-space: nowrap;
}

.tc__f--2 {
  display: none;
}

.tc__xl,
.tc__yl {
  position: absolute;
  font-size: 1.5cqw;
  font-weight: 700;
  white-space: nowrap;
}

.tc__xl {
  left: 50%;
  top: calc(100% + 3cqw);
  translate: -50% 0;
}

.tc__yl {
  left: -6.6cqw;
  top: 50%;
  translate: -50% -50%;
  rotate: -90deg;
}

/* Two faults in turn: Bus3 (R1 clears it, R2 backs it up), then Bus2 (R2, backed up by R3) */
@media (prefers-reduced-motion: no-preference) {
  .js .tc__f--2 {
    display: block;
  }

  .js .tc__f {
    animation: tc-fault 10s infinite both;
  }

  .js .tc__f--2 {
    animation-delay: -5s;
  }

  .js .tc__dt {
    animation: tc-dt 10s infinite both;
  }

  .js .tc__f--2 .tc__dt {
    animation-delay: -5s;
  }
}

@keyframes tc-fault {
  0% { opacity: 0; }
  3%, 47% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

@keyframes tc-dt {
  0%, 8% { clip-path: inset(0 -30cqw 100% -2cqw); }
  16%, 100% { clip-path: inset(-2cqw -30cqw -2cqw -2cqw); }
}

/* ==========================================================================
   PLC conveyor: the CODESYS IDE, logged in and running, with the visualization open.
   The HMI is drawn with CODESYS's own plain elements: framed rectangles,
   lamps, grey buttons, Arial.
   ========================================================================== */

.hmi {
  inset: 4.5cqw 5cqw;
  height: auto;
  background: #f0f0f0;
  --cds-tools: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 428 16'%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M3.5 1.5h6.5l3 3v10h-9.5z' fill='%23fff' stroke='%236d6d6d'/%3E%3Cpath d='M10 1.5v3h3' fill='none' stroke='%236d6d6d'/%3E%3C/g%3E%3Cg transform='translate(19 0)'%3E%3Cpath d='M1.5 4.5h4.5l1.4 1.4h7.1v7.6h-13z' fill='%23f3c55a' stroke='%23a47c1c'/%3E%3C/g%3E%3Cg transform='translate(38 0)'%3E%3Crect x='2' y='2' width='12' height='12' rx='1' fill='%233f6fb2'/%3E%3Crect x='4.5' y='2' width='7' height='4.3' fill='%23e8e8e8'/%3E%3Crect x='4' y='8.8' width='8' height='5.2' fill='%23fff'/%3E%3C/g%3E%3Cpath d='M60.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(65 0)'%3E%3Cpath d='M5.5 5.5H10a3.5 3.5 0 0 1 0 7H6' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Cpath d='M7.5 2.5 4.5 5.5l3 3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3C/g%3E%3Cg transform='translate(84 0)'%3E%3Cpath d='M10.5 5.5H6a3.5 3.5 0 0 0 0 7h4' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Cpath d='M8.5 2.5l3 3-3 3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3C/g%3E%3Cpath d='M106.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(111 0)'%3E%3Ccircle cx='4.5' cy='12' r='2' fill='none' stroke='%23444' stroke-width='1.2'/%3E%3Ccircle cx='11.5' cy='12' r='2' fill='none' stroke='%23444' stroke-width='1.2'/%3E%3Cpath d='M5.8 10.5 11 2M10.2 10.5 5 2' stroke='%23666' stroke-width='1.1'/%3E%3C/g%3E%3Cg transform='translate(130 0)'%3E%3Crect x='2.5' y='2.5' width='7.5' height='9' fill='%23fff' stroke='%23666'/%3E%3Crect x='6' y='5' width='7.5' height='9' fill='%23fff' stroke='%23666'/%3E%3C/g%3E%3Cg transform='translate(149 0)'%3E%3Crect x='3' y='2.5' width='10' height='12' rx='1' fill='%23c9a36a' stroke='%237a5a2a'/%3E%3Crect x='5.5' y='1.5' width='5' height='2.5' fill='%23ddd' stroke='%23777' stroke-width='.7'/%3E%3Crect x='5' y='5.5' width='6' height='7' fill='%23fff'/%3E%3C/g%3E%3Cg transform='translate(168 0)'%3E%3Cpath d='M3.5 3.5l9 9M12.5 3.5l-9 9' stroke='%23d0342c' stroke-width='2'/%3E%3C/g%3E%3Cpath d='M190.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(195 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.3' fill='%23e3f0fc' stroke='%23333' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14 14' stroke='%23333' stroke-width='2'/%3E%3C/g%3E%3Cpath d='M217.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(222 0)'%3E%3Crect x='1.5' y='8.5' width='6' height='5.5' fill='%236aa84f' stroke='%2338761d'/%3E%3Crect x='8.5' y='8.5' width='6' height='5.5' fill='%236aa84f' stroke='%2338761d'/%3E%3Crect x='5' y='2.5' width='6' height='5.5' fill='%236aa84f' stroke='%2338761d'/%3E%3C/g%3E%3Cpath d='M244.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(249 0)'%3E%3Cpath d='M2 8h7M6.5 5 9.5 8l-3 3' fill='none' stroke='%232e9e3a' stroke-width='1.6'/%3E%3Crect x='10.5' y='2.5' width='4' height='11' fill='%23dcdcdc' stroke='%23666'/%3E%3C/g%3E%3Cg transform='translate(268 0)'%3E%3Cpath d='M14 8H7M9.5 5 6.5 8l3 3' fill='none' stroke='%23b0b0b0' stroke-width='1.6'/%3E%3Crect x='1.5' y='2.5' width='4' height='11' fill='%23eee' stroke='%23aaa'/%3E%3C/g%3E%3Cg transform='translate(287 0)'%3E%3Cpath d='M4 2.5 13 8l-9 5.5z' fill='%23c6c6c6'/%3E%3C/g%3E%3Cg transform='translate(306 0)'%3E%3Crect x='3.5' y='3.5' width='9' height='9' fill='%23d0342c'/%3E%3C/g%3E%3Cg transform='translate(325 0)'%3E%3Cpath d='M12.6 7A4.8 4.8 0 1 1 11 3.7' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Cpath d='M11.5 1v3.2H8.3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3C/g%3E%3Cpath d='M347.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(352 0)'%3E%3Ccircle cx='8' cy='8' r='4.5' fill='%23d0342c'/%3E%3C/g%3E%3Cg transform='translate(371 0)'%3E%3Cpath d='M2.5 9c1-5 9-5 10 0' fill='none' stroke='%232f6db5' stroke-width='1.4'/%3E%3Cpath d='M10.5 7.5l2 1.8 1.6-2.3' fill='none' stroke='%232f6db5' stroke-width='1.3'/%3E%3Ccircle cx='8' cy='12.5' r='1.5' fill='%23444'/%3E%3C/g%3E%3Cg transform='translate(390 0)'%3E%3Cpath d='M8 1.5v8M5 6.5l3 3 3-3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Ccircle cx='8' cy='13' r='1.5' fill='%23444'/%3E%3C/g%3E%3Cg transform='translate(409 0)'%3E%3Cpath d='M8 10V2.5M5 5.5l3-3 3 3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Ccircle cx='8' cy='13' r='1.5' fill='%23444'/%3E%3C/g%3E%3C/svg%3E");
}

.hmi .mnu {
  background: #f0f0f0;
}

.cds__tb {
  flex: none;
  height: 4.1cqw;
  border-bottom: 1px solid #d0d0d0;
  background: var(--cds-tools) 1.6cqw 50% / auto 2.2cqw no-repeat;
}

/* Editor tabs: the program, and the visualization in front */
.cds__tabs {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: 0.3cqw;
  height: 3.6cqw;
  padding: 0 1.2cqw;
  border-bottom: 1px solid #aeb8c4;
  font: 400 1.6cqw/1 var(--f-ui);
  color: #333;
}

.cds__tabs span {
  padding: 0.7cqw 1.6cqw 0.6cqw;
  border: 1px solid #c4cad1;
  border-bottom: 0;
  background: #e4e8ec;
}

.cds__tabs .on {
  border-color: #aeb8c4;
  background: #fff;
  box-shadow: inset 0 0.3cqw 0 #3a78c3;
}

.cds__status {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.6cqw;
  height: 3.4cqw;
  padding: 0 1.4cqw;
  border-top: 1px solid #d0d0d0;
  font: 400 1.45cqw/1 var(--f-ui);
  color: #333;
  white-space: nowrap;
  overflow: hidden;
}

.cds__status i {
  display: inline-block;
  width: 1.2cqw;
  height: 1.2cqw;
  margin: 0 0.3cqw 0 0.6cqw;
  border-radius: 50%;
  vertical-align: -0.15cqw;
  background: #d0342c;
}

.cds__status i.warn {
  border-radius: 0;
  background: #e8a317;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

/* The application is running on the controller */
.cds__run {
  margin-left: auto;
  padding: 0.35cqw 1cqw;
  background: #3cb43c;
  color: #fff;
  font-weight: 700;
}

.hmi__panel {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 1.4cqw 2cqw 1.6cqw;
  background: #fff;
  font: 400 1.6cqw/1 Arial, var(--f-plot);
  color: #000;
}

.hmi__head {
  display: flex;
  align-items: center;
  gap: 1.8cqw;
}

.hmi__head b {
  margin-right: auto;
  font-size: 2.2cqw;
}

/* A CODESYS lamp: a metal bezel, lit or dark */
.hmi__lamp {
  display: inline-flex;
  align-items: center;
  gap: 0.8cqw;
}

.hmi__lamp::before {
  content: "";
  width: 2.6cqw;
  height: 2.6cqw;
  border-radius: 50%;
  border: 0.45cqw solid #9b9b9b;
  box-shadow: 0 0 0 1px #5a5a5a;
  background: #1f4d1f;
}

.hmi__lamp--fault::before {
  background: #5a1a1a;
}

.hmi__lamp--run.is-on::before {
  background: radial-gradient(circle at 38% 34%, #d6ffd6 0 12%, #20e020 16%);
}

.hmi__lamp--fault.is-on::before {
  background: radial-gradient(circle at 38% 34%, #ffd6d6 0 12%, #ff2020 16%);
}

.hmi__line {
  position: relative;
  flex: 1;
  margin: 1.2cqw 0 1.4cqw;
  overflow: hidden;
}

/* Seen from above: the belt is a band, items ride inside it */
.hmi__belt {
  position: absolute;
  left: 2%;
  right: 13%;
  top: 34%;
  height: 30%;
  border: 1px solid #000;
  background: #a0a0a0;
  overflow: hidden;
}

.hmi__belt::before {
  content: "";
  position: absolute;
  inset: 0 -10% 0 0;
  background: repeating-linear-gradient(90deg, transparent 0 3.2cqw, #8a8a8a 3.2cqw 3.5cqw);
}

@media (prefers-reduced-motion: no-preference) {
  .js .hmi__belt::before {
    animation: hmi-belt 0.9s linear infinite;
  }

  .js .hmi.is-stopped .hmi__belt::before {
    animation-play-state: paused;
  }
}

@keyframes hmi-belt {
  to { transform: translateX(3.5cqw); }
}

.hmi__items {
  position: absolute;
  inset: 0;
}

.hmi__item {
  position: absolute;
  left: 0;
  top: 0;
  width: 4.4cqw;
  height: 4.4cqw;
  border: 1px solid #000;
  will-change: transform;
}

.hmi__item--metal { background: #c0c0c0; }
.hmi__item--plastic { background: #1e90ff; }

/* Inductive sensor S1 at the belt's edge */
.hmi__sensor {
  position: absolute;
  left: 38%;
  top: 17%;
  width: 3.2cqw;
  height: 17%;
  border: 1px solid #000;
  background: #c0c0c0;
}

.hmi__sensor.is-on {
  background: #ffff00;
}

.hmi__sensor::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  height: 176%;
  border-left: 1px dashed transparent;
}

.hmi__sensor.is-on::before {
  border-color: #ff0000;
}

.hmi__sensor b,
.hmi__pusher b {
  position: absolute;
  bottom: calc(100% + 0.5cqw);
  left: 50%;
  translate: -50% 0;
  font-weight: 400;
  font-style: normal;
  white-space: nowrap;
}

.hmi__pusher b {
  bottom: auto;
  top: 8%;
  left: calc(100% - 0.4cqw);
  translate: 0 0;
}

/* Cylinder Y1 above the belt; its head crosses the belt into bin 1 */
.hmi__pusher {
  position: absolute;
  left: 58%;
  top: 6%;
  width: 6cqw;
  height: 28%;
}

.hmi__pusher::before {
  content: "";
  position: absolute;
  inset: 0 1.2cqw 40%;
  border: 1px solid #000;
  background: #c0c0c0;
}

.hmi__pusher i {
  position: absolute;
  left: 0;
  right: 0;
  top: 40%;
  height: 60%;
  transition: transform 0.2s var(--ease-out);
}

.hmi__pusher i::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 30%;
  width: 0.9cqw;
  margin-left: -0.45cqw;
  border: 1px solid #000;
  border-block: 0;
  background: #e0e0e0;
}

.hmi__pusher i::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 30%;
  border: 1px solid #000;
  background: #ff8c00;
}

.hmi__pusher.is-out i {
  transform: translateY(var(--stroke, 10cqw));
}

.hmi__bin {
  position: absolute;
  border: 1px solid #000;
  background: #fff;
  font-style: normal;
}

.hmi__bin b {
  position: absolute;
  left: 0.8cqw;
  bottom: 0.7cqw;
  font-weight: 400;
  font-style: normal;
  white-space: nowrap;
}

.hmi__bin--1 { left: 53%; width: 19%; top: 70%; bottom: 1%; }
.hmi__bin--2 { left: 88%; right: 0.5%; top: 26%; bottom: 28%; }

.hmi__foot {
  display: flex;
  align-items: center;
  gap: 1.3cqw;
}

/* Text fields: 'Bin 1: %d' */
.hmi__cnt {
  padding: 0.7cqw 1.1cqw;
  border: 1px solid #000;
  font-variant-numeric: tabular-nums;
}

.hmi__cnt b {
  font-weight: 400;
}

.hmi__btn {
  padding: 0.85cqw 1.7cqw;
  border: 1px solid #707070;
  border-radius: 0.35cqw;
  background: linear-gradient(#f6f6f6, #dcdcdc);
}

.hmi__btn[data-act="start"] {
  margin-left: auto;
}

/* The emergency stop: a red button on a yellow plate */
.hmi__estop {
  display: grid;
  place-items: center;
  width: 6.6cqw;
  height: 6.6cqw;
  margin-block: -1.2cqw;
  border: 1px solid #000;
  border-radius: 50%;
  background: #ffd700;
}

.hmi__estop i {
  display: grid;
  place-items: center;
  width: 4.6cqw;
  height: 4.6cqw;
  border: 1px solid #000;
  border-radius: 50%;
  background: #e00000;
  font: 700 0.95cqw/1 Arial, sans-serif;
  font-style: normal;
  color: #fff;
}

.hmi.is-estop .hmi__estop i {
  background: #a00000;
}

/* Interactive copy in the dialog */
.modal .hmi__btn,
.modal .hmi__estop i {
  cursor: pointer;
}

.modal .hmi__btn:active,
.hmi__btn.is-down {
  background: linear-gradient(#d4d4d4, #eaeaea);
}

/* The mushroom head goes in when it's hit */
.hmi__estop i.is-down {
  scale: 0.9;
  background: #b80000;
}

.modal .hmi__btn:focus-visible,
.modal .hmi__estop i:focus-visible {
  outline: 0.4cqw solid #1a73e8;
  outline-offset: 0.3cqw;
}

/* ==========================================================================
   Line follower: its board in KiCad's PCB Editor, one track left to route
   Default KiCad colours: red front copper, blue back copper with a ground
   pour, gold through-hole pads, pale yellow silkscreen on a navy canvas.
   ========================================================================== */

.pv .kc {
  height: 55cqw;
}

.kc {
  background: #f0f0f0;
  --kc-top: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 261 16'%3E%3Cg transform='translate(0 0)'%3E%3Crect x='2' y='2' width='12' height='12' rx='1' fill='%233f6fb2'/%3E%3Crect x='4.5' y='2' width='7' height='4.3' fill='%23e8e8e8'/%3E%3Crect x='4' y='8.8' width='8' height='5.2' fill='%23fff'/%3E%3C/g%3E%3Cg transform='translate(20 0)'%3E%3Crect x='2' y='3' width='12' height='10' rx='1' fill='%231f7a3f'/%3E%3Cpath d='M4 6h4l2 2h2M4 10h3l1 1h4' fill='none' stroke='%23e8a948' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(40 0)'%3E%3Crect x='3' y='1.5' width='10' height='13' fill='%23fff' stroke='%23777'/%3E%3Cpath d='M5 5h6M5 7.5h6M5 10h4' stroke='%23999'/%3E%3C/g%3E%3Cg transform='translate(60 0)'%3E%3Crect x='4.5' y='1.5' width='7' height='4.5' fill='%23fff' stroke='%23777'/%3E%3Crect x='1.5' y='5.5' width='13' height='6' rx='1' fill='%238c8c8c'/%3E%3Crect x='4.5' y='9.5' width='7' height='5' fill='%23fff' stroke='%23777'/%3E%3C/g%3E%3Cpath d='M83.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(87 0)'%3E%3Cpath d='M5.5 5.5H10a3.5 3.5 0 0 1 0 7H6' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Cpath d='M7.5 2.5 4.5 5.5l3 3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3C/g%3E%3Cg transform='translate(107 0)'%3E%3Cpath d='M10.5 5.5H6a3.5 3.5 0 0 0 0 7h4' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3Cpath d='M8.5 2.5l3 3-3 3' fill='none' stroke='%232f6db5' stroke-width='1.5'/%3E%3C/g%3E%3Cpath d='M130.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(134 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.3' fill='%23e3f0fc' stroke='%23333' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14 14' stroke='%23333' stroke-width='2'/%3E%3Cpath d='M4.5 6.6h4.2M6.6 4.5v4.2' stroke='%231f5fa8'/%3E%3C/g%3E%3Cg transform='translate(154 0)'%3E%3Ccircle cx='6.6' cy='6.6' r='4.3' fill='%23e3f0fc' stroke='%23333' stroke-width='1.2'/%3E%3Cpath d='M9.8 9.8 14 14' stroke='%23333' stroke-width='2'/%3E%3Cpath d='M4.5 6.6h4.2' stroke='%231f5fa8'/%3E%3C/g%3E%3Cg transform='translate(174 0)'%3E%3Crect x='2' y='2' width='12' height='12' fill='none' stroke='%23555' stroke-dasharray='2 1.5'/%3E%3Cpath d='M5 8h6M8 5v6' stroke='%231f5fa8' stroke-width='1.2'/%3E%3C/g%3E%3Cpath d='M197.5 1.5v13' stroke='%23c8c8c8'/%3E%3Cg transform='translate(201 0)'%3E%3Cpath d='M3 12.5 8 3l5 9.5z' fill='%23f3c540' stroke='%238a6d00' stroke-width='.8' stroke-linejoin='round'/%3E%3Cpath d='M8 6.5v3.2' stroke='%23333' stroke-width='1.2'/%3E%3Ccircle cx='8' cy='11' r='.7' fill='%23333'/%3E%3C/g%3E%3Cg transform='translate(221 0)'%3E%3Crect x='2' y='2' width='12' height='12' rx='1' fill='%23fff' stroke='%23555'/%3E%3Cpath d='M4.5 8.5 7 11l4.5-6' fill='none' stroke='%232e9e3a' stroke-width='1.5'/%3E%3C/g%3E%3Cg transform='translate(241 0)'%3E%3Ccircle cx='8' cy='8' r='5.5' fill='none' stroke='%23555' stroke-width='1.2'/%3E%3Cpath d='M3 8h10M8 3c2 1.5 2 8.5 0 10M8 3c-2 1.5-2 8.5 0 10' fill='none' stroke='%23555' stroke-width='.8'/%3E%3C/g%3E%3C/svg%3E");
  --kc-left: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 176'%3E%3Cg transform='translate(0 0)'%3E%3Cg fill='%23555'%3E%3Ccircle cx='3' cy='3' r='.9'/%3E%3Ccircle cx='8' cy='3' r='.9'/%3E%3Ccircle cx='13' cy='3' r='.9'/%3E%3Ccircle cx='3' cy='8' r='.9'/%3E%3Ccircle cx='8' cy='8' r='.9'/%3E%3Ccircle cx='13' cy='8' r='.9'/%3E%3Ccircle cx='3' cy='13' r='.9'/%3E%3Ccircle cx='8' cy='13' r='.9'/%3E%3Ccircle cx='13' cy='13' r='.9'/%3E%3C/g%3E%3C/g%3E%3Cg transform='translate(0 22)'%3E%3Ccircle cx='8' cy='8' r='6' fill='none' stroke='%23555'/%3E%3Ccircle cx='8' cy='8' r='3' fill='none' stroke='%23555'/%3E%3Cpath d='M8 2v12M2 8h12' stroke='%23555' stroke-width='.7'/%3E%3C/g%3E%3Cg transform='translate(0 44)'%3E%3Crect x='1.5' y='4' width='13' height='8' rx='1.5' fill='%23fff' stroke='%23555'/%3E%3Ctext x='8' y='10.6' font-family='Arial' font-size='6.4' font-weight='bold' text-anchor='middle' fill='%23333'%3Emm%3C/text%3E%3C/g%3E%3Cg transform='translate(0 66)'%3E%3Cpath d='M8 1v14M1 8h14' stroke='%23555' stroke-width='1.1'/%3E%3C/g%3E%3Cg transform='translate(0 88)'%3E%3Ccircle cx='3.5' cy='12.5' r='2' fill='%23d7b73c'/%3E%3Ccircle cx='12.5' cy='3.5' r='2' fill='%23d7b73c'/%3E%3Cpath d='M3.5 12.5 12.5 3.5' stroke='%23333' stroke-width='.8'/%3E%3C/g%3E%3Cg transform='translate(0 110)'%3E%3Cpath d='M2 3h9l3 3v7H2z' fill='%232e9e3a' fill-opacity='.35' stroke='%231c7a2c'/%3E%3C/g%3E%3Cg transform='translate(0 132)'%3E%3Crect x='2' y='2' width='12' height='12' fill='%23fff' stroke='%23555'/%3E%3Cpath d='M2 14 14 2v12z' fill='%23555'/%3E%3C/g%3E%3Cg transform='translate(0 154)'%3E%3Cpath d='M8 2 14 5 8 8 2 5z' fill='%23c83434'/%3E%3Cpath d='M2 8l6 3 6-3' fill='none' stroke='%234d7fc4' stroke-width='1.4'/%3E%3Cpath d='M2 11l6 3 6-3' fill='none' stroke='%232e9e3a' stroke-width='1.4'/%3E%3C/g%3E%3C/svg%3E");
  --kc-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 242'%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M4 1.8v11.4l2.9-2.8 2 4.4 1.7-.8-2-4.3h4z' fill='%23fff' stroke='%23222' stroke-width='.9' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(0 22)'%3E%3Ccircle cx='3.5' cy='12.5' r='2' fill='%23d7b73c'/%3E%3Cpath d='M3.5 12.5 12 3M3.5 12.5 13 10' stroke='%23555' stroke-width='.8'/%3E%3C/g%3E%3Cg transform='translate(0 44)'%3E%3Crect x='.5' y='.5' width='15' height='15' rx='2' fill='%23cfe3f7' stroke='%236a9fd4'/%3E%3Cpath d='M2.5 13 7 8.5h6.5' fill='none' stroke='%23c83434' stroke-width='1.8'/%3E%3Ccircle cx='13.5' cy='8.5' r='1.2' fill='%23d7b73c'/%3E%3C/g%3E%3Cg transform='translate(0 66)'%3E%3Cpath d='M2 11 6 7h8M2 14 7 9h7' fill='none' stroke='%23c83434' stroke-width='1.2'/%3E%3C/g%3E%3Cg transform='translate(0 88)'%3E%3Cpath d='M1.5 8h2v-4h2v8h2v-8h2v8h2v-4h3' fill='none' stroke='%23c83434' stroke-width='1.1'/%3E%3C/g%3E%3Cg transform='translate(0 110)'%3E%3Ccircle cx='8' cy='8' r='5' fill='%23bdbdbd'/%3E%3Ccircle cx='8' cy='8' r='2.2' fill='%233c3c3c'/%3E%3C/g%3E%3Cg transform='translate(0 132)'%3E%3Crect x='4' y='3' width='8' height='10' fill='%23555'/%3E%3Cpath d='M2 5h2M2 8h2M2 11h2M12 5h2M12 8h2M12 11h2' stroke='%23d7b73c' stroke-width='1.2'/%3E%3C/g%3E%3Cg transform='translate(0 154)'%3E%3Cpath d='M2 4h8l4 4v5H2z' fill='%234d7fc4' fill-opacity='.45' stroke='%232f6db5'/%3E%3C/g%3E%3Cg transform='translate(0 176)'%3E%3Ctext x='8' y='13' font-family='Arial' font-size='13' font-weight='bold' text-anchor='middle' fill='%23555'%3ET%3C/text%3E%3C/g%3E%3Cg transform='translate(0 198)'%3E%3Cpath d='M1.5 8h13M1.5 5v6M14.5 5v6' stroke='%23555'/%3E%3Cpath d='M3.5 6.5 1.8 8l1.7 1.5M12.5 6.5 14.2 8l-1.7 1.5' fill='none' stroke='%23555'/%3E%3C/g%3E%3Cg transform='translate(0 220)'%3E%3Cpath d='M3.5 3.5l9 9M12.5 3.5l-9 9' stroke='%23d0342c' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E");
}

.kc .mnu {
  background: #f0f0f0;
}

.kc__tb {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.2cqw;
  height: 4.2cqw;
  padding: 0 1.4cqw;
  border-bottom: 1px solid #d0d0d0;
  font: 400 1.45cqw/1 var(--f-ui);
  color: #1b1b1b;
  white-space: nowrap;
  overflow: hidden;
}

.kc__tb i {
  flex: none;
  width: 37cqw;
  height: 2.2cqw;
  background: var(--kc-top) left center / auto 100% no-repeat;
}

/* The layer and track width pickers */
.kc__tb span {
  display: flex;
  align-items: center;
  gap: 0.6cqw;
  padding: 0.45cqw 2.6cqw 0.45cqw 0.7cqw;
  border: 1px solid #a8a8a8;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 5'%3E%3Cpath d='M1 1l3 3 3-3' fill='none' stroke='%23555'/%3E%3C/svg%3E") right 0.7cqw center / 1cqw no-repeat;
}

.kc__tb span b {
  width: 1.3cqw;
  height: 1.3cqw;
  background: #c83434;
}

.kc__main {
  flex: 1;
  display: flex;
  min-height: 0;
}

.kc__lt,
.kc__rt {
  flex: none;
  width: 3.4cqw;
  background: var(--kc-left) center 0.9cqw / 2.1cqw auto no-repeat;
}

.kc__lt { border-right: 1px solid #d0d0d0; }
.kc__rt { border-left: 1px solid #d0d0d0; background-image: var(--kc-right); }

/* The canvas, with its grid of dots */
.kc__canvas {
  position: relative;
  flex: 1;
  min-width: 0;
  background: #001023 radial-gradient(circle, rgb(132 132 132 / 0.5) 0.07cqw, transparent 0.09cqw) 0 0 / 1.6cqw 1.6cqw;
}

/* The board is a static image; the track being routed is drawn over it in the same coordinates */
.kc__canvas img,
.kc__canvas svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  overflow: hidden;
}

/* Tracks are real widths, so they scale with the board */
.kc__canvas svg path,
.kc__canvas svg circle {
  vector-effect: none;
}

.kc__new {
  stroke-dasharray: 100 100;
  stroke-dashoffset: 100;
}

/* Appearance: the layer list, front copper active */
.kc__app {
  flex: none;
  width: 17.5cqw;
  border-left: 1px solid #d0d0d0;
  background: #fff;
  font: 400 1.35cqw/1 var(--f-ui);
  color: #1b1b1b;
  overflow: hidden;
}

.kc__app p {
  display: flex;
  gap: 1.4cqw;
  margin: 0;
  padding: 0.8cqw 1cqw 0.7cqw;
  border-bottom: 1px solid #d0d0d0;
  background: #f0f0f0;
  color: #666;
}

.kc__app p b {
  font-weight: 400;
  color: #1b1b1b;
  box-shadow: 0 0.55cqw 0 -0.25cqw #3a78c3;
}

.kc__app span {
  display: flex;
  align-items: center;
  gap: 0.8cqw;
  height: 2.25cqw;
  padding: 0 0.8cqw;
  white-space: nowrap;
}

.kc__app span::before {
  content: "";
  flex: none;
  width: 1.3cqw;
  height: 1.3cqw;
  border: 1px solid rgb(0 0 0 / 0.35);
  background: var(--c);
}

.kc__app .on {
  background: #cce8ff;
}

.kc__status {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.5cqw;
  height: 3.4cqw;
  padding: 0 1.4cqw;
  border-top: 1px solid #d0d0d0;
  font: 400 1.4cqw/1 var(--f-ui);
  color: #333;
  white-space: nowrap;
  overflow: hidden;
}

.kc__status b {
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.kc__xy {
  margin-left: auto;
}

/* ==========================================================================
   Discord bot: the server, with the bot answering in #bot-commands
   The desktop client in dark mode: server list, channel list, chat.
   ========================================================================== */

.dc {
  inset: 5.5cqw 5cqw auto;
  height: 55cqw;
  display: grid;
  grid-template-columns: 7.4cqw 21cqw minmax(0, 1fr);
  background: #313338;
  color: #dbdee1;
  font-family: "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* Server list down the left */
.dc__rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1cqw;
  padding-top: 1.3cqw;
  background: #1e1f22;
}

.dc__srv {
  position: relative;
  display: grid;
  place-items: center;
  width: 4.9cqw;
  height: 4.9cqw;
  border-radius: 50%;
  background: #313338;
  font-size: 1.7cqw;
  font-weight: 500;
  line-height: 1;
  font-style: normal;
  color: #dbdee1;
}

.dc__srv.is-on {
  border-radius: 1.5cqw;
  background: #5865f2;
  color: #fff;
}

/* Home: Discord's own mark */
.dc__srv--home {
  border-radius: 1.5cqw;
  background: #5865f2 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19.3 5.3A17 17 0 0 0 15 4l-.5 1a15.7 15.7 0 0 0-5 0L9 4a17 17 0 0 0-4.3 1.3C2 9.4 1.2 13.4 1.6 17.3A17 17 0 0 0 6.9 20l1.1-1.8c-.6-.2-1.2-.5-1.8-.9l.4-.3a12 12 0 0 0 10.8 0l.4.3c-.6.4-1.2.7-1.8.9L17.1 20a17 17 0 0 0 5.3-2.7c.5-4.5-.8-8.5-3.1-12z' fill='white'/%3E%3Cellipse cx='8.5' cy='13' rx='1.6' ry='1.8' fill='%235865f2'/%3E%3Cellipse cx='15.5' cy='13' rx='1.6' ry='1.8' fill='%235865f2'/%3E%3C/svg%3E") center / 58% no-repeat;
}

.dc__srv.is-on::before {
  content: "";
  position: absolute;
  left: -1.25cqw;
  top: 16%;
  bottom: 16%;
  width: 0.6cqw;
  border-radius: 0 1cqw 1cqw 0;
  background: #f2f3f5;
}

/* Unread mentions */
.dc__srv b {
  position: absolute;
  right: -0.4cqw;
  bottom: -0.4cqw;
  display: grid;
  place-items: center;
  min-width: 2.1cqw;
  height: 2.1cqw;
  border: 0.45cqw solid #1e1f22;
  border-radius: 1.2cqw;
  background: #f23f43;
  font-size: 1.1cqw;
  font-weight: 700;
  line-height: 1;
  color: #fff;
}

.dc__srv--add {
  background: #313338 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2323a55a' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M12 6v12M6 12h12'/%3E%3C/svg%3E") center / 50% no-repeat;
}

.dc__sep {
  width: 3cqw;
  height: 0.25cqw;
  border-radius: 0.2cqw;
  background: #35363c;
}

/* Channel list */
.dc__side {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: #2b2d31;
  font-size: 1.75cqw;
  color: #949ba4;
}

.dc__guild {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 5.6cqw;
  padding: 0 1.6cqw;
  box-shadow: 0 1px 0 rgb(0 0 0 / 0.3);
  font-weight: 600;
  color: #f2f3f5;
  white-space: nowrap;
}

.dc__guild::after,
.dc__cat::before {
  content: "";
  width: 1.2cqw;
  height: 1.2cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='%23b5bac1' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M2.5 3.8 5 6.3l2.5-2.5'/%3E%3C/svg%3E") center / contain no-repeat;
}

.dc__cat {
  display: flex;
  align-items: center;
  gap: 0.3cqw;
  margin: 1.9cqw 0 0.5cqw 0.8cqw;
  font-size: 1.3cqw;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.dc__cat::before {
  width: 1cqw;
  height: 1cqw;
}

.dc__ch {
  display: flex;
  align-items: center;
  gap: 0.8cqw;
  margin: 0.2cqw 0.9cqw;
  padding: 0.6cqw 0.9cqw;
  border-radius: 0.5cqw;
  white-space: nowrap;
}

.dc__ch::before {
  content: "#";
  font-size: 2.1cqw;
  line-height: 1;
  color: #80848e;
}

.dc__ch.is-on {
  background: #404249;
  color: #fff;
}

.dc__ch.is-unread {
  color: #f2f3f5;
  font-weight: 600;
}

.dc__ch--voice::before {
  content: "";
  width: 1.9cqw;
  height: 1.9cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2380848e'%3E%3Cpath d='M11 5 6.5 9H3v6h3.5l4.5 4z'/%3E%3Cpath d='M15 9a4 4 0 0 1 0 6M17.5 6.5a7.5 7.5 0 0 1 0 11' fill='none' stroke='%2380848e' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Someone sitting in the voice channel */
.dc__vu {
  display: flex;
  align-items: center;
  gap: 0.8cqw;
  margin: 0.2cqw 0 0 4.6cqw;
  font-size: 1.55cqw;
  color: #b5bac1;
}

.dc__vu i {
  width: 2.2cqw;
  height: 2.2cqw;
  border-radius: 50%;
  background: var(--av);
}

/* You, at the bottom */
.dc__me {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.9cqw;
  margin-top: auto;
  height: 6cqw;
  padding: 0 1.2cqw;
  background: #232428;
  font-size: 1.55cqw;
  line-height: 1.25;
}

.dc__me > i {
  position: relative;
  flex: none;
  width: 3.4cqw;
  height: 3.4cqw;
  border-radius: 50%;
  background: #b6572f;
}

.dc__me > i::after {
  content: "";
  position: absolute;
  right: -0.3cqw;
  bottom: -0.3cqw;
  width: 1.3cqw;
  height: 1.3cqw;
  border: 0.35cqw solid #232428;
  border-radius: 50%;
  background: #23a55a;
}

.dc__me b {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 600;
  color: #f2f3f5;
}

.dc__me span {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
}

.dc__me em {
  flex: none;
  width: 6.2cqw;
  height: 2cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 16' fill='none' stroke='%23b5bac1' stroke-width='1.5' stroke-linecap='round'%3E%3Crect x='5' y='1.5' width='5' height='8' rx='2.5'/%3E%3Cpath d='M3 7.5a4.5 4.5 0 0 0 9 0M7.5 12v2.5'/%3E%3Cpath d='M23 11V8a5 5 0 0 1 10 0v3M22 10h3v4h-3zM31 10h3v4h-3z'/%3E%3Ccircle cx='51' cy='8' r='2.2'/%3E%3Cpath d='M51 2.5v1.5M51 12v1.5M45.5 8H47M55 8h1.5M47.2 4.2l1 1M53.8 10.8l1 1M47.2 11.8l1-1M53.8 5.2l1-1'/%3E%3C/svg%3E") center / contain no-repeat;
}

.dc__main {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.dc__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.9cqw;
  height: 5.6cqw;
  padding: 0 1.8cqw;
  box-shadow: 0 1px 0 rgb(0 0 0 / 0.3);
  font-size: 1.95cqw;
  font-weight: 600;
  color: #f2f3f5;
  white-space: nowrap;
}

.dc__head > i {
  font-style: normal;
  font-size: 2.6cqw;
  font-weight: 400;
  color: #80848e;
}

.dc__head > span {
  min-width: 0;
  margin-left: 0.6cqw;
  padding-left: 1.4cqw;
  border-left: 1px solid #3f4147;
  font-size: 1.55cqw;
  font-weight: 400;
  color: #949ba4;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Threads, notifications, pins, members */
.dc__head > em {
  flex: none;
  width: 10cqw;
  height: 2cqw;
  margin-left: auto;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 16' fill='none' stroke='%23b5bac1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4h9M3 8h6M3 12h8'/%3E%3Cpath d='M25 12h6M27 12V7a3 3 0 0 1 6 0v5h1.5M26.5 12a1.5 1.5 0 0 0 3 0' transform='translate(-3)'/%3E%3Cpath d='M47 2.5l5 5-2 .8-2.5 2.5.3 2.2-1.3 1.3-6.3-6.3L41.5 6.7l2.2.3 2.5-2.5z'/%3E%3Ccircle cx='66' cy='5.5' r='2.5'/%3E%3Cpath d='M61.5 13.5a4.5 4.5 0 0 1 9 0M71 3.5a2.2 2.2 0 0 1 0 4.4M73.5 13.5a3.8 3.8 0 0 0-2-3.3'/%3E%3C/svg%3E") right center / contain no-repeat;
}

/* New messages come in at the bottom and push the older ones up (discord.js) */
.dc__log {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 1.7cqw;
  min-height: 0;
  padding: 0 1.8cqw 1.8cqw;
  overflow: hidden;
}

.dc__msg {
  flex: none;
  display: grid;
  grid-template-columns: 4.4cqw minmax(0, 1fr);
  column-gap: 1.4cqw;
}

.dc__reply {
  position: relative;
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 0.6cqw;
  margin-bottom: 0.3cqw;
  font-size: 1.6cqw;
  color: #b5bac1;
  white-space: nowrap;
}

/* The little elbow Discord draws from the avatar up to the command */
.dc__reply::before {
  content: "";
  position: absolute;
  right: calc(100% + 0.7cqw);
  top: 50%;
  width: 3cqw;
  height: 1.6cqw;
  border: solid #4e5058;
  border-width: 0.25cqw 0 0 0.25cqw;
  border-top-left-radius: 0.7cqw;
}

.dc__reply b {
  font-weight: 600;
  color: #dbdee1;
}

.dc__cmd {
  color: #00a8fc;
}

.dc__av {
  display: block;
  width: 4.4cqw;
  height: 4.4cqw;
  border-radius: 50%;
  background: var(--av, #5865f2);
}

.dc__reply .dc__av {
  flex: none;
  width: 1.9cqw;
  height: 1.9cqw;
}

.dc__av--bot {
  grid-row: 2 / span 3;
  background: #f0944e url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%231d1007' stroke-width='1.6' stroke-linecap='round'%3E%3Crect x='5' y='7' width='10' height='8' rx='2.5'/%3E%3Cpath d='M10 4.5V7M8.2 11h.01M11.8 11h.01'/%3E%3C/svg%3E") center / 64% no-repeat;
}

.dc__msg--plain .dc__av--bot {
  grid-row: 1 / span 3;
}

.dc__who {
  display: flex;
  align-items: baseline;
  gap: 0.8cqw;
  font-size: 1.95cqw;
  white-space: nowrap;
}

.dc__who b {
  font-weight: 600;
  color: #f0944e;
}

/* The APP tag, with its verified tick */
.dc__who em {
  display: inline-flex;
  align-items: center;
  gap: 0.25cqw;
  padding: 0.1cqw 0.5cqw;
  border-radius: 0.45cqw;
  background: #5865f2;
  font-size: 1.2cqw;
  font-weight: 600;
  line-height: 1.35;
  font-style: normal;
  color: #fff;
  translate: 0 -0.2cqw;
}

.dc__who em::before {
  content: "";
  width: 1cqw;
  height: 1cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 5.2 4 7.2 8 2.8'/%3E%3C/svg%3E") center / contain no-repeat;
}

.dc__who time {
  font-size: 1.45cqw;
  color: #949ba4;
}

.dc__text {
  font-size: 1.95cqw;
}

.dc__text b {
  font-weight: 600;
}

.dc__embed {
  justify-self: start;
  width: 92%;
  margin-top: 0.5cqw;
  padding: 1.1cqw 1.6cqw 1.2cqw;
  border-left: 0.5cqw solid #f0944e;
  border-radius: 0.5cqw;
  background: #2b2d31;
  font-size: 1.75cqw;
}

.dc__embed--mod {
  border-left-color: #f23f43;
}

.dc__embed b {
  font-weight: 700;
  color: #f2f3f5;
}

.dc__xp {
  height: 1.1cqw;
  margin: 0.9cqw 0 0.7cqw;
  border-radius: 1cqw;
  background: #1e1f22;
  overflow: hidden;
}

.dc__xp i {
  display: block;
  width: 85.5%;
  height: 100%;
  border-radius: inherit;
  background: #f0944e;
  transform-origin: left;
}

.dc__meta {
  display: flex;
  justify-content: space-between;
  gap: 1.4cqw;
  margin-top: 0.3cqw;
  font-size: 1.55cqw;
  color: #b5bac1;
}

.dc__top {
  display: grid;
  gap: 0.4cqw;
  margin-top: 0.7cqw;
  font-size: 1.6cqw;
}

.dc__top li {
  display: flex;
  justify-content: space-between;
  color: #b5bac1;
}

.dc__top li b {
  font-weight: 600;
  color: #dbdee1;
}

/* The message box, and under it who's typing */
.dc__input {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.3cqw;
  margin: 0 1.8cqw;
  padding: 1.3cqw 1.5cqw;
  border-radius: 0.9cqw;
  background: #383a40;
  font-size: 1.75cqw;
  color: #6d6f78;
}

.dc__input::before {
  content: "";
  flex: none;
  width: 2.3cqw;
  height: 2.3cqw;
  border-radius: 50%;
  background: #b5bac1 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' stroke='%23383a40' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M5 2.5v5M2.5 5h5'/%3E%3C/svg%3E") center / 70% no-repeat;
}

.dc__typing {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.4cqw;
  height: 3.4cqw;
  padding-left: 2.4cqw;
  font-size: 1.4cqw;
  color: #b5bac1;
}

.dc__typing {
  opacity: 0;
  transition: opacity 0.2s;
}

.dc__typing.is-on {
  opacity: 1;
}

.dc__typing b {
  margin-left: 0.5cqw;
  font-weight: 700;
  color: #dbdee1;
}

.dc__typing i {
  width: 0.75cqw;
  height: 0.75cqw;
  border-radius: 50%;
  background: #dbdee1;
}

@media (prefers-reduced-motion: no-preference) {
  .js .dc__typing i { animation: dc-dot 1s ease-in-out infinite; }
  .js .dc__typing i:nth-child(2) { animation-delay: 0.15s; }
  .js .dc__typing i:nth-child(3) { animation-delay: 0.3s; }

  /* The level bar fills when a rank card arrives */
  .js .dc__msg.is-new .dc__xp i {
    animation: dc-xp 1.1s 0.2s var(--ease-out) both;
  }
}

@keyframes dc-xp {
  from { transform: scaleX(0.7); }
}

@keyframes dc-dot {
  0%, 60%, 100% { opacity: 0.35; translate: 0 0; }
  30% { opacity: 1; translate: 0 -0.35cqw; }
}

/* ==========================================================================
   Python browser: the PyQt5 browser, open on this site, with its DOM inspector
   Qt on Windows: Segoe UI 9 pt, a flat toolbar, vista tabs that close,
   and the inspector in a dock widget.
   ========================================================================== */

.qt {
  background: #f0f0f0;
  font-family: var(--f-ui);
  --qt-nav: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 88 16'%3E%3Cg transform='translate(0 0)'%3E%3Cpath d='M13 8H4.5M8 4 4 8l4 4' fill='none' stroke='%232f6db5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(24 0)'%3E%3Cpath d='M3 8h8.5M8 4l4 4-4 4' fill='none' stroke='%239bb4d4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(48 0)'%3E%3Cpath d='M12.8 7.2A4.9 4.9 0 1 1 11 4' fill='none' stroke='%232e9e3a' stroke-width='1.8' stroke-linecap='round'/%3E%3Cpath d='M11.8 1.6v3.1H8.7' fill='none' stroke='%232e9e3a' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/g%3E%3Cg transform='translate(72 0)'%3E%3Cpath d='M2.5 8.2 8 3l5.5 5.2' fill='none' stroke='%23b0413e' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M4.3 7v6.5h7.4V7' fill='%23f3e3c3' stroke='%238a6a3c' stroke-width='1.1'/%3E%3Cpath d='M7 13.5v-3.3h2v3.3' fill='%238a6a3c'/%3E%3C/g%3E%3C/svg%3E");
}

.qt__nav {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.4cqw;
  padding: 0.8cqw 1.4cqw;
}

.qt__btns {
  flex: none;
  width: 13cqw;
  height: 2.4cqw;
  background: var(--qt-nav) left center / auto 100% no-repeat;
}

.qt__url {
  flex: 1;
  padding: 0.6cqw 0.9cqw;
  border: 1px solid #7a7a7a;
  background: #fff;
  font-size: 1.75cqw;
  color: #000;
  white-space: nowrap;
  overflow: hidden;
}

.qt__tabs {
  flex: none;
  display: flex;
  align-items: flex-end;
  height: 4.2cqw;
  padding: 0 1.4cqw;
  border-bottom: 1px solid #d9d9d9;
  font-size: 1.6cqw;
}

.qt__tabs span {
  display: flex;
  align-items: center;
  gap: 1.2cqw;
  margin-right: -1px;
  padding: 0.75cqw 1cqw 0.75cqw 1.4cqw;
  border: 1px solid #adadad;
  border-bottom: 0;
  background: linear-gradient(#fdfdfd, #e9e9e9);
  color: #000;
  white-space: nowrap;
}

.qt__tabs .is-on {
  position: relative;
  z-index: 1;
  margin-bottom: -1px;
  padding-bottom: calc(0.75cqw + 1px);
  background: #fff;
}

/* setTabsClosable(True) */
.qt__tabs i {
  flex: none;
  width: 1.3cqw;
  height: 1.3cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' stroke='%23555' stroke-width='1.1'%3E%3Cpath d='M2 2l6 6M8 2 2 8'/%3E%3C/svg%3E") center / contain no-repeat;
}

.qt__split {
  flex: 1;
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  min-height: 0;
}

.qt__page {
  position: relative;
  overflow: hidden;
  background: #090b10;
}

/* The page itself: this portfolio's hero at 1280 px, small */
.mini {
  padding: 1.1cqw 1.8cqw;
  color: #f8fafc;
  font-family: var(--font-sans);
}

/* Full width and 60 px tall at 1280, like the real sticky header */
.mini__nav {
  display: flex;
  align-items: center;
  gap: 0.9cqw;
  height: 2.54cqw;
  margin: -1.1cqw -1.8cqw 0.93cqw;
  padding: 0 1.8cqw;
  border-bottom: 1px solid rgb(248 250 252 / 0.09);
  font-size: 0.72cqw;
  color: #94a3b8;
  white-space: nowrap;
}

/* The logo is dark ink; the site inverts it on the dark theme */
.mini__nav img {
  width: 1.4cqw;
  height: 1.4cqw;
  filter: invert(1);
}

.mini__nav b {
  margin-right: auto;
  font-size: 0.95cqw;
  font-weight: 600;
  color: #f8fafc;
}

.mini__nav em {
  margin-left: 0.4cqw;
  padding: 0.25cqw 0.5cqw;
  border: 1px solid rgba(248, 250, 252, 0.24);
  border-radius: 0.35cqw;
  font-style: normal;
  font-weight: 600;
  color: #f8fafc;
}

.mini__hero {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 2cqw;
  align-items: center;
  margin-top: 2.6cqw;
}

.mini__pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45cqw;
  padding: 0.25cqw 0.7cqw;
  border: 1px solid rgba(248, 250, 252, 0.24);
  border-radius: 2cqw;
  font-size: 0.72cqw;
  color: #94a3b8;
  white-space: nowrap;
}

.mini__pill i {
  width: 0.55cqw;
  height: 0.55cqw;
  border-radius: 50%;
  background: #34d399;
}

.mini__hand {
  width: max-content;
  margin-top: 1cqw;
  font: 600 1.7cqw/1 "Caveat", cursive;
  color: #60a5fa;
  rotate: -4deg;
  transform-origin: left bottom;
}

.mini__h1 {
  width: max-content;
  max-width: 100%;
  margin-top: 0.3cqw;
  font-size: 3cqw;
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.035em;
}

.mini__role {
  margin-top: 0.9cqw;
  font-size: 1.12cqw;
  line-height: 1.35;
}

.mini__btns {
  display: flex;
  gap: 0.6cqw;
  margin-top: 1.2cqw;
}

.mini__btn {
  display: inline-block;
  padding: 0.5cqw 0.9cqw;
  border-radius: 0.5cqw;
  background: #60a5fa;
  color: #090b10;
  font-size: 0.85cqw;
  font-weight: 500;
  white-space: nowrap;
}

.mini__btn--ghost {
  border: 1px solid rgba(248, 250, 252, 0.24);
  background: none;
  color: #f8fafc;
}

.mini__card {
  border: 1px solid rgba(248, 250, 252, 0.14);
  border-radius: 1cqw;
  background: #10141d;
  font-size: 0.62cqw;
  color: #94a3b8;
}

.mini__ch {
  display: flex;
  justify-content: space-between;
  padding: 0.6cqw 0.9cqw;
  border-bottom: 1px solid rgba(248, 250, 252, 0.14);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
}

.mini__card svg {
  width: 88%;
  margin: 0.8cqw auto 0.3cqw;
}

.mini__cap {
  padding: 0 0.9cqw 0.7cqw;
  border-bottom: 1px solid rgba(248, 250, 252, 0.14);
  font-family: var(--font-mono);
}

.mini__rows div {
  display: grid;
  grid-template-columns: 3.4cqw 1fr;
  padding: 0.45cqw 0.9cqw;
  border-bottom: 1px solid rgba(248, 250, 252, 0.09);
}

.mini__rows dt {
  font-family: var(--font-mono);
}

.mini__rows dd {
  color: #f8fafc;
  white-space: nowrap;
  overflow: hidden;
}

/* Inspector highlight on the page, and the size tag under it (placed by browser.js).
   They follow the mouse instantly, the way devtools does. */
.qt__hl {
  position: absolute;
  z-index: 2;
  left: 0;
  top: 0;
  border: 1px solid rgb(61 142 221 / 0.95);
  background: rgb(111 168 220 / 0.32);
}

.qt__tip {
  position: absolute;
  z-index: 3;
  left: 0;
  top: 0;
  padding: 0.4cqw 0.8cqw;
  border-radius: 0.4cqw;
  background: #fff;
  box-shadow: 0 0.3cqw 1cqw rgb(0 0 0 / 0.35);
  font: 400 1.3cqw/1.2 Consolas, var(--font-mono);
  color: #555;
  white-space: nowrap;
}

.qt__tip b {
  font-weight: 500;
  color: #881280;
}

.qt__tip i {
  font-style: normal;
  color: #994500;
}

/* Hidden until browser.js has measured where they go */
.qt__hl:not(.is-on),
.qt__tip:not(.is-on) {
  opacity: 0;
}

/* The inspector, docked on the right */
.qt__dom {
  position: relative;
  border-left: 1px solid #c8c8c8;
  background: #fff;
  font: 400 1.6cqw/1 Consolas, var(--font-mono);
  color: #888;
}

.qt__dh {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.8cqw 1cqw;
  background: #f0f0f0;
  font: 400 1.6cqw/1 var(--f-ui);
  color: #000;
}

/* Float and close */
.qt__dh i {
  width: 3.4cqw;
  height: 1.3cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 10' fill='none' stroke='%23444' stroke-width='1'%3E%3Crect x='1.5' y='1.5' width='7' height='7'/%3E%3Cpath d='M1.5 3.5h7M18 2l6 6M24 2l-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
}

.qt__dom ul {
  display: grid;
  padding: 0.5cqw 0;
}

.qt__dom li {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.2cqw;
  padding: 0.6cqw 1cqw 0.6cqw 2.2cqw;
  white-space: nowrap;
}

/* Branch arrows, the way Qt draws them on Windows */
.qt__dom li::before {
  content: "";
  position: absolute;
  left: calc(var(--d, 0) * 1.6cqw + 0.6cqw);
  width: 1cqw;
  height: 1cqw;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='%23777' stroke-width='1.2'%3E%3Cpath d='M3.5 2 6.5 5l-3 3'/%3E%3C/svg%3E") center / contain no-repeat;
}

.qt__dom li.open::before {
  rotate: 90deg;
}

.qt__dom li.d3::before {
  display: none;
}

.qt__dom li b {
  font-weight: 400;
  color: #881280;
}

.qt__dom li i {
  font-style: normal;
  color: #994500;
}

.qt__dom .d1 { --d: 1; padding-left: 3.8cqw; }
.qt__dom .d2 { --d: 2; padding-left: 5.4cqw; }
.qt__dom .d3 { --d: 3; padding-left: 7cqw; }

.qt__sel {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2.8cqw;
  background: #cce8ff;
  box-shadow: inset 0 0 0 1px #99d1ff;
}

.js .qt__sel:not(.is-on) {
  opacity: 0;
}

/* ==========================================================================
   Communication simulator: the MATLAB App Designer app, Aura included
   uifigure grey, uipanels with a title and a thin border, Helvetica 12,
   drop-downs, a slider with its ticks, uiaxes, and a text area for Aura.
   ========================================================================== */

.ad {
  inset: 4.5cqw 5cqw;
  height: auto;
  background: #f0f0f0;
  font: 400 1.6cqw/1.2 var(--f-plot);
  color: #000;
}

.ad__body {
  flex: 1;
  display: grid;
  grid-template-columns: 21cqw minmax(0, 1fr);
  gap: 1.4cqw;
  min-height: 0;
  padding: 1.4cqw 1.4cqw 0;
}

/* A uipanel: title on top, thin grey border */
.ad__ctl,
.aura {
  position: relative;
  border: 1px solid #a0a0a0;
  background: #f0f0f0;
}

.ad__pt,
.aura__h {
  padding: 0.5cqw 1cqw;
  border-bottom: 1px solid #a0a0a0;
  background: #fafafa;
  font-weight: 700;
}

.ad__ctl {
  display: flex;
  flex-direction: column;
  gap: 0.6cqw;
}

.ad__ctl > :not(.ad__pt) {
  margin-inline: 1.1cqw;
}

.ad__ctl label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 0.3cqw;
}

/* uieditfield (numeric), right-aligned like MATLAB's */
.ad__ctl label b {
  width: 5cqw;
  padding: 0.3cqw 0.6cqw;
  border: 1px solid #a3a3a3;
  border-radius: 0.3cqw;
  background: #fff;
  font-weight: 400;
  text-align: right;
}

.ad__dd {
  position: relative;
  padding: 0.55cqw 0.9cqw;
  border: 1px solid #a3a3a3;
  border-radius: 0.3cqw;
  background: #fff;
}

.ad__dd::after {
  content: "";
  position: absolute;
  right: 0.9cqw;
  top: 50%;
  border: 0.55cqw solid transparent;
  border-top: 0.6cqw solid #333;
  border-bottom: 0;
  translate: 0 -40%;
}

/* uislider: a thin track and a round thumb, ticks every 10 dB */
.ad__slider {
  position: relative;
  height: 2.4cqw;
  margin-inline: 1.6cqw !important;
}

.ad__slider::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 1.05cqw;
  height: 0.35cqw;
  border-radius: 0.2cqw;
  background: #b4b4b4;
}

.ad__slider i {
  position: absolute;
  top: 0.25cqw;
  left: var(--p);
  width: 1.9cqw;
  height: 1.9cqw;
  margin-left: -0.95cqw;
  border: 1px solid #7a7a7a;
  border-radius: 50%;
  background: linear-gradient(#ffffff, #e4e4e4);
}

/* Held by the mouse */
.ad__slider i.is-down {
  border-color: #0072bd;
  background: linear-gradient(#f2f8fc, #d6e6f2);
}

/* The open drop-down: its list hangs off the bottom of the box */
.ad__dd.is-open {
  border-color: #0072bd;
  border-radius: 0.3cqw 0.3cqw 0 0;
}

.ad__list {
  position: absolute;
  z-index: 20;
  display: none;
  margin: 0;
  padding: 0.2cqw 0;
  list-style: none;
  border: 1px solid #0072bd;
  border-top-color: #a3a3a3;
  background: #fff;
  box-shadow: 0 0.5cqw 1.2cqw rgb(0 0 0 / 0.2);
}

.ad__list.is-on {
  display: block;
}

.ad__list li {
  padding: 0.45cqw 0.9cqw;
}

.ad__list li.is-sel {
  background: #e6e6e6;
}

.ad__list li.is-hover {
  background: #d4e8f8;
}

.ad__ticks {
  display: flex;
  justify-content: space-between;
  margin-inline: 0.9cqw !important;
  font-size: 1.3cqw;
}

.ad__ticks b::before {
  content: "";
  display: block;
  width: 1px;
  height: 0.5cqw;
  margin: 0 auto 0.3cqw;
  background: #7a7a7a;
}

.ad__ticks b {
  width: 1.4cqw;
  font-weight: 400;
  text-align: center;
}

/* A uibutton restyled blue, the way the app has it */
.ad__btn {
  margin-top: auto;
  margin-bottom: 1.1cqw;
  padding: 0.75cqw;
  border: 1px solid #0b5a9e;
  border-radius: 0.35cqw;
  background: #0072bd;
  color: #fff;
  text-align: center;
  font-weight: 700;
}

.ad__plots {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 3.3cqw;
  min-height: 0;
  padding: 2.6cqw 0.6cqw 2.4cqw 4.2cqw;
}

.ad__ax {
  position: relative;
  border: 1px solid #262626;
  background: #fff;
  background-image:
    linear-gradient(90deg, rgb(38 38 38 / 0.12) 1px, transparent 1px),
    linear-gradient(rgb(38 38 38 / 0.12) 1px, transparent 1px);
  background-size: 20% 100%, 100% 50%;
  background-position: -1px 0, 0 -1px;
}

.ad__ax svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.ad__ti {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 0.5cqw);
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
}

.ad__yt,
.ad__xt {
  position: absolute;
  inset: 0;
  font-size: 1.3cqw;
}

.ad__yt b,
.ad__xt b {
  position: absolute;
  font-weight: 400;
}

.ad__yt b {
  right: calc(100% + 0.6cqw);
  top: calc(var(--y) * 1%);
  translate: 0 -50%;
}

.ad__xt b {
  top: calc(100% + 0.5cqw);
  left: calc(var(--x) * 1%);
  translate: -50% 0;
}

/* Aura: a panel with a text area and two buttons */
.aura {
  flex: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto;
  column-gap: 1.2cqw;
  margin: 1.4cqw;
}

.aura__h {
  grid-column: 1 / -1;
}

/* Two lines, always, so the panel doesn't jump while Aura types */
.aura__t {
  height: 4.4cqw;
  margin: 0.9cqw 0 0.9cqw 1cqw;
  padding: 0.3cqw 0.7cqw;
  border: 1px solid #a3a3a3;
  background: #fff;
  font-size: 1.5cqw;
  line-height: 1.3;
  overflow: hidden;
}

.aura__t[dir="rtl"] {
  font-family: "Segoe UI", Tahoma, "Noto Naskh Arabic", "Geeza Pro", sans-serif;
  font-size: 1.6cqw;
  line-height: 1.25;
}

.aura__acts {
  display: grid;
  align-content: center;
  gap: 0.6cqw;
  margin-right: 1cqw;
}

.aura__acts span {
  padding: 0.45cqw 1cqw;
  border: 1px solid #8c8c8c;
  border-radius: 0.35cqw;
  background: linear-gradient(#fbfbfb, #ececec);
  font-size: 1.35cqw;
  text-align: center;
  white-space: nowrap;
}

/* ==========================================================================
   Flappy Bird clone: the pygame window
   ========================================================================== */

.py {
  inset: 6cqw 9cqw auto;
  height: 57cqw;
  background: #111;
}

.fb {
  display: block;
  flex: 1;
  width: 100%;
  min-height: 0;
  background: linear-gradient(#7dd3e8, #d7f4f7 80%, #e9d7a8 80%);
  image-rendering: pixelated;
}

.modal .fb {
  cursor: pointer;
  touch-action: manipulation;
}

/* ==========================================================================
   Pixel art adventure: the Godot 4 editor, mid-build
   The default dark theme: the 2D workspace, the Scene dock with blue 2D node
   icons, rulers, the red and green axes, the game's viewport outlined, and
   the TileMap panel along the bottom.
   ========================================================================== */

.gd {
  background: #21262e;
  color: #cdcfd2;
  font: 400 1.6cqw/1 var(--f-ui);
  --gi-node2d: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5' fill='none' stroke='%238da5f3' stroke-width='2'/%3E%3C/svg%3E");
  --gi-tilemap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%238da5f3' d='M2 2h5v5H2zM9 2h5v5H9zM2 9h5v5H2z'/%3E%3Cpath fill='none' stroke='%238da5f3' stroke-width='1.2' d='M9.6 9.6h3.8v3.8H9.6z'/%3E%3C/svg%3E");
  --gi-body: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='4.5' r='2.6' fill='%238da5f3'/%3E%3Cpath fill='%238da5f3' d='M3.5 14.5c0-3.2 2-5.3 4.5-5.3s4.5 2.1 4.5 5.3z'/%3E%3C/svg%3E");
  --gi-sprite: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1.8' y='2.8' width='12.4' height='10.4' rx='1.4' fill='none' stroke='%238da5f3' stroke-width='1.6'/%3E%3Cpath fill='%238da5f3' d='M3.5 11.5 6.5 7.5l2.2 2.6 1.6-1.6 2.2 3z'/%3E%3Ccircle cx='10.8' cy='5.6' r='1.2' fill='%238da5f3'/%3E%3C/svg%3E");
  --gi-shape: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='2.5' y='2.5' width='11' height='11' fill='none' stroke='%238da5f3' stroke-width='1.6' stroke-dasharray='2.4 1.6'/%3E%3C/svg%3E");
  --gi-camera: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1.5' y='4.5' width='9' height='7' rx='1.2' fill='%238da5f3'/%3E%3Cpath fill='%238da5f3' d='M11 7l3.5-2v6L11 9z'/%3E%3C/svg%3E");
  --gi-eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23cdcfd2' stroke-width='1.3' d='M1.5 8S4 3.8 8 3.8 14.5 8 14.5 8 12 12.2 8 12.2 1.5 8 1.5 8z'/%3E%3Ccircle cx='8' cy='8' r='2' fill='%23cdcfd2'/%3E%3C/svg%3E");
  --gi-script: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23cdcfd2' d='M4 2h7.5L14 4.5V14H4z'/%3E%3Cpath stroke='%2321262e' stroke-width='1.1' d='M6 6h5M6 8.5h5M6 11h3.5'/%3E%3C/svg%3E");
  --gi-ws2d: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%238da5f3' stroke-width='1.5' d='M2.5 12.5 7 3.5l6.5 9z'/%3E%3C/svg%3E");
  --gi-ws3d: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fc7f7f' stroke-width='1.5' d='M8 2 13.5 5v6L8 14 2.5 11V5z'/%3E%3C/svg%3E");
  --gi-wsscript: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23cdcfd2' stroke-width='1.4' d='M3 2.5h8l2 2v9H3z'/%3E%3Cpath stroke='%23cdcfd2' d='M5.5 6.5h5M5.5 9h5M5.5 11.5h3'/%3E%3C/svg%3E");
  --gi-wsasset: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23cdcfd2' stroke-width='1.4' d='M2.5 5.5 8 2.5l5.5 3v6L8 14.5l-5.5-3z'/%3E%3Cpath stroke='%23cdcfd2' d='M2.5 5.5 8 8.5l5.5-3M8 8.5v6'/%3E%3C/svg%3E");
}

.pv .gd {
  height: 55cqw;
}

.gd__top {
  flex: none;
  display: flex;
  align-items: center;
  gap: 1.8cqw;
  height: 4.6cqw;
  padding: 0 1.6cqw;
  background: #1b1f26;
}

.gd__menu {
  display: flex;
  gap: 1.5cqw;
  color: #b6b9bd;
}

.gd__menu b {
  font-weight: 400;
}

.gd__ws {
  display: flex;
  gap: 0.4cqw;
  margin-inline: auto;
}

.gd__ws b {
  display: flex;
  align-items: center;
  gap: 0.6cqw;
  padding: 0.7cqw 1cqw;
  border-radius: 0.4cqw;
  font-weight: 400;
  color: #a8abb0;
}

.gd__ws b::before {
  content: "";
  width: 1.6cqw;
  height: 1.6cqw;
  background: var(--i) center / contain no-repeat;
}

.gd__ws b:nth-child(1) { --i: var(--gi-ws2d); }
.gd__ws b:nth-child(2) { --i: var(--gi-ws3d); }
.gd__ws b:nth-child(3) { --i: var(--gi-wsscript); }
.gd__ws b:nth-child(4) { --i: var(--gi-wsasset); }

.gd__ws b.is-on {
  background: #363d4a;
  color: #fff;
}

.gd__play {
  display: flex;
  gap: 1.1cqw;
}

.gd__play i {
  width: 1.7cqw;
  height: 1.7cqw;
  background: #cdcfd2;
  -webkit-mask: var(--g) center / contain no-repeat;
  mask: var(--g) center / contain no-repeat;
}

.gd__play i:nth-child(1) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2 1l7 4-7 4z'/%3E%3C/svg%3E"); }
.gd__play i:nth-child(2) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2 1h2v8H2zM6 1h2v8H6z'/%3E%3C/svg%3E"); }
.gd__play i:nth-child(3) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 1.5h7v7h-7z'/%3E%3C/svg%3E"); }
.gd__play i:nth-child(4) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1 1.5h8v7H1zM3 3.5l3.5 1.5L3 6.5z' fill-rule='evenodd'/%3E%3C/svg%3E"); }

/* The renderer, top right */
.gd__top em {
  font-style: normal;
  font-size: 1.35cqw;
  color: #5fb2ff;
}

.gd__main {
  flex: 1;
  display: grid;
  grid-template-columns: 22.5cqw minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.4cqw;
  min-height: 0;
  padding: 0.4cqw;
}

.gd__dock {
  grid-row: 1 / -1;
  border-radius: 0.4cqw;
  background: #282e38;
}

.gd__dh {
  padding: 1cqw 1.2cqw;
  border-bottom: 1px solid #1d2229;
  color: #fff;
}

.gd__dock ul {
  display: grid;
  gap: 0.1cqw;
  padding: 0.8cqw 0.6cqw;
}

.gd__dock li {
  display: flex;
  align-items: center;
  gap: 0.6cqw;
  padding: 0.6cqw 0.5cqw;
  font-size: 1.5cqw;
  border-radius: 0.3cqw;
  white-space: nowrap;
}

/* Every 2D node's icon is blue in Godot; the shape says which kind */
.gd__dock li::before {
  content: "";
  flex: none;
  width: 1.6cqw;
  height: 1.6cqw;
  background: var(--i) center / contain no-repeat;
}

/* Script attached, and the visibility eye every CanvasItem gets */
.gd__dock li::after {
  content: "";
  flex: none;
  width: var(--sw, 1.5cqw);
  height: 1.5cqw;
  margin-left: auto;
  background: var(--s, none) left center / 1.5cqw no-repeat, var(--gi-eye) right center / 1.5cqw no-repeat;
}

.gd__dock li.sc { --s: var(--gi-script); --sw: 3.6cqw; }
.gd__dock li.d1 { padding-left: 1.9cqw; }
.gd__dock li.d2 { padding-left: 3.3cqw; }
.gd__dock li.is-on { background: #3b4a64; color: #fff; }

.gd__dock .n2 { --i: var(--gi-node2d); }
.gd__dock .tm { --i: var(--gi-tilemap); }
.gd__dock .cb { --i: var(--gi-body); }
.gd__dock .sp { --i: var(--gi-sprite); }
.gd__dock .cs { --i: var(--gi-shape); }
.gd__dock .cam { --i: var(--gi-camera); }

.gd__view {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border-radius: 0.4cqw;
  background: #1b1f26;
}

/* The open scene's tab, unsaved */
.gd__file {
  flex: none;
  align-self: flex-start;
  padding: 0.8cqw 1.3cqw;
  border-radius: 0.4cqw 0.4cqw 0 0;
  background: #282e38;
  box-shadow: inset 0 0.25cqw 0 #70bafa;
  color: #e3e5e8;
}

.gd__file b {
  font-weight: 400;
}

/* 2D toolbar: select, move, rotate, scale, and the TileMap brush */
.gd__tools {
  flex: none;
  display: flex;
  gap: 1cqw;
  padding: 0.7cqw 1.1cqw;
  background: #282e38;
  border-bottom: 1px solid #1b1f26;
}

.gd__tools i {
  width: 1.7cqw;
  height: 1.7cqw;
  border-radius: 0.3cqw;
  background: #cdcfd2;
  -webkit-mask: var(--g) center / contain no-repeat;
  mask: var(--g) center / contain no-repeat;
}

.gd__tools i:nth-child(1) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2 1l6 4.2-2.7.5L7 9 5.8 9.5 4.2 6.3 2 8z'/%3E%3C/svg%3E"); }
.gd__tools i:nth-child(2) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='black' stroke-width='1.1'%3E%3Cpath d='M5 1v8M1 5h8M5 1 3.8 2.2M5 1l1.2 1.2M5 9 3.8 7.8M5 9l1.2-1.2M1 5l1.2-1.2M1 5l1.2 1.2M9 5 7.8 3.8M9 5 7.8 6.2'/%3E%3C/svg%3E"); }
.gd__tools i:nth-child(3) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='black' stroke-width='1.2'%3E%3Cpath d='M8.2 5.5A3.3 3.3 0 1 1 7 2.4M7.4 1v1.9H5.5'/%3E%3C/svg%3E"); }
.gd__tools i:nth-child(4) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='black' stroke-width='1.1'%3E%3Crect x='1' y='4' width='5' height='5'/%3E%3Cpath d='M5 1h4v4M9 1 5.6 4.4'/%3E%3C/svg%3E"); }
.gd__tools i:nth-child(5) { --g: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M6.5 1.2 8.8 3.5 4.6 7.7 2.3 5.4zM1.9 6l2.1 2.1L1 9z'/%3E%3C/svg%3E"); }

.gd__tools i.is-on {
  background: #70bafa;
}

/* The canvas, with rulers along the top and left */
.gd__stage {
  --r: 1.5cqw;
  position: relative;
  flex: 1;
  min-height: 0;
  background: #4d4d4d;
}

.gd__stage::before,
.gd__stage::after {
  content: "";
  position: absolute;
  z-index: 2;
  background-color: #2b3039;
}

.gd__stage::before {
  left: 0;
  right: 0;
  top: 0;
  height: var(--r);
  background-image: repeating-linear-gradient(90deg, rgb(205 207 210 / 0.45) 0 1px, transparent 1px 3cqw);
  background-position: calc(var(--r) + 1.4cqw) 100%;
  background-size: 100% 45%;
  background-repeat: no-repeat;
}

.gd__stage::after {
  left: 0;
  top: var(--r);
  bottom: 0;
  width: var(--r);
  background-image: repeating-linear-gradient(rgb(205 207 210 / 0.45) 0 1px, transparent 1px 3cqw);
  background-position: 100% 1.4cqw;
  background-size: 45% 100%;
  background-repeat: no-repeat;
}

/* godot.js sizes the level to the stage, and tells the grid how many rows there are */
.gd__canvas {
  position: absolute;
  left: calc(var(--r) + 1.4cqw);
  top: calc(var(--r) + 1.4cqw);
  right: 0;
  bottom: 0;
  width: calc(100% - var(--r) - 1.4cqw);
  height: calc(100% - var(--r) - 1.4cqw);
  image-rendering: pixelated;
  background-image:
    linear-gradient(rgb(255 255 255 / 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 0.06) 1px, transparent 1px);
  background-size: 6.25% calc(100% / var(--rows, 11));
}

/* The origin: X axis red, Y axis green, and the game's window outlined in purple */
.gd__axes {
  position: absolute;
  z-index: 1;
  inset: calc(var(--r) + 1.4cqw) 0 0 calc(var(--r) + 1.4cqw);
  border-top: 1px solid rgb(255 80 80 / 0.8);
  border-left: 1px solid rgb(100 220 110 / 0.8);
  pointer-events: none;
}

.gd__axes::after {
  content: "";
  position: absolute;
  inset: -1px 12% 18% -1px;
  border: 1px solid rgb(157 157 255 / 0.9);
}

/* The TileMap panel: the tile set, one tile picked */
.gd__panel {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 1.2cqw;
  height: 6.4cqw;
  padding: 0 1cqw;
  border-radius: 0.4cqw;
  background: #282e38;
}

.gd__panel p {
  display: grid;
  gap: 0.6cqw;
  font-size: 1.35cqw;
  color: #9da1a8;
  white-space: nowrap;
}

.gd__panel p b {
  font-weight: 400;
  color: #fff;
}

.gd__tiles {
  height: 4.4cqw;
  aspect-ratio: 4 / 1;
  border: 1px solid #1b1f26;
  background: #1f232a;
  image-rendering: pixelated;
}

/* ==========================================================================
   Siraj: the phones get proper frames and the middle one flips through screens
   ========================================================================== */

.phone {
  border: 0;
  box-shadow:
    0 0 0 2px #1a1a1f,
    0 0 0 3.5px #3a3a42,
    0 24px 40px -20px rgb(0 0 0 / 0.7);
  background: #0b0b0d;
}

.phone--c.phone--cycle {
  position: relative;
  z-index: 1;
  display: grid;
  overflow: hidden;
}

.phone--cycle img {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Without motion it's just the prayer screen */
.phone--cycle img + img {
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .js .phone--cycle img {
    animation: screen-cycle 16s infinite;
  }

  .js .phone--cycle img:nth-child(2) { animation-delay: 4s; }
  .js .phone--cycle img:nth-child(3) { animation-delay: 8s; }
  .js .phone--cycle img:nth-child(4) { animation-delay: 12s; }

  /* Spread the fan as the card scrolls into view */
  @supports (animation-timeline: view()) {
    .js .phones .phone--l,
    .js .phones .phone--r {
      animation: fan-in linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 40%;
    }

    .js .phones .phone--r {
      animation-name: fan-in-r;
    }
  }
}

@keyframes screen-cycle {
  0% { opacity: 0; }
  3%, 25% { opacity: 1; }
  28%, 100% { opacity: 0; }
}

@keyframes fan-in {
  from { translate: 45% 6%; rotate: 5deg; }
  to { translate: 0 0; rotate: 0deg; }
}

@keyframes fan-in-r {
  from { translate: -45% 6%; rotate: -5deg; }
  to { translate: 0 0; rotate: 0deg; }
}

/* ==========================================================================
   Dialog: the preview grows into a big live copy at the top
   ========================================================================== */

.modal__body > .pv {
  margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-5);
  border-bottom: 1px solid var(--line);
  pointer-events: auto;
}

.modal__body > .pv > * {
  opacity: 1;
  translate: 0 0;
}

/* It arrives by flying in from the card, so it skips the body's cascade */
.modal[open] .modal__body > .pv {
  animation: none;
}

/* Opening and closing a project: the card's preview grows into the dialog and
   shrinks back (projects.js). The dialog itself just fades while that happens.
   The flag stays on the dialog until it closes, so its own intro can't replay. */
.modal.no-intro[open],
.modal.no-intro[open]::backdrop {
  animation: none;
}

::view-transition-group(pv-open) {
  animation-duration: 0.55s;
  animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}

::view-transition-old(pv-open),
::view-transition-new(pv-open) {
  animation-duration: 0.3s;
  height: 100%;
  object-fit: cover;
  object-position: top;
}

html.is-opening::view-transition-old(root),
html.is-closing::view-transition-old(root) {
  animation: fade-out 0.3s ease both;
}

html.is-opening::view-transition-new(root),
html.is-closing::view-transition-new(root) {
  animation: fade-in 0.3s 0.05s ease both;
}

/* "You can play with this" tag, in the margin above the window */
.pv__hint {
  position: absolute;
  z-index: 6;
  left: 50%;
  top: 0.9cqw;
  transform: translateX(-50%);
  padding: max(0.7cqw, 3px) max(1.8cqw, 9px);
  border-radius: 3cqw;
  background: var(--accent);
  color: var(--on-accent);
  font: 500 max(1.9cqw, 11px)/1.2 var(--font-sans);
  white-space: nowrap;
  box-shadow: 0 0.6cqw 1.6cqw -0.6cqw rgb(0 0 0 / 0.5);
  transition: opacity 0.4s, transform 0.4s var(--ease-out);
}

.pv__hint.is-gone {
  opacity: 0;
  transform: translate(-50%, -1cqw);
}
