/* sindrehenriksen.dev: page chrome, rendered markdown and the CV page.
   Phone-first (iPhone 17 Pro, 402px), light and dark from the system setting
   or from the toggle at the end of the nav. System fonts only: no requests
   beyond this file and the images. */

/* Each token names its light and its dark value once; which one resolves is
   decided by `color-scheme` alone, so a colour has a single place to edit. */
:root {
  --bg: light-dark(#fbfaf7, #121314);
  --surface: light-dark(#f1efe9, #1c1d1f);
  --text: light-dark(#1b1b1a, #e9e8e4);
  --muted: light-dark(#5d5d58, #a3a29c);
  --rule: light-dark(#e2dfd7, #2c2d30);
  --rule-strong: light-dark(#b9b5ab, #4a4b4f);
  --accent: light-dark(#1f4fd1, #8db1ff);
  --accent-strong: light-dark(#143a9e, #b8cdff);
  --measure: 38rem;
  --gutter: 1.25rem;
  color-scheme: light dark;
}

/* The reader's own choice, when they have made one: the script in
   layout.html sets data-theme on <html> before the first paint. Without it
   the system decides, which is what `color-scheme: light dark` above says. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

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

/* The scrollbar's gutter is always reserved, so a short page such as About
   does not centre its content a few pixels off from the pages that scroll. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  padding-inline: var(--gutter);
  background: var(--bg);
  color: var(--text);
  font: 400 1.0625rem/1.6 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Header, footer and prose keep the reading measure on every page, so the
   nav never moves and text starts and ends in the same place everywhere.
   The one thing that breaks out of it is the CV's dates, into the left
   margin, and only at a width where the margin has room for them. */
.site-header, main, .site-footer {
  max-width: var(--measure);
  margin-inline: auto;
}

.skip {
  position: absolute;
  left: -999px;
}
.skip:focus {
  left: 1rem;
  top: 1rem;
  z-index: 1;
  padding: .5rem .75rem;
  background: var(--bg);
}

/* ---------- Header and nav ---------- */

.site-header {
  padding-block: 1rem .25rem;
  border-bottom: 1px solid var(--rule);
}

.site-name {
  display: inline-block;
  padding-block: .5rem;
  color: var(--text);
  font-weight: 650;
  letter-spacing: -.01em;
  text-decoration: none;
}
.site-name:hover, .site-name:focus-visible {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: .3em;
}

/* The links, then the theme toggle pushed to the far right of the measure. */
.site-nav {
  display: flex;
  align-items: center;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  margin: 0 0 0 -.375rem;
  padding: 0;
  list-style: none;
}

.site-nav li { margin: 0; }

/* Padding makes each link a 44px-high target, and wide enough for "CV". It is
   as tight sideways as it is because the row has to hold the theme toggle too
   and still fit on one line on a phone. */
.site-nav a {
  display: block;
  min-width: 2.75rem;
  padding: .625rem .375rem;
  color: var(--muted);
  text-align: center;
  font-size: .9375rem;
  text-decoration: none;
}

.site-nav a:hover { color: var(--text); }

.site-nav a[aria-current="page"] {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: .4em;
}

/* The theme toggle sits last in the nav, its icon flush with the right of the
   measure: the padding makes it a 44px target like the links, and the negative
   right margin takes that padding back out of the column. It is hidden until
   its script runs, so it is never a dead control. */
.theme-toggle {
  display: flex;
  align-items: center;
  margin: 0 -.5625rem 0 auto;
  padding: .8125rem .5625rem;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.theme-toggle[hidden] { display: none; }
.theme-toggle:hover { color: var(--text); }
.theme-toggle svg { display: block; }

@media (min-width: 48rem) {
  .site-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    column-gap: 2rem;
  }
}

/* ---------- Rendered markdown ---------- */

/* The page's own space inside the chrome: the header's rule down to the title,
   and the last line down to the footer's rule. Both are kept near the space a
   section rule gets, so the page reads as one rhythm rather than as text
   marooned between two lines.

   The space below is a margin rather than padding, and main carries no bottom
   padding, so whatever a page ends with — a paragraph, a caption, a list buried
   in the CV's article — collapses its own margin out through main, and every
   page ends the same distance above the rule. A border or an overflow on main
   would stop that collapse and put the margin back. */
main {
  padding-block: 1.75rem 0;
  margin-block-end: 2.5rem;
}

main > :first-child { margin-top: 0; }

h1, h2, h3 {
  line-height: 1.2;
  letter-spacing: -.015em;
  text-wrap: balance;
}

h1 {
  margin: 0 0 .75rem;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -.025em;
}

h2 {
  margin: 2.75rem 0 .75rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--rule);
  font-size: 1.3125rem;
  font-weight: 650;
}

h1 + h2 {
  margin-top: 1.75rem;
  padding-top: 0;
  border-top: 0;
}

h3 {
  margin: 2rem 0 .5rem;
  font-size: 1.0625rem;
  font-weight: 650;
}

p, ul, ol, table, pre, blockquote { margin: 0 0 1rem; }

/* No `text-wrap: pretty` on body text: WebKit implements it as a
   whole-paragraph optimiser rather than Chromium's last-few-lines tweak, so
   it pulls every line back and each block ends a different distance short of
   the measure. Headings still balance, which is what a short block wants. */

/* The paragraph right after the page title is its lede. */
h1 + p {
  color: var(--muted);
  font-size: 1.1875rem;
  line-height: 1.45;
}

/* A paragraph right after a section heading that holds only emphasis is a
   meta line: dates, role, status. Content relies on this convention. */
h2 + p:has(> em:only-child) {
  margin-top: -.25rem;
  color: var(--muted);
  font-size: .875rem;
  font-variant-numeric: tabular-nums;
}
h2 + p:has(> em:only-child) em { font-style: normal; }

ul, ol { padding-left: 1.25rem; }
li { margin-bottom: .5rem; }
li::marker { color: var(--muted); }

strong { font-weight: 650; }

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
}
a:hover {
  color: var(--accent-strong);
  text-decoration-thickness: 2px;
}

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

blockquote {
  padding-left: 1rem;
  border-left: 3px solid var(--rule-strong);
  color: var(--muted);
}

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

code {
  padding: .1em .3em;
  border-radius: 4px;
  background: var(--surface);
  font: .875em/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
pre {
  overflow-x: auto;
  padding: 1rem;
  border-radius: .5rem;
  background: var(--surface);
}
pre code { padding: 0; background: none; }

/* Markdown tables get no wrapper, so the table itself scrolls when too wide. */
table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: .9375rem;
}
th, td {
  padding: .5rem 1rem .5rem 0;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}
th { font-weight: 650; }

/* Images: a markdown image, optionally wrapped in a link to the full file,
   alone in its paragraph. A following emphasis-only paragraph is its caption. */
img {
  max-width: 100%;
  height: auto;
}
p:has(> img), p:has(> a > img) { margin: 1.75rem 0 .5rem; }
p > img, p > a > img {
  display: block;
  border: 1px solid var(--rule);
  border-radius: .625rem;
  background: var(--surface);
}
/* A figure taller than wide, such as a phone screenshot, is capped by height
   rather than by the measure, so it carries about the weight of a wide figure
   instead of towering over the text. */
p > img.portrait, p > a > img.portrait {
  max-height: 24rem;
  width: auto;
}
p:has(> img) + p:has(> em:only-child),
p:has(> a > img) + p:has(> em:only-child) {
  margin-bottom: 1.75rem;
  color: var(--muted);
  font-size: .875rem;
  line-height: 1.45;
}

/* Front page link row (email ... CV PDF): padded like the footer links. */
p:has(> a[href^="mailto:"]):has(> a[href="/cv.pdf"]) { margin: -.25rem 0 1rem; }
p:has(> a[href^="mailto:"]):has(> a[href="/cv.pdf"]) a {
  display: inline-block;
  padding-block: .625rem;
}

/* Light-background figures would glare on a dark page. The dimming is a
   number rather than a colour, so `light-dark()` cannot carry it and the
   theme has to be read from a selector on both branches instead. */
:root { --figure-dim: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --figure-dim: .82; }
}
:root[data-theme="dark"] { --figure-dim: .82; }

img[src$="thesis.webp"], img[src$="tournament.webp"], img[src$="lykkepromille.webp"] {
  filter: brightness(var(--figure-dim));
}

/* Front page portrait, matched by file name so the markdown stays plain.
   The photo is landscape; the circle crops it to the head and shoulders. */
p:has(> img[src$="sindre-henriksen.jpg"]) { margin: 0 0 1.25rem; }
img[src$="sindre-henriksen.jpg"] {
  width: 5.5rem;
  height: 5.5rem;
  border: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--rule);
  object-fit: cover;
  object-position: 54% 50%;
}

@media (min-width: 48rem) {
  main {
    padding-block: 2.5rem 0;
    margin-block-end: 3.25rem;
  }
  h1 { font-size: 2.5rem; }
}

/* ---------- Footer ---------- */

.site-footer {
  padding-block: .75rem 2.5rem;
  border-top: 1px solid var(--rule);
}
.footer-contact {
  display: flex;
  flex-wrap: wrap;
  column-gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer-contact li { margin: 0; }
.footer-contact a {
  display: block;
  padding-block: .625rem;
  color: var(--muted);
  font-size: .9375rem;
  text-decoration: none;
}
.footer-contact a:hover { color: var(--text); }

/* Read out but not drawn: the toggle's name, since its icon carries none. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- CV page (markup from cv_body() in site/build.py) ---------- */

.cv-header { margin-bottom: 2rem; }

/* The CV header's first paragraph is contact or the PDF button, not a lede. */
.cv-header h1 + p {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.6;
}

.cv-contact {
  margin: -.25rem 0 .75rem;
  color: var(--muted);
}
.cv-contact a {
  display: inline-block;
  padding-block: .5rem;
}

.cv-download {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding-inline: 1.125rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-weight: 600;
  text-decoration: none;
}
.cv-download:hover {
  background: var(--accent);
  color: var(--bg);
}

/* Section titles echo the PDF: small caps over a rule. */
.cv h2 {
  margin: 2.25rem 0 1rem;
  padding: 0 0 .3rem;
  border-top: 0;
  border-bottom: 1px solid var(--rule-strong);
  font-size: 1.5rem;
  font-weight: 600;
  font-variant-caps: all-small-caps;
  letter-spacing: .05em;
}

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

.cv-entry { margin: 0 0 1.5rem; }

/* Dates in small caps, like the PDF's date column. */
.cv-dates {
  margin: 0 0 .125rem;
  color: var(--muted);
  font-size: 1.125rem;
  font-variant-caps: all-small-caps;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

/* An endpoint never breaks inside itself. Where the dates stack, below, the
   two sit on their own lines; where they are inline they stay on one. */
.cv-date { white-space: nowrap; }

.cv-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 650;
  letter-spacing: -.01em;
}

.cv-org {
  margin: 0 0 .5rem;
  color: var(--muted);
}

.cv-points { margin: 0; list-style: disc; }
.cv-points li { margin-bottom: .375rem; }

.cv-skills { margin: 0; }
.cv-skills > div { margin-bottom: .75rem; }
.cv-skills dt { font-weight: 650; }
.cv-skills dd { margin: 0; }

.cv-list { padding-left: 1.25rem; }

/* The PDF's two columns — dates right-aligned, then a rule — from the width
   where the margin can hold them. The entry hangs left by the date column,
   the gap, the rule and the padding, so its text keeps the same measure as
   every other page. Below that there is no margin to hang in, and a date
   column would narrow the CV's text alone, so the entries stack instead. */
@media (min-width: 64rem) {
  .cv-entry, .cv-skills > div {
    display: grid;
    grid-template-columns: 8.5rem 1fr;
    column-gap: 1.25rem;
    margin-left: calc(-11rem - 1px);
  }
  .cv-dates, .cv-skills dt {
    padding-top: .1rem;
    text-align: right;
  }
  /* One endpoint per line, so every range breaks in the same place. */
  .cv-dates .cv-date { display: block; }
  .cv-body, .cv-skills dd {
    padding-left: 1.25rem;
    border-left: 1px solid var(--rule-strong);
  }
}
