/* ==========================================================================
   Whisk Mobile Development - whiskmobile.com
   Direction: mono-tech editorial. Royal blue grounds, cream type,
   Major Mono Display for display type, Comfortaa for reading.
   ========================================================================== */

/* --- self-hosted faces ---------------------------------------------------- */

@font-face {
  font-family: 'Comfortaa';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/comfortaa-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: 'Major Mono Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/major-mono-display-latin-400-normal.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;
}

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

:root {
  --blue: #4169e1;
  --blue-deep: #1c2a5e;
  --cream: #ede3e3;
  --ink: #16181d;

  /* cream at reduced opacity, for rules and secondary type on blue */
  --rule-on-blue: rgba(237, 227, 227, 0.28);
  --edge-on-blue: rgba(237, 227, 227, 0.45);
  --edge-on-blue-hover: rgba(237, 227, 227, 0.85);
  --wash-on-blue: rgba(237, 227, 227, 0.07);

  /* deep blue at reduced opacity, for rules on cream */
  --rule-on-cream: rgba(28, 42, 94, 0.22);
  --rule-on-cream-soft: rgba(28, 42, 94, 0.16);
  --edge-on-cream: rgba(28, 42, 94, 0.35);
  --wash-on-cream: rgba(28, 42, 94, 0.05);

  /* placeholder copy still to be written */
  --placeholder: #7f8aa8;

  --font-display: 'Major Mono Display', ui-monospace, 'SF Mono', Menlo, monospace;
  --font-body: 'Comfortaa', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-code: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --wrap: 1180px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);

  /* fluid display sizes: phone floor -> desktop ceiling */
  --size-hero: clamp(2.125rem, 5.4vw, 4.25rem);
  --size-page-title: clamp(1.875rem, 3.8vw, 3.25rem);
  --size-post-title: clamp(1.75rem, 3.4vw, 2.875rem);
  --size-app-name: clamp(1.1875rem, 1.6vw, 1.3125rem);
  --size-h2: clamp(1.375rem, 2vw, 1.625rem);
}

/* --- reset --------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--font-body);
  font-weight: 400;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

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

h1,
h2,
h3,
p,
ul,
ol,
figure,
pre,
blockquote {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

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

/* --- bands and wrapper --------------------------------------------------- */

.band--blue {
  background: var(--blue);
  color: var(--cream);
}

.band--cream {
  background: var(--cream);
  color: var(--blue-deep);
}

.band--ink {
  background: var(--ink);
  color: var(--cream);
}

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* --- mono labels and section headers ------------------------------------- */

.mono {
  font-family: var(--font-display);
  font-weight: 400;
}

.eyebrow {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
  line-height: 1.7;
  opacity: 0.72;
}

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
  padding-bottom: 1.125rem;
  margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--rule-on-blue);
}

.band--cream .section-head {
  border-bottom-color: var(--rule-on-cream);
}

.section-head__aside {
  letter-spacing: 0.06em;
  opacity: 0.65;
  white-space: nowrap;
}

.band--cream .section-head__aside {
  opacity: 1;
}

.section-head__aside:hover {
  opacity: 1;
}

/* --- nav ----------------------------------------------------------------- */

.nav {
  border-bottom: 1px solid var(--rule-on-blue);
}

.nav__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  padding-block: 1.375rem;
}

.nav__logo img {
  height: 2.75rem;
  width: auto;
}

.nav__links {
  display: flex;
  gap: 2.25rem;
  list-style: none;
  padding: 0;
  font-family: var(--font-display);
  font-size: 0.875rem;
  letter-spacing: 0.06em;
}

.nav__links a {
  opacity: 0.62;
  transition: opacity 120ms ease;
}

.nav__links a:hover,
.nav__links a[aria-current='page'] {
  opacity: 1;
}

/* phone nav: a <details> so it works with no JavaScript at all */
.nav__menu {
  display: none;
}

.nav__menu > summary {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  cursor: pointer;
  list-style: none;
}

.nav__menu > summary::-webkit-details-marker {
  display: none;
}

.nav__menu > summary span {
  display: block;
  height: 1.5px;
  background: var(--cream);
  width: 22px;
}

.nav__menu > summary span:last-child {
  width: 14px;
}

.nav__menu[open] > summary span:last-child {
  width: 22px;
}

.nav__menu .nav__links {
  flex-direction: column;
  gap: 0;
  padding-bottom: 0.75rem;
}

.nav__menu .nav__links a {
  display: block;
  padding-block: 0.875rem;
  opacity: 1;
}

@media (max-width: 46.25rem) {
  .nav__inner > .nav__links {
    display: none;
  }
  .nav__menu {
    display: block;
  }
  .nav__menu[open] {
    position: relative;
  }
}

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

.btn {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 0.875rem;
  letter-spacing: 0.08em;
  padding: 1.0625rem 2rem;
  border: 1px solid transparent;
  transition: transform 120ms ease, background 140ms ease;
}

.btn--solid {
  background: var(--cream);
  color: var(--blue-deep);
}

.btn--solid:hover {
  transform: translateY(-1px);
}

.btn--ghost {
  border-color: rgba(237, 227, 227, 0.5);
  color: var(--cream);
}

.btn--ghost:hover {
  background: rgba(237, 227, 227, 0.1);
}

.btn--disabled {
  border-color: rgba(237, 227, 227, 0.3);
  color: rgba(237, 227, 227, 0.55);
  cursor: not-allowed;
}

/*
 * The official App Store badge.
 *
 * Apple supplies this as fixed artwork and its guidelines say not to recolour,
 * restyle, crop, outline or add effects to it, so the badge is an <img> of
 * Apple's own SVG rather than anything we draw. Two rules follow from that:
 *
 * - at least 40px tall on the web. 48 here, to carry the same weight as the
 *   button beside it.
 * - clear space all round of at least 10% of its height. That is the padding,
 *   cancelled by a matching negative margin so the badge still lines up with
 *   the edge of the text above it.
 *
 * Hover moves the badge, it does not restyle it, which keeps the artwork
 * untouched while still reading as a control.
 */
.store-badge {
  display: inline-block;
  line-height: 0;
  padding: 0.3rem;
  margin: -0.3rem;
  transition: transform 120ms ease;
}

.store-badge:hover {
  transform: translateY(-1px);
}

.store-badge img {
  display: block;
  width: auto;
  height: 48px;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
}

@media (max-width: 30rem) {
  .btn-row {
    flex-direction: column;
    align-items: stretch;
  }
  .btn {
    text-align: center;
  }
  /* the badge is fixed artwork, so it stays its own size rather than stretching */
  .store-badge {
    align-self: flex-start;
  }
}

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

.hero {
  padding-block: clamp(2.75rem, 8vw, 7.25rem) clamp(3rem, 7vw, 6.5rem);
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-hero);
  line-height: 1.1;
  margin-top: 1.875rem;
  max-width: 52ch;
  text-wrap: pretty;
}

.hero__intro {
  font-size: clamp(1rem, 1.3vw, 1.1875rem);
  line-height: 1.75;
  max-width: 52ch;
  margin-top: 2.125rem;
  opacity: 0.9;
}

.hero__actions {
  margin-top: 2.875rem;
}

/* --- app grid ------------------------------------------------------------ */

.apps {
  padding-block: clamp(3rem, 6vw, 5rem) clamp(3.5rem, 8vw, 6.875rem);
}

/* the grid sits on cream on the home page; these repaint the card for that ground */
.band--cream .app-card {
  border-color: var(--edge-on-cream);
}

.band--cream .app-card:hover {
  background: var(--wash-on-cream);
  border-color: var(--blue-deep);
}

.band--cream .app-card__blurb {
  opacity: 1;
  color: rgba(28, 42, 94, 0.78);
}

.band--cream .app-card__foot {
  opacity: 1;
  color: rgba(28, 42, 94, 0.62);
}

.app-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.375rem;
}

.app-card {
  display: flex;
  flex-direction: column;
  gap: 1.375rem;
  min-height: 16.75rem;
  padding: 2.125rem 2rem 1.875rem;
  border: 1px solid var(--edge-on-blue);
  transition: background 140ms ease, border-color 140ms ease;
}

.app-card:hover {
  background: var(--wash-on-blue);
  border-color: var(--edge-on-blue-hover);
}

.app-card__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.75rem;
  height: 3.75rem;
  overflow: hidden;
  flex-shrink: 0;
}

.app-card__icon svg {
  width: 1.875rem;
  height: 1.875rem;
}

.app-card__name,
.app-card__blurb,
.teaser__meta,
.teaser__title,
.teaser__hook,
.post-row__title,
.post-row__hook,
.post-row__date,
.post-row__body,
.post-nav__label,
.post-nav__title {
  display: block;
}

.app-card__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-app-name);
  margin-bottom: 0.75rem;
}

.app-card__blurb {
  font-size: 0.9375rem;
  line-height: 1.7;
  opacity: 0.85;
}

.app-card__foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-top: auto;
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  opacity: 0.7;
}

/* --- link affordance ----------------------------------------------------- *

 * Inline text links only. Deliberately NOT applied to .btn, .app-card,
 * .post-row, .teaser, .post-nav__item, .chip or the logos: those are whole
 * blocks or buttons with their own hover states, and an underline across them
 * looks like a mistake.
 */

.nav__links a,
.footer__col a,
.section-head__aside,
.back-link,
.app-header__facts a,
.prose a {
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.nav__links a:hover,
.footer__col a:hover,
.section-head__aside:hover,
.back-link:hover,
.app-header__facts a:hover {
  text-decoration: underline;
}

/*
 * The facts row is a line of dim metadata with exactly one link in it, so hover
 * alone is not enough: at rest it has to look different from the spans beside
 * it. Full strength against their 0.7, and a standing underline.
 */
.app-header__facts a {
  opacity: 1;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.app-header__facts a::after {
  content: '\2192';
  display: inline-block;
  margin-left: 0.35em;
  transition: transform 140ms ease;
}

.app-header__facts a:hover::after {
  transform: translateX(2px);
}

/*
 * A trailing arrow, so a bare word reads as a link. Space is reserved at rest
 * rather than added on hover, so nothing shifts sideways as the cursor moves.
 * Links that already carry an arrow in their text are excluded below.
 */
.nav__links a::after,
.footer__col a::after {
  content: '\2192';
  display: inline-block;
  margin-left: 0.4em;
  opacity: 0;
  transform: translateX(-3px);
  transition: opacity 140ms ease, transform 140ms ease;
}

.nav__links a:hover::after,
.footer__col a:hover::after,
.nav__links a:focus-visible::after,
.footer__col a:focus-visible::after {
  opacity: 0.75;
  transform: translateX(0);
}

/* leaving the site gets the outbound arrow instead, wherever it appears */
.nav__links a[href^='http']::after,
.footer__col a[href^='http']::after {
  content: '\2197';
}

/* an outbound link says so, and says it permanently */
.prose a[href^='http']::after {
  content: '\2197';
  margin-left: 0.15em;
  text-decoration: none;
  display: inline-block;
}

/* --- icon shapes --------------------------------------------------------- */

/*
 * Real app icons are masked to match how iOS draws them: a squircle for phone
 * icons, a circle for watch icons. 22.37% is the usual border-radius stand-in
 * for Apple's superellipse - indistinguishable at these sizes.
 * Set "iconShape": "circle" | "squircle" | "square" per app in apps.json.
 */
.shape-squircle {
  border-radius: 22.37%;
}

.shape-circle {
  border-radius: 50%;
}

.shape-square {
  border-radius: 0;
}

/*
 * Every icon box is a fixed square with overflow hidden, so the image inside it
 * has to be told to fill that square. This was three separate rules, one per
 * component, and the post footer's copy was missing: the <img> kept its 120px
 * height attribute inside a 52px box and rendered the icon stretched to more
 * than twice its height, clipped to the middle slice. One rule for all of them
 * now, so adding a fourth icon box cannot reintroduce it.
 */
.app-card__icon img,
.app-header__icon img,
.post-app__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* an app with no real icon yet keeps the drawn mark inside a ruled box */
.icon-placeholder {
  border: 1px solid var(--edge-on-blue);
}

.band--cream .icon-placeholder,
.post-app__icon.icon-placeholder {
  border-color: var(--edge-on-cream);
}

/* --- post listings ------------------------------------------------------- */

.post-teasers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2.5rem;
}

.teaser {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.teaser__meta,
.post-row__date {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  opacity: 0.6;
}

.teaser__title {
  font-size: clamp(1.25rem, 1.7vw, 1.5rem);
  font-weight: 600;
  line-height: 1.35;
}

.teaser:hover .teaser__title,
.post-row:hover .post-row__title {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.teaser__hook,
.post-row__hook {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--placeholder);
}

.post-row {
  display: flex;
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: baseline;
  padding: 2rem 0.25rem;
  border-bottom: 1px solid var(--rule-on-cream-soft);
  transition: background 140ms ease;
}

.post-row:hover {
  background: var(--wash-on-cream);
}

.post-row__date {
  width: 6.75rem;
  flex-shrink: 0;
  font-size: 0.8125rem;
  opacity: 0.7;
}

.post-row__body {
  flex-grow: 1;
}

.post-row__title {
  font-size: clamp(1.25rem, 1.9vw, 1.5625rem);
  font-weight: 600;
  line-height: 1.32;
  margin-bottom: 0.625rem;
}

.post-row__tag {
  flex-shrink: 0;
}

@media (max-width: 40rem) {
  .post-row {
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .post-row__date {
    width: auto;
  }
  .post-row__body {
    flex-basis: 100%;
    order: 3;
  }
}

/* --- chips and tags ------------------------------------------------------ */

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  align-items: center;
  padding-bottom: 2.125rem;
  border-bottom: 1px solid var(--rule-on-cream);
}

.chip-row__label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  opacity: 0.6;
  margin-right: 0.5rem;
}

.chip {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  padding: 0.5rem 1rem;
  border: 1px solid var(--edge-on-cream);
  white-space: nowrap;
}

.chip:hover {
  background: var(--wash-on-cream);
}

.chip--on {
  background: var(--blue-deep);
  border-color: var(--blue-deep);
  color: var(--cream);
}

.chip--on:hover {
  background: var(--blue-deep);
}

.tag {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  padding: 0.375rem 0.75rem;
  border: 1px solid var(--edge-on-cream);
}

.band--blue .tag {
  border-color: rgba(237, 227, 227, 0.5);
}

/* --- empty state --------------------------------------------------------- */

.empty {
  padding: 3rem 0;
  font-size: 1rem;
  line-height: 1.8;
  color: var(--placeholder);
  border-bottom: 1px solid var(--rule-on-cream-soft);
}

/* --- article ------------------------------------------------------------- */

.post-header {
  padding-block: 2.75rem clamp(3rem, 6vw, 4.75rem);
}

.post-header__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1.125rem;
  align-items: center;
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  opacity: 0.75;
  margin-bottom: 1.375rem;
}

.post-header__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-post-title);
  line-height: 1.16;
  max-width: 30ch;
  /* Same reason as .prose > h2: Major Mono draws lowercase small and uppercase
     tall, so a mixed-case post title reads as a mistake. Done in CSS rather
     than with a `| lower` filter so the real title stays in the markup for
     assistive tech, search engines and the share card. */
  text-transform: lowercase;
}

.back-link {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  opacity: 0.72;
  margin-bottom: 2.625rem;
}

.back-link:hover {
  opacity: 1;
}

.article {
  max-width: 46rem;
  margin-inline: auto;
  padding-block: clamp(2.75rem, 5vw, 4.5rem) clamp(3.5rem, 7vw, 6rem);
}

.prose {
  font-size: clamp(1rem, 1.15vw, 1.0625rem);
  line-height: 1.85;
}

.prose > * + * {
  margin-top: 1.625rem;
}

.prose > h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-h2);
  line-height: 1.3;
  margin-top: 2.75rem;
  /* Major Mono draws lowercase as the small form and uppercase as the tall one,
     so mixed case reads as a typo. Display type on this site is all lowercase. */
  text-transform: lowercase;
}

.prose > h3 {
  font-size: 1.125rem;
  font-weight: 700;
  margin-top: 2.25rem;
}

.prose .standfirst,
.prose > p:first-child {
  font-size: clamp(1.125rem, 1.4vw, 1.25rem);
  font-weight: 500;
  line-height: 1.75;
}

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

.prose a:hover {
  color: var(--blue);
}

.prose ul,
.prose ol {
  padding-left: 1.375rem;
}

.prose li + li {
  margin-top: 0.625rem;
}

.prose blockquote {
  border-left: 2px solid var(--blue);
  padding: 0.25rem 0 0.25rem 1.625rem;
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  font-style: italic;
  line-height: 1.7;
}

.prose pre {
  background: var(--blue-deep);
  color: #dde4f5;
  padding: 1.5rem 1.625rem;
  overflow-x: auto;
  font-family: var(--font-code);
  font-size: 0.84375rem;
  line-height: 1.7;
}

.prose code {
  font-family: var(--font-code);
  font-size: 0.9em;
}

.prose :not(pre) > code {
  background: rgba(28, 42, 94, 0.08);
  padding: 0.15em 0.4em;
}

.prose img {
  width: 100%;
  height: auto;
}

.prose figure {
  margin-top: 2rem;
}

.prose figcaption {
  font-size: 0.8125rem;
  opacity: 0.6;
  margin-top: 0.75rem;
}

/*
 * --- the questions block at the end of a post ---------------------------- *
 *
 * <details> so a long list stays scannable, with the first one open so it is
 * obvious the rest expand. Kept inside .prose so it inherits the measure and
 * the type, and the marker is replaced with a sign that reads at a glance.
 */
.faq {
  border-top: 1px solid var(--edge-on-cream);
}

.faq__item {
  border-bottom: 1px solid var(--edge-on-cream);
}

.faq__q {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 1.125rem 0;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own triangle unless both of these are set */
.faq__q::-webkit-details-marker {
  display: none;
}

.faq__q::before {
  content: '+';
  font-family: var(--font-display);
  flex: none;
  width: 1ch;
  opacity: 0.55;
}

.faq__item[open] .faq__q::before {
  content: '\2013';
}

.faq__q:hover {
  color: var(--blue);
}

.faq__a {
  padding: 0 0 1.375rem 1.75rem;
  margin: 0;
}

/* --- article footer: the app this post is about, then prev/next ---------- */

.post-app {
  display: flex;
  gap: 1.25rem;
  align-items: center;
  flex-wrap: nowrap;
  border-top: 1px solid var(--rule-on-cream);
  padding-top: 2.125rem;
  margin-top: 3rem;
}

.post-app__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  overflow: hidden;
  flex-shrink: 0;
}

.post-app__icon svg {
  width: 1.625rem;
  height: 1.625rem;
}

.post-app__body {
  flex-grow: 1;
  min-width: 0;
}

.post-app > .chip {
  margin-left: auto;
  flex-shrink: 0;
}

@media (max-width: 34rem) {
  .post-app {
    flex-wrap: wrap;
  }
  .post-app > .chip {
    margin-left: 0;
  }
}

.post-app__name {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  margin-bottom: 0.375rem;
}

.post-app__blurb {
  font-size: 0.875rem;
  line-height: 1.6;
  opacity: 0.75;
}

.post-nav {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.25rem;
  margin-top: 2.75rem;
}

.post-nav__item {
  border: 1px solid var(--rule-on-cream);
  padding: 1.375rem 1.5rem;
  transition: background 140ms ease;
}

.post-nav__item:hover {
  background: var(--wash-on-cream);
}

.post-nav__item--next {
  text-align: right;
}

.post-nav__label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  opacity: 0.6;
  margin-bottom: 0.625rem;
}

.post-nav__title {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.45;
}

/* --- app detail ---------------------------------------------------------- */

.app-header {
  padding-block: 2.75rem clamp(3rem, 6vw, 5.5rem);
}

.app-header__top {
  display: flex;
  gap: clamp(1.5rem, 3vw, 2.75rem);
  align-items: flex-start;
  flex-wrap: wrap;
}

.app-header__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 7rem;
  height: 7rem;
  overflow: hidden;
  flex-shrink: 0;
}

.app-header__icon svg {
  width: 3.5rem;
  height: 3.5rem;
}

.app-header__body {
  /* An explicit basis, not `auto`: with auto the body is sized from its widest
     content (the facts row), which can exceed the space left beside the icon and
     wrap it onto its own line. 17rem keeps the intended wrap on narrow screens. */
  flex: 1 1 17rem;
  min-width: 0;
}

.app-header__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-page-title);
  line-height: 1.14;
}

.app-header__blurb {
  font-size: clamp(1.0625rem, 1.4vw, 1.25rem);
  line-height: 1.65;
  max-width: 46ch;
  margin-top: 1.125rem;
  opacity: 0.9;
}

.app-header__promise {
  font-family: var(--font-display);
  font-size: 0.875rem;
  letter-spacing: 0.1em;
  margin-top: 1.125rem;
}

.app-header__facts {
  display: flex;
  flex-wrap: wrap;
  column-gap: clamp(1rem, 2.4vw, 2.125rem);
  row-gap: 0.5rem;
  margin-top: 2.125rem;
  font-family: var(--font-display);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  opacity: 0.7;
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  align-items: start;
  max-width: 52rem;
  gap: 1.375rem;
  padding-top: clamp(2.75rem, 5vw, 4.75rem);
}

.shot {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* a real capture defines its own shape - phone, watch, whatever it is */
.shot img {
  width: 100%;
  height: auto;
}

/* the empty state is a phone-shaped dashed box */
.shot--empty {
  aspect-ratio: 9 / 19.5;
  border: 1px dashed var(--edge-on-cream);
  font-family: var(--font-display);
  font-size: 0.75rem;
  opacity: 0.5;
}

.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 2.5rem;
}

.feature__title {
  font-family: var(--font-display);
  font-size: 1.125rem;
  margin-bottom: 0.75rem;
}

.feature__body {
  font-size: 0.9375rem;
  line-height: 1.75;
  color: var(--placeholder);
}

.block {
  padding-top: clamp(3rem, 6vw, 5rem);
}

/* two cream sections butted together: no double gap, the section rule separates them */
.band--cream + .band--cream > .wrap > .block:first-child {
  padding-top: 0;
}

.block--last {
  padding-bottom: clamp(3.5rem, 7vw, 6.25rem);
}

/* --- pagination ---------------------------------------------------------- */

.pager {
  display: flex;
  justify-content: center;
  gap: 0.875rem;
  margin-top: 3rem;
  font-family: var(--font-display);
  font-size: 0.8125rem;
}

.pager__link {
  border: 1px solid var(--edge-on-cream);
  padding: 0.6875rem 1.25rem;
}

.pager__link:hover {
  background: var(--wash-on-cream);
}

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

.footer__inner {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: clamp(1.75rem, 4vw, 2.5rem);
  flex-wrap: wrap;
  padding-block: 2.75rem;
}

.footer__logo img {
  height: 2.25rem;
  width: auto;
  opacity: 0.9;
  margin-bottom: 1rem;
}

.footer__legal {
  font-size: 0.8125rem;
  line-height: 1.7;
  opacity: 0.6;
}

.footer__cols {
  display: flex;
  gap: clamp(2rem, 5vw, 3.5rem);
  flex-wrap: wrap;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  font-size: 0.8125rem;
}

.footer__col h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  opacity: 0.5;
  margin-bottom: 0.25rem;
}

.footer__col a {
  opacity: 0.85;
}

.footer__col a:hover {
  opacity: 1;
}

/* --- simple prose page (privacy) ---------------------------------------- */

.page-header {
  padding-block: 2.75rem clamp(2.5rem, 5vw, 4rem);
}

.page-header__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-page-title);
  line-height: 1.16;
  /* Lowercased here rather than in the template, because minimal mode drops the
     display font and shows this heading in the system stack, where a lowercased
     "games night privacy policy" reads as sloppy rather than as a house style.
     The minimal block below resets this to none. */
  text-transform: lowercase;
}

/* --- minimal mode ---------------------------------------------------------
 *
 * ?minimal=1 on any page drops the chrome and the brand colours: no nav, no
 * footer, black on white, inverted when the OS asks for dark. Intended for
 * showing a policy inside an app or handing it to someone to print.
 * The class is set by an inline script in <head> before first paint.
 */

.minimal body,
.minimal .band--blue,
.minimal .band--cream,
.minimal .band--ink {
  background: #ffffff;
  color: #111111;
}

/* The system stack, so a policy shown inside an app reads as part of the app
   rather than as a page from the website. */
.minimal body,
.minimal .prose,
.minimal .page-header__title,
.minimal .eyebrow,
.minimal .prose > h2,
.minimal .prose > h3 {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui,
    'Segoe UI', Roboto, sans-serif;
}

.minimal .page-header__title,
.minimal .prose > h2,
.minimal .prose > h3 {
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: none;
}

.minimal .eyebrow {
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 0.75rem;
}

.minimal .nav,
.minimal footer,
.minimal .back-link {
  display: none;
}

/* one measure for the whole document, so the title lines up with the body */
.minimal .wrap {
  max-width: 46rem;
}

.minimal .page-header {
  padding-block: 2.5rem 0;
}

.minimal .page-header__title {
  font-size: clamp(1.5rem, 4vw, 2.125rem);
}

.minimal .eyebrow {
  opacity: 0.55;
}

.minimal .article {
  padding-block: 1.5rem 3rem;
}

.minimal .prose > h2 {
  color: inherit;
}

.minimal .prose a {
  text-decoration-color: currentColor;
}

.minimal .prose a:hover {
  color: inherit;
}

.minimal .prose a[href^='http']::after {
  content: '';
}

.minimal .prose blockquote {
  border-left-color: #999999;
}

.minimal .prose pre {
  background: #f2f2f2;
  color: #111111;
}

.minimal .prose :not(pre) > code {
  background: rgba(0, 0, 0, 0.07);
}

@media (prefers-color-scheme: dark) {
  .minimal body,
  .minimal .band--blue,
  .minimal .band--cream,
  .minimal .band--ink {
    background: #000000;
    color: #ededed;
  }

  .minimal .prose blockquote {
    border-left-color: #666666;
  }

  .minimal .prose pre {
    background: #151515;
    color: #ededed;
  }

  .minimal .prose :not(pre) > code {
    background: rgba(255, 255, 255, 0.12);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

@media (max-width: 30rem) {
  .eyebrow {
    letter-spacing: 0.14em;
  }
}
