/* OnlyQR — local mockup.
   A site whose pitch is "we took the clutter out" should not arrive in four
   colours, so the accent is rationed to buttons and selected states.

   Violet, not blue. The neutrals are tinted toward violet too — a grey that is
   genuinely neutral next to a violet accent reads as a mistake, and the tint is
   what makes the accent look chosen rather than dropped in. Kept deep and low
   in saturation on purpose: a bright purple reads as a free template, a dark
   one reads as considered.
   Three theme blocks, and all three are needed. Bare :root is light and is the
   ONLY place a light value is defined, so nothing depends on a media query
   being matched. The media block is guarded with :not([data-theme="light"]) so
   an explicit Light choice still wins on a dark OS, and the [data-theme="dark"]
   block repeats the dark values so an explicit Dark choice wins on a light OS.
   Drop any one of the three and the toggle stops working in one direction
   only - which is exactly the bug nobody notices until someone reports it. */
:root{
  color-scheme:light;
  --bg:#f5f4f9;--card:#fff;--text:#1e1b31;--mut:#6b6880;--line:#e6e3ef;
  --accent:#6d28d9;--accent-soft:#f0ebfe;
  --ok:#0f7a37;--okb:#dcfce7;--warn:#8a5311;--warnb:#fdead0;--bad:#9a201d;--badb:#fde2e1;
  --shadow:rgba(30,27,49,.10);--field:#fff;--heart:#be123c;--heartb:#ffe4e6;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --bg:#100d1c;--card:#1c1830;--text:#e7e4f2;--mut:#9b96b3;--line:#332c4d;
    --accent:#a78bfa;--accent-soft:rgba(167,139,250,.16);
    --ok:#4ade80;--okb:rgba(74,222,128,.16);--warn:#ffbf6b;--warnb:rgba(224,138,31,.18);
    --bad:#ff8b87;--badb:rgba(224,67,63,.18);
    --shadow:rgba(0,0,0,.5);--field:#141024;--heart:#fda4af;--heartb:rgba(190,18,60,.22);
  }
}
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#100d1c;--card:#1c1830;--text:#e7e4f2;--mut:#9b96b3;--line:#332c4d;
  --accent:#a78bfa;--accent-soft:rgba(167,139,250,.16);
  --ok:#4ade80;--okb:rgba(74,222,128,.16);--warn:#ffbf6b;--warnb:rgba(224,138,31,.18);
  --bad:#ff8b87;--badb:rgba(224,67,63,.18);
  --shadow:rgba(0,0,0,.5);--field:#141024;--heart:#fda4af;--heartb:rgba(190,18,60,.22);
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);
  font:14px/1.5 Inter,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}

/* ------------------------------------------------------------- ad slot */
/* Slim, labelled and honest. Kept visually quiet on purpose: an ad bar that
   shouts is the thing this site exists to argue with. */
.adslot{background:var(--card);border-bottom:1px solid var(--line)}
.adslot-inner{max-width:1180px;margin:0 auto;padding:10px 24px;display:flex;
  align-items:center;gap:12px}
.adlabel{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--mut);
  writing-mode:vertical-rl;transform:rotate(180deg);flex:0 0 auto;opacity:.65}
.adbox{flex:1;min-height:62px;display:flex;align-items:center;justify-content:center;gap:14px;
  flex-wrap:wrap;border:1px dashed var(--line);border-radius:8px;color:var(--mut);font-size:12px;
  text-align:center;padding:10px}
.adcopy{margin:0;font-size:12.5px;line-height:1.45}
.adcopy b{color:var(--text);font-weight:650}
.adcta{padding:6px 14px;border:1px solid var(--heart);background:var(--heartb);color:var(--heart);
  border-radius:999px;font:inherit;font-size:12px;font-weight:600;cursor:pointer;flex:0 0 auto}
.adcta:hover{filter:brightness(1.05)}
@media (max-width:640px){
  .adlabel{writing-mode:horizontal-tb;transform:none}
  .adslot-inner{flex-direction:column;gap:6px;padding:10px 16px}
}

/* -------------------------------------------------------------- header */
.topbar{padding:18px 24px;border-bottom:1px solid var(--line);background:var(--card)}
.topbar-inner{max-width:1180px;margin:0 auto;display:flex;align-items:center;
  gap:20px;flex-wrap:wrap}
.brand{color:var(--text);flex:0 0 auto;line-height:0;text-decoration:none}
.brand svg{display:block}
.tagline{margin:0;flex:1 1 240px;min-width:0;font-size:13px;line-height:1.45;
  border-left:1px solid var(--line);padding-left:20px}
.tagline b{display:block;font-size:15px;font-weight:700;letter-spacing:-.01em}
.tagline span{color:var(--mut)}
@media (max-width:760px){.tagline{border-left:0;padding-left:0;flex-basis:100%}}
.topnav{display:flex;gap:7px;flex:0 0 auto}
.topnav button{padding:7px 13px;border:1px solid var(--line);background:transparent;
  color:var(--mut);border-radius:8px;font:inherit;font-size:12.5px;font-weight:600;cursor:pointer}
.topnav button:hover{border-color:var(--accent);color:var(--accent)}
.topnav button#themeBtn{min-width:66px;font-variant-numeric:tabular-nums}
.topnav button.accent{border-color:var(--heart);color:var(--heart);background:var(--heartb)}

main{display:grid;grid-template-columns:minmax(0,1fr) 400px;gap:20px;
  padding:20px 24px 40px;max-width:1180px;margin:0 auto;align-items:start}
@media (max-width:900px){main{grid-template-columns:1fr}}

/* --------------------------------------------------------------- panels */
.panel{background:var(--card);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 1px 3px var(--shadow);margin-bottom:16px;overflow:hidden}
.panel > h2{margin:0;padding:12px 16px;font-size:13px;text-transform:uppercase;
  letter-spacing:.06em;color:var(--mut);border-bottom:1px solid var(--line)}
.panel .body{padding:16px}
.row{display:flex;gap:12px;flex-wrap:wrap}
.row > *{flex:1 1 150px;min-width:0}
label.f{display:block;margin-bottom:12px}
label.f > span{display:block;font-size:12px;font-weight:600;color:var(--mut);margin-bottom:5px}
input[type=text],input[type=url],input[type=password],input[type=number],select{
  width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:8px;
  background:var(--field);color:var(--text);font:inherit;font-size:13.5px}
input:focus,select:focus{outline:2px solid var(--accent);outline-offset:-1px;border-color:transparent}
.check{display:flex;align-items:center;gap:8px;font-size:13px;margin-bottom:10px;cursor:pointer}
.check input{width:16px;height:16px;accent-color:var(--accent);cursor:pointer}
.hint{font-size:12px;color:var(--mut);margin:-6px 0 12px}
.mini{flex:0 0 auto;padding:7px 12px;border:1px solid var(--line);background:transparent;
  color:var(--mut);border-radius:8px;font:inherit;font-size:12.5px;cursor:pointer}
.mini:hover{border-color:var(--accent);color:var(--accent)}

/* content-mode tabs */
.tabs{display:flex;gap:6px;padding:12px 16px 0}
.tabs button{flex:1;padding:9px 12px;border:1px solid var(--line);background:transparent;
  color:var(--mut);border-radius:8px;font:inherit;font-weight:600;font-size:13px;cursor:pointer}
.tabs button[aria-selected=true]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}

/* shape pickers */
.shapes{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.shapes input{position:absolute;opacity:0;pointer-events:none}
.shapes label{display:flex;flex-direction:column;align-items:center;gap:4px;cursor:pointer;
  padding:7px 8px 5px;border:1px solid var(--line);border-radius:9px;min-width:60px;
  font-size:10.5px;color:var(--mut);text-align:center;line-height:1.25}
.shapes label:hover{border-color:var(--accent)}
.shapes input:checked + label{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.shapes svg{display:block}
.shapes svg .m{fill:currentColor}

/* colour fields */
.colour{display:flex;align-items:center;gap:8px}
.colour input[type=color]{width:38px;height:34px;padding:2px;border:1px solid var(--line);
  border-radius:8px;background:var(--field);cursor:pointer;flex:0 0 auto}
.colour input[type=text]{font-family:ui-monospace,Consolas,monospace;font-size:12.5px;text-transform:uppercase}

/* presets */
.presets{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.presets button{display:flex;align-items:center;gap:7px;padding:6px 11px 6px 7px;border:1px solid var(--line);
  background:transparent;color:var(--text);border-radius:20px;font:inherit;font-size:12px;cursor:pointer}
.presets button:hover{border-color:var(--accent)}
/* The inset ring, not the border, is what keeps a near-black swatch visible on
   a near-black card - the Ink preset was invisible in dark mode without it. */
.swatch{width:15px;height:15px;border-radius:4px;border:1px solid var(--line);flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16)}

/* logo dropzone */
.drop{border:1.5px dashed var(--line);border-radius:10px;padding:18px;text-align:center;
  color:var(--mut);font-size:13px;cursor:pointer;transition:.12s}
.drop:hover,.drop.over{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.logo-row{display:flex;gap:12px;align-items:center;margin-bottom:12px}
.logo-chip{width:50px;height:50px;flex:0 0 auto;border:1px solid var(--line);border-radius:8px;
  background:#fff;background-image:linear-gradient(45deg,#e6e3ef 25%,transparent 25%,transparent 75%,#e6e3ef 75%),
    linear-gradient(45deg,#e6e3ef 25%,transparent 25%,transparent 75%,#e6e3ef 75%);
  background-size:12px 12px;background-position:0 0,6px 6px}
.logo-chip img{width:100%;height:100%;display:block;border-radius:7px}
.logo-meta{font-size:12px;color:var(--mut);min-width:0;flex:1}
.logo-meta b{color:var(--text);font-weight:600}

/* range */
input[type=range]{width:100%;accent-color:var(--accent);margin:2px 0 0}
.rangelab{display:flex;justify-content:space-between;font-size:12px;font-weight:600;color:var(--mut);margin-bottom:3px}
.rangelab i{font-style:normal;color:var(--text);font-variant-numeric:tabular-nums}

/* preview */
.side{position:sticky;top:20px}
.qrwrap{display:flex;justify-content:center;align-items:center;padding:20px;min-height:300px;
  background-image:linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%),
    linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%);
  background-size:16px 16px;background-position:0 0,8px 8px}
.qrwrap canvas,.qrwrap svg{max-width:100%;height:auto;border-radius:4px}
.btns{display:flex;gap:8px;padding:0 16px 16px;flex-wrap:wrap}
.btns button{flex:1 1 90px;padding:9px 10px;border-radius:8px;border:1px solid var(--accent);
  background:var(--accent);color:#fff;font:inherit;font-weight:600;font-size:13px;cursor:pointer}
.btns button.ghost{background:transparent;color:var(--accent)}
.btns button:hover{filter:brightness(1.08)}
/* The donate ask sits with the download buttons because that is the one moment
   someone has just been given something. Full-width on its own line so it reads
   as an offer rather than a fourth thing to click by mistake. */
.btns button.donate{flex:1 1 100%;background:var(--heartb);border-color:var(--heart);
  color:var(--heart);display:flex;align-items:center;justify-content:center;gap:7px;font-size:12.5px}

.notes{padding:0 16px 14px;display:grid;gap:7px}
.note{display:flex;gap:8px;padding:8px 10px;border-radius:8px;font-size:12.5px;line-height:1.4}
.note.ok{background:var(--okb);color:var(--ok)}
.note.warn{background:var(--warnb);color:var(--warn)}
.note.bad{background:var(--badb);color:var(--bad)}
.note b{font-weight:700}
.note.mut{background:transparent;color:var(--mut);border:1px dashed var(--line)}

.payload{margin:0;padding:10px 12px;background:var(--field);border:1px solid var(--line);
  border-radius:8px;font-family:ui-monospace,Consolas,monospace;font-size:11.5px;
  color:var(--mut);word-break:break-all;white-space:pre-wrap;max-height:110px;overflow:auto}

/* --------------------------------------------------------------- footer */
footer{border-top:1px solid var(--line);background:var(--card);padding:16px 24px 26px}
.foot-inner{max-width:1180px;margin:0 auto;display:flex;gap:14px;flex-wrap:wrap;
  align-items:center;justify-content:space-between;font-size:12.5px;color:var(--mut)}
.foot-inner nav{display:flex;gap:4px;flex-wrap:wrap}
.foot-inner button{background:none;border:0;padding:4px 8px;font:inherit;font-size:12.5px;
  color:var(--mut);cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.foot-inner button:hover{color:var(--accent)}

/* --------------------------------------------------------------- dialog */
dialog#info{width:min(660px,calc(100vw - 32px));max-height:min(86vh,760px);padding:0;border:0;
  border-radius:16px;background:var(--card);color:var(--text);box-shadow:0 24px 60px rgba(0,0,0,.28);
  overflow:hidden}
dialog#info::backdrop{background:rgba(15,23,42,.55);backdrop-filter:blur(2px)}
.dlg-head{display:flex;align-items:center;gap:12px;padding:18px 20px;border-bottom:1px solid var(--line)}
.dlg-head svg{flex:0 0 auto}
.dlg-head h2{margin:0;font-size:17px;flex:1;letter-spacing:-.01em}
#dlgX{background:none;border:0;font-size:26px;line-height:1;color:var(--mut);cursor:pointer;
  padding:0 4px;flex:0 0 auto}
#dlgX:hover{color:var(--text)}
/* overflow-x must be stated. A computed `visible` paired with a non-visible
   other axis becomes `auto`, so overflow-y:auto alone makes the browser draw an
   empty horizontal scrollbar track here. `clip` rather than `hidden` out of
   habit: hidden creates a scroll container and kills position:sticky. */
.dlg-body{padding:4px 20px 8px;overflow-y:auto;overflow-x:clip;max-height:calc(86vh - 150px)}
.dlg-body section{padding:18px 0;border-bottom:1px solid var(--line);scroll-margin-top:10px}
.dlg-body section:last-child{border-bottom:0}
.dlg-body h3{margin:0 0 9px;font-size:14px;letter-spacing:.01em}
.dlg-body p{margin:0 0 9px;font-size:13.5px;line-height:1.6;color:var(--text)}
.dlg-body p.fine{font-size:12px;color:var(--mut);line-height:1.55}
.dlg-body ul{margin:0 0 10px;padding:0;list-style:none;display:grid;gap:7px}
.dlg-body li{font-size:13px;line-height:1.55;padding-left:24px;position:relative}
.ticks li::before{content:"✓";position:absolute;left:2px;top:0;color:var(--ok);font-weight:700}
.crosses li::before{content:"!";position:absolute;left:6px;top:0;color:var(--warn);font-weight:700}
.flash{animation:flash 1.1s ease-out}
@keyframes flash{from{background:var(--accent-soft)}to{background:transparent}}

.donate-box{border:1.5px dashed var(--line);border-radius:11px;padding:18px;margin:12px 0 10px;
  text-align:center;background:var(--bg)}
.donate-empty b{display:block;font-size:13.5px;margin-bottom:3px}
.donate-empty span{font-size:12px;color:var(--mut)}
.kofi{display:inline-block;padding:11px 22px;border-radius:9px;background:var(--heart);color:#fff;
  text-decoration:none;font-weight:650;font-size:13.5px}
.kofi:hover{filter:brightness(1.08)}
.donate-sub{display:block;margin-top:9px;font-size:11.5px;color:var(--mut)}
/* Funded state: a statement, not a button. Nothing here should be clickable -
   the entire point of the cap is that the asking stops. */
.btns .funded{flex:1 1 100%;padding:9px 10px;border:1px dashed var(--line);border-radius:8px;
  color:var(--mut);font-size:12.5px;text-align:center;cursor:default}

.dlg-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:14px 20px;border-top:1px solid var(--line);background:var(--bg)}
.dlg-foot .fine{font-size:12px;color:var(--mut)}
.primary{padding:10px 18px;border-radius:9px;border:1px solid var(--accent);background:var(--accent);
  color:#fff;font:inherit;font-weight:600;font-size:13.5px;cursor:pointer}
.primary:hover{filter:brightness(1.08)}
