/* The paper: a page of lined notebook paper (design C). Every page in the house style links
   it, here and elsewhere, together with pencil.css, which styles everything drawn on it, and
   fonts/, which holds the face. Every vertical measure is a whole number of rules (--L), and
   text sits on the rules. A page that declares both color schemes turns to the dark sheet (at
   the end) where the reader's system asks for dark. See README.md. */

/* The face, served from fonts/ (a Latin subset made by tools/font_subset.py) with the
   three axes that the dial uses at their full ranges. The URL is relative to this file. A
   page preloads the file so that it starts early (rel="preload", as="font", type="font/woff2"
   and crossorigin, which a font request needs even from the same origin). Opened from disk, a
   browser refuses a font fetched with crossorigin, though this rule still loads it, so a page
   that may be opened from disk adds the preload from a script only where it is served. */
@font-face {
  font-family: 'Shantell Sans'; font-style: normal; font-weight: 300 800; font-display: swap;
  src: url('fonts/ShantellSans-Latin.woff2') format('woff2');
}

:root {
  --L: 32px;                /* Rule spacing. */
  --paper: #fbf9f3;
  --rule: #cfdbe8;          /* Pale blue rules. */
  --margin: #e6aaa3;        /* The red margin line. */
  --margin-x: 88px;
  --ink: #3d3c39;           /* Graphite. */
  --ink-2: #6d6a63;
  --ink-3: #97938a;         /* For marks only, never for text. */
  --red: #a64a3f;           /* For errors only: a darker margin red. */
  --blue-pencil: #1c77ad;   /* An illustrator's non-photo blue, deepened to be read: a page's workings, shown on request. */
  --band: 4;                /* Blank header band, in rules; the title sits on the first rule. */
  /* One typeface on one dial (STYLE.md §3). --informal sets how informal the work is:
     0 for a paper's diagram, 50 for a site, 100 for a hobby project. */
  --face: 'Shantell Sans', ui-rounded, system-ui, sans-serif;
  --informal: 50;
}
* { box-sizing: border-box; }
/* Running text (the print) uses the dial value as its informality (INFM). Hand-lettered
   text (a title, a note, a name; marked with --hand: 50) never drops below INFM 50, and
   in the top half of the dial it also bounces, reaching BNCE 50 at 100. More bounce
   lifts a lower-case p or s to capital height, so "phy" would read "Phy".
   The declaration is !important because the font shorthand resets it; for the same
   reason every font shorthand states its weight (300).
   --sit is the distance a line of text moves down so that its baseline sits on its
   rule: half a rule, minus the rule's 1px, minus half the face's ascent less its descent
   ((1.02 - 0.32) / 2 em). It is declared on every element so that a component with its
   own --L computes its own value. */
h1, .hand { --hand: 50; }
*, ::before, ::after { --sit: calc(var(--L) / 2 - 1px - .35em);
  font-variation-settings: 'INFM' max(var(--informal), var(--hand, 0)),
    'BNCE' max(var(--informal) + var(--hand, 0) - 100, 0) !important; }
strong, b { font-weight: 600; }  /* Bold is the only heavier weight. */
em, i, cite, var, dfn, address { font-style: normal; }  /* The face has no italics, so a browser would only slant it (STYLE.md §3). */
html { background: var(--paper); }
body {
  margin: 0; min-height: 100vh; color: var(--ink); font: 300 18px/var(--L) var(--face);
  -webkit-font-smoothing: antialiased;
  /* Ruled lines (1px at the bottom of every --L band) and the margin line. */
  background:
    linear-gradient(var(--margin), var(--margin)) var(--margin-x) 0 / 1px 100% no-repeat,
    repeating-linear-gradient(transparent 0 calc(var(--L) - 1px), var(--rule) calc(var(--L) - 1px) var(--L)) 0 calc(var(--L) * var(--band)) / 100% 100% no-repeat,
    var(--paper);
  background-attachment: local;
}
/* Paper texture: the paper's tooth, and on the dark sheet the tooth showing through the graphite as specks and the
   strokes in which the graphite was laid on. They are tokens, so that another sheet (papers.css) can take them up. */
:root {
  --tooth: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .36  0 0 0 0 .34  0 0 0 0 .3  .5 0 0 0 -.2'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  --speckle: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .98  0 0 0 0 .98  0 0 0 0 .95  .5 0 0 0 -.2'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  --streaks: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1600' height='1600'><filter id='s' x='0' y='0' width='100%' height='100%'><feTurbulence type='fractalNoise' baseFrequency='.002 .5' numOctaves='3' seed='7'/><feColorMatrix values='0 0 0 0 .9  0 0 0 0 .9  0 0 0 0 .88  1.6 0 0 0 -.62'/></filter><g transform='rotate(-30 800 800)'><rect x='-800' y='-800' width='3200' height='3200' filter='url(%23s)'/></g></svg>");
}
body::before {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 10;
  background-image: var(--tooth);
  opacity: .4; mix-blend-mode: multiply;
}
/* The column beside the margin line. main keeps it, and so do a header and a footer that stand beside main in the
   body, where a screen reader finds them as the page's banner and footer; a header or footer inside main keeps to
   main's. */
:root { --column-left: calc(var(--margin-x) + 28px); --column-right: 40px; }
main, body > header { max-width: 1280px; padding-left: var(--column-left); padding-right: var(--column-right); }
main { padding-top: calc(var(--L) * 2); padding-bottom: var(--L); }
body > header { padding-top: calc(var(--L) * 2); }
body > header + main { padding-top: 0; }
main:has(+ footer) { padding-bottom: 0; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }
a:focus-visible { outline: 1.5px dashed var(--ink-2); outline-offset: 3px; border-radius: 3px; }
::selection { background: var(--rule); }

/* The hand-lettered title, textured by the #graphite filter that graphite.js writes into the page. */
h1 {
  font: 300 64px/calc(var(--L) * 3) var(--face); margin: 0; height: calc(var(--L) * 3);
  width: fit-content; position: relative; top: calc(var(--sit) + var(--L));
  filter: url(#graphite); transform: rotate(-1deg); transform-origin: 0 100%;
}
h1 a { text-decoration: none; }
/* min-height rather than height, so a wrapped intro grows by whole rules. The intro
   skips one rule to leave room for the title's descenders. */
.intro { margin: 0; min-height: var(--L); color: var(--ink-2); font-size: 22px; position: relative; top: var(--sit); text-wrap: balance; }
header > .intro { margin-top: var(--L); }

/* Footer items wrap as whole items. Each begins with a separator dot in a strip hidden
   to the left of the text, so a wrapped line never begins or ends with a dot. The dot
   has empty alternative text, so that screen readers pass over it; a browser without
   that syntax keeps the first declaration. */
footer { margin: calc(var(--L) * 2) -4px 0; padding: 0 4px; min-height: var(--L); font-size: 15px; color: var(--ink-2); position: relative; top: var(--sit); overflow: hidden; overflow-wrap: anywhere; }  /* The padding leaves room for a focus ring. */
body > footer { margin-left: calc(var(--column-left) - 4px); margin-right: calc(var(--column-right) - 4px); padding-bottom: var(--L);
  max-width: calc(1280px - var(--column-left) - var(--column-right) + 8px); }
footer ul { list-style: none; margin: 0 0 0 -1.4em; padding: 0; display: flex; flex-wrap: wrap; }
footer li { padding-left: 1.4em; text-indent: -1.4em; text-wrap: balance; }  /* A wrapped item indents its second line under its text. */
footer li::before { content: '\b7'; content: '\b7' / ''; display: inline-block; width: 1.4em; text-indent: 0; text-align: center; }
footer a:hover { color: var(--ink); }

@media (max-width: 720px) {
  :root { --L: 30px; --margin-x: 22px; --band: 3; }
  :root { --column-left: calc(var(--margin-x) + 12px); --column-right: 12px; }
  /* The title stays on one line; the smallest phones get a smaller size instead. */
  h1 { font-size: min(54px, 13vw); white-space: nowrap; height: calc(var(--L) * 2); line-height: calc(var(--L) * 2); top: calc(var(--sit) + var(--L) / 2); }
  .intro { min-height: calc(var(--L) * 2); font-size: 18px; line-height: var(--L); }
  header > .intro { margin-top: 0; }  /* The smaller title's descenders clear the next line. */
}
/* Phones in landscape: a shorter header keeps the characters on the first screen. It is
   the phone's header: the title and the intro step down one, and the title's two rules
   give its descenders room, so the intro follows at once. */
@media (max-height: 500px) and (orientation: landscape) {
  :root { --band: 2; }
  main, body > header { padding-top: var(--L); }
  h1 { font-size: 54px; height: calc(var(--L) * 2); line-height: calc(var(--L) * 2); top: calc(var(--sit) + var(--L) / 2); }
  .intro { font-size: 18px; }
  header > .intro { margin-top: 0; }
}

/* The dark sheet (STYLE.md §3). A page that declares both schemes (<meta name="color-scheme" content="light dark">)
   turns to it where the reader's system asks for dark: the paper and the ink swap, and every other ink keeps its
   contrast with the sheet. A page made for paper alone, and any print, stays on paper. */
/* The dark sheet's inks, written by `python3 tools/dark_sheet.py` from the paper's above: edit those and run it. */
@media screen and (prefers-color-scheme: dark) {
  :root:has(meta[name="color-scheme"][content~="dark"]) { --paper: #3d3c39; --rule: #45505a; --margin: #8b5751; --ink: #fbf9f3; --ink-2: #b4b1a9; --ink-3: #86837a; --red: #fe9c8c; --blue-pencil: #66afe8; }
}
/* The end of the dark sheet's inks. */
@media screen and (prefers-color-scheme: dark) and (forced-colors: none) {
  /* The graphite was laid on in strokes rising to the right, and the paper's tooth shows through it in light specks. */
  :root:has(meta[name="color-scheme"][content~="dark"]) body::before { mix-blend-mode: screen; opacity: .22;
    background-image: var(--speckle); }
  :root:has(meta[name="color-scheme"][content~="dark"]) body::after { content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 9; mix-blend-mode: screen; opacity: .07;
    background: var(--streaks) 0 0 / 1600px 1600px; }
}
/* Forced colors are the system's, neither the paper nor the dark sheet, so neither texture (the dark sheet's is kept
   to forced-colors: none above) lies over them. */
@media (forced-colors: active) { body::before { content: none; } }
