/* Every knob lives in this one block. The canvas colours (guides, ink) are read
   from these same properties by app.js, so the page and the drawing stay in step. */
:root {
  color-scheme: light;

  /* Paper and ink. Light only for now: a practice sheet is meant to look like paper. */
  --paper: #fbf8f1;
  --paper-sunk: #f2ede1;
  --ink: #1d1f22;
  --ink-soft: #4b5058;
  --ink-faint: #868c94;
  --rule: #e2dccd;
  --accent: #1f3a5f;
  --accent-ink: #fff;

  /* Canvas colours. */
  --guide-strong: #9fb4cf;
  --guide-faint: #d6dfeb;
  --model-ink: #2a2c30;
  --pen-ink: #14213d;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* --ref-font is set by the generated font.css from FONT_FAMILY. */

  --text: clamp(1rem, 0.95rem + 0.2vw, 1.1rem);
  --title-page: clamp(1.6rem, 1.3rem + 1.5vw, 2.4rem);

  --gap-xs: 0.35rem;
  --gap-sm: 0.7rem;
  --gap-md: 1.2rem;
  --gap-lg: 2rem;

  --radius: 8px;
  --measure: 62ch;
  --page: 1100px;
  --tap: 44px; /* minimum touch target */
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  font: var(--text)/1.5 var(--font);
  color: var(--ink);
  background: var(--paper);
}

.inner {
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: max(var(--gap-md), env(safe-area-inset-left));
}

h1 {
  font-size: var(--title-page);
  line-height: 1.15;
  text-wrap: balance;
  margin: var(--gap-lg) 0 var(--gap-sm);
}

p { max-width: var(--measure); }
.lede { color: var(--ink-soft); margin-top: 0; }

a { color: var(--accent); }

.site-header {
  border-bottom: 1px solid var(--rule);
  background: var(--paper-sunk);

  .inner { display: flex; align-items: center; min-height: 3.25rem; }
}

.site-header .inner { justify-content: space-between; }

.site-nav {
  display: flex;
  gap: var(--gap-md);

  a {
    color: var(--ink-soft);
    text-decoration: none;
    padding-block: var(--gap-xs);

    &:hover { color: var(--accent); }
  }
}

.site-nav { align-items: center; }

/* The GitHub mark (Octicons, MIT), drawn in the text colour. */
.site-nav .repo {
  display: inline-flex;
  padding: var(--gap-xs);
  border-radius: var(--radius);

  svg { display: block; }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.brand {
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
}

/* ---- Worksheet list ---------------------------------------------------- */

.sheet-list {
  list-style: none;
  margin: var(--gap-md) 0 var(--gap-lg);
  padding: 0;
  display: grid;
  gap: var(--gap-sm);
  grid-template-columns: repeat(auto-fill, minmax(clamp(14rem, 40vw, 20rem), 1fr));

  a {
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
    padding: var(--gap-md);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: #fff;
    color: inherit;
    text-decoration: none;

    &:hover { border-color: var(--guide-strong); }
    &:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  }
}

.sheet-title { font-weight: 600; }

.sheet-section {
  margin: var(--gap-lg) 0 0;
  font-size: 1.1rem;
  color: var(--ink-soft);
}

.sheet-sample {
  font-family: var(--ref-font), cursive;
  font-size: 1.4rem;
  color: var(--ink-soft);
}

/* ---- Toolbar ------------------------------------------------------------- */

.toolbar {
  position: sticky;
  top: 0;
  z-index: 1;
  background: color-mix(in oklab, var(--paper-sunk), transparent 6%);
  border-bottom: 1px solid var(--rule);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  user-select: none;
  -webkit-user-select: none;
}

.toolbar-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-sm) var(--gap-md);
  padding-block: var(--gap-sm);
}

/* Visually hidden but still announced. */
legend, .preview figcaption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Picture buttons for the model font and the pen: a drawing of the thing,
   with its name underneath. The radio itself is hidden; the tile is the target. */
.tiles {
  display: inline-flex;
  gap: var(--gap-xs);
  margin: 0;
  padding: 0;
  border: 0;
}

.tile {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  min-width: 4.75rem;
  min-height: 3.75rem;
  padding: var(--gap-xs) var(--gap-sm);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
  touch-action: manipulation;

  input { position: absolute; opacity: 0; pointer-events: none; }

  &:has(:checked) {
    border-color: var(--accent);
    background: color-mix(in oklab, #fff, var(--accent) 10%);
    color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
  }
  &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
}

.tile-art {
  width: 1.9rem;
  height: 1.9rem;
}

span.tile-art {
  width: auto;
  font-size: 1.6rem;
  line-height: 1.9rem;
  color: var(--ink);
}

.tile-label { font-size: 0.8rem; line-height: 1.1; }

/* A live sample of the current pen, drawn by app.js. */
.preview {
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;

  canvas { display: block; }
}

.sliders {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-xs) var(--gap-md);
}

.slider {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  min-height: var(--tap);
  color: var(--ink-soft);
  font-size: 0.9rem;

  &[hidden] { display: none; }

  input[type="range"] { width: 6rem; accent-color: var(--accent); }
  /* The nib slider's value counts nib widths per x-height, so fewer means a
     wider nib; reversing it puts the wide end on the right like the others. */
  input.reversed { direction: rtl; }
  output { min-width: 3.5ch; font-variant-numeric: tabular-nums; }
}

.slider-name { min-width: 2.6rem; }

.slider-end {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  color: var(--ink-soft);
  text-align: center;
}

.size-small, .size-large {
  font-family: var(--ref-font);
  line-height: 1;
}
.size-small { font-size: 0.85rem; }
.size-large { font-size: 1.6rem; }

.toggle {
  display: inline-grid;
  justify-items: center;
  gap: 2px;
  min-width: 4.75rem;
  min-height: 3.75rem;
  align-content: center;
  padding: var(--gap-xs) var(--gap-sm);
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
  font-size: 0.8rem;
  color: var(--ink-soft);
  cursor: pointer;
  touch-action: manipulation;

  input { position: absolute; opacity: 0; pointer-events: none; }
  svg { width: 1.6rem; height: 1.6rem; }

  &:has(:checked) {
    border-style: solid;
    border-color: var(--accent);
    color: var(--accent);
    background: color-mix(in oklab, #fff, var(--accent) 10%);
  }
  &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
}

/* ---- Writing area -------------------------------------------------------
   Everything below the toolbar. The hand rests here while writing, so the
   browser's own touch handling is switched off: no selection, no callout,
   no native panning. web/pen.ts scrolls for a finger and ignores palms. */

.writing-area {
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* ---- Practice rows ------------------------------------------------------- */

.rows {
  list-style: none;
  margin: var(--gap-md) 0;
  padding: 0;
  display: grid;
  gap: var(--gap-lg);
}

.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* The model sits directly above the practice line and is exactly as wide,
     so the two compare letter for letter, and so both canvases are laid out
     for the same width. */
  grid-template-areas:
    "ref      ."
    "practice actions"
    "result   result";
  gap: var(--gap-xs) var(--gap-sm);
  align-items: start;
}

.band {
  position: relative;
  border-radius: var(--radius);
  /* app.js sets the height from the x-height; this is the pre-script size. */
  min-height: 6rem;

  overflow: hidden;

  /* app.js sets the canvas's CSS size to exactly its backing store / dpr, so
     a layout mismatch can only clip, never stretch the ink away from the pen. */
  canvas { display: block; }
}

.reference {
  grid-area: ref;

  canvas { position: absolute; inset: 0; }
}

/* The model is drawn on the canvas so it can sit exactly on the guides. The
   text stays in the page for screen readers, and is shown as a fallback
   until the script has drawn it. */
.model {
  margin: 0;
  padding: 1.5rem var(--gap-sm);
  font: 2.5rem/1 var(--ref-font), cursive;
  color: var(--model-ink);
  max-width: none;
}

.js-ready .model {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.practice {
  grid-area: practice;
  background: #fff;
  box-shadow: 0 0 0 1px var(--rule);

  canvas {
    /* The Pencil must never scroll, zoom, select or magnify. Fingers scroll
       the page from script instead (see web/pen.ts). */
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
  }
}

.row-actions {
  grid-area: actions;
  /* A fixed width, so "Check again" doesn't make one line narrower than the rest. */
  width: 10.5rem;

  button { white-space: nowrap; }
  display: flex;
  flex-direction: column;
  gap: var(--gap-xs);
}

button {
  min-height: var(--tap);
  min-width: 4.5rem;
  padding: 0 var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-size: 0.95rem;
  cursor: pointer;
  touch-action: manipulation;

  &:hover:not(:disabled) { background: color-mix(in oklab, #fff, var(--accent) 8%); }
  &:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  &:disabled { color: var(--ink-faint); cursor: default; }
}

/* On a narrow screen the buttons go under the line, so the practice band keeps
   the full width. */
@media (max-width: 600px) {
  /* On a phone the toolbar would cover a third of the screen if it stuck. */
  .toolbar { position: static; }
  .row {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "ref" "practice" "actions" "result";
  }
  .row-actions { flex-direction: row; justify-content: flex-end; width: auto; }
  .slider input[type="range"] { width: 5.5rem; }
}

.back {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-md);
  margin-block: var(--gap-lg);

  form { margin: 0; }
}

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

/* ---- Your own text ------------------------------------------------------- */

.sheet-list .own a {
  border-style: dashed;
  background: transparent;
}

.custom-form {
  display: grid;
  gap: var(--gap-sm);
  max-width: var(--measure);
  margin-bottom: var(--gap-lg);

  label { font-weight: 600; }

  textarea {
    width: 100%;
    min-height: 12rem;
    padding: var(--gap-sm);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: #fff;
    color: var(--ink);
    font: 1.5rem/1.4 var(--ref-font);
    resize: vertical;

    &:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
  }

  .hint { margin: 0; font-size: 0.9rem; color: var(--ink-soft); }
  .error { margin: 0; color: #9b2c2c; font-weight: 600; }
}

.form-actions {
  display: flex;
  align-items: center;
  gap: var(--gap-md);
}

button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);

  &:hover:not(:disabled) { background: color-mix(in oklab, var(--accent), black 12%); }
}

/* ---- Model picker -------------------------------------------------------- */

.models {
  padding-top: var(--gap-md);

  h2 {
    margin: 0 0 var(--gap-xs);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-soft);
  }
}

.family-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-xs);

  .tile {
    min-width: 6.5rem;
    max-width: 9rem;
    text-align: center;
  }
}

/* The selected family's variants: the real font name, written in that font,
   with a plain note underneath. Script hides the other families' chips. */
.variant-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-xs);
  margin-top: var(--gap-sm);

  &:not(:has(.chip:not([hidden]))) { margin-top: 0; }
}

.chip {
  display: grid;
  gap: 1px;
  min-height: var(--tap);
  padding: var(--gap-xs) var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
  touch-action: manipulation;

  &[hidden] { display: none; }

  input { position: absolute; opacity: 0; pointer-events: none; }

  &:has(:checked) {
    border-color: var(--accent);
    background: color-mix(in oklab, #fff, var(--accent) 10%);
    color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
  }
  &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
}

/* Room below the name for deep descenders (Playwrite's y and g). */
.chip-name { font-size: 1.15rem; line-height: 1.8; color: var(--ink); }
.chip-note { font-size: 0.75rem; line-height: 1.1; }

.custom-model { position: absolute; opacity: 0; pointer-events: none; }

.custom-art { font-family: var(--font); }

.custom-font {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-sm) var(--gap-md);
  margin-top: var(--gap-sm);
  padding: var(--gap-sm) var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;

  &[hidden] { display: none; }

  .field {
    display: inline-flex;
    align-items: center;
    gap: var(--gap-xs);
    min-height: var(--tap);
    color: var(--ink-soft);
    font-size: 0.9rem;
  }

  input[type="text"] {
    width: 13rem;
    min-height: var(--tap);
    padding: 0 var(--gap-sm);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    font: inherit;
    font-size: 1rem;
    color: var(--ink);

    &:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
  }
}

.custom-status {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.9rem;
  color: var(--ink-soft);

  &:empty { display: none; }
  &.error { color: #9b2c2c; }
}

/* ---- Check my writing ---------------------------------------------------- */

.check-result {
  grid-area: result;
  display: grid;
  gap: var(--gap-xs);
  padding: var(--gap-sm) var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;

  &[hidden] { display: none; }
}

.result-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-md);
}

.result-score {
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
}

.result-toggle { min-width: 0; font-size: 0.85rem; }

.result-letters {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.letter {
  display: grid;
  justify-items: center;
  min-width: 2.6rem;
  padding: 2px 6px;
  border-radius: 6px;
  border: 1px solid currentColor;

  .letter-char { font-family: var(--ref-font); font-size: 1.3rem; line-height: 1.2; color: var(--ink); }
  .letter-score { font-size: 0.75rem; font-variant-numeric: tabular-nums; }
}

/* Score bands. The same three colours mark the ink on the canvas
   (deviationColors in web/evaluate.ts). */
.good { color: #2e8540; }
.fair { color: #a86d00; }
.poor, .missing { color: #c0392b; }
.letter.missing { border-style: dashed; }

.result-notes {
  margin: 0;
  padding-left: 1.2rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.check-all {
  display: grid;
  justify-items: start;
  gap: var(--gap-md);
  margin-block: var(--gap-lg);
}

.sheet-summary {
  width: 100%;
  padding: var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;

  &[hidden] { display: none; }

  h2 { margin: 0 0 var(--gap-xs); font-size: 1.1rem; }
  p { margin: var(--gap-xs) 0; }
  ul { margin: var(--gap-xs) 0 0; padding-left: 1.2rem; color: var(--ink-soft); }
}

/* ---- Progress ------------------------------------------------------------ */

.progress { padding-bottom: var(--gap-lg); }

.progress-empty {
  padding: var(--gap-md);
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
  background: #fff;
}

/* The time range: one row, above everything it filters. */
.range {
  display: inline-flex;
  margin: 0 0 var(--gap-md);
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;

  label {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    padding-inline: var(--gap-md);
    cursor: pointer;
    touch-action: manipulation;

    + label { border-left: 1px solid var(--rule); }
    &:has(:checked) { background: var(--accent); color: var(--accent-ink); }
    &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: -4px; }
  }

  input { position: absolute; opacity: 0; pointer-events: none; }
}

.stat-tiles {
  display: grid;
  gap: var(--gap-sm);
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  margin-bottom: var(--gap-md);
}

.stat-tile {
  display: grid;
  gap: 2px;
  padding: var(--gap-sm) var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;
}

.stat-label { font-size: 0.85rem; color: var(--ink-soft); }
.stat-value { font-size: 1.8rem; font-weight: 600; line-height: 1.2; }
.stat-delta { font-size: 0.8rem; }
.stat-delta.up { color: #006300; }
.stat-delta.down { color: #b3261e; }

.chart-card {
  margin-bottom: var(--gap-md);
  padding: var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;

  h2 { margin: 0; font-size: 1.15rem; }
}

.chart-sub {
  margin: var(--gap-xs) 0 var(--gap-sm);
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* A fixed height that includes the axes, so labels are never cut off. */
.chart-box {
  position: relative;
  height: 260px;
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-md);
  margin: 0 0 var(--gap-xs);
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
  color: var(--ink-soft);

  li { display: inline-flex; align-items: center; gap: 6px; }
}

/* Legend keys mirror the marks: a short line for the line, a dot for the dots. */
.key { display: inline-block; }
.key-line { width: 18px; height: 2px; border-radius: 1px; background: #2a78d6; }
.key-dot { width: 8px; height: 8px; border-radius: 50%; background: #b9b7ae; }

.chart-card details {
  margin-top: var(--gap-sm);

  summary { cursor: pointer; color: var(--accent); font-size: 0.9rem; }
}

.data-table {
  width: 100%;
  margin-top: var(--gap-sm);
  border-collapse: collapse;
  font-size: 0.9rem;

  th, td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--rule);
    text-align: right;
    font-variant-numeric: tabular-nums;
  }
  th:first-child, thead th:first-child { text-align: left; }
  thead th { color: var(--ink-soft); font-weight: 600; }
  tbody th { font-weight: 400; }
}

/* Wide tables scroll inside their card, never the page. */
.chart-card:has(.data-table) { overflow-x: auto; }

.history-tools {
  margin-top: var(--gap-lg);

  h2 { font-size: 1.15rem; margin-bottom: var(--gap-xs); }
  p { color: var(--ink-soft); }
}

.history-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-sm);
}

.button-like {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--gap-md);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: #fff;
  font-size: 0.95rem;
  cursor: pointer;

  input { position: absolute; opacity: 0; width: 1px; height: 1px; }
  &:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
}

.history-status {
  margin-top: var(--gap-sm);
  font-size: 0.9rem;

  &:empty { display: none; }
  &.error { color: #b3261e; }
}

/* ---- Icon buttons -------------------------------------------------------- */

/* Line icons drawn in the text colour, so disabled and hover states follow it. */
.icon-button svg, .tool-button svg {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.history-buttons { display: inline-flex; gap: var(--gap-xs); }

/* Undo and redo match the picture tiles beside them: icon above, word below. */
.tool-button {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  min-width: 4.25rem;
  min-height: 3.75rem;
  padding: var(--gap-xs) var(--gap-sm);
  font-size: 0.8rem;
  color: var(--ink-soft);

  svg { width: 1.6rem; height: 1.6rem; }
  &:not(:disabled) { color: var(--ink); }
}
