/* The theme. Every color on the page is one of these tokens: light values
   here, dark values in the block below, which wins when theme-boot.js (or
   lib/theme.js) sets <html data-theme="dark">. Both blocks set the same names,
   and no other rule in any stylesheet may write a literal color (both are
   checked by static-guards.test.js). --paper stays white in both: the
   handwritten pages, thumbnails and glyph previews are paper, never themed. */
:root {
  color-scheme: light;
  --admin-warning: #866000;
  --bg: #f3f1eb;
  --sidebar: #efece5;
  --panel: #fffefa;
  --sunken: #f8f8f2;
  --hover: #e4e1d8;
  --active: #f0f2e9;
  --line: #dedbd2;
  --line-strong: #b9b9aa;
  --text: #262a26;
  --muted: #76796f;
  --faint: #94978b;
  --accent: #ac4d31;
  --accent-strong: #903f27;
  --accent-fill: #ac4d31;
  --accent-fill-hover: #903f27;
  --on-accent: #ffffff;
  --accent-soft: #f4e9df;
  --accent-line: #e7d3c3;
  --accent-wash: #ac4d311f;
  --accent-ring: #ac4d3159;
  --green: #48634d;
  --green-soft: #e8eee4;
  --green-line: #d2dccc;
  --neutral-soft: #eeeee6;
  --track: #e8e9df;
  --wash: #0000000d;
  --danger-text: #963e28;
  --danger-bg: #fbefe8;
  --danger-line: #e2c4b6;
  --danger-fill: #903f27;
  --inverse-bg: #262a26;
  --on-inverse: #ffffff;
  --overlay: #1f231f66;
  --shadow: #242a2420;
  --shadow-soft: #242a2410;
  --shadow-mid: #242a2418;
  --page-shadow: 0 5px 22px #242a2410, 0 1px 3px #242a2418;
  --paper: #ffffff;
  --radius: 16px;
}
/* Dark: warm greys rather than black, the accent lifted so text and icons in
   it stay readable (4.5:1 on the panel and on --accent-soft, which pills and
   notices sit on; theme.test.js checks the pairs), and a deeper accent fill
   under white button text. --wash is see-through so a hover shows on any
   tone beneath it. A page loses its shadow, which vanishes on a dark desk,
   for a hairline edge. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --admin-warning: #e2b759;
  --bg: #1c1d1a;
  --sidebar: #191a17;
  --panel: #262723;
  --sunken: #20211e;
  --hover: #2e2f2a;
  --active: #2a2e27;
  --line: #393a34;
  --line-strong: #55574e;
  --text: #ebe9e1;
  --muted: #a09f93;
  --faint: #7d7e73;
  --accent: #d8805c;
  --accent-strong: #e08a67;
  --accent-fill: #b5583a;
  --accent-fill-hover: #9d4a30;
  --on-accent: #ffffff;
  --accent-soft: #3a2a22;
  --accent-line: #5a3a2c;
  --accent-wash: #d8805c2e;
  --accent-ring: #d8805c80;
  --green: #8fb895;
  --green-soft: #26332a;
  --green-line: #3d5242;
  --neutral-soft: #2e2f2a;
  --track: #34352f;
  --wash: #ffffff14;
  --danger-text: #f0a58a;
  --danger-bg: #3a2420;
  --danger-line: #6b3a2c;
  --danger-fill: #9d4a30;
  --inverse-bg: #ebe9e1;
  --on-inverse: #1c1d1a;
  --overlay: #000000a3;
  --shadow: #00000066;
  --shadow-soft: #00000033;
  --shadow-mid: #0000004d;
  --page-shadow: 0 0 0 1px #393a34;
  --paper: #ffffff;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin: 0; background: var(--bg); color: var(--text); font: 14px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
button, input, textarea, select { font: inherit; }
button, .button { cursor: pointer; border: 1px solid var(--line); background: var(--panel); color: var(--text); padding: 9px 14px; border-radius: 8px; transition: background .15s, border-color .15s; text-align: center; }
button:hover:not(:disabled), .button:hover { background: var(--hover); border-color: var(--line-strong); }
button:disabled { opacity: .4; cursor: default; }
button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* A file picker is a .button label round its own input. The input is out of
   sight but not hidden, so Tab reaches it and Enter or Space opens it, and
   the label draws its focus ring. A rule of its own, so a browser without
   :has() drops only this one. */
.button:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 4px; }
.button { position: relative; }
.button > input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; pointer-events: none; }
.button > input[type="file"]:focus-visible { outline: none; }
.primary { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); font-weight: 550; }
.primary:hover:not(:disabled) { background: var(--accent-fill-hover); border-color: var(--accent-fill-hover); }
.ghost { background: transparent; }
/* Terms and Privacy keep a top bar with the brand; the app's own shell
   (sidebar, mini-bar, account menu) is shell.css. */
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 20px; min-height: 68px; padding: 14px 36px; border-bottom: 1px solid var(--line); }
.brand { display: flex; align-items: center; gap: 10px; font-family: Georgia, serif; font-size: 25px; letter-spacing: -.8px; }
.brand img { filter: saturate(.5); }
/* The solver's status line (#engineStatus): quiet, or rust when something is wrong. */
.status { color: var(--muted); font-size: 11px; }
.status.bad { color: var(--accent); }
main { max-width: 1180px; margin: 0 auto; padding: 40px 32px 64px; }
.intro { padding: 12px 0 34px; }
.eyebrow { font-size: 10px; font-weight: 650; letter-spacing: 1.5px; color: var(--muted); }
.intro h1 { font: 54px/1.05 Georgia, "Times New Roman", serif; letter-spacing: -2px; margin: 18px 0; }
.intro h1 span { color: var(--accent); }
.intro p { color: var(--muted); margin-bottom: 0; max-width: 460px; font-size: 15px; }
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; min-width: 0; }
.panel-head { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 16px; }
.panel-head h2 { font-size: 16px; font-weight: 600; margin: 0; }
.hint { color: var(--muted); font-size: 13px; margin: 8px 0 20px; }
.pill { display: inline-block; font-size: 11px; padding: 4px 9px; border-radius: 999px; background: var(--accent-soft); color: var(--accent); font-weight: 550; }
.pill.neutral { background: var(--neutral-soft); color: var(--muted); }
.pill.good { background: var(--green-soft); color: var(--green); }
.row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 14px; min-width: 0; }
.subjects-label { margin-top: 4px; }
/* The class picker (lib/class-picker.js, styled in class-picker.css) lives in here. */
.subjects { margin: 8px 0 4px; }
/* The sheet's buttons share a line when it is wide enough for them and each
   take a whole line when it isn't, so the narrow panel gets a tidy stack
   rather than a ragged row. Clear stays its own size beside Upload. */
.sheet-actions > button, .sheet-actions > .button { flex: 1 1 auto; }
.sheet-actions > .ghost { flex: 0 0 auto; }
.sheet-actions + .sheet-actions { margin-top: 10px; }
input[type="text"], input[type="email"], textarea, select { color: var(--text); border: 1px solid var(--line); border-radius: 7px; padding: 10px 12px; background: var(--panel); }
input[type="text"], input[type="email"] { flex: 1 1 150px; min-width: 0; width: 100%; font-size: 12px; }
textarea { width: 100%; resize: vertical; min-height: 112px; margin-top: 8px; font-size: 13px; }
textarea::placeholder, input::placeholder { color: var(--faint); }
.field-label { display: block; font-size: 12px; font-weight: 600; margin-top: 22px; }
.select { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 11px; }
.select select { padding: 7px; font-size: 12px; }
/* The Messiness sliders, in the page's accent, with the word for their value
   beside them in a width of its own, so the slider stays put as it changes. */
.select input[type="range"] { width: 110px; margin: 0; accent-color: var(--accent); cursor: pointer; }
.select input[type="range"]:disabled { opacity: .4; cursor: default; }
.select output { min-width: 50px; color: var(--text); }
.character-details { margin-top: 24px; border-top: 1px solid var(--line); padding-top: 14px; }
.character-details summary { color: var(--muted); cursor: pointer; font-size: 12px; }
.glyph-preview { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 14px; max-height: 260px; overflow: auto; }
.glyph-preview figure { margin: 0; width: 38px; text-align: center; }
.glyph-preview canvas { width: 100%; height: 38px; object-fit: contain; background: var(--paper); border: 1px solid var(--line); border-radius: 5px; }
.glyph-preview figcaption { font: 10px ui-monospace, monospace; color: var(--muted); }
.small-note { font-size: 11px; color: var(--muted); line-height: 1.7; }
kbd { font: inherit; border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 4px; padding: 1px 4px; }

/* The writing desk's pages: a continuous paper stack. The desk around them
   (the status column, the header, the docked composer) is shell.css's. */
.page-stack { position: relative; }
.pages { display: grid; gap: 28px; }
.pages canvas { width: 100%; height: auto; display: block; background: var(--paper); scroll-margin-top: 64px; box-shadow: var(--page-shadow); }
.page-waiting { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; padding: 24% 24px 24px; text-align: center; pointer-events: none; }
/* Before the first page is drawn the stack has no height, so the waiting note
   takes its own space instead of spilling over the site footer below. */
.pages:empty + .page-waiting { position: static; }
.waiting-mark { font-size: 30px; color: var(--faint); animation: breathe 2s ease-in-out infinite; }
.page-waiting h2 { font: 23px Georgia, serif; color: var(--muted); margin: 20px 0 8px; }
.page-waiting p { font-size: 12px; color: var(--faint); max-width: 240px; }
.page-footnote { text-align: center; color: var(--muted); font-size: 10px; margin-top: 24px; }
progress { display: block; width: 100%; height: 4px; border: 0; border-radius: 8px; overflow: hidden; background: var(--track); accent-color: var(--green); }
progress::-webkit-progress-bar { background: var(--track); }
progress::-webkit-progress-value { background: var(--green); transition: width .2s; }
progress::-moz-progress-bar { background: var(--green); }
/* While the solver works, how many problems there will be isn't known: the
   bar slides a stripe across rather than claim a share of them, so it
   visibly moves. Reduced motion holds it still (below). */
progress:indeterminate {
  background: linear-gradient(90deg, var(--track) 0 35%, var(--green) 35% 65%, var(--track) 65% 100%);
  background-size: 300% 100%;
  animation: slide 1.4s linear infinite;
}
progress:indeterminate::-webkit-progress-bar { background: transparent; }
progress:indeterminate::-moz-progress-bar { background: transparent; }
.failure { padding: 12px; border: 1px solid var(--danger-line); border-radius: 7px; color: var(--danger-text); background: var(--danger-bg); font-size: 12px; overflow-wrap: anywhere; margin-bottom: 12px; }
#retryGenerate { width: 100%; margin-bottom: 22px; font-size: 12px; }

/* Signing in: the intro's voice, one narrow panel, one step at a time. */
.signin-view { max-width: 560px; }
.signin-view .intro { text-align: center; padding-top: 36px; }
.signin-view .intro h1 { font-size: 46px; }
/* Signing in and re-agreeing to changed Terms each have their own heading. */
.signin-view[data-step="consent"] .signin-only,
.signin-view:not([data-step="consent"]) .consent-only { display: none; }
/* Turnstile's widget: invisible unless Cloudflare wants a click, and never on the consent step. */
.captcha-box { display: flex; justify-content: center; margin-top: 14px; }
.captcha-box:empty, .signin-view[data-step="consent"] .captcha-box { display: none; }
.panel.narrow { max-width: 440px; margin: 0 auto; }
.panel.narrow form > .field-label:first-child, .panel.narrow form > p:first-child { margin-top: 0; }
.panel.narrow input[type="email"], .panel.narrow input[type="text"] { display: block; margin-top: 8px; font-size: 14px; }
.panel.narrow .primary { display: block; width: 100%; margin-top: 22px; padding: 11px 16px; }
.panel.narrow .failure { margin: 18px 0 0; }
.panel.narrow .small-note { margin: 16px 0 0; }
#signInCode { font: 20px/1.2 ui-monospace, monospace; letter-spacing: 4px; text-align: center; }
#codeStep .hint { margin-top: 0; }
#codeStep strong { color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
#consentStep > p:first-child { margin-bottom: 4px; }
.consent-note { margin: 12px 0 0; font-size: 11px; line-height: 1.6; color: var(--muted); text-align: center; }
.consent-note a { color: var(--text); }
/* Pricing, Terms and Privacy links under whichever view is showing; main's bottom padding spaces it. */
.site-footer { max-width: 560px; margin: 0 auto; padding: 0 16px 40px; }
/* Before any view shows, and only if the server is slow to say which: a quiet
   note between the brand and the footer, with the writing desk's mark. */
.page-loading { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 0; padding: 120px 16px 96px; color: var(--muted); font-size: 12px; }
.page-loading .waiting-mark { font-size: 18px; }

/* The Terms page: one readable column in the page's own type. */
a.brand { color: inherit; text-decoration: none; }
.terms { max-width: 760px; }
.terms .panel { padding: 30px 34px; }
.terms .panel h2 { font-size: 15px; font-weight: 600; margin: 28px 0 8px; }
.terms .panel h2:first-child { margin-top: 0; }
.terms .panel p, .terms .panel li { font-size: 13px; line-height: 1.7; }
.terms .panel ul { padding-left: 20px; }
.terms .page-footnote a, .site-footer a { color: var(--muted); }
.signin-actions { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; margin-top: 10px; }
.signin-actions .ghost { border-color: transparent; padding: 6px 8px; font-size: 12px; color: var(--muted); }
.signin-notice { margin: 0 0 18px; padding: 10px 12px; border-radius: 8px; background: var(--accent-soft); color: var(--accent); font-size: 12px; }
/* The waitlist's note sits under the Sign in button, with the actions below it. */
#waitlistNote { margin: 12px 0 0; line-height: 1.6; }
/* Over the tour's sheet on a phone (--tour-dock, tour.css), not on its words. */
.toast { position: fixed; bottom: calc(24px + var(--tour-dock, 0px)); left: 50%; transform: translateX(-50%); max-width: min(70ch, calc(100vw - 32px)); padding: 12px 18px; background: var(--inverse-bg); color: var(--on-inverse); border-radius: 9px; box-shadow: 0 6px 24px var(--shadow); font-size: 12px; z-index: 50; }
.toast.bad { background: var(--danger-fill); color: var(--on-accent); }
@keyframes breathe { 50% { opacity: .35; } }
@keyframes slide { from { background-position: 100% 0; } to { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
@media (max-width: 1000px) {
  .panel { padding: 20px; }
  main { padding-left: 24px; padding-right: 24px; }
}
@media (max-width: 740px) {
  .topbar { padding: 12px 20px; min-height: 60px; }
  .signin-view .intro { padding-top: 12px; }
  .signin-view .intro h1 { font-size: 36px; }
  main { padding: 24px 18px 40px; }
  .intro { padding: 0 0 24px; }
  .intro h1 { font-size: 44px; }
  .page-waiting h2 { font-size: 20px; }
}

/* The demo (app.js, "The demo"): one sample assignment someone signed out can
   watch from start to finish, with nothing sent to a solver. */
.demo-offer { margin-top: 22px; text-align: center; }
.signin-view:not([data-step="email"]) .demo-offer { display: none; }
.demo-or { display: flex; align-items: center; gap: 12px; margin: 0 0 14px; color: var(--muted); font-size: 11px; }
.demo-or::before, .demo-or::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
.demo-offer button { display: block; width: 100%; padding: 10px 16px; }
.demo-bar { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px 16px; padding: 10px 36px; background: var(--accent-soft); border-bottom: 1px solid var(--accent-line); font-size: 12px; }
.demo-bar p { margin: 0; }
.demo-bar .pill { margin-right: 6px; background: var(--accent-fill); color: var(--on-accent); font-size: 9px; letter-spacing: .8px; text-transform: uppercase; }
.demo-bar button { padding: 5px 12px; font-size: 12px; }
body:not(.demo) .demo-only { display: none; }
/* Its assignment is fixed: nothing that would change it looks usable (the
   composer's + is shell.css's). */
body.demo #uploadSheet { opacity: .4; pointer-events: none; }
body.demo textarea[readonly], body.demo input[readonly] { background: var(--sunken); }
html:has(.demo-finish[open]) { overflow: hidden; scrollbar-gutter: stable; }
.demo-finish { width: min(420px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); margin: auto; padding: 32px; border: 1px solid var(--line); border-radius: 18px; background: var(--panel); color: var(--text); box-shadow: 0 24px 70px var(--shadow); text-align: center; }
.demo-finish::backdrop { background: var(--overlay); }
.demo-finish h2 { margin: 0 0 28px; font: 32px/1.15 Georgia, serif; letter-spacing: -.6px; text-wrap: balance; }
.demo-finish button { display: block; width: 100%; font-size: 14px; padding: 13px 16px; }
.demo-finish .ghost { margin-top: 8px; border-color: transparent; color: var(--muted); }
@media (prefers-reduced-motion: no-preference) {
  .demo-finish[open] { animation: demo-finish-enter 320ms cubic-bezier(.2, .8, .2, 1) both; }
  .demo-finish[open]::backdrop { animation: demo-backdrop-enter 320ms ease-out both; }
}
@keyframes demo-finish-enter {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes demo-backdrop-enter {
  from { opacity: 0; }
  to { opacity: 1; }
}
@media (max-width: 740px) { .demo-bar { justify-content: space-between; padding: 10px 20px; } }
