@import url('https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@600;700;800&family=Big+Shoulders+Stencil:wght@700;800&family=Overpass:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Courier+Prime:ital,wght@0,400;0,700&family=Permanent+Marker&display=swap');

/* Design system, 3rd pass -- 2nd pass (IBM Plex + one orange + sharp
   corners + hard shadows) tested badly: it turned out to be its own
   template cliche ("tactile brutalism" -- mono font, one signal color,
   hard offset shadows -- is all over 2025/2026 SaaS templates) rather
   than an escape from one. This pass commits harder to the literal
   "Send Shed" idea instead of a generic technical/brutalist mood, and
   swaps every font for one with a real non-tech pedigree rather than a
   "distinctive-looking" pick off a designer's Google Fonts list:

     - Big Shoulders (Display + Stencil) for every heading and the brand
       mark -- built for the Chicago civic design system, modeled on that
       city's actual condensed industrial-era warehouse signage lettering.
     - Overpass for body copy and UI chrome -- an open reinterpretation of
       Highway Gothic (FHWA series), the actual typeface mandated on US
       road and warehouse/wayfinding signage since the 1950s.
     - Courier Prime (--mono below) for tags, labels, serials, and table
       headers -- a straight typewriter-face revival, used wherever
       something should read like a printed form field or price tag, not
       a "geometric mono" trend font.
     - Permanent Marker, used exactly once (the hero's taped-on kicker),
       modeled on real Sharpie hand-lettering -- restricted to one spot
       on purpose so it reads as an actual handwritten note, not a
       decorative script applied everywhere.

   Colors move off the flat off-white/near-black + one orange scheme to
   an actual material palette: --bg is now a pegboard tan (the wall
   behind a workbench), --bg-soft a slightly darker hardboard tone,
   --surface a cream card-stock/paper tone (warranty cards, shipping
   labels, price tags). --steel/--steel-soft are new, used only for the
   Encrypted Share tier's panel -- a literal "galvanized steel" locked-
   panel look. --metal/--metal-2/--metal-dark/--rivet dress the top nav
   and footer as a corrugated-metal shed-siding band on every page,
   independent of the light/dark theme (real siding doesn't invert),
   which is also what ties every other page on the site back to the
   homepage's fixtures without needing its own bespoke devices. */
:root {
  color-scheme: light;
  --bg:          #c9a877;
  --bg-soft:     #b78f57;
  --surface:     #eee3c3;
  --border:      #c9b587;
  --text:        #241f18;
  --muted:       #5a4f3e;
  /* Was #8f8262 -- too close in tone to --surface (2.96:1, under WCAG AA's
     4.5:1 for the small uppercase labels this token is used for: .label,
     table headers, .blogmeta, .fieldhint). #69593e clears 5.3:1 there. */
  --dim:         #69593e;
  --primary:     #d1520f;
  --primary-2:   #ad4008;
  --accent:      #4d7c2f;
  --danger:      #a3341f;
  --steel:       #46586c;
  --steel-soft:  #7688a0;
  --metal:       #767d80;
  --metal-2:     #63696c;
  --metal-dark:  #3c4143;
  --rivet:       #2c3032;
  --pegboard-hole: rgba(35, 28, 18, .4);
  --sans:      'Overpass', ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --display:   'Big Shoulders Display', ui-sans-serif, system-ui, sans-serif;
  --stencil:   'Big Shoulders Stencil', var(--display);
  --mono:      'Courier Prime', ui-monospace, "SF Mono", Menlo, monospace;
  --marker:    'Permanent Marker', cursive;
  --radius:    2px;
}

/* --------------------------- Themes ---------------------------
   Two themes on purpose, not three: a third ("Aurora") used to exist as
   a recolor of this exact same layout (same fonts, same shapes, same
   shadows -- only the hue changed), which is why it read as barely
   different from the default. Two themes, each carried all the way
   through (not just a swapped accent hex), reads as more deliberate than
   three similar ones -- see the design pass notes in the repo history.

   "Classic" (above) is the unnamed default -- no [data-theme] attribute,
   or an explicit data-theme="classic", both render it. "Studio" below is
   the dark counterpart. Nothing outside this section should ever
   reference a color literal instead of one of these tokens, or it'll
   silently ignore whichever theme is active.

   theme.js sets data-theme on <html> from a `theme` cookie (anonymous
   visitors and first paint) and/or the logged-in user's saved
   preference; see that file for how selection and persistence work.

   --primary-rgb-free note: color-mix() is used everywhere a translucent
   tint of a token is needed (focus rings, hover washes, status-pill
   backgrounds) instead of a parallel set of rgba() literals, so every
   tint automatically follows whichever theme is active. */
:root[data-theme="studio"] {
  color-scheme: dark;
  --bg:          #4b3c26;
  --bg-soft:     #3a2f1d;
  --surface:     #2b2416;
  --border:      #5a4d33;
  --text:        #ece4cf;
  --muted:       #b9ac8c;
  /* Same fix as the light theme above -- #786c53 was 2.98:1 on --surface,
     #9a8c6d clears 4.64:1. */
  --dim:         #9a8c6d;
  --primary:     #e2691c;
  --primary-2:   #f07d33;
  --accent:      #7cb35a;
  --danger:      #e0654a;
  --steel:       #8fa3bd;
  --steel-soft:  #4a5a70;
  /* Metal siding stays dark in both themes on purpose -- real corrugated
     shed panel doesn't get lighter because the rest of the page did. */
  --metal:       #33383a;
  --metal-2:     #2a2e30;
  --metal-dark:  #1e2122;
  --rivet:       #101314;
  --pegboard-hole: rgba(0, 0, 0, .55);
}
/* No `prefers-color-scheme` media query here on purpose -- this site's
   dark mode is an explicit choice via the theme picker (theme.js), backed
   by a cookie/account preference, not an automatic follow of the OS
   setting. A visitor whose OS is set to dark but who never picked "Dark"
   here still gets the default light look -- see theme-init.js. */

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-2); }

/* --------------------------- Top nav ---------------------------
   Styled as a strip of corrugated metal shed siding -- fixed dark-on-light
   text regardless of the page's own light/dark theme (--metal/--metal-2
   stay dark-ish in both, see the :root blocks above), same as real siding
   doesn't repaint itself. The diagonal ridged texture is a repeating linear
   gradient, not an image, so it costs nothing extra to load. */
.topnav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem 1.75rem;
  background:
    repeating-linear-gradient(113deg, rgba(255,255,255,.05) 0 2px, transparent 2px 7px),
    linear-gradient(180deg, var(--metal) 0%, var(--metal-2) 100%);
  border-top: 2px solid var(--metal-dark);
  border-bottom: 2px solid var(--metal-dark);
}
.rivet {
  position: absolute;
  top: 8px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #cfd3d4, var(--rivet) 70%);
  box-shadow: 0 1px 1px rgba(0,0,0,.4);
}
.rivet-l { left: 10px; }
.rivet-r { right: 10px; }
.topnav .brand {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.15rem;
  color: #f2efe3;
}
.topnav .brand .shedmark { flex: none; width: 22px; height: 19px; }
.topnav nav {
  display: flex;
  align-items: center;
  gap: 1.6rem;
}
.topnav nav a {
  color: #e8e5d8;
  opacity: .88;
  font-size: .85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.topnav nav a:hover { opacity: 1; text-decoration: underline; text-underline-offset: 3px; }
.topnav .navcta {
  display: flex;
  gap: .6rem;
  align-items: center;
}
/* .btn-ghost is normally transparent-with-a-border, tuned against the
   page's own --bg -- against the metal band (always dark-ish, in both
   themes) that would leave low-contrast text with no real background of
   its own. Solid cream instead, same idea as a price-tag sticker. */
.topnav .btn-ghost { background: #e8e2cc; border-color: transparent; color: #241f18; }
.topnav .btn-ghost:hover { background: #f2ecd8; color: #241f18; border-color: transparent; }
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  border-radius: 8px;
  padding: .55rem 1.05rem;
  font-family: var(--sans);
  font-size: .88rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background .15s, border-color .15s, color .15s, transform .05s;
}
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-2); color: #fff; }
.btn-ghost { background: transparent; border-color: var(--border); color: var(--text); }
.btn-ghost:hover { border-color: var(--primary); color: var(--primary); }
.btn-block { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: translateY(1px); }

main { flex: 1; width: 100%; }
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 1.75rem; }
.narrow { max-width: 560px; margin: 0 auto; padding: 3rem 1.5rem 4rem; }

/* --------------------------- Hero ---------------------------
   The pegboard-hole grid is the wall behind the workbench -- a repeating
   radial-gradient dot pattern, scoped to .hero only (not the whole page)
   so it doesn't fight with reading long-form content elsewhere. */
.hero {
  padding: 4.5rem 0 3rem;
  text-align: center;
  background-color: var(--bg);
  background-image: radial-gradient(circle, var(--pegboard-hole) 2.1px, transparent 2.4px);
  background-size: 27px 27px;
  background-position: 14px 14px;
}
.hero .kicker {
  display: inline-block;
  font-family: var(--marker);
  font-size: .95rem;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--primary);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: .5rem 1rem;
  border-radius: var(--radius);
  transform: rotate(-1.2deg);
  box-shadow: 2px 3px 0 rgba(0,0,0,.15);
  margin-bottom: 1.7rem;
}
.hero h1 {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  line-height: 1.05;
  letter-spacing: 0;
  margin: 0 auto .9rem;
  max-width: 20ch;
  color: var(--text);
}
.hero h1 .accent { font-family: var(--stencil); font-weight: 800; color: var(--primary); }
.hero p.sub {
  max-width: 46ch;
  margin: 0 auto 2.2rem;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: .6rem .9rem;
  display: inline-block;
  font-size: 1rem;
}
.hero .ctas { display: flex; gap: .75rem; justify-content: center; flex-wrap: wrap; }
.hero .btn { padding: .8rem 1.5rem; font-size: .85rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; }

/* Tape-measure divider between the hero and the chooser below -- doing
   double duty as a literal size comparison for the two tiers. Fixed
   colors (not theme tokens): a tape measure is a physical object, it
   doesn't repaint itself when the page switches theme. */
.tape {
  position: relative;
  height: 46px;
  background-color: #e9d9a0;
  border-top: 2px solid #8a7745;
  border-bottom: 2px solid #8a7745;
  overflow: hidden;
}
:root[data-theme="studio"] .tape { background-color: #4a3f24; border-color: #2e2716; }
.tape-ticks {
  position: absolute; inset: 0;
  background-image:
    repeating-linear-gradient(90deg, #3a2f14 0 1.5px, transparent 1.5px 20px),
    repeating-linear-gradient(90deg, #3a2f14 0 1.5px, transparent 1.5px 100px);
  background-size: 20px 16px, 100px 30px;
  background-position: 0 bottom, 0 bottom;
  background-repeat: repeat-x;
  opacity: .55;
}
.tape-callout {
  position: absolute; top: 4px;
  font-family: var(--mono); font-weight: 700; font-size: .78rem; color: #3a2f14;
  background: #e9d9a0; padding: 0 .4rem;
}
.tape-callout .flag { display: block; font-size: .62rem; font-weight: 400; color: var(--primary); }
.tape-callout.a { left: 16%; }
.tape-callout.b { left: 63%; }
@media (max-width: 560px) { .tape-callout.b { left: auto; right: 4%; } }

/* --------------------------- Two-path chooser ---------------------------
   Quick Share is a shipping label -- a printed paper tag, fixed colors
   throughout (a label doesn't repaint itself when the page's theme
   switches, same reasoning as the metal nav/footer). Encrypted Share is a
   locked galvanized-steel hasp panel, using the --steel tokens which do
   shift slightly between themes (steel *can* look different under
   different light) but stay legible in both -- see the :root blocks. */
.chip-row { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; }
.chip { width: 26px; height: 26px; border-radius: 2px; border: 1px solid rgba(0,0,0,.25); flex: none; }
.chip.orange { background: var(--primary); }
.chip.steel { background: var(--steel); }
.chip-label { font-family: var(--mono); font-size: .72rem; color: var(--muted); letter-spacing: .03em; }

.chooser {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.75rem;
  margin: 3.25rem 0 4.5rem;
}
@media (max-width: 720px) { .chooser { grid-template-columns: 1fr; } }
.choice {
  position: relative;
  display: block;
  color: inherit;
  border-radius: var(--radius);
  padding: 1.9rem 1.75rem 1.75rem;
  transition: transform .12s, box-shadow .12s;
}
.choice:hover { transform: translate(-2px, -2px); box-shadow: 4px 4px 0 rgba(0,0,0,.18); }

/* Quick Share label -- every color here is a fixed hex, not a theme
   token, on purpose: this card is meant to read as a printed shipping
   label stuck to the page, not as themed UI chrome. */
.choice.label {
  background: #f4efdf;
  color: #241f18;
  border: 1.5px solid #241f18;
  background-image: linear-gradient(90deg, transparent 0 8px, repeating-linear-gradient(180deg, #000 0 4px, transparent 4px 9px) 8px 12px, transparent 12px);
}
/* Stamp-corner badge is absolutely positioned over the top of the label
   card, so the chip row underneath it needs extra clearance the base
   .choice h3 rule's top margin isn't tuned for. */
.label-chip-row { margin-top: 2.1rem; }
.choice.label h3 { color: #241f18; margin-top: .4rem; }
.choice.label p.desc,
.choice.label ul,
.choice.label .chip-label { color: #5a4f3e; }
.choice.label li { border-top-color: rgba(0,0,0,.2); }
.choice.label::before {
  content: "";
  position: absolute; top: 26px; right: 26px;
  width: 70px; height: 26px;
  background: repeating-linear-gradient(90deg, #1a1a1a 0 2px, transparent 2px 3px, #1a1a1a 3px 4px, transparent 4px 7px);
}
.stamp-corner {
  position: absolute; top: 24px; left: 26px;
  font-family: var(--mono); font-weight: 700; font-size: .62rem;
  color: #241f18;
  border: 1.5px solid #241f18;
  padding: .2rem .45rem;
  transform: rotate(-4deg);
  letter-spacing: .03em;
}

.choice.hasp {
  background: linear-gradient(180deg, var(--steel-soft), var(--steel));
  color: #f2f5f8;
  border: 1.5px solid var(--metal-dark);
}
.padlock { position: absolute; top: 22px; right: 24px; width: 46px; height: 46px; }
.choice h3 { font-family: var(--display); font-weight: 700; font-size: 1.45rem; margin: 2.1rem 0 .6rem; }
.choice.hasp h3 { margin-top: .9rem; }
.choice p.desc { margin: 0 0 1.1rem; font-size: .92rem; }
.choice.hasp p.desc { color: #e4ecf3; }
.choice.hasp .chip-label { color: #e4ecf3; }
.choice ul { list-style: none; margin: 0; padding: 0; font-family: var(--mono); font-size: .76rem; }
.choice li { padding: .45rem 0; border-top: 1px dashed rgba(0,0,0,.2); }
.choice.hasp li { border-top: 1px dashed rgba(255,255,255,.28); }
.choice li:first-child { border-top: none; }
.choice li::before { content: '— '; }

/* --------------------------- Features: warranty card ---------------------------
   A punched inventory / warranty-card list, replacing the old 4-up icon
   grid -- one continuous card with a perforated top edge and a punched
   circular index number per row, instead of a separate bordered tile per
   feature. */
.features { padding: 3.5rem 0 5rem; }
.warranty {
  position: relative;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
}
.warranty::before {
  content: "";
  position: absolute; top: -1px; left: 1.5rem; right: 1.5rem; height: 0;
  border-top: 2px dashed var(--border);
}
.warranty-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem;
  padding: 1.5rem 1.85rem 1rem;
  border-bottom: 2px solid var(--text);
}
.warranty-head h2 { font-family: var(--display); font-weight: 800; font-size: 1.6rem; margin: 0; color: var(--text); }
.warranty-head .serial { font-family: var(--mono); font-size: .72rem; color: var(--muted); }
.itemrow {
  display: grid;
  grid-template-columns: 62px 1fr 2fr;
  gap: 1.25rem;
  align-items: start;
  padding: 1.25rem 1.85rem;
  border-bottom: 1px dashed var(--border);
}
.itemrow:last-child { border-bottom: none; }
.punch {
  position: relative;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 2px solid var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-weight: 700;
  font-size: .72rem;
}
.punch::after {
  content: "";
  position: absolute; top: 3px; left: 50%; transform: translateX(-50%);
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--border);
}
.itemrow h3 { margin: 0 0 .25rem; font-family: var(--sans); font-weight: 700; font-size: .95rem; color: var(--text); }
.itemrow p { margin: 0; color: var(--muted); font-size: .84rem; }
@media (max-width: 680px) {
  .itemrow { grid-template-columns: 44px 1fr; }
  .itemrow p { grid-column: 2; }
}

/* --------------------------- Cards / forms (upload, auth, dashboard) --------------------------- */
.card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 2rem;
}
.card h1 {
  font-family: var(--display);
  font-size: 1.6rem;
  margin: 0 0 .4rem;
}
.card .subtitle { color: var(--muted); font-size: .9rem; margin: 0 0 1.8rem; }

.label {
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 .5rem;
  display: block;
}

.drop {
  border: 1.5px dashed var(--border);
  border-radius: var(--radius);
  background: var(--bg-soft);
  padding: 2rem 1.5rem;
  text-align: center;
  margin-bottom: 1.4rem;
  transition: border-color .15s, background .15s;
}
.drop.drag { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 5%, transparent); }
.drop input[type="file"] { display: none; }
.filebtn {
  display: inline-block;
  padding: .6rem 1.15rem;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  font-family: var(--sans);
  font-size: .87rem;
  font-weight: 600;
  border-radius: 8px;
  transition: border-color .15s, color .15s;
}
.filebtn:hover { border-color: var(--primary); color: var(--primary); }
.filename { margin: 1rem 0 0; color: var(--muted); font-size: .85rem; word-break: break-all; }
.filename .size { color: var(--dim); margin-left: .5rem; }

.opts { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.6rem; }
@media (max-width: 480px) { .opts { grid-template-columns: 1fr; } }
.opts label { display: block; }
.opts .label { margin-bottom: .35rem; }

select, input[type="text"], input[type="email"], input[type="password"], input[readonly] {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: .62rem .8rem;
  font-family: var(--sans);
  font-size: .9rem;
  border-radius: 8px;
}
select:focus, input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 12%, transparent); }
select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  padding-right: 2rem;
}
.field { margin-bottom: 1.1rem; }
.field-error { color: var(--danger); font-size: .82rem; margin-top: .4rem; }

.progress { margin-top: 1.4rem; }
.bar { height: 6px; border-radius: var(--radius); background: var(--bg-soft); position: relative; overflow: hidden; min-width: 80px; }
.bar > div { height: 100%; width: 0; background: var(--primary); transition: width .15s linear; }
.status { margin: .6rem 0 0; color: var(--muted); font-size: .82rem; font-feature-settings: "tnum"; }

/* Downloader (yt-dlp) job rows: a plain 0%-or-99% bar reads as frozen
   during the (often several-second) gap before yt-dlp has any percentage
   to report at all, or during the ffmpeg mux/convert step afterward, which
   reports none either -- .indeterminate swaps in a moving sweep instead of
   a static fill so it's visibly alive through both. */
.progresswrap { display: flex; align-items: center; gap: .6rem; }
.progresswrap .bar { flex: 1; }
.progresslabel { font-size: .78rem; color: var(--muted); white-space: nowrap; font-feature-settings: "tnum"; }
.bar.indeterminate > div { width: 40%; animation: barsweep 1.1s ease-in-out infinite; }
@keyframes barsweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
@media (prefers-reduced-motion: reduce) {
  .bar.indeterminate > div { animation: none; width: 100%; opacity: .5; }
}

/* --------------------------- Inline video/image preview --------------------------- */
.previewbox {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #0b0e14;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.previewbox video, .previewbox img { width: 100%; height: 100%; object-fit: contain; display: block; background: #0b0e14; }
.previewbox iframe { width: 100%; height: 100%; border: 0; display: block; background: #fff; }
.previewbox audio { width: 100%; }
/* Audio has no natural aspect ratio to letterbox -- drop the fixed 16:9 box
   for a normal-height card instead. PDF keeps a fixed box (so the layout
   doesn't jump while it loads) but taller/narrower than video's 16:9. */
.previewbox.audio { aspect-ratio: auto; background: var(--bg-soft); padding: 1.8rem 1.4rem; }
.previewbox.pdf { aspect-ratio: 3 / 4; max-height: 80vh; }
.previewbox .previewloading { display: flex; flex-direction: column; align-items: center; gap: .8rem; padding: 0 1.2rem; text-align: center; }
.previewbox .spinner {
  width: 26px; height: 26px;
  border: 3px solid rgba(255,255,255,.18);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: previewspin .8s linear infinite;
}
@keyframes previewspin { to { transform: rotate(360deg); } }
.previewbox .previewstatus { color: rgba(255,255,255,.75); font-size: .82rem; font-feature-settings: "tnum"; margin: 0; }
.previewbox .previewerror { color: #ff8a75; font-size: .85rem; margin: 0; }
.previewdownload { display: inline-block; margin-top: .8rem; font-size: .85rem; }

.result { margin-top: 2rem; padding-top: 1.6rem; border-top: 1px solid var(--border); }
.result h2 { font-family: var(--display); font-size: 1.2rem; margin: 0 0 1rem; color: var(--accent); }
.urlrow { display: flex; gap: .5rem; }
.urlrow input { flex: 1; }
.copy {
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  padding: 0 1rem; font-size: .85rem; font-weight: 600; cursor: pointer; border-radius: 8px;
}
.copy:hover { border-color: var(--primary); color: var(--primary); }

.note { margin: .9rem 0 0; color: var(--muted); font-size: .8rem; line-height: 1.55; }
.note code { background: var(--bg-soft); padding: 1px 6px; border-radius: 4px; color: var(--primary-2); }

/* --------------------------- Bundle gallery + lightbox ---------------------------
   Shown on the bundle-download page (public/bundle-download.js) instead of
   the plain .queue list whenever a bundle has 2+ recognized images -- an
   imgur-style thumbnail grid rather than a file-by-file list. */
.gallerygrid {
  margin-top: 1.4rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: .6rem;
}
.gallery-item {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-soft);
  overflow: hidden;
  cursor: pointer;
  font-family: var(--sans);
}
.gallery-item:hover { border-color: var(--primary); }
.gallery-thumb { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-item.gallery-skel .gallery-thumb { opacity: 0; }
.gallery-item.gallery-skel::before {
  /* A simple pulse instead of a spinner -- cheaper to run across a grid of
     many thumbnails at once than an animated SVG per tile. */
  content: "";
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  animation: gallery-pulse 1.4s ease-in-out infinite;
}
@keyframes gallery-pulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
.gallery-item.gallery-error::before {
  content: "!";
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; font-weight: 700; color: var(--danger);
  background: color-mix(in srgb, var(--danger) 10%, var(--bg-soft));
}
.gallery-caption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: .3rem .45rem;
  font-size: .68rem;
  color: #fff;
  background: linear-gradient(0deg, rgba(0,0,0,.65), transparent);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: left;
}

.lightbox {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(10, 8, 4, .92);
  display: flex; align-items: center; justify-content: center;
  padding: 2.5rem 1rem;
}
/* Same reason as .themepicker-menu[hidden] elsewhere in this file: an
   unconditional `display: flex` above beats the browser's own low-
   specificity `[hidden] { display: none }` UA rule, so toggling the
   `hidden` attribute alone would do nothing without this override. */
.lightbox[hidden] { display: none; }
.lightbox-figure { display: flex; flex-direction: column; align-items: center; gap: .9rem; max-width: 90vw; }
.lightbox-imgwrap { position: relative; display: flex; align-items: center; justify-content: center; max-width: 90vw; max-height: 74vh; }
.lightbox-imgwrap img { max-width: 90vw; max-height: 74vh; border-radius: var(--radius); box-shadow: 0 8px 30px rgba(0,0,0,.5); }
.lightbox-spinner {
  width: 40px; height: 40px;
  border: 3px solid rgba(255,255,255,.25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: gallery-spin .8s linear infinite;
}
@keyframes gallery-spin { to { transform: rotate(360deg); } }
.lightbox-figure figcaption {
  display: flex; align-items: center; gap: 1rem;
  color: #f2efe3; font-size: .85rem; text-align: center;
}
.lightbox-figure figcaption .btn { flex: none; }
.lightbox-close, .lightbox-nav {
  position: absolute;
  background: rgba(0,0,0,.4);
  border: 1px solid rgba(255,255,255,.25);
  color: #f2efe3;
  border-radius: 50%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  line-height: 1;
}
.lightbox-close:hover, .lightbox-nav:hover { background: rgba(0,0,0,.65); border-color: var(--primary); }
.lightbox-close { top: 1rem; right: 1rem; width: 40px; height: 40px; font-size: 1.4rem; }
.lightbox-nav { top: 50%; transform: translateY(-50%); width: 48px; height: 48px; font-size: 2rem; }
.lightbox-prev { left: 1rem; }
.lightbox-next { right: 1rem; }
@media (max-width: 640px) {
  .lightbox-nav { width: 40px; height: 40px; font-size: 1.6rem; }
  .lightbox-prev { left: .4rem; }
  .lightbox-next { right: .4rem; }
}
body.no-scroll { overflow: hidden; }

/* --------------------------- Multi-file upload queue --------------------------- */
.queue { margin-top: 1.4rem; display: flex; flex-direction: column; gap: 1rem; }
.qitem { border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.2rem; background: var(--bg-soft); }
.qitem.done { background: var(--surface); }
.qitem.error { border-color: var(--danger); }
.qname { display: flex; justify-content: space-between; gap: .6rem; font-size: .87rem; color: var(--text); margin: 0 0 .5rem; word-break: break-all; }
.qname .qsize { color: var(--dim); font-size: .8rem; white-space: nowrap; }
.qbar { margin-bottom: .5rem; }
.qstatus { font-size: .78rem; color: var(--muted); margin: 0; font-feature-settings: "tnum"; }
.qresult { margin-top: .8rem; }
.qresult .urlrow { margin-bottom: .3rem; }
.qremove { font-size: .78rem; }
.urlfetch { display: flex; gap: .5rem; margin-bottom: 1.4rem; }
.urlfetch input { flex: 1; }

/* --------------------------- Share result extras: QR + email --------------------------- */
.qrshare {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.qrbox { flex: none; line-height: 0; }
.qrbox img { width: 92px; height: 92px; border-radius: 6px; border: 1px solid var(--border); background: #fff; }
.qremail { flex: 1; min-width: 0; }
.qremailrow { display: flex; gap: .5rem; }
.qremailrow input { flex: 1; }
.qremailwarn { color: var(--danger); }
.qremailstatus { margin: .5rem 0 0; font-size: .82rem; color: var(--muted); }
.qremailstatus.field-error { color: var(--danger); }

details { margin-top: 1.2rem; }
summary { cursor: pointer; color: var(--muted); font-size: .85rem; font-weight: 600; list-style: none; }
summary::before { content: '+ '; color: var(--primary); }
details[open] summary::before { content: '− '; }
details > *:not(summary) { margin-top: .6rem; }

.fileinfo { border: 1px solid var(--border); background: var(--bg-soft); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; }
.fileinfo .name { font-family: var(--display); font-size: 1.3rem; color: var(--text); margin: 0 0 .5rem; word-break: break-all; }
.fileinfo .meta { color: var(--muted); font-size: .84rem; margin: 0; }
.fileinfo .meta span + span::before { content: '·'; margin: 0 .6rem; color: var(--dim); }

.error {
  border-left: 3px solid var(--danger);
  padding: .8rem 1rem;
  background: color-mix(in srgb, var(--danger) 12%, var(--surface));
  color: var(--text);
  font-size: .87rem;
  margin-bottom: 1.5rem;
  border-radius: 0 8px 8px 0;
}
.banner {
  border-left: 3px solid var(--primary);
  padding: .8rem 1rem;
  background: color-mix(in srgb, var(--primary) 8%, var(--surface));
  color: var(--text);
  font-size: .87rem;
  margin-bottom: 1.5rem;
  border-radius: 0 8px 8px 0;
}

.formfoot { margin-top: 1.3rem; font-size: .87rem; color: var(--muted); text-align: center; }

/* --------------------------- Dashboard --------------------------- */
.quotabar { margin-bottom: 2rem; }
.quotabar .bar { height: 8px; }
.quotarow { display: flex; justify-content: space-between; font-size: .82rem; color: var(--muted); margin-top: .5rem; }

.files-wrap { overflow-x: auto; }
table.files { width: 100%; border-collapse: collapse; font-size: .87rem; }
table.files th {
  text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--dim); font-weight: 700; padding: .6rem .5rem; border-bottom: 1px solid var(--border);
}
table.files td { padding: .7rem .5rem; border-bottom: 1px solid var(--border); color: var(--text); }
table.files tr:last-child td { border-bottom: none; }
.linkbtn { background: none; border: none; color: var(--primary); font-weight: 600; font-size: .85rem; cursor: pointer; padding: 0; }
.linkbtn:hover { color: var(--primary-2); }
.linkbtn.danger { color: var(--danger); }
.empty { color: var(--muted); font-size: .88rem; padding: 2rem 0; text-align: center; }

/* --------------------------- Small layout utilities ---------------------
   (kept as named classes rather than inline style="" attributes so the
   Content-Security-Policy in server.js can drop 'unsafe-inline' from
   style-src) */
.pagewrap { padding-top: 2.5rem; padding-bottom: 4rem; }
.pagewrap-narrow { max-width: 760px; padding-top: 2.5rem; padding-bottom: 4rem; }
.pagetitle { font-family: var(--display); font-size: 1.7rem; margin: 0 0 1.5rem; }
.note-flush { margin: 0 0 1rem; }
.btn-google { margin-bottom: 1.2rem; }
.divider-or { margin: 0 0 1.2rem; }
.mb-tight { margin-bottom: 1.4rem; }
.mt-tight { margin-top: 1.6rem; }
.grow { flex: 1; max-width: none; }
.text-center { text-align: center; }
.fw-normal { font-weight: 400; }
.configSectionTitle { font-family: var(--display); font-size: 1.05rem; margin: 1.6rem 0 .8rem; }
.configGroupTitle { font-family: var(--display); font-size: 1.05rem; margin: 0 0 .8rem; }

/* --------------------------- FAQ --------------------------- */
.faqgroup { margin-top: 2.2rem; }
.faqgroup h2 { font-family: var(--display); font-size: 1.15rem; margin: 0 0 .9rem; }
.faqgroup details {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .9rem 1.1rem;
  margin-top: .6rem;
}
.faqgroup summary { font-size: .92rem; color: var(--text); }
.faqgroup details > p { color: var(--muted); font-size: .9rem; line-height: 1.65; }

/* --------------------------- Blog --------------------------- */
.blogindex { margin-top: 1.8rem; display: flex; flex-direction: column; gap: 1rem; }
.blogcard {
  display: block; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.3rem 1.4rem; text-decoration: none; transition: border-color .15s ease;
}
.blogcard:hover { border-color: var(--primary); }
.blogcard h2 { font-family: var(--display); font-size: 1.05rem; margin: 0 0 .4rem; color: var(--text); }
.blogcard p { margin: 0; color: var(--muted); font-size: .88rem; line-height: 1.6; }
.blogmeta { font-size: .74rem; color: var(--dim); text-transform: uppercase; letter-spacing: .04em; margin: 0 0 .5rem; }

.blogpost h2 { font-family: var(--display); font-size: 1.3rem; margin: 2.2rem 0 .8rem; }
.blogpost h3 { font-family: var(--display); font-size: 1.05rem; margin: 1.6rem 0 .6rem; }
.blogpost p { color: var(--text); font-size: .95rem; line-height: 1.7; margin: 0 0 1rem; }
.blogpost ul, .blogpost ol { color: var(--text); font-size: .95rem; line-height: 1.7; margin: 0 0 1rem; padding-left: 1.4rem; }
.blogpost li { margin-bottom: .35rem; }
.blogpost a { color: var(--primary); }
.blogpost strong { color: var(--text); }
.blogbyline { color: var(--muted); font-size: .82rem; margin: -.8rem 0 1.8rem; }

.comptable-wrap { overflow-x: auto; margin: 0 0 1.6rem; border: 1px solid var(--border); border-radius: var(--radius); }
table.comptable { width: 100%; border-collapse: collapse; font-size: .85rem; min-width: 480px; }
table.comptable th {
  /* var(--dim) read fine against the old near-white surface but is too
     close in tone to --bg-soft's new pegboard/hardboard values to stay
     legible (checked: ~1.3:1 light / ~2.5:1 dark, both well under WCAG AA)
     -- var(--text) clears 5.5:1+ in both themes. */
  text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text); font-weight: 700; padding: .7rem .9rem; border-bottom: 1px solid var(--border);
  background: var(--bg-soft);
}
table.comptable td { padding: .8rem .9rem; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: top; }
table.comptable tr:last-child td { border-bottom: none; }
table.comptable td:first-child, table.comptable th:first-child { color: var(--muted); font-weight: 600; white-space: nowrap; }

.blogcta {
  margin-top: 2.4rem; padding: 1.4rem 1.5rem; border-radius: var(--radius);
  background: var(--bg-soft); border: 1px solid var(--border);
}
.blogcta h3 { font-family: var(--display); font-size: 1.05rem; margin: 0 0 .5rem; }
.blogcta p { color: var(--muted); font-size: .88rem; margin: 0 0 1rem; }

/* --------------------------- Admin dashboard --------------------------- */
.tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1.6rem; flex-wrap: wrap; }
.tab { padding: .65rem 1rem; font-size: .87rem; font-weight: 600; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent; }
.tab.active { color: var(--primary); border-bottom-color: var(--primary); }
.statgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
@media (max-width: 800px) { .statgrid { grid-template-columns: repeat(2, 1fr); } }
.stat { border: 1px solid var(--border); border-radius: var(--radius); padding: 1.1rem; background: var(--bg-soft); }
.stat .n { font-family: var(--display); font-size: 1.5rem; font-weight: 700; }
.stat .l { font-size: .75rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.toolbar { display: flex; gap: .6rem; margin-bottom: 1rem; align-items: center; }
.toolbar input[type="text"] { max-width: 280px; }
.toolbar select { max-width: 160px; }
.pill { display: inline-block; font-size: .72rem; font-weight: 700; padding: .15rem .55rem; border-radius: var(--radius); }
.pill.ok { background: color-mix(in srgb, var(--accent) 14%, var(--surface)); color: var(--accent); }
.pill.warn { background: color-mix(in srgb, var(--danger) 12%, var(--surface)); color: var(--danger); }
.pill.muted { background: var(--bg-soft); color: var(--muted); }
.pager { display: flex; gap: .6rem; justify-content: flex-end; margin-top: 1rem; }
.mono { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .8rem; }
.hidden-panel { display: none; }

/* --------------------------- Admin: editable config --------------------------- */
input[type="number"] {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: .62rem .8rem;
  font-family: var(--sans);
  font-size: .9rem;
  border-radius: 8px;
}
.configGroup { margin-bottom: 1.8rem; }
.configFieldGrid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.2rem; }
@media (max-width: 640px) { .configFieldGrid { grid-template-columns: 1fr; } }
.configField { display: flex; flex-direction: column; gap: .35rem; }
.configField[hidden] { display: none; }
.fieldlabel { font-size: .82rem; color: var(--muted); font-weight: 600; }
.fieldhint { font-size: .78rem; color: var(--dim); }
.secretrow { display: flex; align-items: center; gap: .7rem; }
.secretrow input { flex: 1; }
.checkboxrow { display: flex; align-items: center; gap: .55rem; font-size: .88rem; color: var(--text); cursor: pointer; }
.checkboxrow input { width: auto; }
.configSaveBar { display: flex; align-items: center; gap: 1rem; margin: 1.6rem 0; padding-top: 1.4rem; border-top: 1px solid var(--border); }
.configSaveStatus { font-size: .85rem; }
.configSaveStatus.ok { color: var(--accent); }
.configSaveStatus.error { color: var(--danger); }
.configRestartBar { margin-top: 1.8rem; padding-top: 1.4rem; border-top: 1px solid var(--border); }
.configRestartBar .note { margin-top: .7rem; }

/* --------------------------- Theme picker (theme.js) --------------------------- */
.themepicker { position: relative; }
.themepicker-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  cursor: pointer;
  padding: 0;
}
.themepicker-btn:hover { border-color: var(--primary); }
.themepicker-btn .swatch {
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--primary);
}
.themepicker-menu {
  position: absolute;
  top: calc(100% + .5rem);
  right: 0;
  z-index: 20;
  min-width: 190px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 4px 4px 0 var(--border);
  padding: .4rem;
}
.themepicker-menu[hidden] { display: none; }
.themepicker-option {
  display: flex;
  align-items: center;
  gap: .7rem;
  width: 100%;
  padding: .55rem .6rem;
  border: none;
  background: transparent;
  border-radius: 8px;
  cursor: pointer;
  font-family: var(--sans);
  font-size: .85rem;
  font-weight: 600;
  color: var(--text);
  text-align: left;
}
.themepicker-option:hover { background: var(--bg-soft); }
.themepicker-option.active { color: var(--primary); }
.themepicker-option .swatch {
  flex: none;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
}
.themepicker-option .label { flex: 1; }
.themepicker-option .check { flex: none; opacity: 0; }
.themepicker-option.active .check { opacity: 1; }
/* Hard-stop diagonal split (bg / primary, each solid, no blending) rather
   than a blended gradient -- a small preview of each theme's two defining
   tones without reintroducing the soft-gradient look elsewhere. */
.themepicker-option[data-swatch="classic"] .swatch { background: linear-gradient(135deg, #c9a877 50%, #d1520f 50%); }
.themepicker-option[data-swatch="studio"] .swatch { background: linear-gradient(135deg, #4b3c26 50%, #e2691c 50%); }

/* --------------------------- Footer ---------------------------
   Same corrugated-metal band as .topnav, so every page reads as the same
   shed structure top and bottom regardless of which theme is active. */
footer {
  position: relative;
  padding: 1.75rem 1.75rem 2.25rem;
  text-align: center;
  font-size: .8rem;
  color: #e6e3d6;
  background:
    repeating-linear-gradient(113deg, rgba(255,255,255,.05) 0 2px, transparent 2px 7px),
    linear-gradient(180deg, var(--metal) 0%, var(--metal-2) 100%);
  border-top: 2px solid var(--metal-dark);
  border-bottom: 2px solid var(--metal-dark);
}
footer a { color: #e6e3d6; border-bottom: 1px solid transparent; }
footer a:hover { color: #fff; border-bottom-color: #e6e3d6; }
footer .footlinks + .footlinks,
footer .footcopy { margin-top: .5rem; }
footer .footcopy { opacity: .75; }

/* --------------------------- Mobile nav (nav.js) ---------------------------
   nav.js moves the existing <nav> and .navcta out of .topnav's normal flex
   row and into this wrapper at runtime -- purely a DOM move, no markup
   changes needed per-page. .navpanel is `display: contents` above the
   collapse breakpoint so it's invisible to layout there (nav + navcta still
   sit directly in .topnav's flex row exactly as before nav.js existed);
   only below the breakpoint does it become a real collapsible box. */
.navpanel { display: contents; }
.navtoggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  padding: 0;
  margin-left: auto;
}
.navtoggle:hover { border-color: var(--primary); }
.navtoggle span,
.navtoggle span::before,
.navtoggle span::after {
  content: '';
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--text);
  transition: transform .15s ease, opacity .15s ease, background .15s ease;
}
.navtoggle span { position: relative; }
.navtoggle span::before { position: absolute; top: -6px; left: 0; }
.navtoggle span::after { position: absolute; top: 6px; left: 0; }
.topnav.navopen .navtoggle span { background: transparent; }
.topnav.navopen .navtoggle span::before { top: 0; transform: rotate(45deg); }
.topnav.navopen .navtoggle span::after { top: 0; transform: rotate(-45deg); }

@media (max-width: 760px) {
  .topnav { flex-wrap: wrap; row-gap: .75rem; }
  .navtoggle { display: inline-flex; }
  .navpanel {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 1.1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
  }
  .topnav.navopen .navpanel { display: flex; }
  .navpanel nav { flex-direction: column; align-items: flex-start; gap: .9rem; }
  .navpanel nav a { font-size: 1rem; padding: .35rem 0; }
  .navpanel .navcta { flex-direction: column; align-items: stretch; gap: .6rem; }
  .navpanel .navcta .btn { width: 100%; }
}

/* --------------------------- Theme picker: fixed bottom-left ---------------------------
   Moved out of the top nav entirely (position: fixed removes it from any
   parent's flex flow, so this needed no HTML changes -- see theme.js, which
   only ever looks it up by id, never by its position in the page). Fixed
   everywhere, not just on mobile: a floating corner button is easier to
   find/tap consistently across phone, tablet, and desktop alike than a
   different spot on every breakpoint. */
.themepicker {
  position: fixed;
  left: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  z-index: 40;
}
.themepicker-btn {
  width: 44px;
  height: 44px;
  background: var(--surface);
  box-shadow: 3px 3px 0 var(--border);
}
.themepicker-menu {
  top: auto;
  bottom: calc(100% + .6rem);
  left: 0;
  right: auto;
}

/* --------------------------- Mobile: forms, tables, touch targets --------------------------- */
@media (max-width: 480px) {
  /* Below 16px, iOS Safari auto-zooms the viewport on focus -- these were
     .9rem (~13.5px). Scoped to narrow viewports rather than changed
     everywhere so the desktop layout's sizing is untouched. */
  select, input[type="text"], input[type="email"], input[type="password"],
  input[type="number"], input[readonly] {
    font-size: 16px;
  }
  .qrshare { flex-direction: column; align-items: stretch; }
  .qrbox { align-self: center; }
}

@media (max-width: 640px) {
  /* .copy (Copy/Open/Send buttons) and .linkbtn (table row actions) are
     comfortably tap-sized on a mouse-driven desktop layout but run under
     the ~44px minimum touch target on a phone -- bumped only at this
     breakpoint rather than site-wide, since the tighter desktop table rows
     are still fine with a pointer. */
  .copy { min-height: 44px; }
  table.files .linkbtn { padding: .55rem 0; }
}

/* --------------------------- Donation goal widget (home + /donate) --------------------------- */
.goalsection { padding: .2rem 0 1.4rem; }
.goalwidget { display: flex; flex-direction: column; gap: .7rem; padding: 1.4rem 1.6rem; }
.goalwidget-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.goalwidget-label { font-family: var(--display); font-size: 1.05rem; color: var(--text); }
.goalwidget-amount { font-size: .82rem; color: var(--muted); font-feature-settings: "tnum"; white-space: nowrap; }
.goalwidget-bar { height: 10px; }
.goalwidget-cta { align-self: flex-start; }

/* --------------------------- /donate page --------------------------- */
.donate-intro { color: var(--muted); font-size: .92rem; line-height: 1.65; margin: 0 0 1.6rem; }
.donate-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin: 0 0 1.6rem; }
.donate-option {
  display: block; width: 100%; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.1rem 1.2rem; text-decoration: none; transition: border-color .15s ease;
  background: var(--surface);
  /* Sits on both <a> (the plain link tiles) and <div>/<button> (the
     Bitcoin tile below has its own copy button inside it) -- reset the
     parts an interactive element's own UA styling would otherwise diverge
     on, so every tile in the grid looks the same regardless of tag. */
  font: inherit; text-align: left; cursor: pointer; color: inherit;
}
.donate-option:disabled { opacity: .6; cursor: default; }
.donate-option:hover { border-color: var(--primary); }
.donate-option h3 { margin: 0 0 .3rem; font-family: var(--display); font-size: 1rem; color: var(--text); }
.donate-option p { margin: 0; font-size: .8rem; color: var(--muted); line-height: 1.5; }
.donate-empty { color: var(--muted); font-size: .88rem; }
.donate-btc { cursor: default; }
.donate-btc .qrbox { margin: .7rem 0; }
.donate-btc .urlrow input { font-size: .72rem; }

/* --------------------------- /speedtest page --------------------------- */
.speedtest-card { text-align: center; }
.speedtest-gauge { margin: 1.6rem 0; }
.speedtest-value { font-family: var(--display); font-weight: 800; font-size: 3.4rem; color: var(--text); line-height: 1; }
.speedtest-unit { font-size: .95rem; color: var(--muted); margin-left: .3rem; }
.speedtest-phase { font-size: .82rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; margin: .3rem 0 0; }
.speedtest-results { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1rem; margin: 1.6rem 0; text-align: left; }
.speedtest-stat { border: 1px solid var(--border); border-radius: var(--radius); padding: .9rem 1rem; }
.speedtest-stat .stat-label { display: block; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--dim); margin-bottom: .3rem; }
.speedtest-stat .stat-value { font-family: var(--display); font-size: 1.3rem; color: var(--text); font-feature-settings: "tnum"; }
.speedtest-meta { font-size: .78rem; color: var(--dim); margin-top: .4rem; }

