/* ==========================================================================
   simplicated — the one stylesheet, shared by the portfolio index and by
   every app on every subdomain.

   An app never adds structural CSS. It sets the custom properties below in
   apps/<slug>/theme.css, which loads after this file and wins. That is the
   whole theming system.
   ========================================================================== */

:root {
  color-scheme: light dark;

  /* --- surfaces ------------------------------------------------------- */
  --bg: #fbfaf7;
  --fg: #1b1a18;
  --muted: #6f6b64;
  --rule: #e4e0d7;

  /* --- the one colour an app usually wants to change ------------------- */
  --accent: #1b1a18;
  --accent-fg: #fbfaf7;

  /* --- type ------------------------------------------------------------ */
  --font-heading: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  /* --- measure --------------------------------------------------------- */
  --measure: 36rem;
  --radius: 12px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161513;
    --fg: #eceae5;
    --muted: #948f86;
    --rule: #2d2a26;
    --accent: #eceae5;
    --accent-fg: #161513;
  }
}

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

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

/* An image is the one element that can wreck the layout on its own: with no
   rule of its own it lays out at its full pixel width and pushes the column
   sideways. This is the floor, so a shot added without a matching component
   still fits the measure. A video has the same problem. */
img,
video {
  max-width: 100%;
  height: auto;
}

body {
  margin: 0;
  padding: 4.5rem 1.5rem 3rem;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  display: flex;
  justify-content: center;
  -webkit-font-smoothing: antialiased;
}

main {
  width: 100%;
  max-width: var(--measure);
}

/* --- type ------------------------------------------------------------- */

h1,
h2,
h3 {
  font-family: var(--font-heading);
  font-weight: 600;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1 {
  margin: 0 0 0.35rem;
  font-size: 2rem;
  line-height: 1.15;
}

h2 {
  margin: 2.75rem 0 0.6rem;
  font-size: 1.125rem;
  letter-spacing: -0.01em;
}

h3 {
  margin: 1.75rem 0 0.35rem;
  font-size: 1rem;
  letter-spacing: 0;
}

p {
  margin: 0 0 1rem;
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-color: var(--rule);
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-color: currentColor;
}

hr {
  margin: 2.5rem 0;
  border: 0;
  border-top: 1px solid var(--rule);
}

/* Standfirst under an h1. */
.tagline {
  margin: 0;
  color: var(--muted);
  font-size: 1.0625rem;
}

/* A small caps label above a list or a block. */
.label {
  margin: 2.75rem 0 0.9rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The "last updated" line on a legal page. */
.updated {
  margin: 0 0 2.25rem;
  font-size: 0.875rem;
  color: var(--muted);
}

.lede {
  margin-bottom: 2.25rem;
  color: var(--muted);
}

/* --- app header ------------------------------------------------------- */

.hero {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin-bottom: 1.75rem;
}

.appicon {
  flex: none;
  width: 84px;
  height: 84px;
  border-radius: 22.5%;
  border: 1px solid var(--rule);
  object-fit: cover;
}

/* --- call to action --------------------------------------------------- */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 2.5rem;
}

.cta {
  display: inline-block;
  padding: 0.6rem 1.15rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 0.9375rem;
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
}

.cta:hover {
  opacity: 0.85;
}

/* The second action in a row, when there is one. Outlined rather than filled,
   so a page with two places to go still has an obvious first one. */
.cta--ghost {
  background: none;
  border-color: var(--rule);
  color: var(--fg);
}

.cta--ghost:hover {
  opacity: 1;
  border-color: var(--muted);
}

/* Same shape, but not a link — for an app that hasn't shipped yet. */
.cta--pending {
  background: none;
  border-color: var(--rule);
  color: var(--muted);
  font-weight: 400;
  cursor: default;
}

.cta--pending:hover {
  opacity: 1;
}

/* Apple's official "Download on the App Store" badge, used as-is. Apple's
   guidelines forbid recoloring or restyling it, so only its size is set. */
.badge {
  display: inline-block;
  line-height: 0;
}

.badge img {
  display: block;
  height: 50px;
  width: auto;
}

.badge:hover {
  opacity: 0.85;
}

/* --- ruled link list -------------------------------------------------- */

.index {
  margin: 0;
  padding: 0;
  list-style: none;
}

.index li {
  border-top: 1px solid var(--rule);
}

.index li:last-child {
  border-bottom: 1px solid var(--rule);
}

.index a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.9rem 0;
  text-decoration: none;
}

.index a:hover .index-name {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.index-name {
  font-weight: 500;
}

.index-note {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--muted);
  font-size: 0.875rem;
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- feature list ----------------------------------------------------- */

.points {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.points li {
  position: relative;
  padding-left: 1.15rem;
  margin-bottom: 0.5rem;
}

.points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
}

/* --- screenshot strip ------------------------------------------------- */

.shots {
  display: flex;
  /* Without this a flex row stretches an auto-height image to match the
     tallest one, which distorts a strip that mixes phone and watch shots. */
  align-items: flex-start;
  gap: 0.85rem;
  margin: 0 0 1rem;
  padding-bottom: 0.75rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
}

.shots img {
  flex: none;
  width: 190px;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  scroll-snap-align: start;
}

/* A shot can link to its full-size file, as on a press page. The link takes
   the image's place in the row, so it mustn't shrink, and its line box mustn't
   open a gap under the image. */
.shots a {
  flex: none;
  line-height: 0;
  scroll-snap-align: start;
}

/* --- desktop screenshots ----------------------------------------------- */

/* A Mac window is landscape: at the strip's 190px it would be an unreadable
   smudge, so these stack down the measure instead. Same border as the strip,
   and it earns its keep here — an app themed after its own window shares the
   page's background, so without an edge the screenshot dissolves into it. The
   shot must be the whole window, ending on its own bottom edge; a capture cut
   off mid-sentence reads as a broken image rather than a scrolled document. */
.shots-window {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  margin: 0 0 1rem;
}

/* The first shot carries the detail. The rest pair off beside it at half the
   width, which reads as "and here is the other view" instead of three
   identical slabs stacked down the page. */
.shots-window figure:first-child {
  grid-column: 1 / -1;
}

.shots-window figure {
  margin: 0;
}

.shots-window img,
.shots-window video {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.shots-window figcaption {
  margin-top: 0.55rem;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* --- questions and answers -------------------------------------------- */

.qa {
  margin: 0;
}

.qa dt {
  margin-top: 1.6rem;
  font-weight: 550;
}

.qa dd {
  margin: 0.25rem 0 0;
  color: var(--muted);
}

/* --- fact sheet ------------------------------------------------------- */

/* The facts a writer copies out — price, platforms, release date — as a term
   beside its value on ruled rows. The term is set smaller, so it takes the
   value's line height in rem; with the same line box, both share a baseline
   without baseline alignment, which would knock the rules out of line. */
.facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  margin: 0 0 1rem;
  border-bottom: 1px solid var(--rule);
}

.facts dt,
.facts dd {
  margin: 0;
  padding: 0.65rem 0;
  border-top: 1px solid var(--rule);
}

.facts dt {
  padding-right: 1.75rem;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.65rem;
}

.facts dd {
  overflow-wrap: anywhere;
}

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

.sitefoot {
  margin-top: 3.5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
  font-size: 0.875rem;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.9rem;
}

/* --- single-message page (404) ---------------------------------------- */

body.centered {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100svh;
  padding-top: 1.5rem;
  text-align: center;
}

/* --- narrow screens --------------------------------------------------- */

@media (max-width: 32rem) {
  body {
    padding-top: 3rem;
  }

  h1 {
    font-size: 1.75rem;
  }

  .index a {
    flex-direction: column;
    gap: 0.15rem;
  }

  .index-note {
    text-align: left;
  }

  /* Half of a phone's width is no width at all for a Mac window. */
  .shots-window {
    grid-template-columns: 1fr;
  }

  /* Term above value: beside it, a long term leaves the value a sliver. */
  .facts {
    grid-template-columns: 1fr;
  }

  .facts dt {
    padding-bottom: 0;
  }

  .facts dd {
    padding-top: 0.1rem;
    border-top: 0;
  }
}
