/* =========================================================================
   scribe — app.css
   One stylesheet, no framework, no build step (C5).
   Light and dark are both first-class; the theme follows the system unless
   the user overrides it, and the override is remembered.
   ========================================================================= */

:root {
  --bg:         #f3f4f7;
  --surface:    #ffffff;
  --surface-2:  #f8f9fb;
  --surface-3:  #eef0f5;
  --border:     #dfe2ea;
  --border-2:   #c9cedb;
  --text:       #161a23;
  --text-dim:   #5c6478;
  /* 4.83:1 on white and ~4.6:1 on --surface-2. The old #8b93a7 measured
     3.07:1, under the 4.5 AA floor, and it is the colour used for every .hint,
     every .field-label and the size tags — i.e. most of the small text in the
     app. */
  --text-faint: #6b7280;
  --accent:     #3d5afe;
  --accent-2:   #6b7cff;
  --accent-fg:  #ffffff;
  --accent-soft:#e8ebff;
  --danger:     #c02b42;   /* 5.73:1 on white; #d6455a measured 4.32 */
  --ok:         #0f7a4e;   /* 5.09:1 on --surface-2; #17915f measured 3.80 */
  --warn:       #8a5a10;   /* 5.61:1 on --surface-2; #b7761a measured 3.55 */
  --shadow-1: 0 1px 2px rgba(20,24,40,.06), 0 1px 3px rgba(20,24,40,.05);
  --shadow-2: 0 4px 12px rgba(20,24,40,.09), 0 2px 4px rgba(20,24,40,.05);
  --shadow-3: 0 24px 60px rgba(16,20,36,.22), 0 4px 14px rgba(16,20,36,.12);
  --r-s: 7px; --r-m: 11px; --r-l: 16px;
  --panel-w: 384px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light;
}

:root[data-theme="dark"], :root:not([data-theme="light"]) {
  /* placeholder — the real dark values live in the two blocks below */
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:         #0d0f14;
    --surface:    #151922;
    --surface-2:  #1b2029;
    --surface-3:  #232936;
    --border:     #2a3040;
    --border-2:   #3a4254;
    --text:       #e7eaf2;
    --text-dim:   #a2abc0;
    --text-faint: #8590a5;   /* 5.47:1 on --surface, 4.53:1 on --surface-3 */
    --accent:     #7d8dff;
    --accent-2:   #9aa6ff;
    --accent-fg:  #0d0f14;
    --accent-soft:#232a44;
    --danger:     #ff7a8a;
    --ok:         #4fd39a;
    --warn:       #e0a54a;
    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 4px 14px rgba(0,0,0,.5);
    --shadow-3: 0 28px 70px rgba(0,0,0,.62);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg:         #0d0f14;
  --surface:    #151922;
  --surface-2:  #1b2029;
  --surface-3:  #232936;
  --border:     #2a3040;
  --border-2:   #3a4254;
  --text:       #e7eaf2;
  --text-dim:   #a2abc0;
  --text-faint: #8590a5;   /* 5.47:1 on --surface, 4.53:1 on --surface-3 */
  --accent:     #7d8dff;
  --accent-2:   #9aa6ff;
  --accent-fg:  #0d0f14;
  --accent-soft:#232a44;
  --danger:     #ff7a8a;
  --ok:         #4fd39a;
  --warn:       #e0a54a;
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 4px 14px rgba(0,0,0,.5);
  --shadow-3: 0 28px 70px rgba(0,0,0,.62);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg); color: var(--text);
  font-family: var(--font);
  font-size: 14px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: var(--accent); }

:where(button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-s);
}

/* Respect reduced motion for UI chrome only. The canvas animation IS the
   product, so it is deliberately not disabled here. */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ============================== app shell ============================== */

#app { display: flex; flex-direction: column; height: 100dvh; min-height: 0; }

header.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 0 16px; height: 56px; flex: 0 0 auto;
  background: var(--surface); border-bottom: 1px solid var(--border);
  z-index: 30;
}

.brand { display: flex; align-items: baseline; gap: 9px; margin-right: 4px; }
.brand b { font-size: 17px; letter-spacing: -.3px; font-weight: 650; }
.brand span { color: var(--text-faint); font-size: 11.5px; letter-spacing: .02em; }

.topbar .spacer { flex: 1 1 auto; }

.langbar { display: flex; gap: 4px; overflow: auto hidden; scrollbar-width: none; max-width: 46vw; }
.langbar::-webkit-scrollbar { display: none; }
.langbar button {
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  border-radius: 100px; padding: 4px 11px; font-size: 12px; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.langbar button:hover { background: var(--surface-3); color: var(--text); }
.langbar button[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
  font-weight: 600;
}

.btn {
  display: inline-flex; align-items: center; gap: 7px; justify-content: center;
  border: 1px solid var(--border-2); background: var(--surface);
  border-radius: var(--r-s); padding: 7px 13px; font-size: 13px; font-weight: 550;
  box-shadow: var(--shadow-1);
  transition: background .12s, border-color .12s, transform .06s;
}
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-fg);
  box-shadow: 0 1px 2px rgba(61,90,254,.3), 0 4px 14px rgba(61,90,254,.22);
}
.btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn.ghost { background: transparent; border-color: transparent; box-shadow: none; }
.btn.ghost:hover { background: var(--surface-3); }
.btn.danger { color: var(--danger); border-color: var(--border-2); }
.btn[disabled] { opacity: .45; pointer-events: none; }
.btn.icon { padding: 7px; width: 34px; height: 34px; }
.btn.sm { padding: 4px 9px; font-size: 12px; }

.main { display: flex; flex: 1 1 auto; min-height: 0; }

/* ============================== control panel ========================== */

aside.panel {
  width: var(--panel-w); flex: 0 0 var(--panel-w);
  background: var(--surface); border-right: 1px solid var(--border);
  overflow: hidden auto; overscroll-behavior: contain;
  scrollbar-width: thin;
}
aside.panel::-webkit-scrollbar { width: 10px; }
aside.panel::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 8px;
  border: 3px solid var(--surface); }

.group { border-bottom: 1px solid var(--border); }
.group > summary {
  display: flex; align-items: center; gap: 9px; cursor: pointer; list-style: none;
  padding: 13px 16px; font-weight: 600; font-size: 13.5px; user-select: none;
  position: sticky; top: 0; background: var(--surface); z-index: 2;
}
.group > summary::-webkit-details-marker { display: none; }
.group > summary:hover { background: var(--surface-2); }
.group > summary .chev {
  margin-left: auto; color: var(--text-faint); transition: transform .16s;
  width: 14px; height: 14px; flex: 0 0 14px;
}
.group[open] > summary .chev { transform: rotate(90deg); }
.group > summary .badge {
  font: 500 10.5px/1.6 var(--mono); color: var(--text-faint);
  background: var(--surface-3); border-radius: 100px; padding: 0 7px;
}
.group .body { padding: 4px 16px 18px; display: grid; gap: 13px; }

.field { display: grid; gap: 6px; }
.field > label, .field-label {
  font-size: 11.5px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--text-faint); display: flex; align-items: center; gap: 6px;
}
.field .hint { font-size: 11.5px; color: var(--text-faint); line-height: 1.45; text-transform: none;
  letter-spacing: 0; font-weight: 400; }
.field .val { margin-left: auto; font: 500 11.5px/1 var(--mono); color: var(--text-dim);
  text-transform: none; letter-spacing: 0; }

input[type="text"], input[type="number"], select, textarea {
  width: 100%; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-s); padding: 8px 10px; font-size: 13.5px;
  transition: border-color .12s, background .12s;
}
input[type="text"]:focus, input[type="number"]:focus, select:focus, textarea:focus {
  border-color: var(--accent); background: var(--surface); outline: none;
}
textarea { resize: vertical; min-height: 84px; line-height: 1.55; }
select { appearance: none; padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-faint) 50%),
                    linear-gradient(135deg, var(--text-faint) 50%, transparent 50%);
  background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

/* 26px, not 22: WCAG 2.2 AA 2.5.8 wants a 24px minimum target and a slider is
   dragged, not tapped, so it is the one control where being a few pixels short
   actually costs you. The track stays 4px — only the grabbable box grows. */
input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 26px;
  background: transparent; cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 4px; background: var(--border-2);
}
input[type="range"]::-moz-range-track { height: 4px; border-radius: 4px; background: var(--border-2); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 15px; height: 15px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface); margin-top: -5.5px;
  box-shadow: var(--shadow-1);
}
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%; background: var(--accent);
  border: 2px solid var(--surface); box-shadow: var(--shadow-1);
}

input[type="color"] {
  -webkit-appearance: none; appearance: none; border: 1px solid var(--border);
  border-radius: var(--r-s); width: 40px; height: 32px; padding: 3px; background: var(--surface-2);
  cursor: pointer; flex: 0 0 auto;
}
input[type="color"]::-webkit-color-swatch { border: none; border-radius: 4px; }
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }

.row { display: flex; gap: 8px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }

.seg { display: flex; background: var(--surface-3); border-radius: var(--r-s); padding: 3px; gap: 3px; }
.seg button {
  flex: 1 1 0; border: none; background: transparent; border-radius: 5px;
  padding: 6px 4px; font-size: 12.5px; font-weight: 550; color: var(--text-dim);
  transition: background .12s, color .12s;
}
.seg button:hover { color: var(--text); }
.seg button[aria-pressed="true"] {
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-1);
}

.swatches { display: flex; gap: 6px; flex-wrap: wrap; }
.swatches button {
  width: 24px; height: 24px; border-radius: 50%; border: 1px solid rgba(128,128,128,.35);
  padding: 0; box-shadow: var(--shadow-1);
}
.swatches button[aria-pressed="true"] { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The whole row is the target, not the 16px box — but the row itself was 22px,
   just under the 24px minimum. */
.check { display: flex; align-items: center; gap: 9px; cursor: pointer; font-size: 13px;
  min-height: 24px; }
.check input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer;
  flex: 0 0 auto; }

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.tile {
  border: 1px solid var(--border); border-radius: var(--r-s); overflow: hidden;
  background: var(--surface-2); padding: 0; display: grid; gap: 0;
  transition: border-color .12s, transform .07s;
}
.tile:hover { border-color: var(--border-2); }
.tile[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.tile .sw { height: 38px; width: 100%; display: block; }
.tile .nm { font-size: 10.5px; padding: 4px 3px; color: var(--text-dim); text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- pen / hand pickers ---------------------------------------------- */

.grouphead {
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); margin: 2px 0 -2px;
}

.pentiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.pentile {
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--surface-2);
  padding: 0; overflow: hidden; display: grid; gap: 0;
  transition: border-color .12s, background .12s;
}
.pentile:hover { border-color: var(--border-2); background: var(--surface-3); }
.pentile[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.pentile canvas { display: block; width: 100%; height: auto; }
.pentile .nm {
  font-size: 9.5px; padding: 3px 2px 4px; color: var(--text-dim); text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pentile[aria-pressed="true"] .nm { color: var(--accent); font-weight: 600; }

.handtiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.arttiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.pentile.art img {
  display: block; width: 100%; aspect-ratio: 1; object-fit: contain;
  padding: 4px; box-sizing: border-box;
}

.penpreview {
  border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%),
    var(--surface-2);
}
.penpreview canvas { display: block; width: 100%; height: auto; }

.tonerow { display: flex; gap: 7px; flex-wrap: wrap; }
.tonerow button {
  width: 28px; height: 28px; border-radius: 50%; padding: 0;
  border: 1px solid rgba(128,128,128,.4); box-shadow: var(--shadow-1);
}
.tonerow button[aria-pressed="true"] { outline: 2px solid var(--accent); outline-offset: 2px; }

.fontlist { display: grid; gap: 5px; max-height: 268px; overflow: auto; padding-right: 3px; }
.fontrow {
  display: flex; align-items: center; gap: 10px; text-align: left;
  border: 1px solid var(--border); background: var(--surface-2);
  border-radius: var(--r-s); padding: 7px 10px; width: 100%;
}
.fontrow:hover { border-color: var(--border-2); background: var(--surface-3); }
.fontrow[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.fontrow .sample { font-size: 22px; line-height: 1.25; flex: 1 1 auto; min-width: 0;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.fontrow .meta { display: grid; justify-items: end; gap: 2px; flex: 0 0 auto; }
.fontrow .nm { font-size: 10.5px; color: var(--text-faint); }
.tag { font-size: 9.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 1px 6px; border-radius: 100px; }
.tag.reveal { background: rgba(183,118,26,.15); color: var(--warn); }
.tag.safe { background: rgba(23,145,95,.14); color: var(--ok); }

.note {
  font-size: 12px; line-height: 1.5; color: var(--text-dim);
  background: var(--surface-2); border: 1px solid var(--border);
  border-left: 3px solid var(--border-2);
  border-radius: var(--r-s); padding: 9px 11px;
}
.note.warn { border-left-color: var(--warn); }
.note.err  { border-left-color: var(--danger); color: var(--danger); }
.note.ok   { border-left-color: var(--ok); }

/* ============================== preview =============================== */

section.stage {
  flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column;
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--accent) 7%, transparent), transparent 62%),
    var(--bg);
}

.viewport {
  flex: 1 1 auto; min-height: 0; display: grid; place-items: center;
  padding: 20px; position: relative;
}

.canvas-wrap {
  position: relative; box-shadow: var(--shadow-3); border-radius: 4px; overflow: hidden;
  max-width: 100%; max-height: 100%; line-height: 0;
  /* Checkerboard for transparent output (§9.1b) — visible only when the
     paper is transparent, so the user sees what they are getting. */
  background-color: #fff;
}
.canvas-wrap.alpha {
  background-color: #cfd3da;
  background-image:
    linear-gradient(45deg, #9ea4ae 25%, transparent 25%, transparent 75%, #9ea4ae 75%),
    linear-gradient(45deg, #9ea4ae 25%, transparent 25%, transparent 75%, #9ea4ae 75%);
  background-size: 22px 22px;
  background-position: 0 0, 11px 11px;
}
.canvas-wrap canvas { display: block; max-width: 100%; max-height: 100%; }

.stage-note {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 10px;
  font-size: 12px; color: var(--text-dim); background: var(--surface);
  border: 1px solid var(--border); border-radius: 100px; padding: 5px 14px;
  box-shadow: var(--shadow-2); pointer-events: none; opacity: 0;
  transition: opacity .2s;
}
.stage-note.show { opacity: 1; }

.busy {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(2px); font-size: 13px; color: var(--text-dim);
  opacity: 0; pointer-events: none; transition: opacity .15s;
}
.busy.show { opacity: 1; }
.spinner {
  width: 26px; height: 26px; border: 2.5px solid var(--border-2);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin .7s linear infinite; margin: 0 auto 10px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ============================== playback bar ========================== */

.playbar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; background: var(--surface); border-top: 1px solid var(--border);
}
.playbar .time { font: 500 12px/1 var(--mono); color: var(--text-dim); min-width: 92px;
  text-align: right; font-variant-numeric: tabular-nums; }
/* The primary action, parked where the eye already is. See ui/timeline.js.
   A split button: the wide half exports, the narrow half opens the settings. */
.pb-exportgroup { flex: 0 0 auto; display: inline-flex; }
.pb-export { flex: 0 0 auto; border-top-right-radius: 0; border-bottom-right-radius: 0; }
.pb-export-opts {
  flex: 0 0 auto; width: 30px; padding: 0; justify-content: center;
  border-top-left-radius: 0; border-bottom-left-radius: 0;
  border-left: 1px solid rgba(255,255,255,.35);
  box-shadow: 0 1px 2px rgba(61,90,254,.3), 0 4px 14px rgba(61,90,254,.22);
}
/* Chevron points up, toward the panel it opens. */
.pb-export-opts svg { transform: rotate(-90deg); }
/* A checker chip on the button when the output will be transparent, so the
   mode is visible without opening anything. */
.pb-exportgroup.transparent .pb-export::after {
  content: ""; width: 11px; height: 11px; border-radius: 3px; margin-left: 2px;
  background: repeating-conic-gradient(#fff 0% 25%, #b9c0d0 0% 50%) 0 0 / 6px 6px;
  outline: 1px solid rgba(255,255,255,.7);
}

/* Brief highlight when the Export settings are revealed from the playbar. */
.group.flash > summary { animation: flashRow 1.4s ease-out; }
@keyframes flashRow {
  0%, 40% { background: var(--accent-soft); }
  100%    { background: var(--surface); }
}

.scrub { flex: 1 1 auto; position: relative; height: 26px; display: flex; align-items: center;
  cursor: pointer; touch-action: none; }
.scrub .track { position: absolute; left: 0; right: 0; height: 5px; border-radius: 5px;
  background: var(--surface-3); overflow: hidden; }
.scrub .fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent);
  border-radius: 5px; }
.scrub .knob {
  position: absolute; width: 14px; height: 14px; border-radius: 50%; background: var(--accent);
  border: 2px solid var(--surface); box-shadow: var(--shadow-2); transform: translateX(-50%);
  pointer-events: none;
}
.scrub .marks { position: absolute; left: 0; right: 0; height: 5px; pointer-events: none; }
.scrub .marks i { position: absolute; top: 0; width: 1px; height: 5px;
  background: color-mix(in srgb, var(--text) 18%, transparent); }

/* ============================== modals ================================ */

.backdrop {
  position: fixed; inset: 0; background: rgba(8,10,18,.55);
  backdrop-filter: blur(3px); z-index: 100;
  display: grid; place-items: center; padding: 24px;
  opacity: 0; animation: fade .16s forwards;
}
@keyframes fade { to { opacity: 1; } }

.modal {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-l);
  box-shadow: var(--shadow-3); width: min(980px, 100%); max-height: 100%;
  display: flex; flex-direction: column; overflow: hidden;
  transform: translateY(8px) scale(.99); animation: pop .18s forwards;
}
@keyframes pop { to { transform: none; } }
.modal.sm { width: min(480px, 100%); }
.modal header {
  display: flex; align-items: center; gap: 12px; padding: 15px 18px;
  border-bottom: 1px solid var(--border);
}
.modal header h2 { margin: 0; font-size: 15.5px; font-weight: 650; }
.modal header .sub { font-size: 12.5px; color: var(--text-faint); }
.modal .content { padding: 18px; overflow: auto; }
.modal footer {
  display: flex; gap: 9px; justify-content: flex-end; padding: 13px 18px;
  border-top: 1px solid var(--border); background: var(--surface-2);
}

/* template gallery */
.gal-tabs { display: flex; gap: 6px; padding: 12px 18px 0; flex-wrap: wrap; }
.gal-tabs button {
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  border-radius: 100px; padding: 5px 13px; font-size: 12.5px;
}
.gal-tabs button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent);
  border-color: var(--accent); font-weight: 600; }

.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(186px, 1fr)); gap: 13px; }
.card {
  border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden;
  background: var(--surface-2); text-align: left; padding: 0; position: relative;
  transition: border-color .13s, transform .09s, box-shadow .13s;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: var(--shadow-2); }
.card[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
/* A fixed-aspect well, so cards of different canvas ratios line up in a tidy
   grid and nothing reflows when a thumbnail finishes building.

   Plain surface, NOT a checkerboard. The well used to carry one unconditionally,
   which meant every 16:9 template — YouTube, Notebook note, Graph paper — showed
   checkerboard letterbox bands above and below its thumbnail. A checkerboard
   means transparency to anyone who has opened an image editor, so opaque
   templates advertised transparent output, and the two that genuinely are
   transparent looked no different from the rest. The checker now appears only on
   .thumb.alpha, which presets.js sets from the template's own paper preset. */
.card .thumb {
  height: 124px; display: grid; place-items: center; overflow: hidden;
  background: var(--surface-3);
}
.card .thumb.alpha {
  background-image:
    linear-gradient(45deg, color-mix(in srgb, var(--text) 5%, transparent) 25%, transparent 25%,
                    transparent 75%, color-mix(in srgb, var(--text) 5%, transparent) 75%),
    linear-gradient(45deg, color-mix(in srgb, var(--text) 5%, transparent) 25%, transparent 25%,
                    transparent 75%, color-mix(in srgb, var(--text) 5%, transparent) 75%);
  background-size: 16px 16px;
  background-position: 0 0, 8px 8px;
}
.card .thumb canvas {
  display: block; max-width: 100%; max-height: 100%; width: auto; height: auto;
  box-shadow: 0 1px 6px rgba(0,0,0,.18);
}
.card .cap { padding: 8px 10px 10px; }
.card .cap b { display: block; font-size: 12.5px; font-weight: 600; }
.card .cap span { display: block; font-size: 11px; color: var(--text-faint); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card .del {
  position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: 50%;
  background: rgba(0,0,0,.55); color: #fff; border: none; font-size: 14px; line-height: 1;
  display: grid; place-items: center; opacity: 0; transition: opacity .12s;
}
.card:hover .del { opacity: 1; }

/* export progress */
.progress { height: 8px; background: var(--surface-3); border-radius: 100px; overflow: hidden; }
.progress i { display: block; height: 100%; background: var(--accent); width: 0;
  transition: width .15s linear; }
.stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; margin-top: 14px;
  font-size: 12.5px; }
.stats div { display: flex; justify-content: space-between; gap: 10px;
  border-bottom: 1px dashed var(--border); padding-bottom: 4px; }
.stats span { color: var(--text-faint); }
.stats b { font: 500 12.5px/1.5 var(--mono); font-variant-numeric: tabular-nums; }

/* ============================== ad slots ============================== */
/* ============================== ad slots ==============================
   Placed OUTSIDE the app area — never over the canvas, never in the control
   panel, never between an input and its result. Accidental clicks on a tool
   are invalid traffic, and invalid traffic loses the account.

   The states, in order of life:
     (default)    zero height, invisible. An ad that never mounts costs nothing.
     .is-loading  mounted, space reserved while the network answers.
     .is-filled   something rendered. Keep the space; no shift.
     .is-empty    nothing came. Collapse completely, leave no trace.

   That last state is the point: a blocked or unfilled unit must be
   indistinguishable from no ad at all, not a grey rectangle.  See js/ads.js. */

.adslot { display: none; }

/* Even with ads switched on, a slot stays invisible until it mounts. */
.ads-on .adslot {
  display: block; overflow: hidden;
  min-height: 0; height: auto;
  /* Deliberately NOT transitioned. Animating min-height on an ad slot is a
     layout animation — it is a CLS risk, it makes the collapse take 180ms the
     user can see, and a transition that is interrupted or throttled leaves
     getComputedStyle reporting the old value indefinitely. A slot that found
     nothing should vanish instantly and unconditionally. */
}

/* Loading: reserved SPACE and nothing else. No box, no border, no skeleton,
   no label. If the unit arrives it drops straight into place with no shift; if
   it does not, the reader never saw anything at all. There is deliberately no
   "Advertisement" or "Sponsored" text anywhere in this stylesheet or in the
   markup — the ad is the only thing that is ever shown. */
.ads-on .adslot.is-loading {
  min-height: 100px;
  background: none; border: none;
}
.ads-on .adslot[data-size="leaderboard"].is-loading { min-height: 90px; }

/* Filled: the unit's own height, centred, with a little room to breathe so it
   does not collide with the paragraph above or below it. */
.ads-on .adslot.is-filled {
  min-height: 0; background: none; border: none; border-radius: 0;
  display: grid; place-items: center;
  margin: 26px 0;
}
.ads-on .adslot.is-filled[data-size="leaderboard"] {
  margin: 0; padding: 12px 0; border-top: 1px solid var(--border);
}

/* Empty: gone. No height, no border, no margin, nothing to notice. */
.ads-on .adslot.is-empty {
  display: none !important;
}

/* Ad units are third-party markup; stop a wide one breaking the layout. */
.adslot img, .adslot iframe { max-width: 100%; }

/* ---- native banner layout on a narrow column ---------------------------
   Adsterra's native banner is a flex row that wraps. Given a phone-width
   column it puts every item on its own line: measured at 390px, one unit came
   out 1198px tall — four stacked cards, 1.4 screens of advertising in a single
   slot. Three of those on one article is more ad than article, which is bad
   for the reader and bad for the ad-to-content ratio.

   Laying the items out two-up halves that to about 600px. Every ad stays fully
   visible and fully clickable — nothing is hidden, cropped or overlaid; only
   the number of columns changes, which is exactly what a responsive unit is
   supposed to do. If Adsterra ever objects, delete this one block. */
@media (max-width: 700px) {
  .adslot [id^="container-"] > div {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    align-items: start;
  }
  .adslot [id^="container-"] > div > div { width: auto !important; }
}

/* ============================== footer / SEO ========================== */

.seo { background: var(--surface); border-top: 1px solid var(--border); padding: 40px 24px 28px; }
.seo-inner { max-width: 1080px; margin: 0 auto; display: grid; gap: 28px; }
.seo h2 { font-size: 19px; margin: 0 0 6px; }
.seo h3 { font-size: 14px; margin: 0 0 4px; }
.seo p  { margin: 0 0 8px; color: var(--text-dim); max-width: 72ch; }
.seo .cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 22px; }
.seo footer { border-top: 1px solid var(--border); padding-top: 16px; font-size: 12.5px;
  color: var(--text-faint); display: flex; gap: 16px; flex-wrap: wrap; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================== responsive ============================ */
/* Tablet and phone: preview on top and sticky, controls underneath (§11.1). */

@media (max-width: 900px) {
  /* The preview goes on top and stays there while the controls scroll under
     it. The DOM keeps the panel first so that keyboard and screen-reader order
     still reaches the controls without passing a canvas, so the swap is done
     with `order` rather than by moving the markup. */
  #app { height: auto; min-height: 100dvh; }
  .main { flex-direction: column; }
  section.stage {
    order: -1;
    position: sticky; top: 0; z-index: 20; flex: 0 0 auto;
    height: 46dvh; min-height: 220px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
  }
  .viewport { padding: 10px; }
  aside.panel {
    order: 1;
    width: 100%; flex: 1 1 auto; border-right: none; overflow: visible;
  }
  .langbar { max-width: 34vw; }
  .brand span { display: none; }
  .tiles { grid-template-columns: repeat(4, 1fr); }

  /* Tablet: cap the control column instead of letting it span the viewport.
     At 768px the panel was 753px wide, which stretched "Start | Centre | End"
     across the whole screen and left the label miles from the control it
     labels — a phone layout inflated rather than a tablet layout designed.
     The preview above is unaffected and still uses the full width. */
  aside.panel > details.group { max-width: 640px; margin-inline: auto; }
  aside.panel > details.group > summary { max-width: none; }

  /* Touch sizing. 24px (WCAG 2.2 AA 2.5.8) is the floor, not the goal — a
     finger is nearer 44px, and these are controls people drag and re-tap while
     watching the preview, so the desktop density is the wrong trade here. */
  .seg button { padding: 13px 4px; font-size: 13px; }
  .btn { min-height: 44px; }
  .btn.sm { min-height: 40px; padding: 10px 12px; }
  .btn.icon { width: 44px; height: 44px; }
  .check { min-height: 44px; }
  .check input { width: 20px; height: 20px; }
  input[type="range"] { height: 44px; }
  input[type="range"]::-webkit-slider-thumb { width: 20px; height: 20px; margin-top: -8px; }
  input[type="range"]::-moz-range-thumb { width: 20px; height: 20px; }
  input[type="number"], input[type="text"], select { min-height: 44px; }
  input[type="color"] { width: 54px; height: 44px; }
  .swatches { gap: 9px; }
  .swatches button { width: 32px; height: 32px; }
  .tonerow button { width: 36px; height: 36px; }
  .playbar .scrub { min-height: 38px; }
}

@media (max-width: 560px) {
  header.topbar { height: auto; padding: 8px 10px; gap: 8px; flex-wrap: wrap; }
  .brand b { font-size: 15px; }

  /* The language chips used to be display:none here. Ten languages across four
     scripts is the one thing this tool does that its competitors do not, and
     hiding the only place that advertises it left phone users with no idea —
     the Script dropdown is an engine override, not an invitation to try
     Bengali. Given its own full-width row it stays visible and scrolls, at the
     cost of about 36px of header. */
  .langbar { order: 10; flex: 1 0 100%; max-width: none; padding-bottom: 2px; }
  .langbar button { padding: 7px 13px; font-size: 12.5px; }
  .gallery { grid-template-columns: repeat(auto-fill, minmax(146px, 1fr)); }
  .modal { border-radius: var(--r-m); }
  .backdrop { padding: 10px; }

  /* Two rows rather than one cramped one: the scrubber gets the full width, and
     the transport controls sit under it with Export pinned to the right. Fitting
     all six into a single 320px row left the scrubber about 38px wide. */
  .playbar { gap: 8px; padding: 8px 10px; flex-wrap: wrap; row-gap: 10px; }
  .scrub { order: -1; flex: 1 0 100%; }
  /* flex-basis 0, not auto: a wrapping flex container breaks lines from each
     item's BASIS before it shrinks anything, so a readout asking for its full
     112px content width pushed Export onto a third row at 320px. With a zero
     basis the clock takes whatever is left and clips instead. */
  .playbar .time { min-width: 0; flex: 1 1 0; text-align: left; font-size: 11px;
    white-space: nowrap; overflow: hidden; }
  .pb-export { margin-left: auto; }
}

/* On the narrowest phones the label goes and the download icon carries it —
   the button is still the only blue thing on the bar, so it still reads as
   the primary action. */
@media (max-width: 400px) {
  .pb-export span { display: none; }
  .pb-export { width: 44px; padding: 0; justify-content: center; }
}

/* ============================== static pages ==========================
   about / contact / privacy / terms. These were four copies of the same
   inline <style> block; one class here is one place to maintain. The pages
   are plain documents, so `body` gets `display:block` back and the app's
   flex shell never applies.
   ====================================================================== */

body.doc { display: block; height: auto; }

.doc main { max-width: 74ch; margin: 0 auto; padding: 48px 24px 64px; }
.doc h1 { font-size: 26px; margin: 0 0 6px; letter-spacing: -.4px; }
.doc .lede { color: var(--text-dim); font-size: 15.5px; margin: 0 0 30px; }
.doc h2 { font-size: 16px; margin: 32px 0 8px; }
.doc h3 { font-size: 14px; margin: 22px 0 6px; }
.doc p, .doc li { color: var(--text-dim); }
.doc ul, .doc ol { padding-left: 20px; }
.doc li { margin-bottom: 6px; }
.doc .back {
  display: inline-flex; gap: 6px; align-items: center;
  margin-bottom: 26px; font-size: 13px; text-decoration: none;
}
.doc code {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 5px;
  padding: 1px 5px; font: 12.5px var(--mono); color: var(--text);
}
.doc table { border-collapse: collapse; width: 100%; margin: 12px 0; font-size: 13.5px; }
.doc th, .doc td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.doc th { color: var(--text); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
.doc td { color: var(--text-dim); }

/* The shared footer nav at the bottom of every static page. */
.doc footer {
  margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--text-faint);
  display: flex; gap: 16px; flex-wrap: wrap; align-items: center;
}
.doc footer nav { display: flex; gap: 14px; flex-wrap: wrap; }

/* A quiet callout for the one or two places a page needs to stress something. */
.doc .callout {
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  background: var(--surface-2); border-radius: var(--r-s);
  padding: 12px 14px; margin: 16px 0;
}
.doc .callout p:last-child { margin-bottom: 0; }

.doc .cta {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--accent); color: var(--accent-fg);
  border-radius: var(--r-m); padding: 10px 16px;
  font-weight: 600; font-size: 13.5px; text-decoration: none;
}

/* ---- landing copy: added SEO sections --------------------------------- */
.seo h1 { font-size: 26px; margin: 0 0 10px; letter-spacing: -.4px; }
.seo .lede { font-size: 15.5px; color: var(--text-dim); max-width: 68ch; margin: 0 0 14px; }
.seo ul, .seo ol { margin: 0 0 8px; padding-left: 20px; max-width: 72ch; color: var(--text-dim); }
.seo li { margin-bottom: 7px; }

/* Numbered steps read as a procedure rather than a list of sentences, which is
   also the shape a step-by-step rich result wants. */
.seo ol.steps { counter-reset: step; list-style: none; padding-left: 0; display: grid; gap: 10px; }
.seo ol.steps li {
  counter-increment: step; position: relative; padding: 11px 14px 11px 46px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-m);
}
.seo ol.steps li::before {
  content: counter(step); position: absolute; left: 13px; top: 11px;
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent); color: var(--accent-fg); font: 600 12px/1 var(--font);
}

.seo table.compare, .doc table { border-collapse: collapse; width: 100%; max-width: 72ch;
  margin: 12px 0; font-size: 13.5px; }
.seo table.compare th, .seo table.compare td {
  text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border); }
.seo table.compare th { color: var(--text); font-size: 12px; text-transform: uppercase;
  letter-spacing: .04em; }
.seo table.compare td { color: var(--text-dim); }
.seo table.compare td b { color: var(--text); }

/* A short row of links from the landing copy into the language pages. */
.seo .cluster { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
.seo .cluster a {
  display: inline-flex; align-items: center; gap: 7px; text-decoration: none;
  border: 1px solid var(--border-2); background: var(--surface-2);
  border-radius: 100px; padding: 8px 15px; font-size: 13px; font-weight: 550;
  color: var(--text); transition: border-color .12s, background .12s;
}
.seo .cluster a:hover { border-color: var(--accent); color: var(--accent); }
