:root {
  --fg: #222;
  --muted: #666;
  --bg: #fafafa;
  --card: #fff;
  --accent: #0a66c2;
  --rule: #e2e2e2;
  --radius: 12px;

  /* Vertical rhythm: every line-height, margin, and padding that stacks
     vertically is a multiple of --unit or --half, so text across the page
     sits on the same invisible grid. */
  --unit: 1.5rem;
  --half: 0.75rem;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 1rem;
  line-height: var(--unit);
  color: var(--fg);
  background: var(--bg);
}

/* Header, content, and footer share one column. main grows, so the footer
   sits at the bottom of short pages and scrolls away on long ones. */
.site-header, main, footer {
  width: 100%;
  max-width: 48rem;
  margin: 0 auto;
  padding: 0 1.25rem;
}

main { flex: 1 0 auto; }

/* The header sticks to the top while scrolling, so the breadcrumb is always
   at hand and pages need no "back" link at the bottom. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  /* Two units tall in total; the 30px home button sets the inner height. */
  min-height: calc(var(--unit) * 2);
  padding-top: calc((var(--unit) * 2 - 30px) / 2);
  padding-bottom: calc((var(--unit) * 2 - 30px) / 2);
  border-bottom: 1px solid var(--rule);
}

/* Breadcrumb */
.crumbs {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  color: var(--muted);
}

.crumbs a {
  color: var(--muted);
  text-decoration: none;
}

.crumbs a:hover { color: var(--accent); }

.crumb-home {
  display: inline-flex;
  height: var(--unit);
  align-items: center;
  margin-right: 0.25rem;   /* the bare chevrons carry whitespace inside their box; the squircle does not */
  color: var(--fg);
}

.crumbs .icon { display: block; }

/* Separators are chevrons. The home link is a chevron in a squircle, turned
   down on the home page like an open disclosure and right elsewhere. */
.crumbs .sep { display: inline-flex; color: var(--rule); }

.crumb-home .squircle {
  fill: var(--card);
  stroke: var(--rule);
  stroke-width: 1;
  transition: stroke 0.15s;
}

.crumb-home:hover .squircle { stroke: var(--accent); }

.crumb-home .chev {
  transform-origin: 12px 12px;
  transition: transform 0.2s;
}

.crumb-home.open .chev { transform: rotate(90deg); }

.crumbs .current {
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Section links */
.sections { display: flex; gap: 1.25rem; flex-shrink: 0; }

.sections a {
  color: var(--muted);
  text-decoration: none;
}

.sections a:hover { color: var(--accent); }
.sections a.active { color: var(--fg); font-weight: 600; }
.sections a.debug { color: #e0a800; }   /* local-only styleguide link */

main a { color: var(--accent); }

/* KO logo. Only the footer signature is on the page now; .logo-sign sizes it
   to six units tall. The include still accepts uid/class for other placements. */
.logo {
  display: block;
  color: var(--fg);
}

.logo-sign {
  width: calc(var(--unit) * 6 * 0.5736);   /* six units tall */
  margin: 0 auto;
  color: var(--rule);
}

.logo svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* Rainbow wave: the gradient rect slides by one gradient period per loop. */
.ko-wave { animation: ko-wave 8s linear infinite; }

@keyframes ko-wave {
  to { transform: translate(300px, 180px); }
}

@media (prefers-reduced-motion: reduce) {
  .ko-wave { animation: none; }
}

main {
  padding-top: calc(var(--unit) * 2);
  padding-bottom: calc(var(--unit) * 2);
}

/* Home page greeting: a single big emoji, eight units tall. */
.greeting {
  margin: calc(var(--unit) * 1.5) 0 calc(var(--unit) * 2);
  text-align: center;
  font-size: 11rem;
  line-height: calc(var(--unit) * 8);
}

/* Type scale on the grid: h1 takes 1.5 units, h2 and body one unit each.
   Block margins are whole or half units, so headings plus their gaps always
   add up to whole units. */
p, ul, ol, pre {
  margin: 0 0 var(--unit);
}

h1 {
  font-size: 2.5rem;
  line-height: calc(var(--unit) * 2);
  font-weight: 600;
  margin: 0;
}

h2 {
  font-size: 1.25rem;
  line-height: var(--unit);
  font-weight: 600;
  margin: calc(var(--unit) * 1.5) 0 var(--half);
}

h3 {
  font-size: 1rem;
  line-height: var(--unit);
  font-weight: 600;
  margin: var(--unit) 0 0;
}

.kicker {
  margin: 0;
  font-size: 0.8rem;
  line-height: var(--unit);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.tagline { color: var(--muted); margin: 0; }

/* On a topic page the tagline is followed by body text, so it ends a paragraph. */
.topic-tagline { margin-bottom: var(--unit); }

/* Intro block on the home page */
.intro {
  display: flex;
  gap: var(--unit);
  align-items: center;
  margin-bottom: calc(var(--unit) * 2);   /* plus the h2's own 1.5 units above it */
}

.intro p { margin: 0; }
.intro .links { margin-top: var(--half); }

.avatar {
  width: calc(var(--unit) * 6);
  height: calc(var(--unit) * 6);
  flex-shrink: 0;
  border-radius: var(--radius);
  image-rendering: pixelated;
}

.links a { margin-right: 1rem; text-decoration: none; }
.links a:hover { text-decoration: underline; }

/* Me page: list of interesting links, newest first, date in a side column */
.linklist {
  list-style: none;
  padding: 0;
  margin: 0;
}

.linklist li {
  display: grid;
  grid-template-columns: 6.5rem 1fr;   /* date, then title and note */
  gap: 0 1rem;
  margin-bottom: var(--half);
}

.linklist time {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.linklist a { text-decoration: none; }
.linklist a:hover { text-decoration: underline; }

.linklist .note {
  display: block;
  color: var(--muted);
}

@media (max-width: 30rem) {
  .linklist li { grid-template-columns: 1fr; }
}

/* Cover images: every cover is the same square box. Images larger than the
   box are scaled down and cropped to fill it; smaller ones sit centered at
   their natural size and are never upscaled. "photo" fills a rounded box;
   "icon" is shown as-is, since app icons bring their own corners. */
.cover {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  width: 100%;
  overflow: hidden;
  border-radius: 8px;
  background: #ededed;
}

.cover img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 1;
  object-fit: cover;
}

.cover.icon { background: none; border-radius: 0; }

/* Play badge on video cards */
.cover { position: relative; }

.play-badge {
  position: absolute;
  inset: 0;
  margin: auto;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  transition: background 0.15s, transform 0.15s;
}

.play-badge svg { width: 24px; height: 24px; margin-left: 3px; }

.project-grid a:hover .play-badge {
  background: var(--accent);
  transform: scale(1.06);
}

/* Talk cover linking out to YouTube. Nothing is embedded, so the page loads
   nothing from Google; the image keeps its own proportions. */
.video {
  position: relative;
  display: block;
  margin: 0 0 var(--unit);
  overflow: hidden;
  border-radius: var(--radius);
  background: #000;
  line-height: 0;
}

.video img {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity 0.15s;
}

.video .play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 5rem;
  height: 5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  transition: background 0.15s, transform 0.15s;
}

.video .play svg { margin-left: 4px; }

.video:hover img { opacity: 0.85; }

.video:hover .play {
  background: var(--accent);
  transform: scale(1.06);
}

/* Project grid: three across, then two, then one */
.project-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  /* minmax(0, 1fr): a column must be allowed to shrink below its longest
     word, or one long title widens it at the expense of the other two. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--unit);
}

/* Pinned overflow: on narrow screens the extra pinned cards leave the pinned
   row and appear in the dated list instead. */
.project-grid .narrow-only { display: none; }

@media (max-width: 40rem) {
  .project-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .project-grid .wide-only { display: none; }
  .project-grid .narrow-only { display: block; }
}

@media (max-width: 26rem) {
  .project-grid { grid-template-columns: 1fr; }
}

.project-grid a {
  display: flex;
  flex-direction: column;
  gap: 0;
  height: 100%;
  padding: 1rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  color: var(--fg);
  text-decoration: none;
  transition: border-color 0.15s, transform 0.15s;
}

.project-grid a:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.project-grid .cover { margin-bottom: var(--half); }
.project-grid strong { font-size: 1.1rem; line-height: var(--unit); overflow-wrap: anywhere; }
.project-grid .tagline { font-size: 0.95rem; line-height: var(--unit); }

/* Topic chips */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--half) 0.4rem;
  margin: 0 0 var(--unit);
}

/* Project page: topic pills and the kind, side by side above the title.
   Both are one unit tall and share a baseline. */
.project-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.6rem;
  margin-bottom: var(--half);
}

/* Chip: 1px border + 2px padding + 18px text line = 24px, one unit. */
.chips a, .project-meta .chip {
  display: inline-block;
  padding: 0.125rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--card);
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.125rem;
  text-decoration: none;
}

.chips a:hover, .project-meta .chip:hover { border-color: var(--accent); color: var(--accent); }

/* Topic icons: an emoji before the topic name, in chips, kickers, and titles */
.ticon {
  display: inline-block;
  margin-right: 0.4em;
  font-style: normal;
  letter-spacing: 0;
}

h1 .ticon { margin-right: 0.35em; }

.muted { color: var(--muted); }

/* Project page */
.project-header {
  display: flex;
  gap: var(--unit);
  align-items: flex-start;
  margin-bottom: calc(var(--unit) * 1.5);
}

/* Cover is 8.5 units tall. The info column beside it stacks meta (1 unit),
   title and tagline (3), version (1), button (1.5) with half- and whole-unit
   gaps that add up to the same 8.5 units, so the column fills the cover's
   height. If a line is missing, space-between spreads the rest. */
.project-header .cover {
  flex-shrink: 0;
  width: calc(var(--unit) * 8.5);
  border-radius: var(--radius);
}

.project-info {
  flex: 1;
  min-width: 0;
  min-height: calc(var(--unit) * 8.5);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.project-title .tagline { margin: 0; }

/* Without a cover the info column just follows its content */
.project-header.no-cover { margin-bottom: var(--unit); }
.project-header.no-cover .project-info { min-height: 0; }

.version {
  margin: var(--half) 0 0;
  font-size: 0.9rem;
  line-height: var(--unit);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.project-links { margin: var(--unit) 0 0; }

/* Button: 6px padding + 24px line = 36px, one and a half units. */
.project-links a {
  display: inline-block;
  margin: 0 0.5rem 0 0;
  padding: 0.375rem 1.1rem;
  line-height: var(--unit);
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  transition: filter 0.15s, transform 0.15s;
}

.project-links a:hover {
  color: #fff;
  filter: brightness(1.1);
  transform: translateY(-1px);
}

/* A link marked disabled in front matter: same pill, greyed out, not clickable */
.project-links .disabled {
  display: inline-block;
  margin: 0 0.5rem 0 0;
  padding: 0.375rem 1.1rem;
  line-height: var(--unit);
  background: var(--rule);
  color: var(--muted);
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: default;
}

/* Gallery tile without a link (shop not live yet) */
.gallery .tile {
  display: block;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: var(--unit);
  text-align: center;
}

.project img { max-width: 100%; border-radius: 8px; }

/* Artwork shown on the background it is meant for */
figure.art {
  margin: 0 0 var(--unit);
  padding: var(--unit);
  border-radius: var(--radius);
}

figure.art a { display: block; }
figure.art img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: calc(var(--unit) * 16);   /* portrait artwork stays a reasonable height */
  margin: 0 auto;
  border-radius: 0;
}
figure.on-dark { background: #1c1c1e; }

/* Screenshots with a caption */
figure.shot { margin: 0 0 var(--unit); }

figure.shot img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 auto;
  border-radius: var(--radius);
}

figure.shot figcaption {
  margin-top: var(--half);
  text-align: center;
  font-size: 0.9rem;
  line-height: var(--unit);
  color: var(--muted);
}

/* Product gallery at the bottom of a project page */
.gallery {
  list-style: none;
  padding: 0;
  margin: calc(var(--unit) * 1.5) 0 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--unit);
}

@media (max-width: 26rem) {
  .gallery { grid-template-columns: repeat(2, 1fr); }
}

.gallery a {
  display: block;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
  line-height: var(--unit);
  text-align: center;
}

.gallery a:hover { color: var(--accent); }

.gallery img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  margin-bottom: var(--half);
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  transition: border-color 0.15s, transform 0.15s;
}

.gallery a:hover img {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.gallery span { display: block; }
figure.on-light { background: var(--card); border: 1px solid var(--rule); }

/* Highlights, marker style. Use <mark>text</mark> in Markdown; add a colour
   class for another pen: <mark class="pink">…</mark>. Colours: yellow
   (default), pink, green, blue, purple, orange. */
mark {
  --hl: #fff3a3;
  background: var(--hl);
  color: inherit;
  /* The padding around the text is a shadow spread, which paints outside the
     box without taking layout space, so line heights do not change. */
  box-shadow: 0 0 0 0.14em var(--hl);
  margin: 0 0.14em;
  border-radius: 0.15em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

mark.pink   { --hl: #ffd0e0; }
mark.green  { --hl: #cdf3c6; }
mark.blue   { --hl: #cfe6ff; }
mark.purple { --hl: #e4d6ff; }
mark.orange { --hl: #ffe0b8; }
mark code   { background: transparent; padding: 0; }   /* let the highlight colour through */

/* Long-form text elements, on the rhythm grid */
blockquote {
  margin: 0 0 var(--unit);
  padding: 0 0 0 calc(var(--unit) - 3px);
  border-left: 3px solid var(--rule);
  color: var(--muted);
}

blockquote p:last-child { margin-bottom: 0; }
blockquote cite { font-style: normal; font-size: 0.9rem; }
blockquote cite::before { content: "— "; }

hr {
  height: 0;
  margin: calc(var(--unit) * 1.5) 0;
  border: 0;
  border-top: 1px solid var(--rule);
}

table {
  width: 100%;
  margin: 0 0 var(--unit);
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

th, td {
  padding: 0 0.75rem;
  line-height: calc(var(--unit) * 1.5);
  text-align: left;
  border-bottom: 1px solid var(--rule);
}

th { font-weight: 600; }
td:first-child, th:first-child { padding-left: 0; }
td:last-child, th:last-child { padding-right: 0; }

del { color: var(--muted); }

kbd {
  display: inline-block;
  padding: 0 0.4em;
  font-family: inherit;
  font-size: 0.85em;
  line-height: 1.5em;
  border: 1px solid var(--rule);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--card);
}

li > ul, li > ol { margin: 0; }

pre, code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}

pre {
  padding: var(--half) 1rem;
  overflow-x: auto;
  background: #f0f0f0;
  border-radius: 8px;
}

code { background: #f0f0f0; padding: 0.1em 0.35em; border-radius: 4px; }
pre code { background: none; padding: 0; }

footer {
  padding-top: calc(var(--unit) * 1.5);
  padding-bottom: calc(var(--unit) * 2);
  border-top: 1px solid var(--rule);
}

@media (max-width: 36rem) {
  .intro, .project-header { flex-direction: column; align-items: flex-start; }
  .project-info { min-height: 0; }
}

/* Colon update check at /projects/colon/update/ */
.update {
  min-height: 55vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.update-verdict {
  margin: 0;
  font-size: 5.5rem;
  line-height: calc(var(--unit) * 4);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.update-detail { margin: var(--half) 0 0; color: var(--muted); }
.update-action { margin: var(--unit) 0 0; }

.update-action a {
  display: inline-block;
  padding: 0.375rem 1.1rem;
  line-height: var(--unit);
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  transition: filter 0.15s, transform 0.15s;
}

.update-action a:hover { filter: brightness(1.1); transform: translateY(-1px); }

/* Release notes, on the project page and the update check */
.release-list { list-style: none; padding: 0; margin: 0; }
.release-list > li { margin-bottom: var(--unit); }

.release-head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin: 0;
}

.release-head time { color: var(--muted); font-size: 0.9rem; }
.release-list ul { margin: 0; padding-left: 1.25rem; }

.update-missed {
  width: 100%;
  max-width: 30rem;
  margin: 0 auto;
  padding-bottom: var(--unit);
  text-align: left;
}

.update-missed h2 { margin-top: 0; }

/* Coming-soon page */
.coming-soon {
  min-height: 80vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.coming-soon .avatar { margin-bottom: 1.5rem; }
.coming-soon h1 { margin-bottom: 0.25rem; }
.coming-soon p { margin: 0.25rem 0; color: var(--muted); }
.coming-soon .links a { margin: 0 0.5rem; }
