Files
booth/booth/templates/base.html
T
vh 88d3cf436e fix(booth): a partial ask answer is recorded, not refused
Operator: the form failed when a question was left blank. Refusing the whole
submission over one blank threw away the picks that were made, and the HTML
`required` on the radios blocked it in the browser before the server saw it.

- answered questions recorded; blank ones land in `unanswered`; `complete` says
  whether the set is finished; a blank question carrying a note keeps the note
- `required` dropped from both templates so the browser cannot block a partial
- refused only when there is no pick anywhere AND no notes (a 400 — that would
  flip an open ask to answered with no decision recorded); a choice outside the
  option list is still an error
- new ◐ partial state with an n/N count; skipped questions render as skipped
- README + global CLAUDE.md tell reading sessions to check `complete`
- 154 tests; v0.1.15
2026-09-09 15:05:18 -07:00

411 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}The Booth{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%23171a23'/%3E%3Ccircle cx='16' cy='16' r='6' fill='none' stroke='%2342dcd1' stroke-width='2.5'/%3E%3Ccircle cx='16' cy='16' r='2.2' fill='%2342dcd1'/%3E%3C/svg%3E">
<style>
/* ============================================================
The Booth — Corviduo "Australis" theme (aurora accents, dark-first).
Token values adopted from ratatoskr-web (colors_and_type.css canonical
palette). Self-contained, no webfont CDN — system fallback stacks.
============================================================ */
:root{
/* ---- Australis raw palette ---- */
--aus-black:#222531; --aus-white:#a9bcc3; --aus-bright-white:#cce7ec; --aus-bright-black:#373b46;
--aus-dark-30:#414751; --aus-dark-40:#565f69; --aus-dark-50:#6e7882; --aus-dark-60:#86929d;
--aus-bright-70:#9daeb6; --aus-bright-80:#b3cbcf;
--aus-blue:#6388d8; --aus-bright-blue:#a4c4ff;
--aus-cyan:#00b1a8; --aus-bright-cyan:#42dcd1;
--aus-green:#16b866; --aus-bright-green:#51e08a;
--aus-red:#ff491a; --aus-bright-red:#ff854f;
--aus-yellow:#e1c631; --aus-bright-yellow:#ffe14e;
--aus-magenta:#9d78ff; --aus-bright-magenta:#d8adff;
/* ---- semantic surface / foreground ---- */
--border-subtle:var(--aus-dark-30); --border-default:var(--aus-dark-40); --border-strong:var(--aus-dark-50);
--fg-0:var(--aus-bright-white); --fg-1:var(--aus-white); --fg-2:var(--aus-bright-70);
--fg-3:var(--aus-dark-60); --fg-muted:var(--aus-dark-50); --fg-on-accent:var(--aus-black);
/* ---- ratatoskr console surfaces ---- */
--rk-deep:#14161d; --rk-canvas:#171a23; --rk-well:#1b1e28; --rk-panel:#1d2029; --rk-ghost:#2c3040;
/* ---- type ---- */
--font-display:"Space Grotesk","Inter",ui-sans-serif,system-ui,sans-serif;
--font-sans:"Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
--font-mono:"Berkeley Mono","JetBrains Mono","IBM Plex Mono",ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;
/* ---- radius / shadow / motion ---- */
--radius-sm:4px; --radius-md:6px; --radius-lg:10px; --radius-pill:9999px;
--shadow-2:0 2px 6px rgba(10,12,18,.45),0 1px 2px rgba(10,12,18,.4);
--shadow-3:0 8px 24px rgba(10,12,18,.5),0 2px 6px rgba(10,12,18,.4);
--glow-cyan:0 0 0 3px rgba(66,220,209,.26);
--ease-out:cubic-bezier(.2,.8,.2,1);
--ease-aurora:cubic-bezier(.65,0,.35,1);
}
@media (prefers-color-scheme: light){
:root{
--rk-deep:#e5edef; --rk-canvas:#eef4f6; --rk-well:#ffffff; --rk-panel:#f6fafb; --rk-ghost:#cad8dd;
--border-subtle:#d3dfe3; --border-default:#bccad0; --border-strong:#9fb0b7;
--fg-0:#10151c; --fg-1:#26313a; --fg-2:#48555f; --fg-3:#64727c; --fg-muted:#8a99a1; --fg-on-accent:#ffffff;
--aus-bright-cyan:#0a938b; --aus-cyan:#0a938b; --aus-bright-green:#12925a; --aus-green:#12925a;
--aus-bright-blue:#3f66bd; --aus-blue:#4a6fc0; --aus-bright-magenta:#7a52d8; --aus-magenta:#7a52d8;
--aus-bright-red:#d63a15; --aus-red:#d63a15; --aus-bright-yellow:#a9820a; --aus-yellow:#b98f0c;
--aus-dark-40:#b0bec4;
--shadow-3:0 8px 24px rgba(30,50,60,.16),0 2px 6px rgba(30,50,60,.1);
--glow-cyan:0 0 0 3px rgba(10,147,139,.2);
}
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:var(--rk-canvas);color:var(--fg-1);font-family:var(--font-sans);
line-height:1.5;-webkit-font-smoothing:antialiased;min-height:100vh;display:flex;flex-direction:column;
transition:background-color .32s var(--ease-aurora),color .32s var(--ease-aurora)}
a{color:var(--aus-bright-cyan);text-decoration:none}
a:hover{color:var(--aus-cyan);text-decoration:underline}
code{font-family:var(--font-mono);font-size:.84em;background:var(--rk-well);color:var(--fg-2);
padding:.12em .42em;border-radius:var(--radius-sm);border:1px solid var(--border-subtle)}
.topbar{display:flex;align-items:center;gap:1.1rem;flex-wrap:wrap;
padding:1rem 1.5rem;border-bottom:1px solid var(--border-subtle);
background:linear-gradient(180deg,var(--rk-panel),transparent)}
.brand{display:inline-flex;align-items:center;gap:.6rem;color:var(--fg-0)}
.brand:hover{text-decoration:none}
.brand .dot{width:.62rem;height:.62rem;border-radius:50%;background:var(--aus-bright-cyan);
box-shadow:0 0 0 4px rgba(66,220,209,.15),0 0 12px rgba(66,220,209,.5);
animation:pulse 2.8s var(--ease-aurora) infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
.brand .name{font-family:var(--font-display);font-size:1.22rem;font-weight:600;letter-spacing:-.01em}
.tagline{color:var(--aus-cyan);font-size:.66rem;font-family:var(--font-mono);
letter-spacing:.2em;text-transform:uppercase}
main{flex:1;width:100%;max-width:1240px;margin:0 auto;padding:1.7rem 1.5rem 3rem}
/* ---- upload / pickup ---- */
.uploader{display:flex;gap:.9rem;align-items:stretch;margin-bottom:1.7rem;flex-wrap:wrap}
.drop{flex:1 1 300px;position:relative;display:flex;flex-direction:column;align-items:center;
justify-content:center;gap:.15rem;text-align:center;cursor:pointer;padding:1.1rem 1rem;
border:1.5px dashed var(--border-default);border-radius:var(--radius-lg);background:var(--rk-well);
transition:border-color .16s var(--ease-out),background .16s var(--ease-out),box-shadow .16s var(--ease-out)}
.drop:hover{border-color:var(--aus-cyan)}
.drop.over{border-color:var(--aus-bright-cyan);background:rgba(66,220,209,.06);box-shadow:var(--glow-cyan)}
.drop.has{border-style:solid;border-color:var(--aus-cyan)}
.drop input[type=file]{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}
.drop-icon{font-size:1.2rem;color:var(--aus-bright-cyan)}
.drop-main{font-family:var(--font-display);font-weight:600;color:var(--fg-0);font-size:.98rem}
.drop-sub{font-family:var(--font-mono);font-size:.7rem;letter-spacing:.03em;color:var(--fg-3)}
.up-go{flex:0 0 auto;align-self:stretch;cursor:pointer;font-family:var(--font-mono);font-size:.74rem;
letter-spacing:.1em;text-transform:uppercase;padding:0 1.15rem;border-radius:var(--radius-lg);
background:transparent;border:1px solid var(--aus-cyan);color:var(--aus-bright-cyan);
transition:.14s var(--ease-out)}
.up-go:hover{background:var(--aus-bright-cyan);color:var(--fg-on-accent);border-color:var(--aus-bright-cyan)}
.badge{display:inline-block;font-family:var(--font-mono);font-size:.6rem;letter-spacing:.1em;
text-transform:uppercase;font-weight:600;color:var(--fg-on-accent);background:var(--aus-bright-cyan);
padding:.08rem .42rem;border-radius:var(--radius-pill);vertical-align:middle}
.card .thumb{position:relative}
.thumb .badge{position:absolute;top:.5rem;left:.5rem;box-shadow:var(--shadow-2)}
/* Kept lane. The accent is a 2px TOP edge in aurora blue — the one accent
border Australis sanctions (never a coloured left border), and it marks the
card as featured without changing its fill, so kept and ephemeral still
read as the same family of object. */
.lane-head{margin:1.9rem 0 .8rem;font-family:var(--font-mono);font-size:.68rem;font-weight:600;
letter-spacing:.14em;text-transform:uppercase;color:var(--aus-bright-cyan);
display:flex;align-items:center;gap:.7rem}
.lane-head::after{content:"";flex:1;height:1px;background:var(--border-subtle)}
.lane-note{font-weight:400;letter-spacing:.06em;color:var(--fg-3);text-transform:none}
.lane-note code{font-size:.95em;color:var(--fg-2)}
.kept-grid{margin-bottom:.4rem}
.card-kept{border-top:2px solid var(--aus-blue)}
.card-kept:hover{border-color:var(--aus-blue);border-top-color:var(--aus-bright-blue)}
.badge-kept{background:var(--aus-blue);color:var(--fg-on-accent)}
/* Release sits where the ephemeral card's × sits, but reads as a word rather
than a destructive glyph — it is not the delete, it is what unlocks it. */
.release{position:absolute;top:.4rem;right:.4rem;opacity:0;transition:opacity .12s}
.card-kept:hover .release,.release:focus-within{opacity:1}
.release button{font:inherit;font-size:.72rem;line-height:1;padding:.22rem .45rem;
border-radius:.3rem;cursor:pointer;border:1px solid var(--aus-blue);
background:var(--rk-panel);color:var(--aus-blue)}
.release button:hover{background:var(--aus-blue);color:var(--fg-on-accent)}
/* ---- the standing link board ------------------------------------------
Rows, not a markdown blob. Dense enough that thirty entries stay
scannable, with provenance de-emphasised so the description leads and the
× only surfaces on hover — destructive controls should not compete for
attention with the thing you came to read. */
.board{border:1px solid var(--border-subtle);border-radius:.5rem;overflow:hidden;
background:var(--rk-panel);margin:.6rem 0 1rem}
.board-head{display:flex;align-items:center;gap:.6rem;padding:.45rem .75rem;
border-bottom:1px solid var(--border-subtle);background:var(--rk-well)}
.board-selall{display:inline-flex;align-items:center;cursor:pointer;flex:0 0 auto}
.board-title{font-weight:600;font-size:.85rem}
.board-note{font-size:.72rem;color:var(--fg-3)}
.board-spacer{flex:1 1 auto}
/* Bulk delete: quiet until something is selected. Red-outline danger word,
matching the .wipe-lg language — fills on hover, greys out when disabled. */
.board-del-sel{flex:0 0 auto;cursor:pointer;font-family:var(--font-mono);font-size:.7rem;
letter-spacing:.06em;padding:.28rem .6rem;border-radius:var(--radius-sm);
background:transparent;border:1px solid var(--aus-red);color:var(--aus-bright-red);
transition:.14s var(--ease-out)}
.board-del-sel:hover:not(:disabled){background:var(--aus-red);border-color:var(--aus-red);color:#fff}
.board-del-sel:disabled{opacity:.4;cursor:default;border-color:var(--border-default);color:var(--fg-3)}
.board-row{display:flex;align-items:center;gap:.6rem;padding:.45rem .75rem;
border-bottom:1px solid var(--border-subtle);transition:background .1s}
.board-row:last-child{border-bottom:0}
.board-row:hover{background:var(--rk-well)}
/* Pinned rows: a subtle cyan wash + a filled star. NOT a coloured left border
(Australis forbids it); the tint is enough to group them, and the ★ carries
the state at the row level. */
.board-row.is-pinned{background:rgba(66,220,209,.05)}
.board-row.is-pinned:hover{background:rgba(66,220,209,.09)}
.board-check{flex:0 0 auto;width:1rem;height:1rem;cursor:pointer;accent-color:var(--aus-bright-cyan)}
.board-selall input{width:1rem;height:1rem;cursor:pointer;accent-color:var(--aus-bright-cyan)}
/* ★ favorite toggle. Always visible (unlike ×) because it carries state you
need to see; dim-hollow when off, warm-gold and filled when pinned. */
.board-pin{flex:0 0 auto;border:0;background:none;cursor:pointer;line-height:1;
font-size:1.02rem;padding:.05rem .2rem;border-radius:.25rem;color:var(--fg-3);
transition:color .12s,transform .12s var(--ease-out)}
.board-pin:hover{color:var(--aus-bright-yellow);transform:scale(1.15)}
.board-pin.on{color:var(--aus-bright-yellow)}
.board-main{flex:1 1 auto;min-width:0}
.board-link{font-size:.9rem;text-decoration:none;font-weight:500}
.board-link:hover{text-decoration:underline}
.board-url{font-size:.7rem;color:var(--fg-3);opacity:.8;overflow:hidden;text-overflow:ellipsis;
white-space:nowrap;font-family:var(--font-mono)}
.board-meta{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;
gap:.05rem;font-size:.68rem;color:var(--fg-3);white-space:nowrap}
.board-who{font-weight:600}
.board-copy,.board-rm-btn{opacity:0;transition:opacity .12s;flex:0 0 auto}
.board-row:hover .board-copy,.board-row:hover .board-rm-btn,
.board-copy:focus,.board-rm-btn:focus{opacity:1}
.board-rm-btn{font:inherit;font-size:1rem;line-height:1;padding:.1rem .35rem;
border:0;background:none;cursor:pointer;color:var(--fg-2);border-radius:.25rem}
.board-rm-btn:hover{background:var(--aus-red);color:#fff}
@media (max-width:600px){
/* No hover on touch — controls must be permanently visible or unreachable. */
.board-copy,.board-rm-btn{opacity:1}
.board-meta{display:none}
}
.pickup-note{margin:-.5rem 0 1.5rem;padding:.6rem .85rem;border:1px solid var(--border-subtle);
border-left:3px solid var(--aus-bright-cyan);border-radius:var(--radius-md);background:var(--rk-well);
font-family:var(--font-mono);font-size:.78rem;color:var(--fg-2)}
.copy-btn{cursor:pointer;font-family:var(--font-mono);font-size:.68rem;letter-spacing:.04em;
padding:.12rem .5rem;margin:0 .25rem;border:1px solid var(--border-default);border-radius:var(--radius-sm);
background:transparent;color:var(--aus-bright-cyan);vertical-align:middle;transition:.12s var(--ease-out)}
.copy-btn:hover{border-color:var(--aus-cyan);background:rgba(66,220,209,.08)}
.copy-btn.copied{border-color:var(--aus-green);color:var(--aus-bright-green)}
.dl-link{color:var(--aus-bright-cyan);text-decoration:none;margin-right:.4rem;font-size:.95em}
.dl-link:hover{color:var(--aus-cyan)}
.cap-text{color:var(--fg-2)}
/* ---- image viewer (fixed full-viewport overlay) ---- */
.viewer{position:fixed;inset:0;z-index:50;background:var(--rk-canvas);display:flex;flex-direction:column}
.vbar{display:flex;align-items:center;gap:.7rem;padding:.5rem .8rem;
border-bottom:1px solid var(--border-subtle);background:var(--rk-panel)}
.vname{font-family:var(--font-mono);font-size:.8rem;color:var(--fg-2);
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:50vw}
.vspacer{flex:1}
.vbtn{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;
padding:0 .55rem;border:1px solid var(--border-default);border-radius:var(--radius-md);
color:var(--fg-1);background:transparent;font-family:var(--font-mono);font-size:.9rem;
transition:.14s var(--ease-out)}
.vbtn:hover{border-color:var(--aus-cyan);color:var(--aus-bright-cyan);text-decoration:none}
.vx:hover{border-color:var(--aus-red);color:#fff;background:var(--aus-red)}
.vtoggle{border:1px solid var(--border-default);border-radius:var(--radius-md);overflow:hidden}
.vseg{cursor:pointer;border:0;background:transparent;color:var(--fg-3);font-family:var(--font-mono);
font-size:.72rem;letter-spacing:.06em;padding:.4rem .75rem;transition:.14s var(--ease-out)}
.vseg+.vseg{border-left:1px solid var(--border-default)}
.vseg:hover{color:var(--fg-1)}
.vseg.on{background:var(--aus-bright-cyan);color:var(--fg-on-accent)}
.vstage{flex:1;min-height:0;background:var(--rk-deep)}
.vstage.fit{display:flex;align-items:center;justify-content:center;overflow:hidden;padding:1rem}
.vstage.fit img{max-width:100%;max-height:100%;width:auto;height:auto;box-shadow:var(--shadow-3)}
.vstage.one{overflow:auto;text-align:center}
.vstage.one img{max-width:none;max-height:none;margin:auto}
.foot{border-top:1px solid var(--border-subtle);color:var(--fg-muted);
font-size:.72rem;font-family:var(--font-mono);letter-spacing:.04em;padding:1rem 1.5rem;text-align:center}
.empty{border:1px dashed var(--border-default);border-radius:var(--radius-lg);
padding:3rem 1.5rem;text-align:center;color:var(--fg-3);background:var(--rk-well);font-family:var(--font-mono);font-size:.92rem}
/* index grid */
.grid{display:grid;gap:1.1rem;grid-template-columns:repeat(auto-fill,minmax(248px,1fr))}
.card{position:relative;background:var(--rk-panel);border:1px solid var(--border-subtle);
border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-2);
transition:transform .16s var(--ease-out),border-color .16s var(--ease-out),box-shadow .16s var(--ease-out)}
.card:hover{transform:translateY(-3px);border-color:var(--aus-cyan);box-shadow:var(--shadow-3),var(--glow-cyan)}
.card .thumb{display:block;aspect-ratio:16/10;background:var(--rk-deep);overflow:hidden}
.card .thumb img{width:100%;height:100%;object-fit:cover;display:block}
.card .ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;
color:var(--fg-3);font-family:var(--font-mono);font-size:.82rem;letter-spacing:.16em;text-transform:uppercase}
.card .meta{padding:.7rem .85rem .85rem}
.card .name{display:block;font-family:var(--font-display);font-weight:600;color:var(--fg-0);word-break:break-word}
.card .name:hover{text-decoration:none;color:var(--aus-bright-cyan)}
.card .sub{color:var(--fg-3);font-size:.72rem;font-family:var(--font-mono);letter-spacing:.03em;margin-top:.3rem}
.wipe{position:absolute;top:.5rem;right:.5rem;margin:0}
/* opaque dark control-scrim + always-light glyph — legible over any thumbnail
AND in both themes (glyph must NOT follow --fg-*, which flips dark on light). */
.wipe button{cursor:pointer;border:1px solid rgba(255,255,255,.16);background:rgba(16,18,25,.86);
color:#e9eef0;width:1.9rem;height:1.9rem;border-radius:var(--radius-md);font-size:1.1rem;line-height:1;
backdrop-filter:blur(6px);transition:.14s var(--ease-out)}
.wipe button:hover{border-color:var(--aus-red);color:#fff;background:var(--aus-red)}
/* Asks — a session's multiple-choice question awaiting the operator.
Amber = "needs you" while open (the one colour the page does not otherwise
use for state), green check once answered; the accent is a TOP edge, per
Australis, never a coloured left border. */
.badge-ask{background:var(--aus-bright-yellow);color:var(--fg-on-accent)}
.thumb .badge+.badge-ask{top:2.2rem}
.asks{display:flex;flex-direction:column;gap:.9rem;margin:.2rem 0 1.4rem}
.ask{border:1px solid var(--border-subtle);border-top:2px solid var(--aus-bright-yellow);
border-radius:.5rem;background:var(--rk-panel);overflow:hidden}
.ask.is-answered{border-top-color:var(--aus-bright-green)}
/* Partial: answered SOME questions. Not a failure and not done — blanks are a
legal outcome (operator ruling 2026-09-09), so it gets its own state rather
than being forced into one of the other two. */
.ask.is-partial{border-top-color:var(--aus-bright-blue)}
.ask.is-partial .ask-state{color:var(--aus-bright-blue)}
.ask-part{font-family:var(--font-mono);font-size:.68rem;color:var(--aus-bright-blue);font-weight:700}
.ask-answer-choice.is-skipped{opacity:.55;font-style:italic}
.ask-answer-choice.is-skipped::before{content:"— ";color:var(--fg-3)}
.ask.is-broken{border-top-color:var(--aus-bright-red)}
.ask-head{display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;
border-bottom:1px solid var(--border-subtle);background:var(--rk-well);
font-family:var(--font-mono);font-size:.68rem;color:var(--fg-3)}
.ask-state{font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--aus-bright-yellow)}
.ask.is-answered .ask-state{color:var(--aus-bright-green)}
.ask.is-broken .ask-state{color:var(--aus-bright-red)}
.ask-when{white-space:nowrap}
.ask-title{margin:.8rem .9rem -.35rem;font-family:var(--font-mono);font-size:.7rem;
letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3)}
.ask-prompt{margin:.85rem .9rem .5rem;font-size:1.02rem;font-weight:600;color:var(--fg-0);white-space:pre-wrap}
.ask-error{margin:.8rem .9rem;color:var(--aus-bright-red);font-size:.85rem}
.ask-answer{margin:.2rem .9rem .6rem;padding:.55rem .75rem;border:1px solid var(--border-subtle);
border-radius:var(--radius-md);background:rgba(81,224,138,.06)}
.ask-answer-choice{font-weight:600;color:var(--fg-0)}
.ask-answer-choice::before{content:"✓ ";color:var(--aus-bright-green)}
.ask-answer-notes{margin:.4rem 0 0;white-space:pre-wrap;font-family:var(--font-sans);font-size:.86rem;
color:var(--fg-1)}
.ask-answer-file{display:block;margin-top:.35rem;font-family:var(--font-mono);font-size:.68rem;color:var(--fg-3)}
.ask-answer-file a{color:var(--fg-2)}
.ask-formwrap{margin:0 .9rem .8rem}
.ask-change{cursor:pointer;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.06em;
text-transform:uppercase;color:var(--fg-3);list-style:none;user-select:none}
.ask-change::-webkit-details-marker{display:none}
.ask-formwrap[open]>.ask-change{margin-bottom:.4rem}
.ask-formwrap:not([open])>.ask-change{color:var(--aus-bright-cyan)}
.ask-q{border:0;margin:0 0 .7rem;padding:0;min-width:0}
.ask-q:last-of-type{margin-bottom:0}
.ask-q-prompt{padding:0;margin:0 0 .35rem;font-size:.9rem;font-weight:600;color:var(--fg-0)}
.ask-qnotes{margin-top:.35rem;font-size:.82rem}
.ask-answer-q{padding:.3rem 0;border-bottom:1px dashed var(--border-subtle)}
.ask-answer-q:last-of-type{border-bottom:0}
.ask-answer-qprompt{display:block;font-size:.76rem;color:var(--fg-3)}
.ask-options{display:flex;flex-direction:column;gap:.35rem}
.ask-opt{display:flex;align-items:flex-start;gap:.6rem;padding:.5rem .65rem;cursor:pointer;
border:1px solid var(--border-subtle);border-radius:var(--radius-md);background:var(--rk-well);
transition:border-color .12s,background .12s}
.ask-opt:hover{border-color:var(--border-strong)}
.ask-opt:has(input:checked){border-color:var(--aus-bright-cyan);background:rgba(66,220,209,.07)}
.ask-opt input{margin:.2rem 0 0;accent-color:var(--aus-bright-cyan);flex:0 0 auto}
.ask-opt-main{display:flex;flex-direction:column;gap:.1rem;min-width:0}
.ask-opt-label{font-size:.92rem;color:var(--fg-0)}
.ask-opt-detail{font-size:.76rem;color:var(--fg-3);white-space:pre-wrap}
.ask-notes{display:block;width:100%;box-sizing:border-box;margin:.6rem 0 0;padding:.5rem .6rem;
font:inherit;font-size:.88rem;color:var(--fg-0);background:var(--rk-well);
border:1px solid var(--border-subtle);border-radius:var(--radius-md);resize:vertical}
.ask-notes:focus{outline:none;border-color:var(--aus-bright-cyan);box-shadow:var(--glow-cyan)}
.ask-actions{display:flex;justify-content:flex-end;margin-top:.6rem}
.ask-submit{cursor:pointer;font-family:var(--font-mono);font-size:.74rem;letter-spacing:.06em;
padding:.42rem .9rem;border-radius:var(--radius-sm);border:1px solid var(--aus-bright-cyan);
background:var(--aus-bright-cyan);color:var(--fg-on-accent);font-weight:700;transition:.14s var(--ease-out)}
.ask-submit:hover{background:var(--aus-cyan);border-color:var(--aus-cyan)}
/* booth page */
.boothhead{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;
padding-bottom:1rem;margin-bottom:1.4rem;border-bottom:1px solid var(--border-subtle)}
.boothhead .back{font-family:var(--font-mono);font-size:.76rem;letter-spacing:.08em;color:var(--fg-3)}
.boothhead h1{margin:0;font-family:var(--font-display);font-weight:600;font-size:1.5rem;
letter-spacing:-.01em;word-break:break-word;flex:1 1 auto;color:var(--fg-0)}
.boothhead .sub{color:var(--fg-3);font-size:.74rem;font-family:var(--font-mono);letter-spacing:.06em}
.wipe-lg{position:static}
/* red-outline danger button — legible on the dark canvas, fills on hover */
.wipe-lg button{width:auto;height:auto;padding:.42rem .85rem;border-radius:var(--radius-md);
font-size:.72rem;font-family:var(--font-mono);letter-spacing:.1em;text-transform:uppercase;
background:transparent;border-color:var(--aus-red);color:var(--aus-bright-red)}
.wipe-lg button:hover{background:var(--aus-red);border-color:var(--aus-red);color:#fff}
.gallery{display:grid;gap:1.4rem;grid-template-columns:repeat(auto-fill,minmax(320px,1fr))}
.item{margin:0;background:var(--rk-panel);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);
overflow:hidden;display:flex;flex-direction:column;box-shadow:var(--shadow-2)}
.item img,.item video{width:100%;height:auto;display:block;background:var(--rk-deep)}
.item audio{width:100%;margin:1.3rem .9rem .4rem;max-width:calc(100% - 1.8rem)}
.item .dl{padding:1.4rem .9rem;font-family:var(--font-mono);font-size:.86rem;word-break:break-all}
.item figcaption{padding:.6rem .85rem .75rem;color:var(--fg-2);font-size:.78rem;
font-family:var(--font-mono);letter-spacing:.02em;border-top:1px solid var(--border-subtle);word-break:break-word}
.item-audio figcaption,.item-other figcaption{border-top:none}
/* Inline doc rendering — a .md/.txt/.log shows in place, collapsible and
closable, instead of a link to a separate page. The item spans the full
grid width so prose has a readable measure. */
.item-doc{grid-column:1 / -1}
.item-doc.is-closed{display:none}
.doc-inline{display:block}
.doc-inline > .doc-bar{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.55rem;
padding:.6rem .85rem;font-family:var(--font-mono);font-size:.8rem;color:var(--fg-2);
background:var(--rk-well);border-bottom:1px solid var(--border-subtle);user-select:none}
.doc-inline > .doc-bar::-webkit-details-marker{display:none}
.doc-chevron{color:var(--fg-3);transition:transform .12s ease;font-size:.7rem}
.doc-inline[open] > .doc-bar .doc-chevron{transform:rotate(90deg)}
.doc-name{color:var(--fg-1);word-break:break-all}
.doc-spacer{flex:1}
.doc-act{color:var(--fg-3);text-decoration:none;padding:.1rem .35rem;border-radius:5px;
font-size:.9rem;line-height:1;background:none;border:0;cursor:pointer;font-family:inherit}
.doc-act:hover{color:var(--aus-bright-cyan,#42dcd1);background:var(--rk-deep)}
.doc-close:hover{color:var(--aus-red,#ff6b6b)}
.doc-body{margin:0;border:0;border-radius:0;max-height:32rem;overflow:auto;padding:1rem 1.15rem}
.doc-body.textview{background:var(--rk-panel)}
/* Shared doc typography — used by the inline body above AND the full-page
doc view (doc.html). Kept here so both surfaces render identically. */
.textview{white-space:pre-wrap;word-break:break-word;font-family:var(--font-mono);
font-size:.86rem;line-height:1.5;color:var(--fg-1);background:var(--rk-well);
border:1px solid var(--rk-line,#252a35);border-radius:10px;padding:1rem 1.15rem;overflow-x:auto}
.markdown-body{color:var(--fg-1);line-height:1.62;font-size:.98rem;overflow-wrap:break-word}
.markdown-body h1,.markdown-body h2,.markdown-body h3{line-height:1.25;margin:1.6em 0 .5em}
.markdown-body h1{font-size:1.7em}.markdown-body h2{font-size:1.35em}.markdown-body h3{font-size:1.12em}
.markdown-body h1,.markdown-body h2{border-bottom:1px solid var(--rk-line,#252a35);padding-bottom:.3em}
.markdown-body :first-child{margin-top:0}
.markdown-body p,.markdown-body ul,.markdown-body ol,.markdown-body blockquote{margin:.7em 0}
.markdown-body a{color:var(--aus-bright-cyan,#42dcd1)}
.markdown-body code{font-family:var(--font-mono);font-size:.86em;background:var(--rk-well);
padding:.12em .38em;border-radius:5px}
.markdown-body pre{background:var(--rk-well);border:1px solid var(--rk-line,#252a35);
border-radius:10px;padding:.9rem 1.05rem;overflow-x:auto}
.markdown-body pre code{background:none;padding:0}
.markdown-body blockquote{border-left:3px solid var(--aus-bright-cyan,#42dcd1);
padding-left:1em;color:var(--fg-2);margin-left:0}
.markdown-body table{border-collapse:collapse;display:block;overflow-x:auto}
.markdown-body th,.markdown-body td{border:1px solid var(--rk-line,#252a35);padding:.4em .7em}
.markdown-body img{max-width:100%}
</style>
</head>
<body>
<header class="topbar">
<a class="brand" href="/"><span class="dot"></span><span class="name">The&nbsp;Booth</span></a>
<span class="tagline">ephemeral media · auto-wipes {{ ttl_hours }}h · kept boards don't</span>
</header>
<main>{% block content %}{% endblock %}</main>
<footer class="foot">
drop a folder into <code>{{ data_dir }}</code>{% if host %} · {{ host }}{% endif %}
</footer>
</body>
</html>