/*
 * Dusk Labs. A terminal-flavored dashboard: a status bar on top, a help bar at the bottom,
 * and bordered panes in a responsive grid. Horizontal spacing is in ch, vertical spacing is in lh.
 *
 * Colors work like Solarized: neutral base tones for the page and text, and muted accent tones
 * that keep the Dusk palette hues. Each pane takes one accent, so the page is not monochrome.
 * All tones are derived from the Dusk palette (dusk-labs-palette.png) by reducing chroma in OKLCH
 * and setting lightness for contrast: accents are at least 4.5:1 in both modes.
 */

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  /* The page follows the system color scheme. The theme toggle in the status bar flips it. */
  color-scheme: light dark;

  /* Base tones, as light-dark(light, dark). Light: tan parchment. Dark: warm dark gray, with the light tones mixed toward it. */
  --bg: light-dark(#e5d7c0, #1d1914);
  --hi: light-dark(#daccb5, #27221d);
  --line: light-dark(#c7b9a2, #342f2a);
  --strong: light-dark(#393945, #a39e95);
  --text: light-dark(#42424c, #98929c);
  --secondary: light-dark(#584e57, #928a9a);
  --meta: light-dark(#5d565c, #8c8796);

  /* Accent tones for text and borders. */
  --amber: light-dark(#755a3c, #9f7b50);
  --blue: light-dark(#575e78, #7780a4);
  --rose: light-dark(#76575c, #a1777e);
  --clay: light-dark(#76584a, #a17965);

  /* Syntax tones for code. Light mode needs more chroma and contrast (6:1) than the accents, or the tokens look faded next to the body text. */
  --syn-rose: light-dark(#783846, #a1777e);
  --syn-blue: light-dark(#3e497f, #7780a4);
  --syn-amber: light-dark(#6d4304, #9f7b50);
  --syn-clay: light-dark(#763d20, #a17965);

  /* Fill tones for solid blocks. They carry Midnight Ink text (6:1 or more) in both themes. */
  --ink: #15132b;
  --fill-amber: light-dark(#cfb291, #b69066);
  --fill-rose: light-dark(#d0adb2, #b78b92);
  --fill-blue: light-dark(#aeb6d3, #8d97bb);

  --rule: 2px;

  background: var(--bg);
  color: var(--text);
  font: 400 16px/1.6 "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  -webkit-text-size-adjust: 100%;
}

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

body { display: flex; flex-direction: column; min-height: 100svh; margin: 0; }
h1, h2, h3, p, ul, ol, table { margin: 0; padding: 0; font: inherit; }
ul, ol { list-style: none; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
::selection { background: var(--fill-rose); color: var(--ink); }

.skip-link { position: absolute; z-index: 10; top: -10lh; left: 1ch; padding: 0 1ch; background: var(--fill-amber); color: var(--ink); }
.skip-link:focus { top: 0; }

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

/* Status bar (top) and help bar (bottom) */

.statusbar, .helpbar { position: sticky; z-index: 5; display: flex; white-space: nowrap; background: var(--hi); }
.statusbar { top: 0; border-bottom: var(--rule) solid var(--line); }
.statusbar a { text-decoration: none; }
.seg { padding: .25lh 1.5ch; }
.seg-brand { background: var(--fill-amber); color: var(--ink); font-weight: 800; letter-spacing: .04em; }
/* The Dusk Labs mark: a pixel D on a 5x5 grid with one amber pixel in the middle. */
.seg-logo { display: flex; align-items: center; }
.seg-logo svg { width: 1em; height: 1em; }
.logo-d { fill: var(--strong); }
.logo-dot { fill: var(--amber); }

/* Theme toggle. theme.js sets data-theme from the saved choice. Without it, the page follows the system color scheme. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
.seg-theme { margin-left: auto; border: 0; background: none; color: var(--secondary); font: inherit; cursor: pointer; }
.seg-theme:hover { color: var(--strong); }
.statusbar .seg:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }

/* RSS link, at the right end of the status bar. The fill sets it apart from the theme toggle. The icon is a pixel feed mark on a 5x5 grid, like the logo. */
.seg-rss { display: flex; align-items: center; gap: .75ch; background: var(--fill-blue); color: var(--ink); font-weight: 700; }
.seg-rss svg { width: 15px; height: 15px; fill: currentColor; }
.seg-rss:hover { background: color-mix(in oklab, var(--fill-blue) 70%, white); }

.helpbar { bottom: 0; justify-content: flex-end; padding: .25lh 1.5ch; border-top: var(--rule) solid var(--line); color: var(--meta); }
.helpbar .sep { margin-inline: 1ch; }
.helpbar a { color: var(--secondary); text-decoration: none; }
.helpbar a:hover { color: var(--strong); }

/* Dashboard grid: one, two, or three columns of panes. */

.app {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "hero" "blog" "work";
  gap: 2.5lh 3ch;
  align-content: start;
  width: min(100% - 4ch, 200ch);
  margin: 2.5lh auto;
}

@media (min-width: 78rem) {
  .app {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto auto 1fr;
    grid-template-areas: "hero blog" "work work" "banner banner";
  }
}

/* Each pane takes one accent hue from the palette. */
.hero { grid-area: hero; --pane: var(--amber); --pane-fill: var(--fill-amber); }
.blog { grid-area: blog; --pane: var(--blue); --pane-fill: var(--fill-blue); }
.work { grid-area: work; --pane: var(--rose); --pane-fill: var(--fill-rose); }
.lost .pane { --pane: var(--clay); --pane-fill: var(--fill-amber); }

/* Pane: a thick bordered box with its title set into the top border. */

.pane {
  position: relative;
  display: grid;
  gap: 1lh;
  align-content: start;
  padding: 2lh 3ch 1.5lh;
  border: var(--rule) solid color-mix(in oklab, var(--pane) 45%, var(--bg));
  scroll-margin-top: 3lh;
  transition: border-color .15s;
}
.pane:hover, .pane:focus-within { border-color: var(--pane); }
.pane-head {
  position: absolute;
  top: calc(-.5lh - var(--rule) / 2);
  left: 2ch;
  right: 2ch;
  display: flex;
  align-items: center;
  font-size: 1.125rem;
  pointer-events: none;
}
.pane-head > * { padding-inline: 1ch; background: var(--bg); white-space: nowrap; }
.pane-title { flex: none; display: flex; align-items: center; gap: 1ch; color: var(--pane); font-weight: 800; }
.pane-title .key { padding-inline: .75ch; background: var(--pane-fill); color: var(--ink); font-size: .875rem; font-weight: 700; }
.pane-foot { margin: .5lh -3ch 0; padding: 1lh 3ch 0; border-top: var(--rule) dashed var(--line); color: var(--secondary); }
.pane-foot a { color: var(--pane); }
.pane-head a { pointer-events: auto; text-decoration: none; }

/* Hero */

/* When the hero shares a row with a taller pane, the copy stays at the top and the button moves to the bottom. */
.hero { align-content: space-between; }
.hero p { font-size: 1.0625rem; }

/* Buttons */

.buttons { display: flex; flex-wrap: wrap; gap: 1lh 2ch; margin-top: 1lh; }
.button { padding: .4lh 2.5ch; background: var(--hi); color: var(--strong); font-weight: 700; text-decoration: none; }
.button.primary { background: var(--pane-fill); color: var(--ink); }
.button:hover, .button:focus-visible { background: var(--strong); color: var(--bg); outline: none; }

/* List: the first item is selected until another item is hovered.
   One, two, or four columns, so the four items always fill complete rows. */

.list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5lh 4ch; }
@media (min-width: 48rem) { .list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 110rem) { .list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.list li { padding-left: 2ch; border-left: 3px solid var(--pane); }
.list .title { display: block; color: var(--pane); font-size: 1.0625rem; font-weight: 800; }
.list .desc { display: block; color: var(--secondary); }

/* Post lists: the newest posts in the blog pane on the home page, and all posts on /blog/. */

.posts { display: grid; gap: .5lh; }
.posts a { display: flex; gap: 2ch; text-decoration: none; }
.posts time { flex: none; color: var(--meta); }
.posts .post-title { color: var(--strong); }
.posts a:hover .post-title { color: var(--pane); text-decoration: underline; text-underline-offset: .2em; }
.posts-full { gap: 1.5lh; }
.post-desc { padding-left: 12ch; color: var(--secondary); }
.more { justify-self: start; color: var(--pane); text-decoration: none; }
.more:hover { color: var(--strong); }
.back { text-decoration: none; }
.back:hover { color: var(--strong); }

/* Blog pages: one pane, centered, at a width that keeps lines of text short enough to read. */

.page { flex: 1; width: min(100% - 4ch, 88ch); margin: 2.5lh auto; }
.page > .pane { border-color: var(--pane); }

/* Post text: rendered Markdown in the spirit of Glamour, Charm's terminal Markdown renderer,
   but without the Markdown syntax. Headings scale up, code and tables get box borders. */

.prose { min-width: 0; }
.prose > * + * { margin-top: 1lh; }
.prose header { margin-bottom: 1lh; }
.prose h1 { color: var(--strong); font-size: clamp(1.5rem, 1.15rem + 1.25vw, 2.125rem); font-weight: 800; line-height: 1.25; letter-spacing: -.02em; text-wrap: balance; }
.post-date { margin-top: .5lh; color: var(--meta); }
.prose :is(h2, h3, h4, h5, h6) { line-height: 1.3; text-wrap: balance; }
.prose h2 { margin-top: 2lh; color: var(--pane); font-size: 1.5rem; font-weight: 800; letter-spacing: -.01em; }
.prose h3 { margin-top: 1.5lh; color: var(--strong); font-size: 1.25rem; font-weight: 800; }
.prose :is(h4, h5, h6) { margin-top: 1.5lh; color: var(--strong); font-weight: 800; }
.prose :is(h2, h3, h4, h5, h6) + * { margin-top: .5lh; }

.prose strong { color: var(--strong); font-weight: 800; }
.prose a { color: var(--pane); text-decoration-thickness: 1px; text-underline-offset: .2em; }
.prose a:hover { color: var(--strong); }
.prose code { font: inherit; }
.prose :not(pre) > code { padding: 0 .5ch; background: var(--hi); color: var(--strong); }

.prose :is(ul, ol) { padding-left: 3ch; }
.prose ul { list-style-type: "• "; }
.prose ol { list-style-type: decimal; }
.prose li::marker { color: var(--pane); }
.prose li + li, .prose li > :is(ul, ol), .prose li > p + * { margin-top: .25lh; }

.prose blockquote { margin-inline: 0; margin-bottom: 0; padding-left: 2ch; border-left: 3px solid color-mix(in oklab, var(--pane) 45%, var(--bg)); color: var(--secondary); }
.prose blockquote > * + * { margin-top: 1lh; }

.prose > hr { height: 0; margin-block: 2lh; border: 0; border-top: var(--rule) dashed var(--line); }

/* Code block: a box with a quiet border and the language name set into the top border, like a pane. */
.prose .code { position: relative; border: var(--rule) solid var(--line); }
.prose .code[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: calc(var(--rule) / -2);
  left: 1.5ch;
  translate: 0 -50%;
  padding-inline: 1ch;
  background: var(--bg);
  color: var(--meta);
  font-size: .875rem;
}
.prose pre { margin: 0; padding: 1lh 2ch; overflow-x: auto; font: inherit; }
/* Syntax colors. Pandoc marks tokens with short class names. */
.prose pre a { display: none; }
.prose code :is(.kw, .cf, .im, .op) { color: var(--syn-rose); }
.prose code :is(.dt, .bu, .fu) { color: var(--syn-blue); }
.prose code :is(.st, .vs, .ss, .ch, .sc, .at, .pp, .ex) { color: var(--syn-amber); }
.prose code :is(.dv, .bn, .fl, .cn) { color: var(--syn-clay); }
.prose code :is(.co, .do, .an, .cv, .in) { color: var(--meta); font-style: italic; }
.prose code :is(.al, .er, .wa) { color: var(--syn-rose); font-weight: 800; }

/* Table: Glamour style. A rule under the header and rules between columns, with no outer box. */
.prose .table { overflow-x: auto; }
.prose table { border-collapse: collapse; }
.prose :is(th, td) { padding: 0 2ch; text-align: left; vertical-align: top; }
.prose :is(th, td):first-child { padding-left: 0; }
.prose :is(th, td):last-child { padding-right: 0; }
.prose :is(th, td) + :is(th, td) { border-left: var(--rule) solid var(--line); }
.prose th { padding-bottom: .25lh; border-bottom: var(--rule) solid var(--line); color: var(--strong); font-weight: 800; }
.prose tbody tr:first-child td { padding-top: .25lh; }
.prose caption { caption-side: bottom; margin-top: .5lh; color: var(--meta); text-align: left; }

.prose figure { margin-inline: 0; margin-bottom: 0; }
.prose img { display: block; max-width: 100%; height: auto; border: var(--rule) solid var(--line); }
.prose figcaption { margin-top: .5lh; color: var(--meta); font-size: .875rem; }

.prose .footnotes { margin-top: 2lh; color: var(--secondary); font-size: .875rem; }
.prose .footnotes hr { margin: 0 0 1lh; border: 0; border-top: var(--rule) dashed var(--line); }
.prose .footnotes ol { list-style-type: decimal; }
.prose sup { line-height: 0; }

/* Banner: the Dusk Labs wordmark in flat block letters at the bottom of the wide layout, where the panes leave empty space.
   It is SVG text, and textLength stretches each row to the full width, so it fills the grid exactly at any size. */

.banner {
  grid-area: banner;
  display: none;
  align-self: end;
  /* Pressed-in look: letters a shade darker than the page, with shaded edges from the #emboss filter. */
  --emboss: light-dark(color-mix(in oklab, var(--bg), black 9%), color-mix(in oklab, var(--bg), black 12%));
  --emboss-shade: light-dark(color-mix(in oklab, var(--bg), black 25%), color-mix(in oklab, var(--bg), black 45%));
  --emboss-light: light-dark(color-mix(in oklab, var(--bg), white 45%), color-mix(in oklab, var(--bg), white 12%));
}
@media (min-width: 78rem) { .banner { display: block; } }
.banner svg { display: block; width: 100%; height: auto; overflow: visible; font-family: inherit; }
.banner text { fill: var(--emboss); white-space: pre; }
.emboss-shade { flood-color: var(--emboss-shade); }
.emboss-light { flood-color: var(--emboss-light); }

/* Not found */

.lost { flex: 1; display: grid; place-content: center; padding: 2lh 2ch; }
.lost .pane { width: min(60ch, 100vw - 4ch); border-color: var(--pane); }
.lost h1 { color: var(--strong); font-size: clamp(1.75rem, 1rem + 3vw, 2.75rem); font-weight: 800; letter-spacing: -.03em; }

@media (max-width: 40rem) {
  .app, .page { width: calc(100% - 2ch); }
  .posts a { flex-direction: column; gap: 0; }
  .post-desc { padding-left: 0; }
  .pane { padding-inline: 1.5ch; }
  .pane-head { left: 1ch; right: 1ch; }
  .pane-foot { margin-inline: -1.5ch; padding-inline: 1.5ch; }
  .seg { padding-inline: 1ch; }
  /* On a phone, a post reads as plain text without the pane border. */
  .page:has(> .post) { margin-top: 1.5lh; }
  .post { padding: 0 1ch; border: 0; }
  .post .pane-foot { margin-inline: 0; padding-inline: 0; }
  .helpbar { position: static; flex-wrap: wrap; white-space: normal; }
}
