/*
  The Moxie Library. Design code (full spec in .design/manifest.json).

  Avoided on purpose: the content-tool look (white canvas, indigo gradient hero,
  rows of stat cards, a calendar of scheduled posts) and the knowledge-tool look
  (a dark graph of floating nodes).

  1. Every piece is an upright slab: round-topped in the ground when nothing she
     wrote links to it, flat-topped on a shelf when something does. Her poster
     says the job is to move her writing from a graveyard to a library, and the
     two objects share a silhouette.
  2. The colours are Moxie-Dude's own, read from her live blog: the turquoise of
     her banner, the charcoal of her type and footer, the white of her page. In
     the morning theme the sky is that turquoise exactly; at dusk it is the same
     hue after sunset. This is a room in a house she already built.
  3. Colour belongs to the three places she publishes, plus one warm lamp colour
     that only ever means "found". Warm, because on a turquoise page it is the
     one thing that cannot be mistaken for the brand.
  4. Everything the software says is set in Raleway, the face her blog speaks in,
     with the wordmark in its heaviest weight like hers. Her own words are set in
     a book face on white, because here her posts are books. You can always tell
     whose sentence it is.
  5. Things arrive with a hop and a settle and are otherwise still, because the
     only event here is a buried piece coming back up. A slab that is pointed at
     answers in a speech bubble, the way the hamster does on her banner.
*/

@font-face {
  font-family: "Raleway";
  src: url("fonts/raleway.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Literata";
  src: url("fonts/literata.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Literata";
  src: url("fonts/literata-italic.woff2") format("woff2");
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}

:root {
  --says: "Raleway", "Trebuchet MS", "Segoe UI", sans-serif;   /* the software's voice: her blog's face */
  --hers: "Literata", Georgia, "Times New Roman", serif;       /* her voice: a book face */

  /* scale: 17px base, ratio 1.25 */
  --t-small: 0.8rem;
  --t-body: 1rem;
  --t-lead: 1.25rem;
  --t-head: 1.563rem;
  --t-mark: 1.953rem;

  --u: 4px;
  --r-book: 3px;
  --r-sheet: 14px;
  --r-round: 999px;
  --edge: 2px;
  --mast: 76px;
  --slab-k: 1;
  --zoom: 1;

  --quick: 160ms;
  --settle: 520ms;
  --spring: linear(0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017, 1.077, 1.121,
    1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%, 1.051 39.6%, 1.017 43.1%, 0.991,
    0.977 51%, 0.974 53.8%, 0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1.004 83.8%, 1);

  /* Her charcoal: type, outlines, the footer of her blog. */
  --ink: #222222;
  --ink-soft: #4A5B5D;
  --line: #222222;

  /* The three outlets as labels on white. Moxie-Dude is her turquoise, darkened to be readable. */
  --moxie-on-paper: #04727A;
  --westmount-on-paper: #B4492F;
  --substack-on-paper: #A63A6E;

  /* The three outlets as slabs standing on the ground, which is dark in both themes. */
  --moxie: #01CDD6;                  /* her banner's turquoise, exactly */
  --westmount: #FF8D6E;
  --substack: #F29BC0;
  --lamp: #FFC65C;
  --lamp-on-paper: #8A5A00;
  --ground-ink: #FFFFFF;
}

/* Dusk is home: her turquoise after sunset, the hour of the poster she made. */
:root[data-theme="dusk"] {
  color-scheme: dark;
  --sky: #066A72;
  --ground: #04484E;
  --ground-dim: #B5E3E6;
  --paper: #F8FDFD;
  --paper-shade: #E3F0F0;
  --chalk: #FFFFFF;
  --chalk-dim: #C9EEF0;
  --stone: #CFE3E4;
  --stone-on-paper: #CFE3E4;
  --focus: #FFC65C;
}

/* Morning is her blog in daylight: turquoise header, white page, charcoal footer. */
:root[data-theme="morning"] {
  color-scheme: light;
  --sky: #01CDD6;
  --ground: #222222;
  --ground-dim: #AAAAAA;
  --paper: #FDFEFE;
  --paper-shade: #E6F3F3;
  --chalk: #222222;
  --chalk-dim: #0E4347;
  --stone: #E9F4F4;
  --stone-on-paper: #D5E6E7;
  --focus: #222222;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html { font-size: 17px; }

body {
  margin: 0;
  min-height: calc(100dvh / var(--zoom));
  background: var(--sky);
  color: var(--chalk);
  font-family: var(--says);
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.45;
  font-variant-numeric: lining-nums tabular-nums;   /* Raleway's default figures are old-style */
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, blockquote { margin: 0; padding: 0; }
ul, ol { list-style: none; }

.visually-hidden, .skip:not(:focus) {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.skip:focus {
  position: fixed; top: 8px; left: 8px; z-index: 10;
  background: var(--paper); color: var(--ink); padding: 10px 14px; border-radius: var(--r-round);
}

:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }

/* ---- masthead ------------------------------------------------------------ */
.mast {
  display: flex; align-items: baseline; gap: calc(var(--u) * 5);
  padding: calc(var(--u) * 5) calc(var(--u) * 8) calc(var(--u) * 3);
  min-height: var(--mast);
}
/* Masthead plus desk plus ground fill the window exactly, so the ground sits
   at the bottom edge whether the desk is empty or full. */
main { display: flex; flex-direction: column; min-height: calc(100dvh / var(--zoom) - var(--mast)); }
main > .desk { flex: 1 0 auto; }

/* Set like the "Moxie-Dude" on her banner: Raleway at its heaviest. */
.wordmark { font-size: var(--t-mark); font-weight: 500; letter-spacing: -0.015em; line-height: 1; }
.wordmark b { font-weight: 900; }
.tally { color: var(--chalk-dim); font-size: var(--t-body); margin-right: auto; }

.sky-switch {
  display: inline-flex; align-items: center; gap: calc(var(--u) * 2);
  min-height: 44px; padding: 0 calc(var(--u) * 4);
  font: 700 var(--t-small)/1 var(--says); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--chalk); background: transparent;
  border: var(--edge) solid var(--chalk-dim); border-radius: var(--r-round);
  cursor: pointer; align-self: center;
}
.sky-switch:hover { border-color: var(--chalk); }
.sky-switch__dot {
  width: 14px; height: 14px; border-radius: 50%; background: var(--lamp); border: 1.5px solid var(--line);
  transition: transform var(--settle) var(--spring);
}
:root[data-theme="morning"] .sky-switch__dot { transform: translateY(-3px) scale(1.15); }

/* ---- the desk ------------------------------------------------------------ */
.desk {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(var(--u) * 8);
  padding: calc(var(--u) * 3) calc(var(--u) * 8) calc(var(--u) * 12);
  align-items: start;
}

.sheet {
  background: var(--paper); color: var(--ink);
  border: var(--edge) solid var(--line); border-radius: var(--r-sheet);
  padding: calc(var(--u) * 5) calc(var(--u) * 6) calc(var(--u) * 4);
  display: flex; flex-direction: column;
  position: sticky; top: calc(var(--u) * 4);
}
.sheet:focus-within { outline: 3px solid var(--focus); outline-offset: 3px; }
.sheet__head { display: flex; align-items: center; justify-content: space-between; min-height: 44px; }
/* Section labels are small capitals in Raleway, the way her navigation is set. */
.sheet__head h2, .colophon h2 {
  font-size: var(--t-small); font-weight: 800; text-transform: uppercase; letter-spacing: 0.09em;
}

#draft {
  width: 100%; height: calc(25vh / var(--zoom)); min-height: 7em; margin-top: var(--u);
  border: 0; outline: 0; resize: vertical; background: transparent; color: var(--ink);
  font: 400 1.06rem/1.65 var(--hers);
}
#draft::placeholder { color: var(--ink-soft); font-style: italic; opacity: 1; }

.starters { border-top: var(--edge) dashed var(--paper-shade); padding-top: calc(var(--u) * 3); margin-top: var(--u); }
.starters__label { display: block; font-size: var(--t-small); color: var(--ink-soft); margin-bottom: calc(var(--u) * 2); }
.starters__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(var(--u) * 2); }

.sheet__foot {
  margin-top: calc(var(--u) * 3); font-size: var(--t-small); color: var(--ink-soft);
  display: flex; align-items: center; gap: calc(var(--u) * 2); min-height: 20px;
}
.sheet__foot::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: var(--paper-shade); border: 1.5px solid var(--ink-soft);
}
.sheet__foot[data-state="ready"]::before { background: var(--lamp); border-color: var(--line); }
.sheet__foot[data-state="busy"]::before { background: var(--lamp); border-color: var(--line); animation: hop 700ms var(--spring) infinite; }
.sheet__foot[data-state="broken"]::before { background: var(--westmount-on-paper); border-color: var(--line); }

/* buttons: chunky, with a ledge that gives when pressed */
.btn, .quiet {
  font: 700 var(--t-small)/1 var(--says); cursor: pointer; color: var(--ink);
  min-height: 44px; padding: 0 calc(var(--u) * 4); border-radius: var(--r-round);
  border: var(--edge) solid var(--line);
  box-shadow: 0 3px 0 var(--line);      /* the ledge: a hard edge, no blur */
  background: var(--paper-shade);
  display: inline-flex; align-items: center; gap: calc(var(--u) * 2); text-decoration: none;
  transition: transform var(--quick) ease-out, box-shadow var(--quick) ease-out;
}
.btn--lamp { background: var(--lamp); }
.btn:hover, .quiet:hover { transform: translateY(-1px); }
.btn:active, .quiet:active { transform: translateY(3px); box-shadow: 0 0 0 var(--line); }
.btn:focus-visible, .quiet:focus-visible, .find a:focus-visible, .seek input:focus-visible { outline-color: var(--lamp-on-paper); }
.quiet { background: transparent; border-color: transparent; box-shadow: none; color: var(--ink-soft); }
.quiet:hover { border-color: var(--ink-soft); }
.btn--starter { font-weight: 600; text-align: left; line-height: 1.2; min-width: 0; padding-inline: calc(var(--u) * 3); }
.btn--starter span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- what the library found ---------------------------------------------- */
.finds__title { font-size: var(--t-head); font-weight: 800; letter-spacing: -0.015em; line-height: 1.1; min-height: 44px; display: flex; align-items: center; }
.finds__note { color: var(--chalk-dim); max-width: 56ch; margin-top: var(--u); }
.finds__note:empty { display: none; }
.finds__list { display: grid; gap: calc(var(--u) * 5); margin-top: calc(var(--u) * 5); }

.find {
  background: var(--paper); color: var(--ink);
  border: var(--edge) solid var(--line); border-radius: var(--r-sheet);
  padding: calc(var(--u) * 4) calc(var(--u) * 5) calc(var(--u) * 4);
  display: grid; grid-template-columns: 30px minmax(0, 1fr); column-gap: calc(var(--u) * 4);
  animation: arrive var(--settle) var(--spring) both;
  animation-delay: calc(var(--n, 0) * 70ms);
  transform-origin: 20px 100%;
}
/* The slab keeps the left column to itself however many rows the card has. */
.find > :not(.find__slab) { grid-column: 2; }
.find__slab {
  grid-column: 1; grid-row: 1 / span 6; align-self: start; width: 30px; height: 46px;
  background: var(--c); border: var(--edge) solid var(--line);
  border-radius: var(--r-book);
}
.find--tomb .find__slab { border-radius: 15px 15px var(--r-book) var(--r-book); background: var(--stone-on-paper); box-shadow: inset 0 -8px 0 var(--c); }

.find__meta { font-size: var(--t-small); color: var(--ink-soft); font-weight: 600; }
.find__meta b { color: var(--c); font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; }
.find__title { font-size: var(--t-lead); font-weight: 800; letter-spacing: -0.01em; line-height: 1.18; margin: 3px 0 calc(var(--u) * 2); }
.find__title a { color: inherit; text-decoration-thickness: 2px; text-underline-offset: 3px; text-decoration-color: var(--c); }
.find__hers {
  font: 400 1rem/1.6 var(--hers);
  border-left: 4px solid var(--c); padding-left: calc(var(--u) * 3);
  max-height: 9.6em; overflow: hidden; position: relative;
}
.find__hers p + p { margin-top: 0.5em; }
.find__hers[data-open="true"] { max-height: none; }
.find__hers:not([data-open="true"])[data-long="true"]::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 2.4em;
  background: linear-gradient(to bottom, transparent, var(--paper));
}
.find__state { font-size: var(--t-small); color: var(--ink-soft); margin-top: calc(var(--u) * 2); }
.find__state b { color: var(--ink); font-weight: 800; }
.find__acts { display: flex; flex-wrap: wrap; gap: calc(var(--u) * 2); margin-top: calc(var(--u) * 3); align-items: center; }
.find__why { font-size: var(--t-small); color: var(--ink-soft); margin-left: auto; max-width: 30ch; text-align: right; }

/* her pull line on an opened slab: her words, so her face */
.find__line { font: italic 500 1.18rem/1.4 var(--hers); margin: 0 0 calc(var(--u) * 3); }
.find__line::before { content: "\201C"; }
.find__line::after { content: "\201D"; }

.find--same { border-style: dashed; }

@keyframes arrive {
  from { opacity: 0; transform: translateY(26px) scale(0.94, 0.9); }
  to { opacity: 1; transform: none; }
}
@keyframes hop {
  0% { transform: translateY(0) scale(1, 1); }
  30% { transform: translateY(-7px) scale(0.9, 1.18); }
  60% { transform: translateY(0) scale(1.15, 0.85); }
  100% { transform: translateY(0) scale(1, 1); }
}

/* ---- the ground: sixteen years of slabs ----------------------------------
   Always at the bottom of the window, the way the ground is, so the slab that
   matches is seen lifting at the moment its card lands. Dark in both themes:
   teal earth at dusk, and in the morning the charcoal of her blog's footer. */
.ground {
  position: sticky; bottom: 0; z-index: 3;
  background: var(--ground); color: var(--ground-ink); border-top: var(--edge) solid var(--line);
  padding: calc(var(--u) * 3) calc(var(--u) * 8) calc(var(--u) * 2);
}
.ground__head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--u) calc(var(--u) * 7); align-items: center;
}
.ground__head h2 { font-size: 1.18rem; font-weight: 800; letter-spacing: -0.015em; line-height: 1.15; }
.ground__head h2 span { color: var(--lamp); }
.legend, .outlets { display: flex; flex-wrap: wrap; gap: var(--u) calc(var(--u) * 4); font-size: var(--t-small); color: var(--ground-dim); }
.legend li, .outlets li { display: flex; align-items: end; gap: 6px; }
.outlets li { align-items: center; }
.outlets i { width: 11px; height: 11px; border-radius: 2px; background: var(--c); }
.outlets b { color: var(--ground-ink); font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; font-size: 0.72rem; }

/* find a piece by title: the keyboard's way into the ground */
.seek { position: relative; justify-self: end; }
.seek input {
  width: 15.5rem; height: 34px; padding: 0 calc(var(--u) * 3);
  font: 600 var(--t-small)/1 var(--says); color: var(--ink);
  background: var(--paper); border: var(--edge) solid var(--line); border-radius: var(--r-round);
}
.seek input::placeholder { color: var(--ink-soft); opacity: 1; }
.seek__list {
  position: absolute; right: 0; bottom: calc(100% + 6px); width: 24rem; max-width: 90vw; z-index: 4;
  background: var(--paper); color: var(--ink); border: var(--edge) solid var(--line);
  border-radius: var(--r-sheet); padding: var(--u); display: grid; gap: 2px;
}
.pick {
  display: block; width: 100%; text-align: left; cursor: pointer;
  font: 500 var(--t-small)/1.3 var(--says); color: var(--ink-soft);
  background: transparent; border: 0; border-radius: 10px; padding: 7px 10px;
}
.pick b { display: block; color: var(--ink); font-weight: 800; }
button.pick:hover, button.pick:focus-visible { background: var(--paper-shade); outline-offset: -2px; outline-color: var(--lamp-on-paper); }
.pick--none { cursor: default; }

.plots {
  display: flex; align-items: end; gap: calc(var(--u) * 2);
  margin-top: calc(var(--u) * 3); overflow-x: auto; scrollbar-width: thin;
}
.year { flex: none; }
.year__plot {
  display: grid; grid-auto-flow: column; grid-template-rows: repeat(5, calc(18px * var(--slab-k)));
  gap: 3px calc(2px * var(--slab-k)); align-items: end;
  border-bottom: var(--edge) solid var(--ground-dim); padding-bottom: 1px;
}
.year__label { display: block; font-size: 0.7rem; font-weight: 600; color: var(--ground-dim); margin-top: 2px; letter-spacing: 0.03em; }

.slab {
  display: block; width: calc(5px * var(--slab-k)); height: calc(var(--h, 12) * 1px * var(--slab-k));
  background: var(--c, var(--stone)); border-radius: 1px;
  transform-origin: 50% 100%;
}
.slab--tomb { background: var(--stone); border-radius: calc(3px * var(--slab-k)) calc(3px * var(--slab-k)) 0 0; }
.slab--lit { background: var(--lamp); outline: 1.5px solid var(--line); animation: hop var(--settle) var(--spring) both; position: relative; z-index: 1; }
.slab--key { width: 8px; height: 14px; flex: none; --slab-k: 1; }
.slab--key.slab--tomb { border-radius: 4px 4px 0 0; }
.slab--key.slab--book { background: var(--moxie); }
.plots .slab { cursor: pointer; }
.plots .slab:hover { outline: 1.5px solid var(--ground-ink); }

/* A slab that is pointed at answers in a speech bubble, like the hamster on her banner. */
.tip {
  position: fixed; z-index: 5; pointer-events: none; max-width: 300px;
  background: var(--paper); color: var(--ink); border: var(--edge) solid var(--line);
  border-radius: 16px; padding: 8px 12px; font-size: var(--t-small); line-height: 1.3;
}
.tip::after {
  content: ""; position: absolute; left: var(--tail, 24px); bottom: -8px; width: 13px; height: 13px;
  background: var(--paper); border-right: var(--edge) solid var(--line); border-bottom: var(--edge) solid var(--line);
  transform: translateX(-50%) rotate(45deg);
}
.tip b { display: block; font-weight: 800; }
.tip q { display: block; margin-top: 4px; font: italic 400 0.86rem/1.35 var(--hers); }

/* ---- colophon ------------------------------------------------------------ */
.colophon {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(var(--u) * 8);
  background: var(--sky); border-top: var(--edge) solid var(--line); padding: calc(var(--u) * 8) calc(var(--u) * 8) calc(var(--u) * 12);
  color: var(--chalk-dim); font-size: 0.92rem;
}
.colophon h2 { color: var(--chalk); margin-bottom: calc(var(--u) * 2); }
.colophon b { color: var(--chalk); font-weight: 800; }
.colophon__credit { grid-column: 1 / -1; border-top: var(--edge) solid var(--chalk-dim); padding-top: calc(var(--u) * 4); max-width: 90ch; }
.colophon a { color: var(--chalk); font-weight: 700; text-underline-offset: 3px; }

/* ---- small screens ------------------------------------------------------- */
@media (max-width: 920px) {
  .mast { flex-wrap: wrap; padding-inline: calc(var(--u) * 4); }
  .desk { grid-template-columns: minmax(0, 1fr); padding-inline: calc(var(--u) * 4); }
  .sheet { position: static; }
  .starters__row { grid-template-columns: minmax(0, 1fr); }
  .ground { position: static; }
  .ground__head { grid-template-columns: minmax(0, 1fr); }
  .seek { justify-self: stretch; }
  .seek input { width: 100%; }
  .seek__list { left: 0; right: auto; }
  .ground, .colophon { padding-inline: calc(var(--u) * 4); }
  .colophon { grid-template-columns: minmax(0, 1fr); gap: calc(var(--u) * 5); }
  .find__why { margin-left: 0; text-align: left; }
}

/* A big monitor, or a 1080p recording: the same picture, drawn one and a half
   times larger. Viewport units are divided by the zoom so the ground still
   lands on the bottom edge. */
@media (min-width: 1700px) and (min-height: 950px) {
  :root { --zoom: 1.5; }
  body { zoom: 1.5; }
}

@media (max-height: 600px) { .ground { position: static; } .sheet { position: static; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
