/* ==========================================================================
   Base stylesheet. Loaded by every page.
   Blog-only rules live in blog.css; there is deliberately no overlap between
   the two files so neither can cancel the other.
   ========================================================================== */

@font-face {
  font-family: "Iosevka Web";
  font-display: swap;
  font-weight: 400;
  font-style: normal;
  src: url("/assets/fonts/iosevka-regular.woff2") format("woff2");
}

@font-face {
  font-family: "Iosevka Web";
  font-display: swap;
  font-weight: 700;
  font-style: normal;
  src: url("/assets/fonts/iosevka-bold.woff2") format("woff2");
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */

:root {
  --background: #ffffff;
  --foreground: #454545;
  --muted: #6b6b6b;
  --accent: #2f6b2f;

  --rule: color-mix(in srgb, var(--foreground) 22%, transparent);
  --tint: color-mix(in srgb, var(--foreground) 5%, transparent);

  --radius: 0;
  --font-size: 1rem;
  --line-height: 1.6;

  /* THE WIDTH KNOB. Change this one value to retune the whole site.
     Iosevka advances 0.5em per character, so Nch is N/2 rem:
       120ch =  960px   140ch = 1120px
       160ch = 1280px   200ch = 1600px      none = full width, no cap
     160ch keeps a 2560px display from rendering 300-character lines while
     still feeling wide. */
  --measure: 160ch;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #000000;
    --foreground: #eceae5;
    --muted: #9a9a9a;
    --accent: #7ee787;
  }
}

/* --------------------------------------------------------------------------
   Summer accent rotation

   The home page picks one of these on every page load (see the inline script
   in base.njk, which sets data-accent on <html>). Measured WCAG contrast of
   each pair against its own background:

     palm     6.43 / 13.67      coral     5.93 / 10.52
     sea      6.47 / 14.20      hibiscus  6.12 / 10.98
     mango    5.73 / 13.04      sky       5.70 / 12.15
     plumeria 6.15 / 12.10

   Worst case is 5.70, so every colour clears AA in both modes. Pages that
   never set data-accent keep the palm green above.
   -------------------------------------------------------------------------- */

html[data-accent="0"] { --accent: #2f6b2f; } /* palm     */
html[data-accent="1"] { --accent: #00696e; } /* sea      */
html[data-accent="2"] { --accent: #8f5b00; } /* mango    */
html[data-accent="3"] { --accent: #b23a2f; } /* coral    */
html[data-accent="4"] { --accent: #b02d6b; } /* hibiscus */
html[data-accent="5"] { --accent: #0b6ba8; } /* sky      */
html[data-accent="6"] { --accent: #6a4bc4; } /* plumeria */

@media (prefers-color-scheme: dark) {
  html[data-accent="0"] { --accent: #7ee787; }
  html[data-accent="1"] { --accent: #5eead4; }
  html[data-accent="2"] { --accent: #ffc15e; }
  html[data-accent="3"] { --accent: #ff9e8c; }
  html[data-accent="4"] { --accent: #ff9ec8; }
  html[data-accent="5"] { --accent: #8fcbff; }
  html[data-accent="6"] { --accent: #c9bcfd; }
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
}

body {
  font-family: "Iosevka Web", ui-monospace, monospace;
  font-size: var(--font-size);
  font-weight: 400;
  line-height: var(--line-height);
  background-color: var(--background);
  color: var(--foreground);
  text-rendering: optimizeLegibility;
  font-variant-ligatures: contextual;
  -webkit-overflow-scrolling: touch;
  -webkit-text-size-adjust: 100%;
}

/* --------------------------------------------------------------------------
   Page measure

   The single most important rule here. Without it prose runs the full width
   of the viewport, which on a wide display is unreadable.
   -------------------------------------------------------------------------- */

body > header,
body > main,
body > footer {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: 1.25rem;
}


/* --------------------------------------------------------------------------
   Masthead

   Shared by the home page and the blog so the two read as one site.
   -------------------------------------------------------------------------- */

#headline {
  display: flex;
  align-items: center;
  white-space: nowrap;
  line-height: 1;
  letter-spacing: 0.04em;
  font-size: 1.125rem;
  text-transform: uppercase;
  margin: 2rem 0;
}

#headline a {
  color: inherit;
  text-decoration: none;
  border-bottom: 2px solid transparent;
  padding-bottom: 0.2em;
}

#headline a + a {
  margin-left: 1.5ch;
}

#headline a:hover,
#headline a[aria-current="page"] {
  border-bottom-color: var(--accent);
}

/* The dashed rule that runs out to the right of the nav. */
#headline::after {
  content: "";
  flex: 1;
  height: 2px;
  margin-left: 2ch;
  background: repeating-linear-gradient(
    90deg,
    var(--accent),
    var(--accent) 2px,
    transparent 0,
    transparent 8px
  );
}

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */

h1 {
  font-size: calc(var(--font-size) * 1.45);
}

h2 {
  font-size: calc(var(--font-size) * 1.35);
}

h3 {
  font-size: calc(var(--font-size) * 1.15);
}

h4,
h5,
h6 {
  font-size: var(--font-size);
}

h1, h2, h3, h4, h5, h6,
b, strong,
th,
button {
  font-weight: 600;
}

h1, h2, h3, h4, h5, h6,
p, ul, ol,
img, figure, video,
table, pre, blockquote {
  margin: 1.5rem 0;
}

a {
  color: var(--accent);
  text-underline-offset: 0.2em;
}

a:hover {
  text-decoration-thickness: 2px;
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

ul,
ol {
  margin-left: 3ch;
  padding: 0;
}

ul ul,
ul ol,
ol ul,
ol ol {
  margin-top: 0;
  margin-bottom: 0;
}

li::marker {
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   Code

   The body font is already a monospace, so code is distinguished by a tint
   and a hairline rather than by a second, clashing mono face.
   -------------------------------------------------------------------------- */

code,
kbd,
pre {
  font-family: "Iosevka Web", ui-monospace, monospace;
  font-feature-settings: normal;
}

code,
kbd {
  background: var(--tint);
  padding: 0.05em 0.4em;
  font-size: 0.95em;
}

code {
  border: 1px solid var(--rule);
}

kbd {
  border: 1px solid var(--accent);
  border-bottom-width: 3px;
  border-radius: 3px;
}

code code {
  background: transparent;
  border: none;
  padding: 0;
}

pre {
  tab-size: 4;
  background: var(--tint);
  color: inherit;
  padding: 1rem 1.25rem;
  font-size: 0.95em;
  line-height: 1.5;
  overflow: auto;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
}

pre code {
  background: none;
  border: none;
  margin: 0;
  padding: 0;
  font-size: inherit;
}

/* --------------------------------------------------------------------------
   Blocks
   -------------------------------------------------------------------------- */

blockquote {
  border-left: 2px solid var(--accent);
  padding: 0 0 0 1.25rem;
  color: var(--muted);
}

blockquote p:first-child {
  margin-top: 0;
}

blockquote p:last-child {
  margin-bottom: 0;
}

/* A hairline frame, not a picture mount. */
img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

figure img,
figure video {
  margin-bottom: 0;
}

figure figcaption {
  color: var(--muted);
  font-size: 0.9em;
  padding-top: 0.5rem;
}

table {
  table-layout: auto;
  border-collapse: collapse;
  display: block;
  overflow-x: auto;
}

/* Cell rules only. A border on `table` as well would draw a second box
   around the outside of the collapsed grid. */
th,
td {
  border: 1px solid var(--rule);
  padding: 0.5rem 0.75rem;
}

th {
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

hr {
  width: 100%;
  border: none;
  background: var(--rule);
  height: 1px;
  margin: 2rem 0;
}

mark {
  background: color-mix(in srgb, var(--accent) 35%, transparent);
  color: var(--foreground);
}

abbr {
  text-decoration-style: wavy;
  text-decoration-color: var(--accent);
  cursor: help;
}

sub { bottom: -0.25em; }
sup { top: -0.25em; line-height: 0; }

::-moz-selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}

::selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* --------------------------------------------------------------------------
   Controls
   -------------------------------------------------------------------------- */

button {
  position: relative;
  font: inherit;
  text-decoration: none;
  text-align: center;
  background: transparent;
  color: var(--accent);
  padding: 5px 18px;
  border: 2px solid var(--accent);
  border-radius: var(--radius);
  transition: background 0.15s linear;
  appearance: none;
  cursor: pointer;
}

button:hover {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
}

.hidden {
  display: none;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: 0;
  padding: 8px 16px;
  background: var(--accent);
  color: var(--background);
  font-weight: bold;
  text-decoration: none;
  z-index: 9999;
}

.skip-link:focus {
  top: 0;
}

#floatingBox {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 20px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
  z-index: 1000;
  /* Not min-width: 300px + max-width: 40%. On a 390px phone the percentage
     resolves to 156px, the min-width overrides it, and the dialog ends up
     wider than its own cap with no gutter left. */
  width: min(92vw, 120ch);
  max-height: 80vh;
  overflow: auto;
  /* Centred only so the Close button below sits centred; the text itself is
     overridden on #floatingContent. */
  text-align: center;
  background-color: var(--background);
  color: var(--foreground);
}

#floatingContent {
  text-align: justify;
}

#floatingBox button {
  margin-top: 10px;
}

/* --------------------------------------------------------------------------
   Home page: man(1) section ladder
   -------------------------------------------------------------------------- */

.section {
  margin-bottom: 2em;
}

.section h2,
.section h3,
.section h4 {
  margin-top: 0;
  margin-bottom: 0.5em;
}

.section h2 {
  font-size: 1.2em;
  margin-left: 0;
}

.section h3 {
  font-size: 1.1em;
  margin-top: 0.5em;
  margin-left: 2em;
}

.section h4 {
  font-size: 1em;
  margin-top: 0.5em;
  margin-left: 4em;
}

.section div {
  text-align: justify;
  word-wrap: break-word;
}

.section p {
  margin-top: 0;
  margin-bottom: 1em;
  margin-left: 2em;
}

.section h3 + div,
.section h3 + p {
  margin-left: 4em;
}

.section h4 + div,
.section h4 + p {
  margin-left: 6em;
}

@media (max-width: 40rem) {
  .section h3,
  .section h4,
  .section p,
  .section h3 + div,
  .section h3 + p,
  .section h4 + div,
  .section h4 + p {
    margin-left: 0;
  }
}

/* The widget grid spaces itself with flex gap and its own margins. The global
   image margin would otherwise stack another 1.5rem on top of that, leaving a
   large hole under the WIDGETS heading. */
.widgets img {
  margin: 0;
}

footer {
  color: var(--muted);
  font-size: 0.9em;
  text-align: center;
  margin-top: 3rem;
  padding-bottom: 2rem;
}

/* The build's commit hash. Body text is already Iosevka, so this only needs to
   stay on one line: a hash broken across a line wrap is unreadable. */
footer .commit {
  white-space: nowrap;
}

@media (prefers-color-scheme: dark) {
  img {
    filter: grayscale(30%);
  }
}
