/* ─────────────────────────────────────────────────────────────────────────────
   Vardnir — shared stylesheet (design manual v3, the signal revision)

   Ground is near-black; the mark is a level meter at rest. Two rules carried
   over from v2 because they are what keeps this from reading as another dark
   SaaS page: hairlines instead of cards, and nothing moves except the mark,
   once, on arrival. One light paper section breaks the dark on purpose — the
   publisher's page has a printed page in it.
   ──────────────────────────────────────────────────────────────────────────── */

/* ── Owned type ─────────────────────────────────────────────────────────────
   Self-hosted: on a system stack Windows fell back to Segoe and Android to
   Roboto, and two thirds of visitors never saw the identity. Schibsted Grotesk
   is variable, so one file carries 400/500/600. See fonts/README.md. */

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('/assets/fonts/SchibstedGrotesk.var-latin.woff2') format('woff2');
  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: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('/assets/fonts/SchibstedGrotesk.var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/IBMPlexMono-400-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/IBMPlexMono-500-latin.woff2') format('woff2');
}

:root {
  /* Ground */
  --void:        #07090D;   /* the page */
  --deep:        #0B0F15;   /* alternating sections */
  --panel:       #10151C;   /* fields, the few real cards */

  /* Ink */
  --faint:       #6E7885;   /* mono labels, timecodes */
  --mute:        #97A1AE;   /* body copy */
  --chalk:       #F1F4F8;   /* headings, the mark */

  /* The one accent — the family green, the same one the apps carry */
  --signal:      #16A878;   /* the accent column, links, the live dot */
  --signal-deep: #0F8A5F;   /* the mark's accent on paper, and foil */
  /* Link text on a light ground. #0F8A5F reads well as a shape but only makes
     3.6:1 against paper — as type it fails AA, so text gets its own deep green. */
  --signal-ink:  #0A6B49;

  /* The printed page */
  --paper:       #EDE9DF;
  /* A second stock, one step brighter. Two paper bands in a row read as one
     long slab; the apps and their screens are near-black, so the way out is
     not a dark band but a lighter one — the showcase is a light table, the
     index is the page. Brighter also lifts every ink on it, so nothing that
     passed AA on --paper loses contrast by moving here. */
  --paper-lift:  #F8F6F0;
  --ink:         #12141A;
  --ink-mute:    #575C66;
  --ink-faint:   #63686F;   /* labels on paper — 4.6:1, the floor for AA */
  --ink-rule:    #D5D0C4;

  --hairline:    rgba(241, 244, 248, 0.10);
  --hairline-strong: rgba(241, 244, 248, 0.18);

  --sans: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI',
          Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo,
          Consolas, monospace;

  --wrap: 1120px;
  --gutter: 28px;
}

/* ── Reset ─────────────────────────────────────────────────────────────────── */

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

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

body {
  margin: 0;
  background: var(--void);
  color: var(--mute);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 {
  color: var(--chalk);
  font-weight: 600;
  letter-spacing: -0.022em;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: clamp(38px, 5.6vw, 66px); line-height: 1.04; letter-spacing: -0.032em; }
h2 { font-size: clamp(26px, 3vw, 34px); line-height: 1.14; }
h3 { font-size: 18px; line-height: 1.3; letter-spacing: -0.012em; }

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

a { color: var(--signal); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

strong { color: var(--chalk); font-weight: 600; }
em { font-style: italic; }

::selection { background: var(--signal); color: var(--ink); }

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

/* ── Layout ────────────────────────────────────────────────────────────────── */

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }
.wrap-narrow { max-width: 680px; margin: 0 auto; padding: 0 var(--gutter); }

main > section { padding: 84px 0; border-top: 1px solid var(--hairline); }
main > section.band-deep { background: var(--deep); }

/* The printed page inside the dark one. */
main > section.band-paper {
  background: var(--paper);
  color: var(--ink-mute);
  border-top: 0;
}
main > section.band-paper--lift { background: var(--paper-lift); }
/* Where two paper bands meet, the seam has to be drawn in ink: the default
   hairline is white at 10% and disappears the moment the ground turns light. */
main > section.band-paper + section.band-paper { border-top: 1px solid var(--ink-rule); }
.band-paper h1, .band-paper h2, .band-paper h3, .band-paper strong { color: var(--ink); }
/* Underline the links a reader reads past — not the block-level ones, where a
   whole row is the target and an underline would run under a paragraph. */
.band-paper a { color: var(--signal-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.band-paper .app-row,
.band-paper .app-name--stretch,
.band-paper .status--store,
.band-paper .tpl-card,
.band-paper .btn,
.band-paper .link-more,
.band-paper .marque,
.band-paper .deck-link { text-decoration: none; }
.band-paper .eyebrow { color: var(--ink-faint); }
.band-paper .eyebrow .tc { color: var(--signal-deep); }
.band-paper .lede { color: var(--ink-mute); }

/* Anything that lives on the paper band needs its rules and its accent
   restated: the hairlines are white-on-dark rgba and vanish here, and the
   signal green drops to 3.6:1 as text. */
.band-paper .app-index,
.band-paper .app-row { border-color: var(--ink-rule); }
.band-paper .app-name { color: var(--ink); }
.band-paper .app-row:hover .app-name,
.band-paper .app-row:hover .app-arrow,
.band-paper .app-row--live:hover .app-name,
.band-paper .app-row--live:hover .app-arrow { color: var(--signal-ink); }
.band-paper .app-tag { color: var(--ink-mute); }
.band-paper .status { color: var(--ink-faint); }
.band-paper .status.live { color: var(--signal-ink); }
.band-paper .app-arrow { color: var(--ink-faint); }
.band-paper .app-icon--letter { background: #E3DFD4; border-color: var(--ink-rule); color: var(--ink-faint); }
.band-paper .hero-meta { border-top-color: var(--ink-rule); color: var(--ink-faint); }
.band-paper .hero-meta b { color: var(--ink); }

/* ── Type helpers ──────────────────────────────────────────────────────────── */

.lede {
  font-size: clamp(17px, 1.5vw, 19px);
  line-height: 1.6;
  color: var(--mute);
  max-width: 62ch;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 20px;
}
/* Timecode numbering: 00:01, never 01. */
.eyebrow .tc { color: var(--signal); margin-right: 12px; }

.section-head { margin-bottom: 44px; max-width: 62ch; }
.section-head h2 { margin-bottom: 14px; }

/* ── The mark ──────────────────────────────────────────────────────────────── */
/* Five columns on one baseline. At rest it is the varde; the accent column is
   the only colour. `.mark--live` runs once on arrival and settles. */

.mark { display: block; overflow: visible; }
.mark rect { transform-box: fill-box; transform-origin: bottom; }

@keyframes mark-settle {
  0%   { transform: scaleY(0.18); }
  55%  { transform: scaleY(1.14); }
  78%  { transform: scaleY(0.94); }
  100% { transform: scaleY(1); }
}

.mark--live rect {
  animation: mark-settle 780ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
.mark--live rect:nth-child(1) { animation-delay: 260ms; }
.mark--live rect:nth-child(2) { animation-delay:   0ms; }
.mark--live rect:nth-child(3) { animation-delay: 130ms; }
.mark--live rect:nth-child(4) { animation-delay: 390ms; }
.mark--live rect:nth-child(5) { animation-delay: 520ms; }

@media (prefers-reduced-motion: reduce) {
  .mark--live rect { animation: none; }
}

/* ── Header ────────────────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(7, 9, 13, 0.82);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--hairline);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 68px;
}

.marque {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: var(--chalk);
  text-decoration: none;
}
.marque:hover { text-decoration: none; }
.marque .word {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.028em;
  line-height: 1;
}
.marque--stack {
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
}

.site-nav { display: flex; align-items: center; gap: 28px; }
.site-nav a {
  font-size: 14px;
  color: var(--mute);
  text-decoration: none;
}
.site-nav a:hover { color: var(--chalk); text-decoration: none; }

/* ── Hero ──────────────────────────────────────────────────────────────────── */

.hero { padding: 108px 0 76px; }
.hero .lede { margin-top: 22px; }

.hero--home { padding: 132px 0 92px; }
.hero--home h1 { max-width: 17ch; }
.hero--home .lede { max-width: 54ch; }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 64px;
  align-items: center;
}
/* The meta strip is its own grid child rather than a paragraph inside the text
   column, so that on a phone it can fall below the screen instead of pushing
   it under the fold. On a wide screen it sits where it always did. */
.hero-grid .hero-say { grid-column: 1; grid-row: 1; }
.hero-grid .hero-shot { grid-column: 2; grid-row: 1 / span 2; }
.hero-grid .hero-meta { grid-column: 1; grid-row: 2; margin-top: 0; }
.hero-mark { color: var(--chalk); opacity: 0.9; }

/* The front page's picture is a screen, not the mark. A logo at 190px was the
   largest thing on a page selling software nobody had seen — this is the same
   slot, spent on the product. The device art is 1200px wide, so it stays a
   retina image at every width below. */
.hero-shot {
  margin: 0;
  width: clamp(230px, 27vw, 332px);
  position: relative;
  /* Distance, not a fisheye. A short perspective on an object this size bows
     the straight edges of the case and the illusion goes with them. */
  perspective: 2400px;
}

/* Behind it: one faint wash in the accent so the device sits in a room rather
   than on a flat black, and a soft ellipse under it for contact with a ground.
   Both are wide and low-contrast — at this strength they read as light, and at
   any more they read as gradients. */
.hero-shot::before {
  content: '';
  position: absolute;
  inset: -16% -28% -10%;
  background:
    radial-gradient(50% 38% at 44% 36%, rgba(22, 168, 120, 0.11), transparent 72%),
    radial-gradient(42% 9% at 50% 96%, rgba(0, 0, 0, 0.55), transparent 70%);
  z-index: 0;
  pointer-events: none;
}

/* The frame carries the turn so the caption underneath stays square to the
   page. Eleven degrees and a two-degree tip — enough to be an object in a
   hand, little enough that no line of the app's own type starts to bend. There
   is deliberately no roll: a rotation in the page's own plane is what makes a
   flat image read as a sticker laid at an angle. */
.shot-frame {
  position: relative;
  z-index: 1;
  transform: rotateY(-11deg) rotateX(2deg);
  transform-origin: 68% 50%;
  /* Two shadows, near and far. One tight and dark for the case's own edge, one
     wide and weak for the light in the room. */
  filter:
    drop-shadow(10px 14px 16px rgba(0, 0, 0, 0.5))
    drop-shadow(26px 46px 60px rgba(0, 0, 0, 0.45));
}
.shot-frame img { display: block; width: 100%; height: auto; }

/* What actually sells the turn: light across the case. The far side falls into
   shadow and the near edge catches a highlight — masked by the device's own
   alpha, so it stops exactly at the rounded corners instead of painting a
   rectangle over them. */
/* Guarded: without mask support this gradient would paint a rectangle across
   the rounded case — worse than no light at all. Where the mask works, it is
   the whole trick; where it does not, the device is simply flat-lit. */
.shot-frame::after { content: none; }

@supports ((-webkit-mask-image: url('#m')) or (mask-image: url('#m'))) {
.shot-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(101deg,
    rgba(255, 255, 255, 0.13) 0%,
    rgba(255, 255, 255, 0.03) 9%,
    rgba(0, 0, 0, 0) 34%,
    rgba(0, 0, 0, 0.06) 68%,
    rgba(0, 0, 0, 0.30) 100%);
  -webkit-mask: var(--shot) center / 100% 100% no-repeat;
  mask: var(--shot) center / 100% 100% no-repeat;
  pointer-events: none;
}
}

/* The deck is a swipe row on a phone and a single picture everywhere else.
   Above 860px the extra cards and every caption inside the row are simply not
   there — and because their images are lazy, a desktop visitor never fetches
   one. */
/* ── The hero deck ─────────────────────────────────────────────────────────
   Three screens, one per app. On a wide page they stand in a row; on a phone
   the same row is swiped. What they replaced was one screen inside a drawn
   case, turned and lit — beautiful, and half a picture of a phone. Three
   screens with their app icons on them say what the shelf below says, in the
   place a visitor looks first. */
.hero-deck {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 30px;
}
.deck-link { display: block; color: inherit; text-decoration: none; }
a.deck-link:hover .deck-cap { color: var(--chalk); }

/* Whose screen this is. Three screens from three products are three screens
   from nothing at all if the reader cannot tell them apart, so each card wears
   its own icon at the size a home screen would draw it. */
.deck-tag {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 15px;
}
.deck-tag img {
  display: block;
  width: 30px; height: 30px;
  border-radius: 8px;
  outline: 1px solid rgba(255, 255, 255, 0.10);
  outline-offset: -1px;
}
.deck-tag b {
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--chalk);
}

/* A screen, not a device: no case, no turn, no light across a silhouette that
   is not there. Used by the hero deck and by every product page — the drawn
   phone they all used to sit in spent half the picture on a case, which is not
   what anyone came to look at. The corners are rounded here rather than baked
   into the file so the radius is right at every width, and the hairline is what
   separates a black screen from a page nearly as black. */
.shot-frame--bare {
  display: block;
  transform: none;
  border-radius: 18px;
  overflow: hidden;
  outline: 1px solid rgba(255, 255, 255, 0.10);
  outline-offset: -1px;
  filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.55));
}
.shot-frame--bare::after { content: none; }

/* The caption belongs to its own card and travels with it — one caption under
   a row of three would describe whichever card happened to be under it. */
.deck-cap {
  display: block;
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: var(--faint);
  transition: color 0.18s ease;
}

/* The sentence keeps a reading measure even though the deck below it runs the
   full width. */
.hero--home .hero-say { max-width: 720px; }

.hero-shot figcaption {
  position: relative;
  z-index: 1;
  margin-top: 20px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: var(--faint);
}
.hero-shot figcaption a { color: inherit; }
.hero-shot figcaption a:hover { color: var(--signal); }

.hero--tpl { padding: 76px 0 56px; }

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 40px;
  margin-top: 44px;
  padding-top: 26px;
  border-top: 1px solid var(--hairline);
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--faint);
}
.hero-meta b { color: var(--chalk); font-weight: 500; }

/* On the paper band the cards change ground: the hairline that separated a
   black screen from a black page has to become a line that separates a white
   screen from cream, and a shadow sized for near-black is a bruise on paper. */
.band-paper .deck-tag b { color: var(--ink); }
.band-paper .deck-tag img { outline-color: var(--ink-rule); }
.band-paper .shot-frame--bare {
  outline-color: var(--ink-rule);
  filter: drop-shadow(0 14px 26px rgba(18, 20, 26, 0.16));
}
/* On the light table the shots are objects lying on a surface, so the shadow
   grows a little — it has a brighter ground to fall on without bruising it. */
.band-paper--lift .shot-frame--bare {
  filter: drop-shadow(0 16px 30px rgba(18, 20, 26, 0.18));
}
.band-paper .deck-cap { color: var(--ink-faint); }
.band-paper a.deck-link:hover .deck-cap { color: var(--ink); }

/* ── Buttons & links ───────────────────────────────────────────────────────── */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 26px;
  margin-top: 34px;
}

/* A line of reassurance beside a button, not under it — the button is the
   thing, and a second block of text below it reads as another step. */
.cta-note {
  font-size: 14px;
  line-height: 1.5;
  color: var(--faint);
  max-width: 38ch;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 13px 22px;
  border-radius: 4px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn:hover { text-decoration: none; }

.btn-primary { background: var(--signal); color: var(--ink); }
.btn-primary:hover { background: #1FBE8A; }

.band-paper .btn-primary { background: var(--ink); color: var(--paper); }
.band-paper .btn-primary:hover { background: #2A2E36; }

.btn-ghost { border-color: var(--hairline-strong); color: var(--chalk); }
.btn-ghost:hover { border-color: var(--chalk); }

.link-more {
  font-size: 15px;
  color: var(--chalk);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline-strong);
  padding-bottom: 2px;
}
.link-more:hover { text-decoration: none; border-bottom-color: var(--signal); color: var(--signal); }

/* ── The releases index (rows, never cards) ────────────────────────────────── */

.app-index { border-top: 1px solid var(--hairline); }

.app-row {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto 22px;
  gap: 26px;
  align-items: start;
  padding: 30px 0;
  border-bottom: 1px solid var(--hairline);
  color: inherit;
  text-decoration: none;
}
a.app-row:hover { text-decoration: none; }
a.app-row:hover .app-name { color: var(--signal); }
a.app-row:hover .app-arrow { color: var(--signal); transform: translateX(3px); }

/* A row for an app whose page is not ready to be read yet. It keeps its place
   on the shelf — it is still one of the apps — and simply stops being a link:
   no arrow, no lift under the cursor, nothing that promises a page. */
.app-row--flat { cursor: default; }

/* The released app's row holds two links. The name's is stretched over the
   whole row, so clicking anywhere still opens the page the row is about; the
   store link is lifted above that overlay, so the words "On the App Store"
   reach the App Store. */
.app-row--live { position: relative; }
.app-name--stretch { display: block; color: inherit; text-decoration: none; }
.app-name--stretch::after { content: ''; position: absolute; inset: 0; }
.app-row--live:hover .app-name { color: var(--signal); }
.app-row--live:hover .app-arrow { color: var(--signal); transform: translateX(3px); }
/* Doubled class, because `.status` sets its own padding-top further down the
   file and would otherwise win on source order and eat half the target. */
.status.status--store {
  position: relative;
  z-index: 1;
  text-decoration: none;
  /* Nineteen pixels of uppercase mono is a line of type, not a target. The
     padding grows the hit area to 45px and the negative margin gives back
     exactly what it took, so nothing on the row moves. */
  padding: 13px 0;
  margin: -7px 0 -13px;
  transition: opacity 0.15s;
}
.status--store:hover { text-decoration: underline; text-underline-offset: 4px; }

.app-icon { border-radius: 12px; width: 56px; height: 56px; }
.app-icon--letter {
  display: grid;
  place-items: center;
  background: var(--panel);
  border: 1px solid var(--hairline);
  color: var(--faint);
  font-size: 22px;
  font-weight: 600;
}
.app-icon--hero { width: 88px; height: 88px; border-radius: 20px; }

.app-name {
  color: var(--chalk);
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.022em;
  transition: color 0.15s;
}
.app-tag { margin: 8px 0 0; font-size: 15px; max-width: 58ch; }

.status {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
  padding-top: 6px;
}
.status.live { color: var(--signal); }
.status::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  margin-right: 9px;
  vertical-align: 1px;
  background: currentColor;
}

.app-arrow {
  color: var(--faint);
  font-size: 19px;
  line-height: 1.4;
  transition: color 0.15s, transform 0.15s;
}

/* ── Stills from the apps ──────────────────────────────────────────────────── */

.stills {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 26px;
}
/* The product page runs the whole arc, so it gets a fourth phone and tighter
   captions — a filmstrip rather than three portraits. */
.stills--four { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }
.stills--four .still p { font-size: 13.5px; }
/* The device is cut out of its background and carries its own bezel, so it gets
   no border and no radius of ours — a rounded corner that is not the phone's
   corner reads as the screen escaping the frame, and a 1px rule alongside the
   bezel reads as two frames. The phone is the frame. */
.still figure { margin: 0; }
.still img { width: 100%; }
.still figcaption {
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
}
.still p { margin: 8px 0 0; font-size: 14.5px; }

/* ── Stages (the product page's spine) ─────────────────────────────────────── */
/* One screen, one sentence, alternating sides. The screen is the argument and
   the text is the caption — not the other way round, which is what three
   columns of prose above a strip of thumbnails amounted to. */

.stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: 56px;
  align-items: center;
  padding: 64px 0;
  border-top: 1px solid var(--hairline);
}
.stage:first-of-type { border-top: 0; padding-top: 8px; }
/* Every other one turns round, so the eye crosses the page instead of running
   down one gutter. */
.stage--flip { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr); }
.stage--flip .stage-shot { order: -1; }

.stage-say .eyebrow { margin-bottom: 14px; }
.stage-say h3 { font-size: clamp(25px, 2.7vw, 33px); line-height: 1.12; letter-spacing: -0.022em; }
.stage-say p { margin: 16px 0 0; color: var(--mute); font-size: 16.5px; line-height: 1.6; max-width: 42ch; }

.stage-shot { margin: 0; justify-self: center; width: clamp(220px, 24vw, 300px); }
.stage-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 18px;
  outline: 1px solid rgba(255, 255, 255, 0.10);
  outline-offset: -1px;
  box-shadow: 0 18px 34px rgba(0, 0, 0, 0.45);
}

/* ── Convictions ───────────────────────────────────────────────────────────── */

.creed { border-top: 1px solid var(--hairline); }
.creed-row {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 20px 48px;
  padding: 30px 0;
  border-bottom: 1px solid var(--hairline);
  align-items: baseline;
}
.creed-row h3 { font-size: 19px; }
.creed-row p { font-size: 15px; margin: 0; }

/* ── Facts (the paper section) ─────────────────────────────────────────────── */

/* Two grounds. The grid is drawn with whichever rule belongs to the section it
   sits in, so the same markup works on the paper band and on the dark one. */
.facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--hairline-strong);
  border: 1px solid var(--hairline-strong);
  margin-top: 40px;
}
.facts--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.fact { background: var(--void); padding: 24px 22px; }
.fact dt {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 8px;
}
.fact dd { margin: 0; color: var(--chalk); font-size: 15.5px; font-weight: 500; }

.band-paper .facts { background: var(--ink-rule); border-color: var(--ink-rule); }
.band-paper .fact { background: var(--paper); }
.band-paper .fact dt { color: var(--ink-faint); }
.band-paper .fact dd { color: var(--ink); }

/* ── Product page furniture ────────────────────────────────────────────────── */

.product-head { display: flex; align-items: center; gap: 22px; margin-bottom: 28px; }
.product-head .eyebrow { margin-bottom: 10px; }

.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
}
.pillar { background: var(--void); padding: 28px 26px; }
.band-deep .pillar { background: var(--deep); }
.pillar h3 { margin-bottom: 10px; }
.pillar p { font-size: 15px; margin: 0; }

/* The player is our own <video>, so the green button is the only button: one
   click hides it and starts the film with sound. An embedded YouTube frame
   cannot do that — see the note beside the markup in scripts/build.mjs. */
.video-figure {
  position: relative;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  overflow: hidden;
  background: var(--void);
}
.video-figure video {
  display: block;
  width: 100%;
  /* height:auto is load-bearing — the element carries width/height attributes
     so the box is reserved before the poster arrives, and a definite height
     would beat the aspect-ratio and letterbox the film. */
  height: auto;
  aspect-ratio: 16 / 9;
  background: var(--void);
}
.video-facade {
  position: absolute;
  inset: 0;
  width: 100%;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.video-facade[hidden] { display: none; }
.video-aside {
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--faint);
}
.video-aside a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.video-aside a:hover { color: var(--signal); }
.video-facade .play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(7, 9, 13, 0.28);
}
.video-facade .play > span {
  width: 76px; height: 76px;
  border-radius: 50%;
  background: var(--signal);
  display: grid;
  place-items: center;
  padding-left: 4px;
}

/* Hairline grid drawn with borders, not with a coloured gap — a half-full last
   row would otherwise leave a grey slab where the missing cards are. */
.tpl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  border-top: 1px solid var(--hairline);
  border-left: 1px solid var(--hairline);
}
.tpl-card {
  border-right: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  padding: 22px 20px;
  color: inherit;
  text-decoration: none;
  display: block;
  transition: background 0.15s;
}
.tpl-card:hover { background: var(--panel); text-decoration: none; }
.tpl-card:hover .tpl-name { color: var(--signal); }
.tpl-dots { display: flex; gap: 4px; margin-bottom: 16px; }
.tpl-dots span { width: 18px; height: 4px; border-radius: 1px; }
.tpl-name { color: var(--chalk); font-weight: 600; font-size: 16px; letter-spacing: -0.015em; transition: color 0.15s; }
.tpl-desc { margin: 6px 0 0; font-size: 14px; line-height: 1.55; }

.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
  max-width: 720px;
}
.plan { background: var(--void); padding: 30px 26px; }
.band-deep .plan { background: var(--deep); }
.plan.featured { background: var(--panel); }
.plan h3 { margin-bottom: 12px; }
.plan .price {
  font-family: var(--mono);
  font-size: 30px;
  color: var(--chalk);
  letter-spacing: -0.02em;
  margin-bottom: 20px;
}
.plan .price small {
  display: block;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--faint);
  letter-spacing: 0;
  margin-top: 4px;
}
.plan ul { list-style: none; margin: 0; padding: 0; }
.plan li {
  font-size: 14.5px;
  padding: 7px 0 7px 20px;
  position: relative;
}
.plan li::before {
  content: '';
  position: absolute;
  left: 0; top: 15px;
  width: 8px; height: 1px;
  background: var(--signal);
}

.faq { border-top: 1px solid var(--hairline); max-width: 760px; }
.faq details { border-bottom: 1px solid var(--hairline); }
.faq summary {
  cursor: pointer;
  padding: 20px 0;
  color: var(--chalk);
  font-size: 16.5px;
  font-weight: 500;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 20px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; color: var(--signal); font-size: 19px; line-height: 1; }
.faq details[open] summary::after { content: '–'; }
.faq details p { padding: 0 0 22px; font-size: 15px; max-width: 68ch; }

.cta-card {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--hairline);
  padding: 24px 26px;
  margin-top: 32px;
}
.cta-card > div { flex: 1 1 260px; }
.cta-card strong { display: block; font-size: 17px; margin-bottom: 5px; }
.cta-card p { margin: 0; font-size: 14.5px; }

.crumbs {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 22px;
}
.crumbs a { color: var(--faint); }
.crumbs a:hover { color: var(--signal); }

/* The template page: the outline is the content, and the panel beside it is
   what stops a 650px text column from floating in a 1120px page. */
.tpl-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 296px;
  gap: 72px;
  align-items: start;
}

.tpl-outline { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hairline); counter-reset: none; }
.tpl-outline li {
  display: grid;
  grid-template-columns: 34px 3px minmax(0, 1fr);
  gap: 0 16px;
  padding: 18px 0;
  border-bottom: 1px solid var(--hairline);
}
/* Numbered because the order is the whole point, and because it is the same
   numbering the app puts on the blocks. */
.tpl-no {
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--faint);
  padding-top: 4px;
  letter-spacing: 0.04em;
}
.tpl-dot { width: 3px; flex: none; align-self: stretch; }
.tpl-outline strong { display: block; font-size: 16.5px; }
.tpl-outline p { margin: 5px 0 0; font-size: 15px; max-width: 56ch; }

.tpl-aside {
  position: sticky;
  top: 92px;
  border: 1px solid var(--hairline);
  padding: 22px 22px 24px;
  background: var(--deep);
}
/* The panel leads with the product rather than a table of facts the page has
   already told you. The screen is clipped and faded rather than cropped to a
   new file — at full height it would make the panel taller than the viewport
   and stickiness would stop working. */
.tpl-shot {
  height: 400px;
  overflow: hidden;
  margin: -22px -22px 20px;
  -webkit-mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
}
.tpl-shot img {
  width: 88%;
  margin: 22px auto 0;
  display: block;
  border-radius: 18px;
  outline: 1px solid rgba(255, 255, 255, 0.10);
  outline-offset: -1px;
}
.tpl-aside-meta {
  margin: 14px 0 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.03em;
  color: var(--faint);
  text-align: center;
}

.tpl-facts { margin: 0 0 18px; }
.tpl-facts > div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid var(--hairline);
}
.tpl-facts > div:first-child { padding-top: 0; }
.tpl-facts dt {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  padding-top: 2px;
}
.tpl-facts dd { margin: 0; color: var(--chalk); font-size: 14.5px; text-align: right; }
.tpl-aside-note { font-size: 14px; line-height: 1.6; margin-bottom: 20px; }
.tpl-aside .btn { width: 100%; justify-content: center; }

/* ── Legal pages ───────────────────────────────────────────────────────────── */

.legal { padding: 76px 0 96px; }
.legal h1 { font-size: clamp(32px, 4vw, 44px); margin-bottom: 10px; }
.legal h2 {
  font-size: 20px;
  margin: 46px 0 14px;
  padding-top: 22px;
  border-top: 1px solid var(--hairline);
}
.legal h3 { margin: 28px 0 10px; }
.legal p, .legal li { font-size: 15.5px; }
.legal ul, .legal ol { padding-left: 20px; }
.legal li { margin-bottom: 8px; }
.legal .meta {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--faint);
  margin-bottom: 40px;
}

/* ── Brand sheet ───────────────────────────────────────────────────────────── */

.specimen-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 34px 26px;
}
.specimen-stage {
  background: var(--deep);
  border: 1px solid var(--hairline);
  padding: 40px 30px;
  display: flex;
  align-items: center;
  gap: 26px;
  min-height: 148px;
  color: var(--chalk);
}
.specimen-stage--dark { background: var(--paper); color: var(--ink); }
.specimen-stage--row { justify-content: space-between; }
.specimen-label { margin-top: 14px; font-size: 14px; color: var(--chalk); }
.specimen-label span { color: var(--mute); font-size: 13.5px; }

.type-display { font-size: 38px; line-height: 1.12; color: var(--chalk); letter-spacing: -0.03em; font-weight: 600; }
.type-marque { font-size: 42px; font-weight: 600; letter-spacing: -0.04em; color: var(--chalk); }
.type-body { font-size: 16px; max-width: 60ch; }

.swatches { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 18px; }
.swatch { display: flex; gap: 16px; align-items: flex-start; font-size: 13.5px; }
.swatch > span { width: 52px; height: 52px; flex: none; border: 1px solid var(--hairline); }
.swatch code { font-family: var(--mono); font-size: 12px; color: var(--faint); }

.voice-pairs { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hairline); }
.voice-pairs li {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 8px 32px;
  padding: 16px 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 15px;
}
.voice-no { color: var(--faint); text-decoration: line-through; }
.voice-yes { color: var(--chalk); }

/* ── Footer ────────────────────────────────────────────────────────────────── */

.site-footer {
  border-top: 1px solid var(--hairline);
  padding: 44px 0 60px;
  background: var(--deep);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 40px;
  align-items: center;
  justify-content: space-between;
}
.footer-brand { display: flex; align-items: center; gap: 12px; color: var(--chalk); }
.footer-brand p { margin: 0; font-size: 13.5px; color: var(--faint); }
.footer-brand a { color: var(--mute); }
.footer-links { display: flex; flex-wrap: wrap; gap: 10px 26px; }
.footer-links a { font-size: 13.5px; color: var(--mute); }
.footer-links a:hover { color: var(--chalk); text-decoration: none; }

/* ── Narrow ────────────────────────────────────────────────────────────────── */

@media (max-width: 860px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: 34px; }
  .hero-mark { display: none; }
  /* The mark goes; the screen stays — and on a phone this is the view almost
     everyone gets, so the order is sentence, screen, facts. Stacked in one
     column the grid rows are set explicitly, because the screen is the second
     child in the source and the meta strip the third. */
  .hero-grid .hero-say  { grid-column: 1; grid-row: 1; }
  .hero-grid .hero-shot { grid-column: 1; grid-row: 2; }
  .hero-grid .hero-meta { grid-column: 1; grid-row: 3; }
  /* The case comes off on the pages that still draw one — the product pages
     and the teasers. A phone drawn on a phone spends half the column on a
     picture of a case the visitor is already holding, and at 47vw the app's own
     type rendered at about 7px: a screen nobody can read is a screen that
     argues nothing. Everything the case brought with it goes too — the turn,
     the perspective, the two shadows and the light across the silhouette. */
  .hero-shot { width: min(100%, 420px); perspective: none; }
  .hero-shot::before { content: none; }
  .hero-shot .shot-frame {
    transform: none;
    border-radius: 18px;
    overflow: hidden;
    outline: 1px solid rgba(255, 255, 255, 0.10);
    outline-offset: -1px;
    /* One soft shadow, straight down, so the screen is seated on the page
       rather than floating in front of it. */
    filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.55));
  }
  .hero-shot .shot-frame::after { content: none; }

  /* The deck stops being a row of three and becomes a row of one, swiped.
     Three cards stacked would run two and a half phone-heights before the
     shelf; side by side they cost one screen, and the sliver of the next card
     is the only instruction anyone needs. The row breaks the gutter on both
     sides so a card can be swiped from the very edge of the glass. */
  .hero-deck {
    display: flex;
    grid-template-columns: none;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: var(--gutter);
    -webkit-overflow-scrolling: touch;
    margin-left: calc(var(--gutter) * -1);
    margin-right: calc(var(--gutter) * -1);
    padding: 0 var(--gutter) 4px;
    scrollbar-width: none;
  }
  .hero-deck::-webkit-scrollbar { display: none; }
  .deck-card { flex: 0 0 88%; min-width: 0; scroll-snap-align: start; }
  .hero-shot::before { content: none; }
  .shot-frame {
    transform: none;
    /* One soft shadow, straight down, so the screen is seated on the page
       rather than floating in front of it. */
    filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.55));
  }
  .shot-frame::after { content: none; }

  /* Stacked, the three screens ran 3130px — 3.7 phone-heights, 45% of the whole
     page — and the app UI inside them rendered at about 7px, so none of it was
     readable anyway. Swiped sideways they cost one screen instead of four, and
     the sliver of the next card is the only instruction anyone needs. */
  .stills, .stills--four {
    display: flex;
    grid-template-columns: none;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    margin: 0 calc(var(--gutter) * -1);
    padding: 0 var(--gutter) 6px;
    scrollbar-width: none;
  }
  .stills::-webkit-scrollbar, .stills--four::-webkit-scrollbar { display: none; }
  /* Two and a bit on a tablet, one and a bit on a phone — in both cases the
     part-card at the edge is what says the row moves. */
  .still { flex: 0 0 46%; min-width: 0; scroll-snap-align: center; }
  .stills--four .still p, .still p { font-size: 15px; }
  .app-row { grid-template-columns: 48px minmax(0, 1fr); gap: 18px; }
  .app-icon { width: 48px; height: 48px; border-radius: 11px; }
  .app-row .status { grid-column: 2; padding-top: 0; margin-top: 12px; }
  /* Stacked under the tagline, the store link is the front page's only way
     into the App Store, so it gets a thumb-sized target. The margins hand
     back exactly what the padding took: 12px of gap above, nothing below. */
  .app-row .status--store { padding: 13px 0; margin-top: -1px; margin-bottom: -13px; }
  .app-arrow { display: none; }
  .creed-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  /* Stacked, and the screen always follows its sentence — a flipped stage that
     kept its order put the picture before the words it belonged to. */
  .stage, .stage--flip { grid-template-columns: minmax(0, 1fr); gap: 32px; padding: 44px 0; }
  .stage--flip .stage-shot { order: 0; }
  .stage-shot { width: min(280px, 62vw); }
  /* The panel stops being a sidebar and becomes the card that closes the
     outline — still above the fold-and-a-half, still the only button. */
  .tpl-layout { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .tpl-aside { position: static; }
  .facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-nav { gap: 18px; }
  main > section { padding: 62px 0; }
  .hero--home { padding: 84px 0 64px; }
  .app-tag, .creed-row p, .pillar p, .tpl-desc, .cta-card p { font-size: 15.5px; }
  .section-head { margin-bottom: 32px; }
}

@media (max-width: 560px) {
  :root { --gutter: 20px; }
  /* One card and a sliver, rather than two and a sliver. */
  .still { flex-basis: 76%; }
  /* The nav wraps under the wordmark rather than disappearing — a legal or
     support link that only exists on desktop is not a link. */
  .site-header .wrap { height: auto; flex-wrap: wrap; padding-top: 12px; padding-bottom: 12px; gap: 6px 18px; }
  /* Five items (the product page's nav) do not fit 320px on one line, and the
     header already wraps — the nav has to be allowed to as well. */
  .site-nav { gap: 6px 18px; flex-wrap: wrap; justify-content: flex-end; }
  .site-nav a { font-size: 13.5px; }
  .hero--home { padding: 60px 0 52px; }
  h1 { font-size: clamp(32px, 9vw, 40px); }
}

/* The paper specimen on the brand sheet: the mark inverts to ink there. */
.specimen-stage--dark .marque,
.specimen-stage--dark .marque .word { color: var(--ink); }
