/*
 *  Copyright 2026 Groundwork contributors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/* Groundwork—one stylesheet, no framework. Plan 3 adds the runner's own styling. */

:root {
  color-scheme: light;
  --paper:   #fbfaf7;
  --ink:     #1f1d1a;
  --soft:    #6b6560;
  --rule:    #e3ded5;
  --panel:   #f4f1ea;
  --code-bg: #f6f4ef;
  --accent:  #1f6f4a;
  --warn:    #8a5a10;
  --warn-bg: #fdf4e3;
  --measure: 38rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --paper:   #16181a;
    --ink:     #e6e3de;
    --soft:    #9a968f;
    --rule:    #2c3033;
    --panel:   #1d2023;
    --code-bg: #1b1e21;
    --accent:  #4bbd85;
    --warn:    #e0b062;
    --warn-bg: #2a2317;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 1.0625rem/1.65 "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  -webkit-text-size-adjust: 100%;
}

code, pre, textarea {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
}

.top {
  position: sticky;
  top: 0;
  display: flex;
  gap: 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.7rem 1.25rem;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}

.home {
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--soft);
  text-decoration: none;
}

.top .volume {
  font-size: 0.8rem;
  color: var(--soft);
}

main {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2.5rem 1.25rem 4rem;
}

.part {
  margin: 0 0 0.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--soft);
}

h1, h2 {
  font-size: 1.85rem;
  line-height: 1.2;
  font-weight: 600;
  margin: 0 0 1.5rem;
  letter-spacing: -0.01em;
}

h3 {
  margin: 2.5rem 0 0.75rem;
  font-size: 1.15rem;
  font-weight: 600;
}

p { margin: 0 0 1.1rem; }
strong { font-weight: 600; }

p code, li code, td code, h3 code {
  /* A run of spaces in code is part of it ("Feature:  The Quiet Harbor"); long code still wraps. */
  white-space: pre-wrap;
  padding: 0.1em 0.35em;
  font-size: 0.86em;
  background: var(--code-bg);
  border-radius: 0.25rem;
}

ol, ul { margin: 0 0 1.1rem; padding-left: 1.5rem; }
li { margin-bottom: 0.4rem; }

blockquote {
  margin: 1.5rem 0;
  padding-left: 1rem;
  border-left: 2px solid var(--accent);
  color: var(--soft);
}

table {
  width: 100%;
  margin: 0 0 1.5rem;
  border-collapse: collapse;
  font-family: inherit;
  font-size: 0.94rem;
}
th, td {
  padding: 0.45rem 0.6rem;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
th { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--soft); }

/* A why-note precedes the box it exempts, so it reads as part of the same aside. */
.note {
  margin: 1.5rem 0 -1rem;
  padding: 0.6rem 0.9rem;
  font-size: 0.88rem;
  color: var(--warn);
  background: var(--warn-bg);
  border-radius: 0.5rem 0.5rem 0 0;
}

.box {
  margin: 1.5rem 0 1.75rem;
  border: 1px solid var(--rule);
  border-radius: 0.6rem;
  background: var(--code-bg);
  overflow: hidden;
}

.box .code {
  display: block;
  width: 100%;
  padding: 0.9rem;
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--ink);
  background: transparent;
  border: 0;
  resize: vertical;
  tab-size: 4;
  /* A code line never wraps: it stays the line javac and a stack trace name, and scrolls inside the box. */
  white-space: pre;
  overflow-x: auto;
}

.box .output {
  margin: 0;
  padding: 0.9rem;
  font-size: 0.84rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
  color: var(--soft);
  background: var(--panel);
  border-top: 1px solid var(--rule);
}

/* Run, End input and Reset under the code (web/page/box.js). */
.box .controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.5rem 0.9rem;
  border-top: 1px solid var(--rule);
}
.box .controls button {
  padding: 0.3rem 0.9rem;
  font: inherit;
  font-size: 0.86rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 0.4rem;
  cursor: pointer;
}
.box .controls button:first-child {
  color: var(--paper);
  background: var(--accent);
  border-color: var(--accent);
}

/* An exercise whose answers cannot be judged fairly has no Check, and says so right under its controls, where Check
   would be (DESIGN section 3; build/Pages.java writes it, web/page/box.js keeps it there). */
.box p.nocheck {
  margin: 0;
  padding: 0.5rem 0.9rem 0.7rem;
  font-size: 0.86rem;
  color: var(--soft);
  border-top: 1px solid var(--rule);
}

/* What a Run printed. Output may wrap (Ruling 22); only code never does. */
.box .run {
  margin: 0;
  padding: 0.9rem;
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.84rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--ink);
  background: var(--panel);
  border-top: 1px solid var(--rule);
}
.box .run:empty { padding: 0; border-top: 0; } /* kept in the page, so a screen reader hears its first words */
.box .run .err { color: var(--warn); }
/* A compile error never wraps, so its caret stays under its character: it scrolls inside the box, as code does. */
.box .run .javac {
  display: block;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}
/* The reader's own words, as typed. */
.box .run .typed { color: var(--accent); font-weight: 600; }
/* web/page/box.js widens it to the rest of the prompt's line. */
.box .run input.answer {
  display: inline-block;
  width: 8ch;
  max-width: 100%;
  margin: 0;
  padding: 0 0.2rem;
  font: inherit;
  color: var(--accent);
  background: var(--paper);
  border: 0;
  border-bottom: 1px solid var(--accent);
}
.box .run p.status {
  margin: 0.6rem 0 0;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 0.88rem;
  white-space: normal;
  color: var(--soft);
}

/* A syntax reminder, not a program: code with nothing to run. */
pre.reference {
  margin: 0;
  padding: 0.9rem;
  font-size: 0.86rem;
  line-height: 1.55;
  white-space: pre;
  overflow-x: auto;
  color: var(--ink);
}

pre:not(.output):not(.reference) {
  margin: 0 0 1.5rem;
  padding: 0.9rem;
  font-size: 0.86rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
  background: var(--panel);
  border-radius: 0.4rem;
}

/* Check (web/page/box.js). After the rule above, so its pre rules win the tie. */
.box pre.predict-code {
  margin: 0;
  padding: 0.9rem;
  font-size: 0.86rem;
  line-height: 1.55;
  white-space: pre;
  overflow-x: auto;
  color: var(--ink);
  background: transparent;
  border-radius: 0;
}
.box label.predict {
  display: block;
  padding: 0.6rem 0.9rem 0.3rem;
  font-size: 0.88rem;
  color: var(--soft);
  border-top: 1px solid var(--rule);
}
.box textarea.prediction {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.5rem;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 0.4rem;
  resize: vertical;
  white-space: pre;
  overflow-x: auto;
}
.box .verdict {
  padding: 0.7rem 0.9rem;
  font-size: 0.9rem;
  background: var(--paper);
  border-top: 1px solid var(--rule);
}
.box .verdict p.summary {
  margin: 0;
  font-weight: 600;
  /* The first difference is two lines, what it is and what it should be, and a line quoted from the program keeps every
     space and wraps inside the box. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A check of the program's output quotes its lines, so the whole summary is monospace and a missing space shows. */
.box .verdict p.summary.quoted {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.84rem;
}
.box .verdict pre {
  margin: 0.5rem 0 0;
  padding: 0.7rem;
  font-size: 0.84rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  border-radius: 0.4rem;
}
/* A compile error never wraps (its caret stays under its character): it scrolls, as code does. */
.box .verdict pre.err { color: var(--warn); background: var(--panel); white-space: pre; overflow-wrap: normal; overflow-x: auto; }
.box .verdict ul {
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
}
.box .verdict li {
  position: relative;
  margin: 0 0 0.3rem;
  padding-left: 1.3rem;
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.84rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A marker drawn here, not an emoji: a filled dot for a pass, a hollow square for a failure. */
.box .verdict li::before {
  content: "";
  position: absolute;
  left: 0.2rem;
  top: 0.45em;
  width: 0.6em;
  height: 0.6em;
  box-sizing: border-box;
}
.box .verdict li.pass::before { background: var(--accent); border-radius: 50%; }
.box .verdict li.fail::before { border: 2px solid var(--warn); }
.box .verdict li.fail { color: var(--warn); }
/* What a method exercise should do (build/Pages.java): its cases, quietly, under the code. A long case wraps. */
.box .cases {
  padding: 0.6rem 0.9rem;
  font-size: 0.88rem;
  color: var(--soft);
  border-top: 1px solid var(--rule);
}
.box .cases p { margin: 0 0 0.3rem; }
.box .cases ul { margin: 0; padding-left: 1.2rem; }
.box .cases li { margin: 0 0 0.15rem; }
.box .cases code {
  padding: 0;
  font-size: 0.84rem;
  background: none;
  overflow-wrap: anywhere;
}

/* A worked solution (build/Pages.java): last in its box, shut until the reader opens it, one box at a time (DESIGN
   section 6). Its code never wraps, as code never does, and scrolls inside it; its note reads as prose. After the pre
   rule above, so its pre rule wins the tie. */
.box .solution {
  border-top: 1px solid var(--rule);
  background: var(--paper);
}
.box .solution summary {
  padding: 0.5rem 0.9rem;
  font-size: 0.86rem;
  color: var(--soft);
  cursor: pointer;
}
.box .solution summary:hover { color: var(--accent); }
.box .solution pre {
  margin: 0;
  padding: 0 0.9rem 0.9rem;
  font-size: 0.86rem;
  line-height: 1.55;
  white-space: pre;
  overflow-x: auto;
  color: var(--ink);
  background: transparent;
  border-radius: 0;
}
.box .solution p {
  margin: 0;
  padding: 0 0.9rem 0.8rem;
  font-size: 0.88rem;
  color: var(--soft);
}

.pager {
  max-width: var(--measure);
  margin: 0 auto 4rem;
  padding: 1.5rem 1.25rem 0;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  border-top: 1px solid var(--rule);
  font-size: 0.9rem;
}
.pager a { color: var(--accent); text-decoration: none; }
.pager .next { margin-left: auto; text-align: right; }

.volume h2 { margin-top: 2.5rem; }
.volume .subtitle { color: var(--soft); margin-top: -0.75rem; }

.volume .contents ul { margin: 0.4rem 0 0; }

/* The end of a chapter's page (build/Pages.java): its quiz and its programs as files. Links that wrap at any width. */
.chapter-links {
  margin: 2.5rem 0 0;
  padding: 0.7rem 0.9rem 0.7rem 2.1rem;
  font-size: 0.9rem;
  color: var(--soft);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 0.5rem;
}
.chapter-links li { margin: 0.2rem 0; }
.chapter-links a { color: var(--accent); font-weight: 600; text-decoration: none; }

/* Java cannot run in this browser (web/app.js, or the noscript copy): a quiet notice, not an error. */
p.nojava {
  margin: 0;
  padding: 0.6rem 0.9rem;
  font-size: 0.88rem;
  color: var(--soft);
  background: var(--panel);
  border-top: 1px solid var(--rule);
}
noscript > p.nojava { border: 0; border-bottom: 1px solid var(--rule); }

/* The scratchpad (web/page/scratchpad.js): a tab at the bottom right opens a sheet with jshell in it. Hidden must
   win over every display rule below, so each element the page hides by the attribute stays hidden. */
.scratch-tab[hidden], .scratchpad[hidden], .scratchpad [hidden] { display: none !important; }
.scratch-tab {
  position: fixed;
  right: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  z-index: 6;
  padding: 0.5rem 1rem;
  font: 600 0.8rem/1.2 ui-sans-serif, system-ui, sans-serif;
  color: var(--paper);
  background: var(--accent);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.18);
  cursor: pointer;
}
.scratchpad {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 7;
  display: flex;
  flex-direction: column;
  max-height: min(60vh, 32rem);
  max-height: min(60dvh, 32rem);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--panel);
  border-top: 1px solid var(--rule);
  box-shadow: 0 -8px 32px rgb(0 0 0 / 0.18);
}
.scratchpad header {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  padding: 0.5rem 0.9rem;
  font: 0.76rem/1.4 ui-sans-serif, system-ui, sans-serif;
  color: var(--soft);
  border-bottom: 1px solid var(--rule);
}
.scratchpad .scratch-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scratchpad header button {
  padding: 0.15rem 0.55rem;
  font: inherit;
  color: var(--soft);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 0.3rem;
  cursor: pointer;
}
.scratchpad .scratch-about, .scratchpad .scratch-note {
  margin: 0;
  padding: 0.4rem 0.9rem 0;
  font: 0.76rem/1.4 ui-sans-serif, system-ui, sans-serif;
  color: var(--soft);
}
/* jshell's transcript is a terminal's: an entry, a caret under an error and a stack frame each stay one line (Ruling
   22), and a long one scrolls inside the transcript, never the page. After pre:not(.output):not(.reference), whose
   specificity this rule ties, so its margin and background lose. */
.scratchpad pre.transcript {
  flex: 1;
  min-height: 5rem;
  margin: 0;
  padding: 0.6rem 0.9rem 0;
  font-size: 0.84rem;
  line-height: 1.5;
  white-space: pre;
  overflow: auto;
  overscroll-behavior: contain;
  background: transparent;
  border-radius: 0;
}
.scratchpad .transcript .typed { color: var(--accent); font-weight: 600; }
.scratchpad .transcript .err { color: var(--warn); }
.scratchpad .transcript .status { color: var(--soft); font-style: italic; }
.scratchpad .entry { display: flex; gap: 0.5rem; align-items: flex-start; padding: 0.5rem 0.9rem 0.75rem; }
.scratchpad .caret {
  padding-top: 0.15rem;
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.84rem;
  color: var(--accent);
  white-space: pre;
  user-select: none;
}
/* What the reader types is code: it never wraps either. */
.scratchpad .entry textarea {
  flex: 1;
  min-width: 0;
  max-height: 9rem;
  padding: 0.15rem 0;
  font-size: 0.84rem;
  line-height: 1.5;
  color: var(--ink);
  background: transparent;
  border: 0;
  resize: none;
  tab-size: 4;
  white-space: pre;
  overflow: auto;
}
.scratchpad .entry textarea:focus { outline: none; }
/* While the sheet is open the page's end, its Previous and Next links included, can still scroll above it (--sheet:
   its height, scratchpad.js). On body, not main: the pager comes after main. */
body[data-sheet=open] { padding-bottom: var(--sheet, 0px); }
