/* Transfer Me It — marketing site.
   The palette, type and motifs are ported from the macOS client so the site and
   the app read as one thing. Everything here is self-contained: no CDN, no
   external font, no network request of any kind. */

@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------- tokens */

:root {
  color-scheme: light dark;

  --ink: #15161a;
  --on-ink: #ffffff;
  --panel: #eceae6;
  --card: #ffffff;
  --inset: #f4f4f3;
  --hairline: #e7e5e0;
  --hairline-strong: #ded9d1;
  /* The app's muted (#8A8A85) sits at 2.9:1 on the panel, so prose uses a
     darkened counterpart and the app value is kept for the faintest marks. */
  --muted: #666560;
  --faint: #c9c6bf;
  --warn: #b4611e;
  --live: #2f8f6f;
  --rule: rgba(0, 0, 0, 0.022);
  --shadow: 0 1px 2px rgba(21, 22, 26, 0.04);

  --radius-card: 8px;
  --radius-control: 5px;
  --measure: 62ch;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #f1eee8;
    --on-ink: #15161a;
    --panel: #1c1b19;
    --card: #262523;
    --inset: #232220;
    --hairline: #35322e;
    --hairline-strong: #423e38;
    --muted: #a8a59c;
    --faint: #56534c;
    --warn: #e0a462;
    --live: #46b48e;
    --rule: rgba(255, 255, 255, 0.03);
    --shadow: none;
  }
}

/* ------------------------------------------------------------------ base */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--panel);
  color: var(--ink);
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13.5px;
  line-height: 1.65;
  font-weight: 400;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img,
svg {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

p {
  margin: 0 0 0.9em;
  max-width: var(--measure);
}

p:last-child {
  margin-bottom: 0;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 2px;
}

.wrap {
  width: 100%;
  max-width: 860px;
  margin: 0 auto;
  padding: 0 22px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 8px 12px;
  background: var(--ink);
  color: var(--on-ink);
  z-index: 10;
}

.skip:focus {
  left: 8px;
  top: 8px;
}

/* --------------------------------------------------------------- labels */

.section-label {
  display: block;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
}

.group-label {
  display: block;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--muted);
}

/* The ↓/↑ chips from the app: filled for what comes in, outlined for what
   goes out. Used here as section markers. */
.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 19px;
  height: 19px;
  flex: 0 0 19px;
  border-radius: var(--radius-control);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
}

.badge-in {
  background: var(--ink);
  color: var(--on-ink);
}

.badge-out {
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}

.heading-row {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 14px;
}

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

.site-header {
  border-bottom: 1px solid var(--hairline);
  background: var(--panel);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 54px;
  padding-top: 10px;
  padding-bottom: 10px;
}

/* The nav landmark repeats the header row's flex box so wrapping the links in
   it does not change the layout. */
.site-nav {
  display: flex;
  align-items: center;
  gap: 14px;
}

.mark {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  margin-right: auto;
}

/* The logo is a monochrome dark mark on transparency, so the dark theme flips
   it rather than shipping a second file. Checked against the panel: the
   inverted grey lands close to ink and keeps its weight. */
.mark img {
  width: 27px;
  height: 27px;
  flex: 0 0 27px;
}

@media (prefers-color-scheme: dark) {
  .mark img {
    filter: invert(1) brightness(1.12);
  }
}

.mark span {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  white-space: nowrap;
}

.nav-link {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
}

.nav-link:hover {
  color: var(--ink);
}

/* -------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 14px;
  border-radius: var(--radius-control);
  border: 1px solid transparent;
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

.btn-ink {
  background: var(--ink);
  color: var(--on-ink);
}

.btn-ink:hover {
  opacity: 0.85;
}

.btn-outline {
  background: var(--card);
  color: var(--ink);
  border-color: var(--hairline-strong);
}

.btn-outline:hover {
  background: var(--inset);
}

.btn-lg {
  padding: 12px 18px;
  font-size: 11.5px;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/* One-off offsets live here rather than in style attributes, which the
   Content-Security-Policy in _headers blocks. */
.btn-row-spaced-sm { margin-top: 18px; }
.btn-row-spaced { margin-top: 22px; }
.btn-row-spaced-lg { margin-top: 26px; }

/* ----------------------------------------------------------------- hero */

.hero {
  position: relative;
  border-bottom: 1px solid var(--hairline);
  overflow: hidden;
}

/* A 1px rule every 6px at barely-there opacity: ruled paper behind the code,
   not a visible pattern. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    90deg,
    var(--rule) 0,
    var(--rule) 1px,
    transparent 1px,
    transparent 6px
  );
  pointer-events: none;
}

.hero .wrap {
  position: relative;
  padding-top: 68px;
  padding-bottom: 62px;
  display: grid;
  gap: 48px;
  align-items: center;
}

@media (min-width: 900px) {
  .hero .wrap {
    grid-template-columns: minmax(0, 1fr) minmax(0, 330px);
  }
}

.hero h1 {
  font-size: clamp(1.5rem, 4.4vw, 2.1rem);
  font-weight: 500;
  max-width: 24ch;
  margin: 0 0 18px;
}

.hero-lede {
  color: var(--muted);
  font-size: 13.5px;
  max-width: 46ch;
  margin-bottom: 28px;
}

/* ----------------------------------------------------------- code card */

.code-card {
  background: var(--card);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  max-width: 420px;
  margin-bottom: 26px;
}

.code-card-body {
  padding: 20px 16px;
  display: flex;
  justify-content: center;
}

.code-stack {
  position: relative;
  display: inline-block;
}

/* What the drain leaves behind: the same code in the faint colour, so the code
   ghosts out rather than simply disappearing. Hidden while letters scramble,
   because a ghost would give the code away mid-fall. */
.code-ghost {
  position: absolute;
  inset: 0;
  color: var(--faint);
  pointer-events: none;
}

.code {
  margin: 0;
  /* Reserved width so a shorter triple never reflows the card. */
  min-width: 23ch;
  text-align: center;
  font-size: clamp(1rem, 4.9vw, 1.7rem);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--code-tint, var(--ink));
}

.code .sep {
  color: var(--faint);
}

/* The drain: the code ghosts out from the left as time is spent, two stops
   apart so the edge stays soft. */
@property --drain {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.code-drain {
  --drain: 0%;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0,
    transparent max(0%, calc(var(--drain) - 12%)),
    #000 var(--drain),
    #000 100%
  );
  mask-image: linear-gradient(
    90deg,
    transparent 0,
    transparent max(0%, calc(var(--drain) - 12%)),
    #000 var(--drain),
    #000 100%
  );
}

.code-card-foot {
  border-top: 1px solid var(--hairline);
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}

.dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--live);
  flex: 0 0 5px;
}

/* ------------------------------------------------------- macOS framing */

/* The app is a menu bar app, so the honest setting for a screenshot is a
   popover hanging under a menu bar. Built in CSS rather than photographed, and
   deliberately vague: a wallpaper wash, a strip, a clock, and the app's own
   mark with the real capture hanging directly beneath it. */
.mac {
  margin: 0;
}

.mac-desk {
  position: relative;
  border: 1px solid var(--hairline-strong);
  border-radius: 12px;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 20% 0%, rgba(255, 255, 255, 0.5), transparent 60%),
    linear-gradient(155deg, var(--hairline-strong), var(--panel) 55%, var(--hairline));
}

@media (prefers-color-scheme: dark) {
  .mac-desk {
    background:
      radial-gradient(120% 90% at 20% 0%, rgba(255, 255, 255, 0.06), transparent 60%),
      linear-gradient(155deg, #2f2b27, #1c1b19 55%, #232220);
  }
}

.mac-bar {
  position: relative;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 7px;
  /* Right padding leaves the status cluster clear of the centred mark, which is
     absolutely positioned and cannot push anything aside. */
  padding: 0 11px 0 11px;
  background: rgba(255, 255, 255, 0.34);
  border-bottom: 1px solid var(--hairline);
}

@media (prefers-color-scheme: dark) {
  .mac-bar {
    background: rgba(255, 255, 255, 0.05);
  }
}

/* Stand-ins for the other things living up there. Three weights rather than one
   so the row reads as a populated menu bar instead of a repeated shape. */
.mac-glyph {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--ink);
  opacity: 0.22;
}

.mac-glyph--soft {
  opacity: 0.12;
}

.mac-glyph--wide {
  width: 13px;
  opacity: 0.3;
}

/* Drawn rather than iconographic: enough to read as wifi, bluetooth and a
   battery at 11px, without imitating Apple's actual glyphs. */
.mac-ico {
  height: 10px;
  width: auto;
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--ink);
  opacity: 0.42;
}

.mac-ico--bt {
  height: 11px;
  stroke-width: 1.2;
}

.mac-ico--batt {
  height: 9px;
  stroke-width: 1.1;
  opacity: 0.36;
}

/* The app's real menu-bar artwork, not a redrawing of it. Centred so the
   popover's arrow lands under it at any width; sized to its own 127:76 ratio. */
.mac-icon {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 20px;
  height: 12px;
  opacity: 0.85;
}

@media (prefers-color-scheme: dark) {
  .mac-icon {
    filter: invert(1) brightness(1.12);
  }
}

.mac-clock {
  font-size: 9.5px;
  letter-spacing: 0.6px;
  color: var(--ink);
  opacity: 0.5;
}

.mac-stage {
  display: flex;
  justify-content: center;
  padding: 0 14px;
}

.mac-shot {
  width: 100%;
  max-width: 366px;
  height: auto;
  margin-top: -1px;
}

.mac-wide {
  max-width: 420px;
}

.mac figcaption {
  margin-top: 10px;
  font-size: 10px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
}

.section .mac {
  margin-top: 34px;
}

.download .mac {
  max-width: 420px;
}

/* -------------------------------------------------------------- section */

.section {
  border-bottom: 1px solid var(--hairline);
}

.section .wrap {
  padding-top: 52px;
  padding-bottom: 52px;
}

.section h2 {
  font-size: clamp(1.15rem, 3vw, 1.4rem);
  max-width: 30ch;
  margin-bottom: 16px;
}

.section p {
  color: var(--muted);
}

.section p strong {
  color: var(--ink);
  font-weight: 500;
}

.lead {
  color: var(--ink) !important;
  font-size: 14.5px;
}

.section p a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--hairline-strong);
}

.section p a:hover {
  text-decoration-color: var(--ink);
}

/* ---------------------------------------------------------------- steps */

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(3, 1fr);
}

.steps li {
  background: var(--inset);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  padding: 14px;
}

.steps h3 {
  font-size: 12.5px;
  font-weight: 500;
  margin: 8px 0 6px;
}

.steps p {
  color: var(--muted);
  font-size: 12.5px;
  margin: 0;
}

.step-n {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 1.8px;
  color: var(--muted);
}

/* -------------------------------------------------------------- specs */

.specs {
  margin: 0;
  background: var(--inset);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.spec {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 4px 16px;
  padding: 11px 14px;
  border-top: 1px solid var(--hairline);
}

.spec:first-child {
  border-top: 0;
}

.spec dt {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 3px;
}

.spec dd {
  margin: 0;
  font-size: 12.5px;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------- prose */

/* The ordered path on the security page: same card as a step, stacked. */
.path {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  display: grid;
  gap: 10px;
}

.path li {
  background: var(--inset);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  padding: 13px 14px;
}

.path h3 {
  font-size: 12.5px;
  font-weight: 500;
  margin: 7px 0 5px;
}

.path p {
  color: var(--muted);
  font-size: 12.5px;
  margin: 0;
  max-width: none;
}

/* One column, one right edge: prose, cards and spec tables all stop together. */
.prose {
  max-width: 600px;
}

.prose p,
.prose ul,
.prose h2 {
  max-width: none;
}

.prose h2 {
  margin-top: 34px;
  font-size: 1.05rem;
}

.formula {
  margin: 0 0 0.9em;
}

.formula code {
  display: block;
  padding: 10px 12px;
  line-height: 1.7;
}

.prose a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--hairline-strong);
}

.prose a:hover {
  text-decoration-color: var(--ink);
}

.prose strong {
  color: var(--ink);
  font-weight: 500;
}

.prose code {
  font-family: inherit;
  font-size: 12px;
  background: var(--inset);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-control);
  padding: 2px 5px;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.prose .specs {
  margin-bottom: 0.9em;
}

.prose .btn {
  text-decoration: none;
}

.prose h2:first-of-type {
  margin-top: 0;
}

.prose ul {
  margin: 0 0 0.9em;
  padding-left: 1.1em;
  max-width: var(--measure);
  color: var(--muted);
}

.prose li {
  margin-bottom: 4px;
}

.prose p {
  color: var(--muted);
}

.page-title {
  font-size: clamp(1.35rem, 4vw, 1.75rem);
  margin-bottom: 10px;
}

.updated {
  font-size: 10px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 30px;
}

/* ------------------------------------------------------------- download */

.download .wrap {
  padding-top: 56px;
  padding-bottom: 56px;
}

.download-note {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 14px;
}

/* --------------------------------------------------------------- footer */

.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  padding-top: 22px;
  padding-bottom: 34px;
  font-size: 10.5px;
  letter-spacing: 0.8px;
  color: var(--muted);
}

.site-footer a {
  color: var(--muted);
  text-decoration: none;
  text-transform: uppercase;
}

.site-footer a:hover {
  color: var(--ink);
}

.site-footer .spacer {
  margin-left: auto;
}

/* ------------------------------------------------------------ responsive */

@media (max-width: 720px) {
  .steps {
    grid-template-columns: 1fr;
  }

  .spec {
    grid-template-columns: 1fr;
  }

  .hero .wrap {
    padding-top: 44px;
    padding-bottom: 44px;
  }

  .section .wrap {
    padding-top: 40px;
    padding-bottom: 40px;
  }

  .site-footer .spacer {
    margin-left: 0;
  }
}

/* Below this the wordmark, both nav links and the button cannot share a line
   without wrapping the wordmark, so the mark carries the brand on its own. */
@media (max-width: 480px) {
  .site-header .wrap {
    gap: 14px;
  }

  .mark span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .nav-link {
    font-size: 10px;
    letter-spacing: 0.8px;
  }
}

/* ------------------------------------------------------------ drawn icons */

/* The icon family: the same 1.4px stroke, round caps and joins as the menu
   bar glyphs. The strokes are pinned to 1.4 screen pixels at any scale, so a
   parcel shrunk into the rack keeps the same line weight as everything else. */
.story-scene svg *,
.lane-art svg * {
  vector-effect: non-scaling-stroke;
}

.ico {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ico-fill {
  fill: currentColor;
  stroke: none;
}

/* Dashed outlines are things drawn by reference rather than held: a public
   key, or the file key the server does not have. */
.ico-dash {
  stroke-dasharray: 3 3;
}

.ico-muted {
  stroke: var(--muted);
}

/* A padlock body filled with the card colour occludes whatever it is
   locked over. */
.ico-card {
  fill: var(--card);
}

/* ------------------------------------------------------------ story scene */

/* One transfer as a scene: the document locks, travels the wire as a sealed
   object, sits in a rack that holds no key for it, and is opened by the key
   from the recipient's keychain. All geometry lives in the SVG; the JS phase
   machine writes transforms and opacities into it every frame. */

.story {
  margin: 26px 0 22px;
  max-width: 720px;
}

.story-scene {
  position: relative;
  color: var(--ink);
}

.story-scene svg {
  width: 100%;
  height: auto;
  display: block;
}

.story-wire {
  stroke: var(--hairline-strong);
  stroke-dasharray: 4 5;
}

/* The station names are HTML rather than SVG text so they hold a readable
   size when the scene scales down on a narrow screen. */
.story-labels {
  position: relative;
  height: 16px;
  margin-top: 4px;
}

.story-labels .group-label {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
}

/* Each label sits over the middle of its group in the 660-wide SVG: the two
   Macs at 90 and 570, the rack at 330. */
.group-label--sender { left: 13.6%; }
.group-label--server { left: 50%; }
.group-label--recipient { left: 86.4%; }

.story-caption {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  min-height: 17px;
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}

.story-caption .dot {
  background: var(--muted);
  transition: background-color 220ms ease;
}

.story-caption .dot.is-live {
  background: var(--live);
}

/* ---------------------------------------------------------- wire sequence */

/* The security page's detailed counterpart to the seal diagram: three lanes,
   one per party, holding the facts each party ends up with. Facts are all
   present from the start at low opacity and light as they become true, so the
   lanes never reflow and the finished picture is the same element as the
   empty one. */

.wire {
  margin: 24px 0 8px;
}

.wire-pre {
  font-size: 11px;
  color: var(--muted);
  margin: 0 0 12px;
}

.wire-grid {
  display: grid;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .wire-grid {
    grid-template-columns: 1fr 30px 1fr 30px 1fr;
    align-items: stretch;
  }
}

.wire-lane {
  background: var(--card);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  padding: 11px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: border-color 220ms ease;
}

.wire-lane.is-active {
  border-color: var(--ink);
}

/* The illustrated strip at the top of each lane. The facts below carry the
   words; the strip carries the same events as drawn objects. */
.lane-art {
  padding-bottom: 9px;
  border-bottom: 1px solid var(--hairline);
  color: var(--ink);
}

.lane-art svg {
  width: 100%;
  max-width: 210px;
  height: auto;
  display: block;
}

/* Scene elements light like the facts do: present from the start, invisible
   until the phase that makes them true. Elements that animate a transform
   instead of an opacity carry .art-anim and their own rules. */
.wire [data-art]:not(.art-anim) {
  opacity: 0;
  transition: opacity 240ms ease;
}

.wire [data-art].is-on:not(.art-anim) {
  opacity: 1;
}

.wire .art-anim {
  transition: transform 420ms ease, opacity 240ms ease;
  transform-box: fill-box;
}

/* The file key slides into the header container when it is sealed. */
.wire .art-slide.is-on {
  transform: translate(73px, 32px);
}

/* The Keychain key turns in place when the header is opened. */
.wire .art-turn {
  transform-origin: 50% 10%;
}

.wire .art-turn.is-on {
  transform: rotate(42deg);
}

/* The bin is furniture until the delete lands. */
.wire .art-bin {
  opacity: 0.45;
}

.wire .art-bin.is-on {
  opacity: 1;
}

/* Ciphertext texture sits at half strength so it reads as unreadable bytes
   rather than as content. */
.wire .art-half {
  opacity: 0;
  transition: opacity 240ms ease;
}

.wire .art-half.is-on {
  opacity: 0.55;
}

/* The document body filling block by block during encryption. */
.wire .chunk {
  opacity: 0;
  transition: opacity 160ms ease;
}

.wire .chunk.is-on {
  opacity: 0.55;
}

.wire-fact {
  font-size: 10.5px;
  line-height: 1.45;
  color: var(--ink);
  opacity: 0.28;
  transition: opacity 240ms ease;
}

.wire-fact.is-on {
  opacity: 1;
}

.wire-val {
  display: block;
  font-size: 10px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
}

.wire-fact--note {
  margin-top: auto;
  padding-top: 7px;
  border-top: 1px solid var(--hairline);
  font-size: 9.5px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--muted);
}

/* The same wire as the homepage: dashed because nothing sits on it, and one
   dot for the one object crossing at a time. */
.wire-link {
  position: relative;
  min-height: 30px;
}

.wire-link::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 7px;
  bottom: 7px;
  border-left: 1px dashed var(--hairline-strong);
}

.wire-dot {
  --t: 0;
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink);
  left: 50%;
  margin-left: -3px;
  top: calc(7px + var(--t) * (100% - 20px));
  opacity: 0;
}

.wire-dot.is-moving {
  opacity: 1;
}

@media (min-width: 640px) {
  .wire-link::before {
    left: 3px;
    right: 3px;
    top: 50%;
    bottom: auto;
    border-left: 0;
    border-top: 1px dashed var(--hairline-strong);
  }

  .wire-dot {
    top: 50%;
    margin-top: -3px;
    margin-left: 0;
    left: calc(3px + var(--t) * (100% - 12px));
  }
}

/* Statuses run one to three lines; the reserved height keeps the prose below
   from stepping as they change. */
.wire-caption {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 12px;
  min-height: 50px;
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}

.wire-caption .dot {
  margin-top: 4px;
  background: var(--muted);
  transition: background-color 220ms ease;
}

.wire-caption .dot.is-live {
  background: var(--live);
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .code-drain {
    animation: none;
    --drain: 0%;
    -webkit-mask-image: none;
    mask-image: none;
  }

  * {
    transition: none !important;
  }
}
