/* apps.mb-networks.ca — shared design system
   Extracted 2026-07-29 from duplicated per-page <style> blocks (see the
   Image Workshop architecture plan). Canonical --success is #16a34a/#4ade80,
   matching documented design-system memory — 4 tools previously carried a
   slightly darker #15803d and shift to this value on migration.
   Page-specific layout (bespoke tool UIs, .wrap max-width) stays inline per page. */

:root{
  --bg:#f4f2ed;--paper:#fff;--ink:#15131e;--ink-2:#38354a;
  --muted:#6e6b7e;--muted-2:#a09daf;
  --rule:#e0ddd5;--rule-2:#cac7bc;
  --amber:#0e7490;--amber-pale:#ecfeff;--amber-ring:#a5f3fc;
  --danger:#dc2626;--info:#0369a1;--success:#16a34a;--warn:#c2410c;
  --mono:ui-monospace,"SF Mono","JetBrains Mono","Menlo","Consolas",monospace;
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
@media(prefers-color-scheme:dark){:root{
  --bg:#0f0e15;--paper:#16141f;--ink:#edeaf8;--ink-2:#b4b0c8;
  --muted:#948fa8;--muted-2:#7a7890;
  --rule:#201e2d;--rule-2:#2c2940;
  --amber:#22d3ee;--amber-pale:#0c2a33;--amber-ring:#155368;
  --danger:#f87171;--info:#38bdf8;--success:#4ade80;--warn:#fb923c;
}}
:root[data-theme="dark"]{--bg:#0f0e15;--paper:#16141f;--ink:#edeaf8;--ink-2:#b4b0c8;--muted:#948fa8;--muted-2:#7a7890;--rule:#201e2d;--rule-2:#2c2940;--amber:#22d3ee;--amber-pale:#0c2a33;--amber-ring:#155368;--danger:#f87171;--info:#38bdf8;--success:#4ade80;--warn:#fb923c}
:root[data-theme="light"]{--bg:#f4f2ed;--paper:#fff;--ink:#15131e;--ink-2:#38354a;--muted:#6e6b7e;--muted-2:#a09daf;--rule:#e0ddd5;--rule-2:#cac7bc;--amber:#0e7490;--amber-pale:#ecfeff;--amber-ring:#a5f3fc;--danger:#dc2626;--info:#0369a1;--success:#16a34a;--warn:#c2410c}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.5;-webkit-font-smoothing:antialiased;padding:clamp(16px,4vw,48px);min-height:100vh;display:flex;flex-direction:column}
/* max-width set per page — pages vary 620–900px. padding-bottom guarantees a
   minimum gap above the footer regardless of page length: footer's own
   margin-top:auto (the sticky-footer mechanism) only creates a gap when page
   content is SHORTER than the viewport -- once content reaches or exceeds
   viewport height (the common case at 100% zoom on a normal desktop), auto
   margin has no leftover space to distribute and the footer sits flush
   against the last piece of content with zero gap. Found 2026-07-30 on the
   apps landing page specifically, but the underlying mechanism is shared
   across every page. */
.wrap{margin:0 auto;padding-bottom:clamp(24px,4vh,48px)}

/* ---- Site chrome ---- */
.site-logo{display:inline-flex;align-items:center;gap:9px;text-decoration:none;margin-bottom:18px}
.site-logo-img{width:32px;height:32px;border-radius:5px;object-fit:cover;opacity:.9}
.site-logo-name{font-size:13px;font-weight:700;letter-spacing:-.01em;color:var(--ink)}
.site-logo-name b{color:var(--amber)}
.theme-btn{position:fixed;top:14px;right:14px;z-index:999;background:var(--paper);border:1px solid var(--rule);border-radius:8px;width:34px;height:34px;font-size:16px;cursor:pointer;color:var(--ink);transition:border-color .15s,background .15s;padding:0;line-height:1;display:flex;align-items:center;justify-content:center}
.theme-btn:hover{border-color:var(--amber)}

.breadcrumb{font-family:var(--mono);font-size:11px;letter-spacing:.08em;color:var(--muted-2);margin:0 0 20px;display:flex;align-items:center;gap:8px}
.breadcrumb a{color:var(--amber);text-decoration:none}
.breadcrumb a:hover{color:var(--ink)}
.breadcrumb-sep{color:var(--rule)}

/* ---- Header / hero ---- */
header{margin-bottom:26px}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--amber);margin:0 0 10px;display:flex;align-items:center;gap:10px}
.eyebrow::before{content:'';display:inline-block;width:24px;height:1px;background:var(--amber-pale)}
h1{font-size:clamp(26px,5vw,40px);line-height:1.1;margin:0 0 8px;font-weight:680;letter-spacing:-.01em}
h1 span{color:var(--amber)}
.sub{color:var(--muted);font-size:15px;margin:0;max-width:56ch;line-height:1.6}
.tag-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.tag{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2);border:1px solid var(--rule);border-radius:4px;padding:3px 8px}

.section-label{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted-2);margin:0 0 14px;padding-bottom:10px;border-bottom:1px solid var(--rule)}

/* ---- Card / button component kit ---- */
.card{background:var(--paper);border:1px solid var(--rule-2);border-radius:14px;padding:20px;margin-bottom:16px}
.card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;gap:8px;flex-wrap:wrap}
.card-title{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--amber);margin:0}
.btn-row{display:flex;gap:6px;flex-wrap:wrap}
.btn{padding:6px 14px;border-radius:6px;border:1px solid var(--rule);background:transparent;color:var(--muted);font-family:var(--mono);font-size:11px;letter-spacing:.06em;cursor:pointer;transition:color .12s,border-color .12s,background .12s;white-space:nowrap}
.btn:hover{color:var(--ink);border-color:var(--muted)}
.btn.primary{background:var(--amber);color:var(--bg);border-color:var(--amber);font-weight:700}
.btn.primary:hover{opacity:.85}
.btn:disabled{opacity:.4;cursor:not-allowed}
.btn:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.options-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.opt-btn{font-family:var(--mono);font-size:11px;padding:5px 12px;border:1px solid var(--rule);border-radius:6px;background:transparent;color:var(--muted-2);cursor:pointer;transition:color .12s,border-color .12s,background .12s}
.opt-btn.active{color:var(--amber);border-color:var(--amber);background:color-mix(in srgb,var(--amber) 8%,transparent)}
.opt-btn:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.error-msg{font-family:var(--mono);font-size:12px;color:var(--danger);margin-top:6px;display:none}
.stats{font-family:var(--mono);font-size:11px;color:var(--muted-2);margin-top:6px}
.tool-note{margin-top:30px;color:var(--muted-2);font-size:12px;text-align:center}

/* ---- Number input + custom spinner (see attachSpinners() in app.js) ---- */
input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
input[type=number]{-moz-appearance:textfield}
input[type=number]:focus-visible{outline:none!important;box-shadow:none!important}
.inp-row{display:flex;align-items:stretch}
.inp-row:focus-within{outline:2px solid var(--amber);outline-offset:2px;border-radius:7px}
.spin-pair{display:flex;flex-direction:column;border:1px solid var(--rule);border-left:none;border-radius:0 7px 7px 0;overflow:hidden;flex-shrink:0;align-self:stretch}
.spin-btn{background:var(--bg);border:none;color:var(--muted-2);cursor:pointer;flex:1;width:24px;font-size:10px;line-height:1;display:flex;align-items:center;justify-content:center;transition:color .12s,background .12s;padding:0;user-select:none;-webkit-user-select:none}
.spin-btn+.spin-btn{border-top:1px solid var(--rule-2)}
.spin-btn:hover{color:var(--amber);background:var(--amber-pale)}

/* ---- Collection grids ---- */
.tools{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:8px}
.tool-card{background:var(--paper);border:1px solid var(--rule);border-radius:12px;padding:18px;text-decoration:none;color:inherit;transition:border-color .15s,background .15s;display:block}
.tool-card:hover{border-color:var(--amber);background:var(--bg)}
.tool-card:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.tool-index{font-family:var(--mono);font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--amber);margin:0 0 4px}
.tool-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2);margin:0 0 6px}
.tool-title{font-size:15px;font-weight:600;margin:0 0 7px;color:var(--ink);line-height:1.3}
.tool-desc{font-size:12.5px;color:var(--muted);margin:0 0 14px;line-height:1.5}
.tool-cta{font-family:var(--mono);font-size:11px;color:var(--amber);letter-spacing:.04em}

.apps{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:16px;margin-top:8px}
.app-card{background:var(--paper);border:1px solid var(--rule);border-radius:12px;padding:24px;text-decoration:none;color:inherit;transition:border-color .15s,background .15s;display:block}
.app-card:hover{border-color:var(--amber);background:var(--bg)}
.app-card:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.app-index{font-family:var(--mono);font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--amber);margin:0 0 4px}
.app-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2);margin:0 0 8px}
.app-title{font-size:19px;font-weight:700;margin:0 0 8px;color:var(--ink);line-height:1.2}
.app-desc{font-size:13.5px;color:var(--muted);margin:0 0 16px;line-height:1.55}
.app-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:16px}
.app-tag{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted-2);border:1px solid var(--rule);border-radius:3px;padding:2px 7px}
.app-cta{font-family:var(--mono);font-size:11px;color:var(--amber);letter-spacing:.04em}

/* Fixed 3-column .tools (above) divides .wrap's 880px cap down to ~200px
   columns only above ~680px viewport width; below that it gets cramped
   well before the 480px phone breakpoint kicks in. Drop to 2 columns
   early enough to stay comfortable through that gap. */
@media(max-width:680px){
  .tools{grid-template-columns:1fr 1fr}
}

@media(max-width:480px){
  .tools{grid-template-columns:1fr 1fr;gap:10px}
  .tool-card{padding:13px}
  .tool-desc{display:none}
  .apps{grid-template-columns:1fr}
  .app-card{padding:18px}
}

/* ---- Footer ---- */
footer{background:var(--ink);color:var(--paper);border-top:1px solid rgba(255,255,255,0.07);padding:clamp(24px,3.5vh,40px) clamp(20px,5vw,80px);margin-top:auto}
.foot-inner{margin:0 auto;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:14px} /* max-width set per page, matches .wrap */
.foot-brand{font-size:13px;font-weight:700;letter-spacing:-.01em;opacity:.8}
.foot-copy{font-size:11px;opacity:.35;margin-top:2px}
.foot-nav{display:flex;gap:18px;list-style:none;flex-wrap:wrap;margin:0;padding:0}
.foot-nav a{font-size:12.5px;color:inherit;opacity:.45;text-decoration:none;transition:opacity .15s}
.foot-nav a:hover{opacity:.9}
.foot-fb{display:inline-flex;align-items:center;gap:5px}
.foot-fb svg{width:13px;height:13px;fill:currentColor;vertical-align:middle}

/* ---- Image Workshop: before/after preview ---- */
.compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:560px){.compare-grid{grid-template-columns:1fr}}
.compare-label{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2);margin:0 0 8px;text-align:center}
.preview-wrap{background:repeating-conic-gradient(#e5e2d9 0% 25%,transparent 0% 50%) 50%/16px 16px;border:1px solid var(--rule-2);border-radius:10px;padding:16px;display:flex;align-items:center;justify-content:center;min-height:160px;max-height:340px;overflow:auto}
[data-theme="dark"] .preview-wrap,@media(prefers-color-scheme:dark){.preview-wrap{background:repeating-conic-gradient(#22202f 0% 25%,transparent 0% 50%) 50%/16px 16px}}

/* ---- Dropzone ----
   Promoted here 2026-07-30 for PDF Workshop -- was duplicated byte-for-byte
   in a per-page <style> block across all 11 Image Workshop tools (never
   caught by the 2026-07-29 consistency pass). Not retrofitted onto those 11
   pages here -- their local copies just harmlessly take precedence, same
   selector loaded later in the cascade -- but any *new* tool, PDF or image,
   should rely on this shared version instead of redefining it. */
.dropzone{border:2px dashed var(--rule-2);border-radius:12px;padding:36px 20px;text-align:center;cursor:pointer;transition:border-color .15s,background .15s}
.dropzone:hover,.dropzone.drag{border-color:var(--amber);background:var(--amber-pale)}
.dropzone-icon{font-size:28px;margin-bottom:8px;opacity:.7}
.dropzone-text{color:var(--muted);font-size:13px}
.dropzone-text b{color:var(--ink)}
.dropzone input[type=file]{display:none}
.file-info{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.file-meta{font-family:var(--mono);font-size:12px;color:var(--muted-2)}
.file-name{color:var(--ink);font-weight:600}

/* ---- PDF Workshop: page thumbnail grid ----
   Used by Delete/Reorder, Split, Rotate, PDF-to-Images -- any tool showing
   one canvas per page. Canvas pixel dimensions are set by JS
   (shared/js/pdf-tool.js's renderThumbnails); these rules only constrain
   layout/chrome around it. */
.pdf-thumb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:14px;margin-top:4px}
.pdf-thumb{position:relative;border:1px solid var(--rule-2);border-radius:10px;padding:8px;background:var(--paper);text-align:center}
.pdf-thumb canvas{display:block;max-width:100%;height:auto;margin:0 auto 6px;border-radius:4px;background:#fff;box-shadow:0 0 0 1px var(--rule-2)}
.pdf-thumb-num{font-family:var(--mono);font-size:11px;color:var(--muted-2)}
.pdf-thumb.removed canvas{opacity:.25}
.pdf-thumb.removed .pdf-thumb-num{text-decoration:line-through;color:var(--danger)}
.pdf-thumb-controls{display:flex;justify-content:center;gap:4px;margin-top:6px;flex-wrap:wrap}
.pdf-thumb-controls button{font-family:var(--mono);font-size:10px;padding:3px 7px;border:1px solid var(--rule);border-radius:5px;background:transparent;color:var(--muted-2);cursor:pointer;transition:color .12s,border-color .12s}
.pdf-thumb-controls button:hover{color:var(--ink);border-color:var(--muted)}
.pdf-thumb-controls button.danger:hover{color:var(--danger);border-color:var(--danger)}

/* ---- PDF Workshop: reorderable source-file list (Merge) ----
   Filenames, not page thumbnails -- rendering a preview page per source
   file adds real cost for little benefit when the thing being reordered is
   whole documents, not pages within one. */
.pdf-file-list{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.pdf-file-row{display:flex;align-items:center;gap:10px;border:1px solid var(--rule-2);border-radius:8px;padding:8px 12px;background:var(--paper)}
.pdf-file-row .file-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pdf-file-row .file-meta{flex-shrink:0}

/* ---- SysAdmin Toolbelt: shared data table shell ----
   Covers only what was byte-identical across tools (width/border-collapse/
   font-family/font-size, row border + last-child). Per-page header font
   size, letter-spacing, cell padding, and border color are deliberately
   left as page-specific overrides -- those differ tool to tool today and
   forcing them identical would be a visual change, not a dedup. */
.data-table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:13px}
.data-table thead th{text-align:left;text-transform:uppercase;color:var(--muted-2);white-space:nowrap}
.data-table tbody tr{border-bottom:1px solid var(--rule-2)}
.data-table tbody tr:last-child{border-bottom:none}

/* ---- Shared status badge ----
   Reference shape: jwt-decoder's .status-badge/.badge-ok/.badge-exp/
   .badge-none, which several tools independently reinvented. Semantic
   modifiers map to the site's existing --success/--danger/--muted/--info/
   --amber tokens. */
.badge{font-family:var(--mono);font-size:11px;padding:3px 10px;border-radius:5px}
.badge-success{background:color-mix(in srgb,var(--success) 10%,transparent);color:var(--success);border:1px solid color-mix(in srgb,var(--success) 30%,transparent)}
.badge-danger{background:color-mix(in srgb,var(--danger) 10%,transparent);color:var(--danger);border:1px solid color-mix(in srgb,var(--danger) 30%,transparent)}
.badge-muted{background:color-mix(in srgb,var(--muted) 8%,transparent);color:var(--muted);border:1px solid var(--rule)}
.badge-info{background:color-mix(in srgb,var(--info) 10%,transparent);color:var(--info);border:1px solid color-mix(in srgb,var(--info) 30%,transparent)}
.badge-amber{background:var(--amber-pale);color:var(--amber);border:1px solid var(--amber-ring)}

/* ---- Prose (content sections: explainers, guides, FAQ answers) ----
   Added 2026-07-31 for the flagship/standard-tier content pass -- tool pages
   previously had no styled h2/h3/p/ul at all beyond the .sub hero line (the
   only paragraph class that existed). Ported from
   sites/mb-networks/privacy/index.html's .content block, the site's own
   established prose scale, but as a scoped .prose class rather than bare
   element selectors -- bare a/h1/h2/p/li rules are exactly what caused the
   iOS privacy-page bug (2026-07-31: an unscoped `a{color:...}` and
   `li{color:...}` bled into the shared nav and footer). Never add a bare
   element selector here; always nest under .prose. */
.prose{max-width:68ch}
.prose h2{font-size:clamp(17px,2vw,22px);font-weight:700;letter-spacing:-.02em;margin:36px 0 12px;color:var(--ink)}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:16px;font-weight:600;margin:24px 0 8px;color:var(--ink)}
.prose p{font-size:15px;color:var(--ink-2);line-height:1.7;margin:0 0 14px}
.prose ul,.prose ol{margin:0 0 14px;padding-left:22px}
.prose li{font-size:15px;color:var(--ink-2);line-height:1.7;margin-bottom:6px}
.prose a{color:var(--amber);text-decoration:none}
.prose a:hover{text-decoration:underline}
.prose strong{color:var(--ink)}

/* ---- FAQ accordion ----
   Native <details>/<summary>, no JS. Content-swap on the +/− marker (not a
   rotation transform on a second element) so opening/closing never changes
   box dimensions -- verified zero CLS impact against the 2026-07-31 baseline
   (docs/content-strategy/cwv-baseline.md) before this shipped anywhere. */
.faq{border-top:1px solid var(--rule);margin:20px 0}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{cursor:pointer;padding:14px 2px;font-weight:600;font-size:14.5px;color:var(--ink);list-style:none;display:flex;justify-content:space-between;align-items:center;gap:12px}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'+';color:var(--muted-2);font-weight:400;font-size:18px;flex-shrink:0}
.faq details[open] summary::after{content:'\2212'}
.faq details[open] summary{color:var(--amber)}
.faq .faq-a{font-size:15px;color:var(--ink-2);line-height:1.7;margin:0 0 16px;padding-right:24px}

/* ---- Callout ----
   Same visual language as the .tip affiliate callout (11 sysadmin-toolbelt
   pages, byte-identical inline rule) -- .callout is the general-purpose name
   for new content (methodology notes, caveats, "why this matters" asides);
   .tip's existing per-page copies are left alone, not worth touching 11
   already-shipped files to dedupe a rule that was never actually drifting. */
.callout{background:var(--amber-pale);border:1px solid var(--amber-ring);border-radius:10px;padding:14px 16px;margin:16px 0;font-size:14px;color:var(--ink)}
.callout b{color:var(--ink)}

/* ---- Privacy badge ----
   Composes with the existing .badge system rather than inventing new colors:
   badge-success ("runs 100% locally") for mbnet:privacy=local,
   badge-info ("makes a network request") for mbnet:privacy=network. Adds
   only the icon gap; every color/border/radius decision stays owned by
   .badge-success/.badge-info so this can't drift from the rest of the badge
   set. Generation belongs to Phase 2 (rendered from metadata); this is the
   component the renderer targets. */
.privacy-badge{display:inline-flex;align-items:center;gap:6px}

/* ---- Chip ----
   7 tool pages use class="chip" today, each with its own local definition
   (2 variants nearly identical, 2 more with a 20px pill radius instead of
   6px) -- none promoted here, all 7 already have a working page-local
   <style> copy and page-local styles load after this stylesheet and still
   win, same precedent as .dropzone above. This shared version exists so new
   tools can reuse it instead of redefining their own. */
.chip{font-family:var(--mono);font-size:11px;padding:5px 12px;border:1px solid var(--rule);border-radius:6px;background:transparent;color:var(--muted);cursor:pointer;transition:color .12s,border-color .12s,background .12s;white-space:nowrap}
.chip:hover{color:var(--ink);border-color:var(--muted)}
.chip.active{color:var(--amber);border-color:var(--amber);background:color-mix(in srgb,var(--amber) 8%,transparent)}

/* ---- Chip row wrapper ----
   Generic flex-wrap container for a row of .chip buttons -- currently used
   by the category filter on collection landing pages (generated, see
   generate-listings.py's FILTERS marker), but not filter-specific itself. */
.chips{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0}

@media(prefers-reduced-motion:reduce){*{transition:none!important}}
