/* ==========================================================================
   Landing page styles. No framework, no build step, no remote request.

   The visual language is Apple's own product pages: a black stage, San
   Francisco set large and tight, one blue reserved for anything you can act
   on, and surfaces that are a lighter grey rather than a bordered box. The
   page describes a Mac utility, so it may as well look like it belongs on a
   Mac.

   Type is the one place this splits from Apple. Prose is set in the system
   sans, which on the machines this tool runs on is San Francisco itself and
   costs no request. Anything that is literally terminal content, a command, a
   prompt, a key legend, stays monospaced, because that is what it is.
   ========================================================================== */

/* --------------------------------------------------------------- typeface */
/*
  JetBrains Mono, resolved in this order:
    1. a copy already installed on the visitor's machine (local())
    2. a woff2 you drop into fonts/ (see fonts/README.md)
    3. the platform monospace stack in --font-mono

  Every source is same origin or local. Nothing here reaches a CDN, which is
  what keeps the strict Content-Security-Policy in vercel.json satisfiable.
  If you ship no woff2 the @font-face block simply does not match and the
  fallback stack takes over, which is a supported outcome, not a bug.
*/
@font-face {
  font-family: "JetBrains Mono Local";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src:
    local("JetBrains Mono"),
    local("JetBrainsMono-Regular"),
    url("fonts/JetBrainsMono-Regular.woff2") format("woff2");
}

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

/* ----------------------------------------------------------------- tokens */
:root {
  /* Measured off apple.com rather than guessed at: #f5f5f7 on #000 for copy,
     #a1a1a6 for the secondary tone, #86868b for small print, #0071e3 for
     anything filled and #2997ff for a link on black. */
  --bg: #000000;
  --surface: #1d1d1f;
  --surface-high: #262629;
  --hairline: #29292b;
  --text: #f5f5f7;
  --dim-text: #a1a1a6;
  --faint: #86868b;

  --accent: #2997ff; /* links and marks on a dark background */
  --accent-solid: #0071e3; /* filled controls, identical in both schemes */
  --accent-solid-hover: #0077ed;
  --on-accent: #ffffff;

  /*
    The backlight. White, because the LED under a MacBook key is white: the
    earlier warm accent made the illustration look like a gaming keyboard,
    which is the one thing the real hardware is not. --kbd is the emitter and
    --kbd-halo the very slightly cool falloff around it.
  */
  --kbd: #ffffff;
  --kbd-halo: #dfe7f5;

  /* Apple's transition curve for interface moves, and the softer entrance
     curve for anything arriving on scroll. */
  --ease: cubic-bezier(0.28, 0.11, 0.32, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --radius: 18px; /* Apple's tile corner */
  --radius-sm: 12px;
  --radius-pill: 980px;

  --measure: 42rem;
  --shell: 980px; /* Apple's content column */
  --gap: clamp(1rem, 2.4vw, 1.5rem);
  --section-y: clamp(3.5rem, 8vw, 6.5rem);
  --nav-h: 52px;

  --font-sans:
    -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono:
    "JetBrains Mono Local", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
    Consolas, "Liberation Mono", monospace;

  color-scheme: dark light;
}

/* Apple ships both. Light is the same page with the stage turned up, not a
   different design: the greys inverse, the blue darkens to stay legible on
   white, and the laptop stays the colour a Space Black laptop actually is. */
@media (prefers-color-scheme: light) {
  :root {
    --bg: #ffffff;
    --surface: #f5f5f7;
    --surface-high: #ececee;
    --hairline: #d2d2d7;
    --text: #1d1d1f;
    --dim-text: #6e6e73;
    --faint: #86868b;

    --accent: #0066cc;
    --accent-solid: #0071e3;
    --accent-solid-hover: #0077ed;
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* An anchor must not land underneath the sticky bar. */
  scroll-padding-block-start: calc(var(--nav-h) + 1rem);
}

body {
  margin: 0;
  /* No element may push the page sideways. */
  overflow-x: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem); /* 17px at the top */
  line-height: 1.47;
  letter-spacing: -0.022em; /* Apple sets body copy slightly tight */
  -webkit-font-smoothing: antialiased;
}

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

/*
  A link is blue and unadorned until you point at it, which is the Apple rule.
  Underlining every link in a page this dense turns the copy into a mesh.
*/
a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.16s var(--ease);
}

a:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

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

::selection {
  background: color-mix(in srgb, var(--accent) 35%, transparent);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  padding: 0.65rem 1rem;
  background: var(--surface);
  border-radius: var(--radius-sm);
  color: var(--text);
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
}

/* ---------------------------------------------------------------- localnav */
/*
  The bar Apple puts under its global navigation on a product page: the name of
  the thing on the left, its sections in the middle, the single action worth
  taking on the right. Translucent and blurred, so the page reads as moving
  underneath it rather than behind a panel.
*/
.localnav {
  position: sticky;
  inset-block-start: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-block-end: 1px solid color-mix(in srgb, var(--hairline) 70%, transparent);
}

/* No blur available means no translucency either: text over a half
   transparent background with nothing softening it is unreadable. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .localnav {
    background: var(--bg);
  }
}

.localnav-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  max-width: var(--shell);
  min-height: var(--nav-h);
  margin-inline: auto;
  padding-inline: clamp(1.1rem, 5vw, 2.5rem);
}

.localnav-title {
  flex: 0 0 auto;
  margin-inline-end: auto;
  color: var(--text);
  font-size: 1.3125rem; /* 21px, Apple's local nav title */
  font-weight: 600;
  letter-spacing: -0.02em;
}

.localnav-title:hover {
  text-decoration: none;
}

.localnav-links {
  display: flex;
  gap: clamp(0.9rem, 2.4vw, 1.6rem);
  font-size: 0.75rem; /* 12px, as Apple sets it */
  letter-spacing: -0.01em;
}

.localnav-link {
  position: relative;
  padding-block: 0.35rem;
  color: var(--dim-text);
}

.localnav-link:hover {
  color: var(--text);
  text-decoration: none;
}

/* The section you are actually looking at, underlined. app.js sets the
   attribute from an IntersectionObserver. */
.localnav-link[aria-current="true"] {
  color: var(--text);
}

.localnav-link[aria-current="true"]::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -0.35rem;
  height: 2px;
  border-radius: 2px;
  background: var(--text);
}

.localnav-cta {
  flex: 0 0 auto;
  padding: 0.28rem 0.75rem;
  border-radius: var(--radius-pill);
  background: var(--accent-solid);
  color: var(--on-accent);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: -0.01em;
  transition: background-color 0.16s var(--ease);
}

.localnav-cta:hover {
  background: var(--accent-solid-hover);
  color: var(--on-accent);
  text-decoration: none;
}

@media (max-width: 40rem) {
  .localnav-links {
    display: none;
  }
}

/* -------------------------------------------------------------- structure */
.section {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1.1rem, 5vw, 2.5rem);
  padding-block: var(--section-y);
}

.section + .section {
  padding-block-start: 0;
}

/*
  Apple centres a section heading and lets the copy under it sit in a narrower
  column. The icon goes above the words rather than beside them: at this size
  an inline glyph fights the type instead of introducing it.
*/
.section-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  margin: 0 0 2rem;
  font-size: clamp(1.75rem, 1.1rem + 2.6vw, 3rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-align: center;
  text-wrap: balance;
  color: var(--text);
}

.icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}

.section-icon {
  width: 30px;
  height: 30px;
  color: var(--accent);
}

.prose {
  max-width: var(--measure);
  margin: 0 auto 1.1rem;
  color: var(--dim-text);
  font-size: 1.0625rem;
}

/* A command flag, held on one line. sync.mjs wraps them; see rich() there. */
.nobrk {
  white-space: nowrap;
}

.note,
.caption {
  max-width: var(--measure);
  margin-inline: auto;
  color: var(--faint);
  font-size: 0.8125rem; /* 13px, Apple's footnote size */
  line-height: 1.4;
}

/* ------------------------------------------------------------------- hero */
.hero {
  padding-block-start: clamp(3.5rem, 9vw, 6rem);
  text-align: center;
}

/* The repository name, small and quiet. The local nav already carries the
   short name, so this one states the full one once and gets out of the way. */
.wordmark {
  margin: 0 0 1.1rem;
  color: var(--faint);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0;
}

/* Apple's eyebrow: the accent colour, above the headline, no box around it. */
.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--accent);
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.3125rem);
  font-weight: 600;
  letter-spacing: -0.015em;
}

.hero-title {
  max-width: 19ch;
  margin: 0 auto 1.2rem;
  font-size: clamp(2.25rem, 1.5rem + 3vw, 4rem);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.015em;
  color: var(--text);
  text-wrap: balance;
}

.hero-sub {
  max-width: 34rem;
  margin: 0 auto 2.25rem;
  color: var(--dim-text);
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem); /* up to 21px */
  line-height: 1.38;
  letter-spacing: -0.017em;
}

.install-strip {
  margin: 0 0 1.75rem;
}

.install-label {
  margin: 0 0 0.6rem;
  color: var(--faint);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.install-then {
  margin: 0.7rem 0 0;
  color: var(--faint);
  font-size: 0.8125rem;
}

/* --------------------------------------------------------- copyable code */
/*
  A command is terminal content, so it stays monospaced and keeps its prompt.
  The container is an Apple surface rather than a bordered box: one fewer line
  on the page, and the shape still reads as a field you can act on.
*/
.copy {
  display: flex;
  align-items: stretch;
  min-width: 0;
  max-width: 34rem;
  margin-inline: auto;
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
  text-align: start;
}

.copy-code {
  /* The code, and only the code, scrolls sideways. */
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 0.8rem 1rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.875rem;
  line-height: 1.5;
  letter-spacing: 0;
  white-space: pre;
  tab-size: 2;
}

.copy-code::before {
  content: "$ ";
  color: var(--faint);
}

.copy-btn {
  flex: 0 0 auto;
  padding-inline: 1rem;
  border: 0;
  background: transparent;
  color: var(--accent);
  font: inherit;
  font-size: 0.8125rem;
  cursor: pointer;
  transition:
    background-color 0.16s var(--ease),
    color 0.16s var(--ease);
}

.copy-btn:hover {
  background: var(--surface-high);
}

.copy-btn[data-copied="true"] {
  color: var(--text);
}

/* ---------------------------------------------------------------- buttons */
.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  align-items: center;
  justify-content: center;
  margin: 0;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.0625rem;
  letter-spacing: -0.022em;
  text-decoration: none;
  transition:
    background-color 0.16s var(--ease),
    color 0.16s var(--ease);
}

/* Apple's filled control: a blue pill, 980px radius, white label, no border
   and no shadow. */
.btn-primary {
  min-height: 44px;
  padding: 0.5rem 1.35rem;
  border-radius: var(--radius-pill);
  background: var(--accent-solid);
  color: var(--on-accent);
}

.btn-primary:hover {
  background: var(--accent-solid-hover);
  color: var(--on-accent);
  text-decoration: none;
}

/*
  And Apple's secondary: not a button at all, a blue link with a chevron. It
  keeps a single filled control per view, which is the reason the filled one
  reads as the thing to do.
*/
.btn-secondary {
  min-height: 44px;
  color: var(--accent);
}

.btn-secondary::after {
  content: "\203A"; /* single right angle quote, the chevron Apple uses */
  margin-inline-start: 0.3em;
  font-size: 1.1em;
  line-height: 1;
  transition: transform 0.16s var(--ease);
}

.btn-secondary:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.btn-secondary:hover::after {
  transform: translateX(2px);
}

/* ------------------------------------------------------------------- demo */
.demo {
  margin: 0;
}

.demo-video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  background: var(--surface);
  object-fit: cover;
}

.demo-caption {
  margin-top: 1rem;
  text-align: center;
}

.demo-alt {
  max-width: var(--measure);
  margin: 0 auto;
  color: var(--dim-text);
  font-size: 0.875rem;
}

.demo-caption .caption {
  margin: 0.4rem auto 0;
}

/* -------------------------------------------------------------------- why */
/*
  The one sentence worth stopping on. Apple sets a pulled-out line larger than
  the copy around it rather than boxing it, so it reads as emphasis instead of
  as an aside.
*/
.highlight {
  max-width: var(--measure);
  margin: 2rem auto 0;
  color: var(--text);
  font-size: clamp(1.1875rem, 1.05rem + 0.7vw, 1.75rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-align: center;
  text-wrap: balance;
}

/* --------------------------------------------------------------- features */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Apple's tile: a lighter surface, a generous corner, no border at all. */
.card {
  padding: 1.75rem 1.6rem;
  border-radius: var(--radius);
  background: var(--surface);
  transition:
    background-color 0.25s var(--ease),
    transform 0.25s var(--ease);
}

.card:hover {
  background: var(--surface-high);
  transform: translateY(-2px);
}

.card-title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0 0 0.6rem;
  font-size: 1.3125rem; /* 21px */
  font-weight: 600;
  line-height: 1.19;
  letter-spacing: -0.015em;
  color: var(--text);
}

.card-icon {
  color: var(--accent);
}

.card-body {
  margin: 0;
  color: var(--dim-text);
  font-size: 0.9375rem;
}

/* ---------------------------------------------------------------- install */
.steps {
  display: grid;
  /* minmax(0, 1fr), not auto: an auto track takes its minimum from the widest
     unbreakable command inside it, which pushes the whole page sideways on a
     narrow screen. */
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
  max-width: var(--measure);
  margin: 2rem auto 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.step {
  padding-inline-start: 2.6rem;
  position: relative;
  counter-increment: step;
}

.step::before {
  content: counter(step);
  position: absolute;
  inset-block-start: 0.15rem;
  inset-inline-start: 0;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--accent-solid);
  color: var(--on-accent);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0;
}

.step-title {
  margin: 0 0 0.35rem;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--text);
}

.step-body {
  margin: 0 0 0.85rem;
  color: var(--dim-text);
  font-size: 0.9375rem;
}

.step .copy {
  margin-inline: 0;
}

/* Any table dropped into the page scrolls inside its own box. */
.table-scroll {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--radius-sm);
  background: var(--surface);
}

.table-scroll table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.table-scroll th,
.table-scroll td {
  padding: 0.65rem 0.9rem;
  border-block-end: 1px solid var(--hairline);
  text-align: start;
  white-space: nowrap;
}

/* ----------------------------------------------------------------- footer */
/* Apple's footer is the smallest type on the page, on a slightly raised
   surface, with a hairline above it. */
.site-footer {
  max-width: none;
  margin-block-start: var(--section-y);
  padding-block: clamp(2.5rem, 6vw, 3.5rem);
  border-block-start: 1px solid var(--hairline);
  background: var(--surface);
  color: var(--faint);
  font-size: 0.75rem;
  line-height: 1.5;
}

.site-footer > * {
  max-width: var(--shell);
  margin-inline: auto;
}

.footer-license {
  /* auto, not 0: these sit in a full width footer and have to line up with the
     content column above them. A margin shorthand here silently resets the
     margin-inline: auto that centres them. */
  margin: 0 auto 0.4rem;
  color: var(--dim-text);
}

.footer-commercial {
  margin: 0 auto 1rem;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  margin: 1rem auto;
}

.footer-link {
  color: var(--dim-text);
}

.footer-link:hover {
  color: var(--text);
}

.footer-copy {
  margin: 0 auto;
}

/* --------------------------------------------------------------- macbook */
/*
  A MacBook, out of elements and 3D transforms. No canvas, no library, no model
  file: the page's Content-Security-Policy forbids fetching one, and a vendored
  WebGL renderer would weigh more than everything else here put together.

  The assembly hangs off the lid, not the deck. The lid is the reference plane,
  and the deck is hinged at the lid's bottom edge and rotated forward until it
  lies down towards the viewer, which is the same joint the real object has and
  the only arrangement where the two parts cannot drift apart when the whole
  thing turns.

  Colour comes from Apple's own product renders: Space Black is a neutral, very
  dark grey, nearly the value of the page behind it, and what separates it from
  that background is not lightness but the bright machined edge running along
  every cut. The earlier warm grey read as bronze.

  --mb-glow, 0 to 1, is the backlight. It is one number driving the keycaps, the
  light bleeding around them, the spill onto the aluminium, the pool on the desk
  and the reflection on the screen, so everything brightens as one thing rather
  than as five.
*/
@property --mb-glow {
  syntax: "<number>";
  inherits: true;
  initial-value: 0.55;
}

.mb-stage {
  --mb-w: clamp(15rem, 60vw, 32rem);
  --mb-glow: 0.55; /* lit by default: a dark keyboard is the boring half of the story */
  /*
    Positive, and that is the whole trick. The deck is rotated back towards the
    viewer about the hinge, so the only way to see its top face is for the camera
    to sit above it, which is what tipping the whole assembly away does. Negative
    here puts the eye under the desk and the keyboard vanishes edge on.
  */
  --mb-rx: 38deg;
  --mb-ry: 0deg;

  margin: 2.5rem 0 0;
  /* A long lens. Apple photographs hardware from far away with a tight field,
     which is why the far edge of a deck barely converges in their renders; a
     short perspective here made the machine look like a wide angle snapshot. */
  perspective: 3000px;
  perspective-origin: 50% 42%;
}

.mb {
  position: relative;
  width: var(--mb-w);
  margin-inline: auto;
  transform-style: preserve-3d;
  transform: rotateX(var(--mb-rx)) rotateY(var(--mb-ry));
  transition: transform 0.5s var(--ease);
  /*
    The deck hangs out of the box: it is absolutely positioned past the bottom
    edge, so it contributes no height and anything after it would be drawn over
    the keyboard. This reserves what the deck actually projects to at this
    angle, which is a little over half the width.
  */
  margin-block-end: calc(var(--mb-w) * 0.6);
}

/* ---- lid ---- */
.mb-lid {
  position: relative;
  aspect-ratio: 16 / 10.2;
  padding: calc(var(--mb-w) * 0.011);
  border-radius: calc(var(--mb-w) * 0.017) calc(var(--mb-w) * 0.017) 0 0;
  /* Anodised aluminium is not a flat grey: it is a narrow vertical gradient
     with a brighter machined edge catching the light at the top. */
  background:
    linear-gradient(180deg, #5c5c62 0%, #303035 5%, #1e1e21 55%, #141417 100%);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 20%),
    inset 1px 0 0 rgb(255 255 255 / 8%),
    inset -1px 0 0 rgb(255 255 255 / 8%);
  transform-style: preserve-3d;
}

.mb-screen {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: calc(var(--mb-w) * 0.008);
  background: #000000;
}

/*
  The desktop behind the terminal line. Cool grey ribbons on black, which is
  the macOS wallpaper Apple ships these machines photographed with, and it
  brightens with the keyboard because a lit room lights the screen too. The
  light it gains is white now, not warm.
*/
.mb-wallpaper {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      95% 70% at 50% 122%,
      color-mix(in srgb, var(--kbd-halo) calc(var(--mb-glow) * 20%), transparent),
      transparent 62%
    ),
    radial-gradient(52% 40% at 26% 24%, rgb(168 182 210 / 26%), transparent 64%),
    radial-gradient(60% 44% at 74% 56%, rgb(132 146 176 / 20%), transparent 66%),
    radial-gradient(34% 26% at 54% 78%, rgb(190 202 226 / 12%), transparent 68%),
    linear-gradient(158deg, #1d1f25 0%, #08090c 66%);
}

.mb-notch {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 50%;
  width: 16%;
  height: calc(var(--mb-w) * 0.018);
  border-radius: 0 0 calc(var(--mb-w) * 0.006) calc(var(--mb-w) * 0.006);
  background: #000000;
  transform: translateX(-50%);
}

.mb-prompt {
  position: absolute;
  inset-block-end: 8%;
  inset-inline-start: 7%;
  margin: 0;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: calc(var(--mb-w) * 0.026);
  letter-spacing: 0;
}

.mb-prompt-caret {
  color: var(--accent);
}

/* One diagonal sheen. Glass is only convincing when something is reflected in
   it, and a single soft band beats a busy fake reflection. */
.mb-glass {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    108deg,
    rgb(255 255 255 / 6%) 0%,
    rgb(255 255 255 / 2%) 22%,
    transparent 46%
  );
  pointer-events: none;
}

/* ---- base ---- */
/*
  Hinged at the lid's bottom edge and laid down towards the viewer. The rotation
  is a shade under 90 degrees, so the deck is not quite flat: a real laptop sits
  with its far edge slightly higher, and the sliver of difference is what stops
  the two halves reading as one folded sheet of card.
*/
/*
  Everything below is measured off a MacBook Pro 14, normalised to the width of
  the machine: 312mm across, 221mm deep, a key area 108mm deep starting 20mm
  down, and a 130 by 81mm trackpad that very nearly reaches the front edge.
  The first version guessed at these and it showed, as a small keyboard adrift
  in a wide empty plate of aluminium.
*/
.mb-base {
  position: absolute;
  inset-block-start: 100%;
  inset-inline-start: 50%;
  width: 100%;
  aspect-ratio: 312 / 221;
  transform-origin: 50% 0%;
  transform: translateX(-50%) rotateX(-83deg);
  transform-style: preserve-3d;
}

.mb-deck {
  position: absolute;
  inset: 0;
  /* 20mm down, 25mm in on each side, which is where the speaker grilles go. */
  padding: 6.4% 8% 0;
  border-radius: 0 0 calc(var(--mb-w) * 0.022) calc(var(--mb-w) * 0.022);
  background:
    linear-gradient(180deg, #2a2a2e00 0%, #2b2b3026 40%, #3a3a4140 100%),
    linear-gradient(96deg, #2b2b30 0%, #212125 42%, #21212500 42%, #1e1e2200 100%),
    #212125;
  /* The hinge: a dark band where the deck meets the lid, and a hairline of
     light on the machined edge just in front of it. Without it the two planes
     merge into one shape at the join. */
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 13%),
    inset 0 10px 14px -10px rgb(0 0 0 / 88%);
}

.mb-keys {
  display: flex;
  flex-direction: column;
  /* A length, not a percentage. A percentage row-gap resolves against the
     block size of a box whose height is auto, which is to say against nothing,
     so the rows were touching. */
  gap: calc(var(--mb-w) * 0.0034);
  width: 100%;
  padding: calc(var(--mb-w) * 0.005);
  border-radius: calc(var(--mb-w) * 0.006);
  /* The well the keys sit in. A board printed flat on the aluminium is the
     single clearest tell that a laptop was drawn rather than photographed. */
  background: #0d0d0f;
  box-shadow:
    inset 0 2px 3px rgb(0 0 0 / 65%),
    0 1px 0 rgb(255 255 255 / 6%);
}

/*
  A 1u key is the key area (84% of the width) over fifteen units, and a MacBook
  keycap is very nearly square, so the row height follows from that rather than
  being picked. The function row is the exception: it is roughly three fifths
  height on the real machine, and that single short row at the top is one of
  the most recognisable things about the board.
*/
.mb-row {
  display: flex;
  gap: 0.55%;
  height: calc(var(--mb-w) * 0.056);
}

.mb-row:first-child {
  height: calc(var(--mb-w) * 0.034);
}

.mb-key {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-basis: 0;
  min-width: 0;
  border-radius: calc(var(--mb-w) * 0.005);
  /* Keycaps are lighter at the top edge and fall away towards the bottom, and
     the shadow under each one is what separates the board into keys. */
  background: linear-gradient(180deg, #3a3a41 0%, #24242800 4%, #17171a 100%);
  box-shadow:
    0 1px 1px rgb(0 0 0 / 60%),
    inset 0 1px 0 rgb(255 255 255 / 8%);
}

/*
  The light escaping around the keycap. This is the layer that sells it: a real
  backlit board leaks more around the edges of the cap than through the legend,
  and the light doing the leaking is white.
*/
.mb-key::after {
  content: "";
  position: absolute;
  inset: calc(var(--mb-w) * -0.0016);
  border-radius: inherit;
  /*
    Deliberately no background. Filling the cap with light was the first
    attempt and it turned every key into a white tile: on the real board the
    cap face stays dark and what you see is the rim, a hard bright line where
    the light escapes under the edge, and a soft bloom past it. So the whole
    effect is shadows, and the keycap underneath shows through untouched.
  */
  box-shadow:
    0 0 calc(var(--mb-w) * 0.0035) calc(var(--mb-w) * 0.0009)
      color-mix(in srgb, var(--kbd) 80%, transparent),
    0 0 calc(var(--mb-w) * 0.016) color-mix(in srgb, var(--kbd-halo) 38%, transparent),
    inset 0 calc(var(--mb-w) * -0.0014) calc(var(--mb-w) * 0.004)
      color-mix(in srgb, var(--kbd) 34%, transparent);
  opacity: calc(var(--mb-glow) * 0.95);
  transition: opacity 0.45s var(--ease);
  pointer-events: none;
}

.mb-key-cap {
  position: relative; /* above the bleed */
  z-index: 1;
  color: color-mix(in srgb, #ffffff calc(22% + var(--mb-glow) * 78%), #55555c);
  /* The legend is a window cut in the cap, not paint on it, so it glows in its
     own right rather than merely being lit. */
  text-shadow: 0 0 calc(var(--mb-w) * 0.004)
    color-mix(in srgb, var(--kbd) calc(var(--mb-glow) * 65%), transparent);
  font-family: var(--font-mono);
  font-size: calc(var(--mb-w) * 0.018);
  line-height: 1;
  letter-spacing: 0;
  transition:
    color 0.45s var(--ease),
    text-shadow 0.45s var(--ease);
}

.mb-key-sm .mb-key-cap {
  font-size: calc(var(--mb-w) * 0.012);
}

.u0-75 { flex-grow: 0.75; }
.u1 { flex-grow: 1; }
.u1-25 { flex-grow: 1.25; }
.u1-5 { flex-grow: 1.5; }
.u1-75 { flex-grow: 1.75; }
.u2 { flex-grow: 2; }
.u2-25 { flex-grow: 2.25; }
.u2-75 { flex-grow: 2.75; }
.u5 { flex-grow: 5; }

/* 130 by 81mm, 13mm below the keys. Sized off --mb-w rather than in percent,
   because a percentage here would resolve against the padded content box and
   quietly come out an eighth too narrow. */
.mb-trackpad {
  width: calc(var(--mb-w) * 0.417);
  margin: calc(var(--mb-w) * 0.042) auto 0;
  aspect-ratio: 130 / 81;
  border-radius: calc(var(--mb-w) * 0.006);
  background: linear-gradient(180deg, #26262b 0%, #1e1e22 100%);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 10%),
    inset 0 -1px 0 rgb(0 0 0 / 45%),
    0 1px 2px rgb(0 0 0 / 50%);
}

/* Speaker grilles, as a dot field rather than drawn holes. */
/* Outboard of the keys, running the depth of the key area, which is where the
   grilles sit on the machine this is a picture of. */
.mb-speaker {
  position: absolute;
  inset-block-start: 9%;
  width: 4.4%;
  height: 48%;
  background-image: radial-gradient(circle, #111114 0.6px, transparent 0.7px);
  background-size: calc(var(--mb-w) * 0.0075) calc(var(--mb-w) * 0.0075);
  opacity: 0.85;
}

.mb-speaker-l { inset-inline-start: 1.8%; }
.mb-speaker-r { inset-inline-end: 1.8%; }

/*
  Light pooling on the aluminium around the board. Sits above the deck and below
  nothing: it is additive, so it only ever brightens what is already there.
*/
.mb-spill {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    82% 58% at 50% 33%,
    color-mix(in srgb, var(--kbd-halo) 34%, transparent),
    transparent 72%
  );
  opacity: var(--mb-glow);
  mix-blend-mode: screen;
  transition: opacity 0.45s var(--ease);
  pointer-events: none;
}

/* The front lip, standing up from the near edge of the deck. Without a visible
   thickness the machine reads as a decal lying on the page. */
.mb-lip {
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 0;
  height: calc(var(--mb-w) * 0.019);
  border-radius: 0 0 calc(var(--mb-w) * 0.01) calc(var(--mb-w) * 0.01);
  background: linear-gradient(180deg, #43434a 0%, #1a1a1d 100%);
  transform-origin: 50% 0%;
  /* Back up to vertical: the deck it hangs off is lying down, and the front edge
     of a laptop is the one face that still looks straight at you. */
  transform: rotateX(83deg);
}

/* Contact shadow. Tight and dark where the machine meets the surface, wide and
   faint further out, which is the whole difference between sitting on a desk
   and floating above one. */
.mb-cast {
  position: absolute;
  inset-block-start: 96%;
  inset-inline-start: 50%;
  width: 116%;
  height: calc(var(--mb-w) * 0.36);
  background: radial-gradient(
    50% 50% at 50% 50%,
    rgb(0 0 0 / 62%),
    rgb(0 0 0 / 22%) 45%,
    transparent 72%
  );
  transform: translateX(-50%) rotateX(-83deg) translateZ(calc(var(--mb-w) * -0.02));
  filter: blur(calc(var(--mb-w) * 0.012));
  pointer-events: none;
}

/* And the light the keyboard throws back onto the desk, which is the half of
   the effect a shadow alone cannot show. It rides the same blur as the shadow
   it sits in, so the two read as one contact. */
.mb-cast::after {
  content: "";
  position: absolute;
  inset: 14% 10%;
  background: radial-gradient(
    50% 50% at 50% 42%,
    color-mix(in srgb, var(--kbd-halo) 20%, transparent),
    transparent 68%
  );
  opacity: var(--mb-glow);
  mix-blend-mode: screen;
  transition: opacity 0.45s var(--ease);
}

/* ---- controls ---- */
.mb-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
  margin-block-start: 1.75rem;
}

.mb-btn {
  padding: 0.4rem 0.9rem;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--dim-text);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0;
  cursor: pointer;
  transition:
    background-color 0.16s var(--ease),
    color 0.16s var(--ease);
}

.mb-btn:hover {
  background: var(--surface-high);
  color: var(--text);
}

.mb-btn[data-active="true"] {
  background: var(--accent-solid);
  color: var(--on-accent);
}

.mb-btn-cmd::before {
  content: "$ ";
  opacity: 0.6;
}

.mb-note {
  margin-block-start: 1.25rem;
  text-align: center;
}

/* -------------------------------------------------------------- sun mode */
/*
  A day drawn as a single 24 hour track: night is the bare panel, daylight is
  the lit band across the middle, and a marker sits at the current time.

  The three positions arrive as custom properties, in percent of the day, set
  by sun-preview.js through the CSSOM. They are not style attributes on purpose:
  the Content-Security-Policy in vercel.json permits no inline style, and the
  defaults below are the example day the generated markup describes, so the
  track is already coherent before any script runs.
*/
.sun-preview {
  max-width: var(--measure);
  margin: 2.25rem auto 0;
  padding: 1.4rem 1.5rem 1.25rem;
  border-radius: var(--radius);
  background: var(--surface);

  --sun-rise: 25%;
  --sun-set: 79.2%;
  --sun-now: 50%;
}

.sun-preview-label {
  margin: 0 0 0.9rem;
  color: var(--dim-text);
  font-size: 0.8125rem;
}

.sun-track {
  position: relative;
  height: 3.25rem;
  border-radius: var(--radius-sm);
  background: var(--surface-high); /* the daytime: keyboard off */
  overflow: hidden;
}

/*
  The glow is the backlight, not the daylight.

  Drawing the daytime as the lit band is the obvious way round and it is the
  wrong one: this is a picture of what the command does, and what it does is
  leave the keyboard dark all day and light it after sunset. So the track itself
  is the day, and the two lit segments at either end are the hours the keyboard
  is actually on. They are white for the same reason the illustration above them
  is: that is the colour of the light being described. The gradient fades
  towards the sunrise and sunset edges, because a hard vertical line there reads
  as a rendering seam rather than as the moment the sun crossed the horizon.
*/
.sun-lit {
  position: absolute;
  inset-block: 0;
  transition:
    inset-inline-start 0.55s var(--ease),
    inset-inline-end 0.55s var(--ease);
}

.sun-lit-early {
  inset-inline-start: 0;
  inset-inline-end: calc(100% - var(--sun-rise));
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--kbd) 52%, transparent),
    color-mix(in srgb, var(--kbd-halo) 6%, transparent)
  );
}

.sun-lit-late {
  inset-inline-start: var(--sun-set);
  inset-inline-end: 0;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--kbd-halo) 6%, transparent),
    color-mix(in srgb, var(--kbd) 52%, transparent)
  );
}

.sun-legend {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0.5rem 0 0;
  color: var(--faint);
  font-size: 0.6875rem;
  letter-spacing: 0;
}

.sun-legend-mid {
  color: var(--dim-text);
}

/*
  Hidden until a script has worked out what "now" is. A marker sitting at a
  guessed time would be the one dishonest pixel on the page.
*/
.sun-now {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--sun-now);
  width: 2px;
  margin-inline-start: -1px;
  background: var(--accent);
  opacity: 0;
  transition:
    inset-inline-start 0.55s var(--ease),
    opacity 0.3s var(--ease);
}

.sun-now::after {
  content: "";
  position: absolute;
  inset-block-start: -3px;
  inset-inline-start: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

[data-sun-live] .sun-now {
  opacity: 1;
}

.sun-marks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: 0.75rem 1.25rem;
  margin: 1.1rem 0 0;
}

.sun-mark {
  min-width: 0;
}

.sun-mark-key {
  color: var(--faint);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.sun-mark-value {
  margin: 0.2rem 0 0;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}

.sun-preview-note {
  margin: 1rem 0 0;
  text-align: start;
}

.section-sun .copy {
  margin-block-start: 2rem;
}

/* -------------------------------------------------------------------- faq */
/* Apple's accordion: hairlines only, no box, the control on the right. */
.faq {
  max-width: var(--measure);
  margin: 2rem auto 0;
  border-block-start: 1px solid var(--hairline);
}

.faq-item {
  border-block-end: 1px solid var(--hairline);
}

.faq-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 0.25rem;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  cursor: pointer;
  list-style: none;
}

/* The default triangle differs per browser and cannot be styled in Safari, so
   it is replaced with one marker that behaves the same everywhere. */
.faq-q::-webkit-details-marker {
  display: none;
}

.faq-q::after {
  content: "+";
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1;
  transition:
    background-color 0.16s var(--ease),
    transform 0.2s var(--ease);
}

.faq-item[open] .faq-q::after {
  content: "\2212"; /* minus, so the control says what it will do next */
}

.faq-q:hover::after {
  background: var(--surface-high);
}

.faq-q:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.faq-a {
  margin: 0;
  padding: 0 2.5rem 1.35rem 0.25rem;
  color: var(--dim-text);
  font-size: 0.9375rem;
}

/* ------------------------------------------------------------------ toast */
.toast {
  position: fixed;
  inset-block-end: 1.25rem;
  inset-inline-start: 50%;
  z-index: 20;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-pill);
  background: var(--surface-high);
  color: var(--text);
  font-size: 0.8125rem;
  opacity: 0;
  transform: translate(-50%, 8px);
  pointer-events: none;
  transition:
    opacity 0.22s var(--ease),
    transform 0.22s var(--ease-out);
}

.toast[data-visible="true"] {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ----------------------------------------------------------------- reveal */
/*
  Apple's one piece of scroll choreography: content rises the last few pixels
  into place as it comes into view. app.js adds the class, so with no script
  everything is simply already in place, which is the correct fallback.

  --reveal-delay staggers a group. It is set through the CSSOM rather than as a
  style attribute, because the Content-Security-Policy allows no inline style.
*/
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.7s var(--ease-out) var(--reveal-delay, 0ms),
    transform 0.7s var(--ease-out) var(--reveal-delay, 0ms);
}

.reveal.is-in {
  opacity: 1;
  transform: none;
}

/* ------------------------------------------------------------ small print */
@media (max-width: 32rem) {
  .btn-primary {
    width: 100%;
  }

  .cta-row {
    flex-direction: column;
    gap: 1rem;
  }
}

/* Motion is decoration here, never information. Removing it costs nothing. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .card:hover {
    transform: none;
  }

  /* Never leave content invisible waiting for a transition that will not run. */
  .reveal {
    opacity: 1;
    transform: none;
  }
}

@media (forced-colors: active) {
  .card,
  .copy,
  .btn-primary,
  .localnav-cta {
    border: 1px solid CanvasText;
  }
}

@media print {
  body {
    background: #ffffff;
    color: #000000;
  }

  .localnav,
  .toast,
  .copy-btn,
  .skip-link {
    display: none;
  }
}
