/* Spinner: .spinner (32px); .spinner-sm for inline use; --spinner-accent recolours the arc. */
.spinner {
  width: 32px; height: 32px; border-radius: 50%; flex: 0 0 auto;
  border: 3px solid #d7d9de; border-top-color: var(--spinner-accent, #2873d6);
  animation: spin .8s linear infinite;
}
.spinner.spinner-sm { width: 14px; height: 14px; border-width: 2px; --spinner-accent: var(--thread); }
@keyframes spin { to { transform: rotate(360deg); } }

/* QuietBookCut shared brand: fonts, palette, base typography, header/nav.
   Extracted from landing.html (2026-10-03) so every page shares ONE cached
   copy of the embedded fonts instead of each page re-downloading its own. */

/* Self-hosted variable fonts (OFL, licences beside them in /static/fonts/):
   Heading = Bricolage Grotesque (used condensed, font-stretch 80%),
   Body = Literata, Hand = Shantell Sans (the marker-pen notes). */
@font-face {
  font-family: 'Heading';
  font-style: normal;
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url(/static/fonts/heading.woff2) format('woff2');
}
@font-face {
  font-family: 'Body';
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url(/static/fonts/body.woff2) format('woff2');
}
@font-face {
  font-family: 'Body';
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url(/static/fonts/body-italic.woff2) format('woff2');
}
@font-face {
  font-family: 'Hand';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(/static/fonts/hand.woff2) format('woff2');
}

:root {
  --paper: #f1f3ec;
  --paper-deep: #e7ebe0;
  --ink: #22201b;
  --mat: #1e4638;
  --mat-deep: #163329;
  --mat-line: #2e5b49;
  /* Accessibility (WCAG AA, 2026-10-18): --thread is dark enough for paper-coloured
     button text (4.7:1); --thread-light is the pink for text on the dark green (4.7:1);
     --chalk is the muted text grey (5:1 on paper). */
  --thread: #b94457;
  --thread-light: #ed93a1;
  --thread-deep: #b73b55;
  --chalk: #5d6b65;
  --chalk-light: #a1afa8; /* muted text on the dark green bars */
  --radius: 3px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: 'Body', Georgia, 'Times New Roman', serif;
  font-size: 17px;
  line-height: 1.6;
  /* The bold display font (Heading) especially looked soft/fuzzy at small UI
     sizes (nav links, form labels, buttons) without this — default subpixel
     anti-aliasing blurs a heavy custom webfont's edges more than it does a
     system font. Inherited site-wide from here. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

a { color: inherit; }

.eyebrow {
  font-family: 'Heading', 'Arial Narrow', sans-serif; font-stretch: 80%;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 13.5px;
  font-weight: 800;
}

h1, h2, h3 {
  font-family: 'Heading', 'Arial Narrow', sans-serif; font-stretch: 80%;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  text-wrap: balance;
  margin: 0;
}

.mark {
  font-family: 'Hand', cursive;
  font-weight: 600;
}


/* ---------- nav ---------- */
header.site {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--mat);
  color: var(--paper);
  border-bottom: 1px solid var(--mat-line);
}
.nav {
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.wordmark {
  font-family: 'Heading', sans-serif; font-stretch: 80%;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 20px;
  text-decoration: none;
  color: var(--paper);
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.wordmark span { color: var(--thread-light); }
.nav-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px 22px;
  font-family: 'Heading', sans-serif; font-stretch: 80%;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.nav-info-links { display: flex; align-items: center; gap: 22px; }
/* "Decoders": every conversion tool in one dropdown, first in the menu (2026-11-06). */
.nav-menu { position: relative; }
.nav-menu > summary {
  list-style: none; cursor: pointer; color: var(--paper);
  border-radius: var(--radius);
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::after { content: " \25BE"; }
.nav-menu[open] > summary::after { content: " \25B4"; }
.nav-menu-list {
  position: absolute; top: calc(100% + 12px); left: -14px; z-index: 30; min-width: 230px;
  display: flex; flex-direction: column; padding: 6px 0;
  background: var(--mat); border: 1px solid var(--mat-line); border-radius: var(--radius);
  box-shadow: 0 10px 20px rgba(0,0,0,.25);
}
.nav-menu-list a.plain, .nav-menu-list button.plain { padding: 10px 16px; white-space: nowrap; }
.nav-menu-list a.plain:hover, .nav-menu-list a.plain:focus-visible,
.nav-menu-list button.plain:hover, .nav-menu-list button.plain:focus-visible { background: var(--mat-deep); }
/* Logout sits in the Profile menu: a button dressed as a menu link. */
.nav-menu-list button.plain {
  background: transparent; border: 0; text-align: left; cursor: pointer; width: 100%;
  font-family: 'Heading', sans-serif; font-stretch: 80%; font-size: 13px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--paper); opacity: 0.86;
}
/* The Profile menu opens leftwards from the right edge of the bar. */
.nav-menu-right .nav-menu-list { left: auto; right: -14px; }
/* Owner rule 2026-11-14: the desktop menu is always ONE line (signed in as admin included). */
@media (min-width: 761px) {
  .nav, .nav-links, .nav-info-links, #nav-user, #nav-auth-links { flex-wrap: nowrap; }
  .nav-links, .nav-info-links { white-space: nowrap; }
}
#nav-user { display: inline-flex; align-items: center; gap: 18px; }
/* Narrow desktops (tablets in landscape, split screens): tighter spacing so the one line fits. */
@media (min-width: 761px) and (max-width: 960px) {
  .nav { padding: 14px 14px; gap: 12px; }
  .nav-links, .nav-info-links { gap: 13px; }
  #nav-user, #nav-auth-links { gap: 10px; }
  .wordmark { font-size: 18px; }
}
/* Phone widths: a compact top bar (logo, account, menu, Jobs last), the other links in the
   menu. No bottom bar (owner, 2026-11-14): each converter page has its own create button. */
.nav-quick { display: none; }
.nav-menu-btn {
  background: transparent; border: 0; color: var(--paper); padding: 6px; line-height: 0;
  cursor: pointer; border-radius: var(--radius);
}
.nav-quick-account { color: var(--paper); line-height: 0; padding: 6px; border-radius: var(--radius); }
@media (max-width: 760px) {
  header.site { position: sticky; }
  .nav { padding: 8px 12px; gap: 8px; flex-wrap: nowrap; position: relative; }
  .wordmark { font-size: 17px; }
  .nav-quick { display: flex; align-items: center; gap: 4px; margin-left: auto; }
  .nav-quick .btn { padding: 7px 12px; }
  .nav-links { display: none; }
  header.site.menu-open .nav-links {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: 100%; left: 0; right: 0;
    background: var(--mat); border-bottom: 1px solid var(--mat-line);
    box-shadow: 0 10px 20px rgba(0,0,0,.25); padding: 6px 0 12px;
  }
  header.site.menu-open .nav-info-links,
  header.site.menu-open #nav-auth-links,
  header.site.menu-open #nav-user { flex-direction: column; align-items: stretch; gap: 0; }
  header.site.menu-open #nav-auth-links, header.site.menu-open .nav-info-links { display: flex; }
  header.site.menu-open #nav-user:not([style*="none"]) { display: flex; }
  header.site.menu-open .nav-links a.plain,
  header.site.menu-open .nav-links .btn,
  header.site.menu-open .nav-links button {
    display: block; text-align: left; padding: 13px 20px; margin: 0; border: 0;
    background: transparent; color: var(--paper); opacity: 1; width: 100%;
  }
  header.site.menu-open .nav-menu > summary { display: block; padding: 13px 20px; }
  header.site.menu-open .nav-menu-list {
    position: static; min-width: 0; padding: 0 0 6px; border: 0; box-shadow: none;
    background: transparent;
  }
  header.site.menu-open .nav-links .nav-menu-list a.plain,
  header.site.menu-open .nav-links .nav-menu-list button.plain { padding: 11px 20px 11px 36px; }
  #nav-jobs-link { display: none !important; }  /* Jobs is in the top bar */
}
/* Not scoped to .nav-links — this is the canonical "plain link on a dark bar"
   treatment (no button chrome, just text), reused anywhere a header/bar needs
   one (e.g. correct.html's "‹ Jobs" link), not just the main nav. Carries its
   own full text styling (not just colour) so it looks identical regardless
   of which bar it's dropped into. */
a.plain {
  font-family: 'Heading', sans-serif; font-stretch: 80%;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--paper);
  opacity: 0.86;
}
a.plain:hover { opacity: 1; }
.btn {
  font-family: 'Heading', sans-serif; font-stretch: 80%;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  display: inline-block;
  padding: 10px 18px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
}
.btn-thread { background: var(--thread); color: var(--paper); border-color: var(--thread); }
.btn.btn-mat { background: var(--mat); color: var(--paper); border-color: var(--mat); }
.btn.btn-mat:hover { background: var(--mat-deep); border-color: var(--mat-deep); }
/* A file picker in the site's style: the browser's own "Choose File" button can't be
   restyled, so the input is hidden (still focusable and still `required`) and its label
   is the button; site-chrome.js writes the chosen file's name beside it. */
.file-pick { position: relative; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin: 0 0 10px; }
.file-pick input[type="file"] { position: absolute; left: 0; top: 0; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.file-pick .file-pick-btn { display: inline-block; margin: 0; font-weight: normal; }
.file-pick input[type="file"]:focus-visible + .file-pick-btn { outline: 3px solid var(--thread); outline-offset: 2px; }
.file-pick-name { color: var(--chalk); font-size: 14px; overflow-wrap: anywhere; }
.btn-thread:hover { background: var(--thread-deep); border-color: var(--thread-deep); }
.btn-ghost-light { background: transparent; color: var(--paper); border-color: var(--paper); }
.btn-ghost-light:hover { background: var(--paper); color: var(--mat); }
.btn-ghost-dark { background: transparent; color: var(--mat); border-color: var(--mat); }
.btn-ghost-dark:hover { background: var(--mat); color: var(--paper); }

/* ---------- cutting-mat grid texture ---------- */
/* Fine grid every 40px + a bolder coral rule every 200px, like a quilting/cutting
   mat. Used by the landing page's hero section and (as the body backdrop, with
   fixed attachment for a slight parallax feel — see auth.css) the app's own pages. */
.mat-grid {
  background-image:
    repeating-linear-gradient(0deg, var(--mat-line) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(90deg, var(--mat-line) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(0deg, rgba(226,83,106,0.35) 0 1px, transparent 1px 200px),
    repeating-linear-gradient(90deg, rgba(226,83,106,0.35) 0 1px, transparent 1px 200px);
  background-color: var(--mat);
}

/* Product Hunt review badge — centered, shown in every page footer. Full-width
   so it wraps onto its own line in the flex app-footer, centered in both the
   flex and plain-block footers. */
.ph-badge { width: 100%; text-align: center; margin-top: 14px; }
.ph-badge img { display: inline-block; max-width: 250px; height: auto; }


/* ---------- standard page widths + shared site footer ----------
   Header and footer markup live in static/partials/ and are copied into every
   public page by scripts/sync_partials.py (tests/test_site_chrome.py checks it).
   A page's <main> uses one of these two widths — no one-off max-widths. */
:root { --page-wide: 1120px; --page-xwide: 1456px; --page-reading: 880px; } /* xwide = admin's many-column tables (wide x 1.3) */

footer.site-footer {
  margin-top: 40px;
  padding: 40px 24px 50px;
  border-top: 1px solid rgba(34, 32, 27, 0.15);
  /* Own background: app pages sit on the dark cutting-mat grid (auth.css). */
  background: var(--paper);
}
/* Three lines: the menu, then who runs the site (one line), then the badge. */
.site-footer-inner {
  max-width: var(--page-wide);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  color: var(--chalk);
  text-align: center;
}
.site-footer-scope strong a { color: var(--ink); text-decoration: none; }
.site-footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 16px; }
.site-footer-links a { text-decoration: none; color: var(--chalk); }
.site-footer-links a:hover { color: var(--ink); }

/* Header chrome must look identical on every page, whatever page CSS loads after
   brand.css (auth.css restyles .btn/button for forms). */
header.site .btn,
header.site button {
  padding: 8px 14px;
  line-height: 1;
  font-size: 13px;
}
header.site .wordmark { font-size: 20px; line-height: 1.2; }

/* Short pages: keep the shared footer at the bottom of the window instead of
   floating mid-screen over the mat backdrop. Not on body.hidden (pre-auth pages
   stay hidden until auth-guard.js reveals them). */
body:not(.hidden):has(> footer.site-footer) {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
body:not(.hidden):has(> footer.site-footer) > main { width: 100%; box-sizing: border-box; }
body:not(.hidden):has(> footer.site-footer) > footer.site-footer { margin-top: auto; }

/* Phone-only hint: the tools are made for a computer, next to the cutting software. */
.pc-note { display: none; }
@media (max-width: 760px) { .pc-note { display: block; } }

/* Content pages (help, guides, about, legal): shared rules that used to be copied
   into each page's <style>. Page-specific tweaks stay inline. */
main.help { max-width: var(--page-reading); margin: 0 auto; padding: 0 24px 80px; }
.help-hero .eyebrow { color: var(--thread-deep); }
.article strong { color: var(--ink); }
.snip::before, .snip::after { content: ""; flex: 1; border-top: 2px dashed var(--chalk); }
.ref-legend strong { color: var(--ink); }
.wow-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.wow-list li { background: var(--paper-deep); border: 1px solid var(--chalk); border-radius: var(--radius); padding: 12px 16px; font-size: 14.5px; }
.wow-list strong { color: var(--mat); }
main.terms { max-width: var(--page-reading); margin: 0 auto; padding: 40px 24px 80px; }
main.terms h1 { font-size: 28px; margin-bottom: 4px; }
main.terms .updated { color: var(--chalk); font-size: 14px; margin-bottom: 36px; }
main.terms h2 { font-size: 18px; margin-top: 36px; margin-bottom: 10px; }
main.terms p, main.terms li { margin: 0 0 12px; }
main.terms ul { padding-left: 22px; }
main.terms .callout { background: var(--paper-deep, #ece9df); border: 1px solid var(--chalk); border-radius: var(--radius, 8px); padding: 14px 18px; margin: 20px 0; }
main.terms .callout strong { display: block; margin-bottom: 4px; }

/* ---------- accessibility ---------- */
/* A clear focus ring for keyboard users on every link, button and field (mouse clicks
   don't show it: :focus-visible). Blue on light backgrounds, paper on the dark bars. */
:focus-visible { outline: 3px solid #1f63c7; outline-offset: 2px; border-radius: 2px; }
header.site :focus-visible, .mat-grid :focus-visible, .cta-band :focus-visible { outline-color: var(--paper); }
/* "Skip to content": the first thing a keyboard / screen-reader user reaches. */
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 1000;
  background: var(--paper); color: var(--ink); padding: 10px 16px; border-radius: 3px;
  font-weight: 700; text-decoration: underline; box-shadow: 0 4px 14px rgba(0,0,0,.25);
}
.skip-link:focus { top: 10px; }

/* Express checkout popup (partials/express-checkout.html, express-checkout-ui.js), on every
   page that downloads. Stripe's form with the billing address is tall, so the popup scrolls
   inside itself and Pay stays reachable on a 1366x768 laptop (pre-mortem PM-I6). On the
   Jobs page and the editor it is a second modal over the download dialog. */
.xc-dialog {
  width: min(560px, calc(100vw - 24px));
  max-height: 90vh;
  overflow-y: auto;
  padding: 0;
  border: 2px solid var(--mat);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
}
.xc-dialog::backdrop { background: rgba(22, 51, 41, 0.55); }
.xc-dialog [hidden] { display: none !important; }
.xc-body { padding: 20px 22px; }
.xc-body h3 { margin: 0 0 10px; }
.xc-status, .xc-error, .xc-partial { margin: 0 0 12px; }
.xc-status:empty { display: none; }
.xc-error { color: var(--thread-deep); font-weight: 700; }
.xc-partial { color: var(--chalk); font-size: 14px; }
.xc-packs { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; margin: 0 0 12px; }
.xc-pack {
  display: flex; flex-direction: column; gap: 4px;
  padding: 14px; text-align: left; font: inherit; color: var(--ink);
  background: var(--paper-deep); border: 2px solid var(--mat-line); border-radius: var(--radius);
  cursor: pointer;
}
.xc-pack:hover:not(:disabled) { border-color: var(--thread); }
.xc-pack:focus-visible { outline: 3px solid var(--thread); outline-offset: 2px; }
.xc-pack:disabled { opacity: 0.6; cursor: progress; }
.xc-pack-credits { font-size: 20px; font-weight: 700; }
.xc-pack-price { color: var(--mat); font-weight: 700; }
.xc-pack-bonus { color: var(--thread-deep); font-size: 14px; }
.xc-pack-leftover { color: var(--chalk); font-size: 14px; }
.xc-checkout { margin: 0 0 12px; min-height: 120px; }
.xc-links { margin: 0 0 12px; padding-left: 20px; }
.xc-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
@media (max-width: 760px) {
  .xc-body { padding: 16px 14px; }
  .xc-actions .btn { flex: 1 1 auto; text-align: center; }
}

/* Pinterest Save button (static/pin-it.js) on images marked data-pin. Pinterest red on
   white text (contrast 5.0:1); always shown on touch screens, on hover/focus elsewhere. */
.pin-wrap { position: relative; display: inline-block; max-width: 100%; }
.pin-wrap > img { display: block; }
.pin-save {
  position: absolute; top: 10px; left: 10px; padding: 6px 14px; border-radius: 999px;
  background: #e60023; color: #fff; font-weight: 700; font-size: 15px; text-decoration: none;
  opacity: 0; transition: opacity 0.15s;
}
.pin-wrap:hover .pin-save, .pin-save:focus-visible { opacity: 1; }
@media (hover: none) { .pin-save { opacity: 1; } }
.pin-figure { margin: 28px auto; max-width: 340px; text-align: center; }
.pin-figure img { width: 100%; height: auto; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); }
.pin-figure figcaption { margin-top: 8px; font-size: 14px; color: var(--chalk); }

/* Converter tiles: the homepage's "Make something new" list (#converters). */
.tool-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
.tool-tile { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border: 1px solid var(--paper-deep);
  border-radius: var(--radius); text-decoration: none; color: var(--ink); background: var(--paper); }
.tool-tile:hover, .tool-tile:focus-visible { border-color: var(--mat); box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.tool-tile-name { font-family: 'Heading', sans-serif; font-stretch: 80%; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; font-size: 16px; }
.tool-tile-text { color: var(--chalk); font-size: 14px; line-height: 1.45; flex: 1; }
.tool-tile-btn { align-self: flex-start; margin-top: 4px; }
/* The Jobs page's one-line row of converter buttons (owner 2026-11-13: buttons only, no text). */
.converter-bar { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.converter-bar .btn { padding: 5px 10px; font-size: 13px; }
