/*
 * mesopod.com landing page. Tokens, type, spacing, and radius come from
 * /DESIGN.md (Amethyst colorway) and mirror platform/frontend/src/styles/tokens.css.
 * Light by default; the shipped warm dark follows the OS preference.
 * No scripts anywhere on this page. Fonts are self-hosted (./fonts, SIL OFL).
 */

@font-face {
  font-family: "Faustina Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 300 800;
  src: url(/fonts/faustina-latin-wght-normal.woff2) format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/fonts/geist-latin-wght-normal.woff2) format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 800;
  src: url(/fonts/jetbrains-mono-latin-wght-normal.woff2) format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- Tokens: light (default) ---- */
:root {
  color-scheme: light;
  --bg: #efedf4;
  --surface: #f8f6fb;
  --sunken: #e4e0ec;
  --hairline: #dad4e4;
  --ink: #1e1830;
  --muted: #6a6280;
  --accent: #7028c4;
  --accent-strong: #58189e;
  --accent-tint: #ebe1fa;
  --on-accent: #ffffff;

  --font-display: "Faustina Variable", ui-serif, Georgia, serif;
  --font-sans: "Geist Variable", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono Variable", ui-monospace, "SF Mono", monospace;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;

  --measure: 1120px;
  --gutter: 24px;
}

/* ---- Tokens: dark (warm-cool espresso, follows the OS) ---- */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --bg: #16111f;
    --surface: #1e1830;
    --sunken: #100b18;
    --hairline: #322843;
    --ink: #ece7f5;
    --muted: #a99ebe;
    --accent: #9d6bf0;
    --accent-strong: #b48df5;
    --accent-tint: #241634;
    --on-accent: #16111f;
  }
}

/* ---- Base ---- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  /* A short page (the door at /homelab/try/) still puts the footer at the
     bottom of the window: the main block takes the slack. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body > main {
  flex: 1 0 auto;
}
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 720;
  letter-spacing: -0.005em;
  margin: 0;
  text-wrap: balance;
}
p {
  margin: 0;
}
a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  color: var(--accent-strong);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--accent-tint);
  border-radius: var(--radius-sm);
}
code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  font-weight: 500;
  color: var(--ink);
  background: var(--sunken);
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
}
ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---- Shared ---- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.lede {
  font-size: 18px;
  line-height: 1.5;
  color: var(--ink);
  max-width: 44ch;
  text-wrap: pretty;
}
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  padding: 14px 20px;
  border-radius: var(--radius-md);
  transition: background 180ms ease-out;
}
.btn:hover {
  background: var(--accent-strong);
  color: var(--on-accent);
  text-decoration: none;
}
.btn-sm {
  font-size: 13px;
  padding: 9px 14px;
}
.textlink {
  font-weight: 500;
}

/* ---- Top bar ---- */
.top {
  /* width and box-sizing because body is a flex column: an item with auto
     side margins is not stretched, and would shrink to its content. */
  width: 100%;
  box-sizing: border-box;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 20px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.wordmark:hover {
  text-decoration: none;
  color: var(--ink);
}
.topnav {
  display: flex;
  align-items: center;
  gap: 20px;
  font-size: 14px;
  font-weight: 500;
}
.topnav a:not(.btn) {
  color: var(--ink);
}
.topnav a:not(.btn):hover {
  color: var(--accent);
}

/* ---- Hero ---- */
.hero {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 56px var(--gutter) 40px;
  display: grid;
  gap: 20px;
}
.hero h1 {
  font-size: clamp(40px, 6vw, 64px);
  line-height: 1.02;
}
/* The cycling app name: a chip as wide as its longest entry, every entry
   centred in it, so the words around it never move. The chip itself is the
   link to the catalog, reachable by keyboard and named for screen readers;
   the names inside are decorative, and the visibility keyframe keeps the
   hidden ones out of the way. */
.rotate {
  display: inline-grid;
  justify-items: center;
  padding: 0 0.5em;
  border-radius: 0.35em;
  background: var(--accent-tint);
  color: var(--accent);
  font-weight: 600;
  white-space: nowrap;
}
.rotate:hover {
  color: var(--accent-strong);
  text-decoration: none;
}
.rotate > * {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  animation: rotate-word 17.5s infinite;
}
.rotate > span:nth-child(2) {
  animation-delay: -15s;
}
.rotate > span:nth-child(3) {
  animation-delay: -12.5s;
}
.rotate > span:nth-child(4) {
  animation-delay: -10s;
}
.rotate > span:nth-child(5) {
  animation-delay: -7.5s;
}
.rotate > span:nth-child(6) {
  animation-delay: -5s;
}
.rotate > span:nth-child(7) {
  animation-delay: -2.5s;
}
@keyframes rotate-word {
  0%,
  11% {
    opacity: 1;
    visibility: visible;
  }
  14.3%,
  97% {
    opacity: 0;
    visibility: hidden;
  }
  100% {
    opacity: 1;
    visibility: visible;
  }
}
@media (prefers-reduced-motion: reduce) {
  .rotate > * {
    animation: none;
  }
  .rotate > :first-child {
    opacity: 1;
    visibility: visible;
  }
}
.hero .lede {
  max-width: 52ch;
}
/* "one click": the claim the page makes, set at 600 under a thick accent
   rule. Not a chip, so the app name keeps its one; not violet text, which
   is a link everywhere else on the page. */
.lede .click {
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 3px;
  text-underline-offset: 0.2em;
}
.cta {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 4px;
}

/* ---- Catalog strip (straight under the hero's buttons, no heading) ---- */
.catalog {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter) 44px;
}
/* The last chip is a note, not an app: no fill, dashed hairline, muted. */
.apps .more {
  background: transparent;
  border-style: dashed;
  color: var(--muted);
}

/* ---- The install clip ---- */
.clip {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 16px var(--gutter) 32px;
}
.clip-frame {
  aspect-ratio: 16 / 10;
  background: var(--sunken);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.clip-frame > video,
.clip-frame > img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
/* The first frame, for a reduced-motion setting; the loop otherwise. */
.clip-frame > img {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .clip-frame > video {
    display: none;
  }
  .clip-frame > img {
    display: block;
  }
}

/* ---- Screenshots (off the page since 2026-10-21; the files, the lightbox
   and these rules stay for their return) ---- */
.shots {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 16px var(--gutter) 24px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.shot {
  margin: 0;
  display: grid;
  gap: 10px;
}
.shot-frame {
  aspect-ratio: 16 / 10;
  background: var(--sunken);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  display: grid;
  place-items: center;
  overflow: hidden;
  cursor: zoom-in;
}
.shot-frame:hover {
  border-color: var(--accent);
}
.shot-frame > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top left;
  display: block;
}
.shot-frame > span {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--muted);
}
.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 10;
  padding: 24px;
  background: rgb(0 0 0 / 0.72);
  place-items: center;
}
.lightbox:target {
  display: grid;
}
.lightbox > img {
  max-width: min(100%, 1600px);
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--radius-lg);
  border: 1px solid var(--hairline);
  background: var(--sunken);
}
.lightbox-close {
  position: absolute;
  inset: 0;
  color: transparent;
  text-decoration: none;
}
.lightbox-close::after {
  content: "×";
  position: absolute;
  top: 12px;
  right: 20px;
  font-size: 32px;
  line-height: 1;
  color: #fff;
}
.lightbox-close:hover {
  text-decoration: none;
}
.shot figcaption {
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}

/* ---- Sections ---- */
.block {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 48px var(--gutter);
  border-top: 1px solid var(--hairline);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 32px;
  align-items: start;
}
.block h2 {
  font-size: 28px;
  line-height: 1.15;
}
.block h3 {
  font-size: 20px;
  line-height: 1.25;
  margin-bottom: 6px;
}

.prose {
  display: grid;
  gap: 14px;
  max-width: 60ch;
  font-size: 17px;
  line-height: 1.55;
}
.prose .strong {
  font-weight: 600;
}
.lead-in {
  font-size: 16px;
  color: var(--muted);
  margin-bottom: 14px;
  max-width: 60ch;
}

.values-block {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 8px var(--gutter) 40px;
}
.values {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px 32px;
}
.values li {
  display: grid;
  align-content: start;
  gap: 6px;
  padding-left: 18px;
  position: relative;
}
.values li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 8px;
  height: 8px;
  border-radius: 9999px;
  background: var(--accent);
}
.values h3 {
  font-size: 20px;
  line-height: 1.25;
  margin: 0;
}
.values p {
  font-size: 15px;
  line-height: 1.5;
}

.steps {
  display: grid;
  gap: 24px;
}
.steps li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  max-width: 64ch;
}
.steps .num {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--accent);
  padding-top: 5px;
}
.steps p {
  color: var(--ink);
}

.apps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.apps li {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 10px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
}
.platforms {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: -12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--muted);
}
.platforms em {
  font-style: normal;
  color: var(--accent);
}

.honest {
  display: grid;
  max-width: 64ch;
}
.honest li {
  padding: 12px 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 15px;
  line-height: 1.5;
}
.honest li:first-child {
  padding-top: 0;
}
.honest li:last-child {
  border-bottom: 0;
}
.honest strong {
  font-weight: 600;
}

.faq {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px 32px;
}
.faq dt {
  font-weight: 600;
  margin-bottom: 4px;
}
.faq dd {
  margin: 0;
  color: var(--muted);
}

/* ---- Closing ---- */
.closing {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 56px var(--gutter) 64px;
  border-top: 1px solid var(--hairline);
  display: grid;
  gap: 16px;
  justify-items: start;
}
.closing h2 {
  font-size: clamp(28px, 4vw, 40px);
  line-height: 1.1;
  max-width: 20ch;
}
.closing .cta {
  margin-top: 8px;
}

/* ---- Deploy steps: four stills in the clip's frame as a carousel without
   a script (the Vaultwarden page). The figure's four radios pick the still
   and the dots under the frame are their labels; until one is picked the
   stills cycle on their own, each fading in for its quarter, and the dots
   follow. The first still is the base, so a browser without :has() shows
   it and the dots still work. A reduced-motion setting holds the first. ---- */
.steps {
  position: relative;
}
.steps-pick {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}
.steps-frame {
  position: relative;
}
.steps-frame > img {
  display: block;
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 400ms ease-out;
}
.steps-frame > img:first-child {
  opacity: 1;
}
/* A picked still: it shows, the first steps back. */
#vw-step-2:checked ~ .steps-frame > img:first-child,
#vw-step-3:checked ~ .steps-frame > img:first-child,
#vw-step-4:checked ~ .steps-frame > img:first-child {
  opacity: 0;
}
#vw-step-1:checked ~ .steps-frame > img:nth-child(1),
#vw-step-2:checked ~ .steps-frame > img:nth-child(2),
#vw-step-3:checked ~ .steps-frame > img:nth-child(3),
#vw-step-4:checked ~ .steps-frame > img:nth-child(4) {
  opacity: 1;
}
.steps-dots {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 12px;
}
.steps-dots > label {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--hairline);
  cursor: pointer;
  transition: background 180ms ease-out;
}
.steps-dots > label:hover {
  background: var(--muted);
}
#vw-step-1:checked ~ .steps-dots > label:nth-child(1),
#vw-step-2:checked ~ .steps-dots > label:nth-child(2),
#vw-step-3:checked ~ .steps-dots > label:nth-child(3),
#vw-step-4:checked ~ .steps-dots > label:nth-child(4) {
  background: var(--accent);
}
#vw-step-1:focus-visible ~ .steps-dots > label:nth-child(1),
#vw-step-2:focus-visible ~ .steps-dots > label:nth-child(2),
#vw-step-3:focus-visible ~ .steps-dots > label:nth-child(3),
#vw-step-4:focus-visible ~ .steps-dots > label:nth-child(4) {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
/* Nothing picked yet: the stills and the dots cycle. */
.steps:not(:has(.steps-pick:checked)) .steps-frame > img {
  animation: steps-cycle 16s infinite;
}
.steps:not(:has(.steps-pick:checked)) .steps-dots > label {
  animation: steps-dot 16s infinite;
}
.steps:not(:has(.steps-pick:checked)) .steps-frame > img:nth-child(2),
.steps:not(:has(.steps-pick:checked)) .steps-dots > label:nth-child(2) {
  animation-delay: 4s;
}
.steps:not(:has(.steps-pick:checked)) .steps-frame > img:nth-child(3),
.steps:not(:has(.steps-pick:checked)) .steps-dots > label:nth-child(3) {
  animation-delay: 8s;
}
.steps:not(:has(.steps-pick:checked)) .steps-frame > img:nth-child(4),
.steps:not(:has(.steps-pick:checked)) .steps-dots > label:nth-child(4) {
  animation-delay: 12s;
}
/* The first still is the base, so its animation starts visible and holds
   the frame while the others are out; it fades for its last quarter only
   when the fourth has gone, which the delays line up: at 12s the fourth is
   in, at 16s the first is back. */
@keyframes steps-cycle {
  0% {
    opacity: 0;
  }
  3% {
    opacity: 1;
  }
  25% {
    opacity: 1;
  }
  28% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes steps-dot {
  0%,
  25% {
    background: var(--accent);
  }
  28%,
  100% {
    background: var(--hairline);
  }
}
@media (prefers-reduced-motion: reduce) {
  .steps:not(:has(.steps-pick:checked)) .steps-frame > img,
  .steps:not(:has(.steps-pick:checked)) .steps-dots > label {
    animation: none;
  }
  .steps:not(:has(.steps-pick:checked)) .steps-dots > label:first-child {
    background: var(--accent);
  }
  .steps-frame > img {
    transition: none;
  }
}

/* ---- The door (/homelab/try/): the hero's words with a figure beside them ---- */
.door {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: center;
  /* Lower than the landing hero, so a short page does not hang at the top. */
  padding-top: clamp(56px, 14vh, 140px);
  padding-bottom: 96px;
}
.door-words {
  display: grid;
  gap: 20px;
}
/* "no-account" in the headline: the browser would break it at the hyphen. */
.nowrap {
  white-space: nowrap;
}
/* The figure is the system's own furniture, not a drawing (DESIGN.md's
   decoration level): a console card with a status ledger and one progress
   bar, in the page's tokens, captioned in mono. The bar creeps forward and
   starts over, so the page reads as work in progress rather than a dead end;
   a reduced-motion setting holds it still. */
.door-figure {
  display: grid;
  gap: 12px;
  justify-items: center;
  margin: 0;
}
.door-figure svg {
  width: min(100%, 320px);
  height: auto;
  display: block;
}
.door-figure figcaption {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.door-progress {
  animation: door-progress 6s ease-in-out infinite;
  transform-origin: 0 0;
}
@keyframes door-progress {
  0% {
    transform: scaleX(0.28);
  }
  70% {
    transform: scaleX(0.72);
  }
  100% {
    transform: scaleX(0.74);
  }
}
@media (min-width: 760px) {
  .door {
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: 48px;
  }
}

/* ---- Footer ---- */
.foot {
  border-top: 1px solid var(--hairline);
  background: var(--surface);
}
.foot-links {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter);
  font-family: var(--font-mono);
  font-size: 12.5px;
}
.foot-links {
  padding-top: 24px;
  padding-bottom: 28px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}
.foot-links a {
  color: var(--ink);
}
.foot-links a:hover {
  color: var(--accent);
}
.foot-brand {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* ---- The apps page (site/apps/): the hero and the wide block ---- */
/* The hero in two columns, the clip beside the words; the text column keeps
   the hero's own vertical rhythm. */
.hero-split {
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 36px;
  align-items: center;
}
.hero-text {
  display: grid;
  gap: 20px;
}
/* Beside the clip the column is half the measure, so the headline stops
   short of the full-width size and breaks in two, not three. */
.hero-split h1 {
  font-size: clamp(36px, 4.5vw, 56px);
}
.hero-split .shot {
  margin: 0;
}
/* The promo cut is 1350×1080; the frame follows it instead of the install
   clip's 16/10, so nothing is cropped. */
.clip-frame-5x4 {
  aspect-ratio: 1350 / 1080;
}
/* A block whose heading sits above its content rather than beside it. */
.block-wide {
  grid-template-columns: 1fr;
  gap: 20px;
}
/* ---- The apps page (site/apps/): the store front ---- */
/* The second line of the hero's lede, the Mesopod line, in ink. */
.lede-strong {
  color: var(--ink);
  font-weight: 500;
}
/* A secondary button: the accent as an outline, the tint on hover. */
.btn-secondary {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  padding: 12px 18px;
}
.btn-secondary:hover {
  background: var(--accent-tint);
  color: var(--accent-strong);
  border-color: var(--accent-strong);
}
/* The small outline button (the nav's "Try the demo"): .btn-sm's padding
   less the border, since .btn-secondary's rule comes later and would win. */
.btn-sm.btn-secondary {
  padding: 8px 13px;
}
/* A section heading with its action beside it; the action drops under the
   heading when the row is too narrow. */
.sechead {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 16px;
}
.block-wide .sechead h2 {
  margin: 0;
}
.lead-line {
  color: var(--muted);
  margin-bottom: 20px;
  max-width: 60ch;
}
/* The catalog tiles: a mark, the name and a line, a small Deploy. */
.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
.tile {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: 14px 14px 14px 16px;
}
.block .tile h3 {
  font-size: 15.5px;
  line-height: 1.3;
  margin: 0;
}
.tile p {
  font-size: 13px;
  line-height: 1.4;
  color: var(--muted);
  margin-top: 2px;
}
/* The mark: a monochrome SVG tinted with the ink through a mask, on a sunken
   plate, as the console's AppLogo draws it; a monogram where no file is. */
.mark {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  background: var(--sunken);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  color: var(--ink);
}
.mark-img {
  width: 60%;
  height: 60%;
  background: currentColor;
  mask-size: contain;
  mask-repeat: no-repeat;
  mask-position: center;
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
}
.mark-mono {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 720;
  line-height: 1;
}
/* ---- The apex (site/index.html): Mesopod Cloud ---- */
/* A mark in colour: the project's own logo as an <img> on the plate, as the
   console's AppLogo draws it since 2026-10-30, taking no tint from the text.
   3/5 of the plate rather than 1/2: contain sizes by the longest edge, so a
   wide mark would read tiny beside square ones. */
.mark-color > img {
  width: 60%;
  height: 60%;
  object-fit: contain;
}
/* A mark drawn in dark ink that would vanish on the dark plate (FreshRSS,
   Paperless-ngx, Vaultwarden): its plate turns white in dark mode, as in
   the console. */
@media (prefers-color-scheme: dark) {
  .mark-light {
    background: #ffffff;
    border-color: #ffffff;
  }
}
/* "Where it runs": the console's three deploy choices as cards, in the
   tiles' dress. The price line leads, so the eye reads the money before
   the words, and the own-machine card's title is the link to /homelab/. */
.plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
.plans li {
  display: grid;
  align-content: start;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: 20px 20px 22px;
}
.plan-price {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
}
.block .plans h3 {
  font-size: 19px;
  margin: 0;
}
.plans h3 a {
  color: inherit;
}
.plans h3 a:hover {
  color: var(--accent);
}
.plans p:not(.plan-price) {
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
}
/* The one button at the end, centred. */
.closing-center {
  justify-items: center;
  text-align: center;
  padding-top: 40px;
}
.closing-center .btn {
  margin-top: 0;
}

/* ---- Narrow screens ---- */
@media (max-width: 860px) {
  .shots {
    grid-template-columns: 1fr;
  }
  .hero-split {
    grid-template-columns: 1fr;
  }
  .tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .plans {
    grid-template-columns: 1fr;
  }
  .block {
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 40px var(--gutter);
  }
  .platforms {
    grid-column: auto;
    margin-top: 0;
  }
  .faq {
    grid-template-columns: 1fr;
  }
  .values {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 560px) {
  .topnav a:not(.btn) {
    display: none;
  }
  /* The nav's "Try the demo" too: the wordmark and two buttons overflow a
     phone's width, and the hero's door button is right below. */
  .topnav .btn-secondary {
    display: none;
  }
  .hero {
    padding-top: 36px;
  }
  .values,
  .tiles {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
  }
  .door-progress {
    animation: none;
    transform: scaleX(0.62);
  }
}
