Compare commits

..

No commits in common. 'main' and 'master' have entirely different histories.
main ... master

  1. 18
      README.md
  2. 2
      VERSION
  3. 549
      brand.css
  4. 54
      brand.js
  5. 51
      deploy-mintme.sh
  6. 66
      deploy-monitor.sh
  7. 48
      deploy-otb-tracker.sh
  8. 42
      deploy-portal.sh
  9. 2
      footer.html
  10. 2
      fragments/footer.html
  11. 42
      fragments/header.html
  12. 30
      header.html

18
README.md

@ -1,21 +1,3 @@
## v0.3.1 - 2026-04-05
- Added Video to the header "Services"
## v0.3.0 - 2026-03-22
- Added shared theme toggle markup and behavior via brand.js.
- Updated shared header to include theme toggle.
- Added deploy scripts that also deploy/inject brand.js where needed.
- Updated tracker deploy to inject shared CSS and shared JS.
## v0.2.0 - 2026-03-22
- Added shared brand.css, header.html, and footer.html as the canonical OTB branding source.
- Added deploy-mintme.sh for outsidethebox.top static pages.
- Added deploy-portal.sh for otb_billing portal shared nav/footer/CSS.
- Added deploy-monitor.sh for monitor shared nav/footer/CSS.
OTB Shared Branding Kit
Provides:

2
VERSION

@ -1 +1 @@
v0.3.1
v0.1.0

549
brand.css

@ -1,549 +0,0 @@
/* ===== OTB shared theme system ===== */
:root{
--otb-bg-main:#050b19;
--otb-bg-grad-1:#1f2a57;
--otb-bg-grad-2:#08111f;
--otb-bg-grad-3:#143c2d;
--otb-panel:#0b1330;
--otb-text:#f1f5ff;
--otb-muted:#c5cde4;
--otb-link:#9fd2ff;
--otb-accent:#62f0cf;
--otb-border:rgba(255,255,255,0.08);
--otb-shadow:0 16px 40px rgba(0,0,0,0.28);
}
html[data-theme="light"]{
--otb-bg-main:#eef3fb;
--otb-bg-grad-1:#f7f9fd;
--otb-bg-grad-2:#edf3fb;
--otb-bg-grad-3:#e7f2ec;
--otb-panel:#ffffff;
--otb-text:#172033;
--otb-muted:#55627c;
--otb-link:#0b63ce;
--otb-accent:#0e8f73;
--otb-border:rgba(18,32,60,0.10);
--otb-shadow:0 10px 28px rgba(16,24,40,0.08);
}
html, body{
background:
linear-gradient(90deg, var(--otb-bg-grad-1) 0%, var(--otb-bg-grad-2) 48%, var(--otb-bg-grad-3) 100%),
var(--otb-bg-main) !important;
color:var(--otb-text) !important;
}
a{ color:var(--otb-link); }
.site-header{ background:transparent; }
.site-brand strong,
.site-navlinks > a,
.dropdown-toggle,
.site-title strong,
.site-title span{
color:var(--otb-text) !important;
}
.site-title span,
.small,
.lead,
.sub,
.portal-sub,
.portal-note,
.muted{
color:var(--otb-muted) !important;
}
.card,
.heroCard,
.sideCard,
.feature,
.portal-card,
.detail-card,
.pay-card,
.snapshot-wrap,
.note,
.tableWrap{
background:var(--otb-panel) !important;
border:1px solid var(--otb-border) !important;
color:var(--otb-text) !important;
box-shadow:var(--otb-shadow);
}
.dropdown-menu{
background:var(--otb-panel) !important;
border:1px solid var(--otb-border) !important;
box-shadow:var(--otb-shadow);
}
.dropdown-menu a{
color:var(--otb-text) !important;
}
input,
select,
textarea{
background:rgba(255,255,255,0.06) !important;
color:var(--otb-text) !important;
border:1px solid var(--otb-border) !important;
}
html[data-theme="light"] input,
html[data-theme="light"] select,
html[data-theme="light"] textarea{
background:#f6f8fc !important;
}
::placeholder{
color:var(--otb-muted);
opacity:0.85;
}
.btn,
.portal-btn{
border:1px solid var(--otb-border) !important;
}
.otb-statusbar{
background:#0b1326 !important;
border-top:1px solid rgba(255,255,255,0.06);
}
.otb-statusbar-inner{
max-width:1200px;
margin:0 auto;
padding:10px 18px;
color:#f3f7ff;
display:flex;
justify-content:center;
align-items:center;
gap:10px;
flex-wrap:wrap;
font-size:13px;
line-height:1.4;
}
.otb-statusbar strong{ color:#f8fbff; }
.otb-statusbar a{
color:#62f0cf !important;
text-decoration:none;
}
.otb-dot{
width:4px;
height:4px;
border-radius:50%;
background:rgba(255,255,255,0.25);
display:inline-block;
}
html[data-theme="light"] .otb-statusbar{
background:#edf2fb !important;
border-top:1px solid rgba(18,32,60,0.08);
}
html[data-theme="light"] .otb-statusbar-inner{
color:#23314a;
}
html[data-theme="light"] .otb-statusbar strong{
color:#16233a;
}
html[data-theme="light"] .otb-dot{
background:rgba(23,32,51,0.22);
}
.portal-shell,
.portal-wrap{
max-width:1200px;
margin:0 auto;
padding:32px 20px 72px;
}
.portal-card{
max-width:760px;
margin:0 auto;
}
@media (max-width: 1100px){
.site-container,
.container{
padding-left:16px !important;
padding-right:16px !important;
}
.site-nav{
display:flex;
flex-direction:column;
align-items:flex-start;
gap:14px;
}
.site-nav-right{
width:100%;
display:flex;
flex-direction:column;
align-items:flex-start;
gap:12px;
}
.site-navlinks{
width:100%;
display:flex;
flex-wrap:wrap;
gap:10px 16px;
align-items:center;
}
.dropdown-menu{
min-width:220px;
}
.portal-shell,
.portal-wrap{
padding:24px 16px 64px;
}
}
@media (max-width: 640px){
.site-brand img{
width:48px;
height:48px;
}
.site-title strong{
font-size:20px;
}
.site-title span{
font-size:13px;
}
.site-navlinks{
gap:8px 14px;
}
.otb-statusbar-inner{
font-size:12px;
gap:8px;
padding:10px 12px;
}
.portal-card{
max-width:100%;
}
}
/* ===== OTB hamburger nav ===== */
.otb-menu-toggle{
display:none !important;
margin-left:auto;
width:46px;
height:42px;
border:1px solid var(--otb-border);
background:rgba(255,255,255,0.04);
border-radius:12px;
padding:0;
align-items:center;
justify-content:center;
flex-direction:column;
gap:5px;
cursor:pointer;
}
.otb-menu-toggle span{
display:block;
width:20px;
height:2px;
background:var(--otb-text);
border-radius:2px;
transition:transform 0.2s ease, opacity 0.2s ease;
}
.site-nav-right{
display:flex;
align-items:center;
gap:16px;
}
@media (max-width: 1100px){
.otb-menu-toggle{
display:flex !important;
}
.site-nav{
display:flex;
align-items:center;
justify-content:space-between;
gap:14px;
flex-wrap:wrap;
}
.site-brand{
min-width:0;
flex:1 1 auto;
}
.site-nav-right{
display:none;
width:100%;
flex-direction:column;
align-items:flex-start;
gap:14px;
padding-top:10px;
}
.site-nav-right.otb-nav-open{
display:flex;
}
.site-navlinks{
width:100%;
display:flex;
flex-direction:column;
align-items:flex-start;
gap:10px;
}
.site-navlinks > a,
.dropdown{
width:100%;
}
.dropdown-toggle{
display:inline-flex;
width:100%;
justify-content:flex-start;
}
.dropdown-menu{
position:static !important;
display:none;
min-width:0;
width:100%;
margin-top:8px;
}
.dropdown:hover .dropdown-menu,
.dropdown:focus-within .dropdown-menu{
display:block;
}
}
/* ===== stronger mobile nav override ===== */
@media (max-width: 1100px){
.otb-menu-toggle{
display:flex !important;
}
.site-nav{
display:flex !important;
align-items:center !important;
justify-content:space-between !important;
gap:14px !important;
flex-wrap:wrap !important;
}
.site-nav-right{
display:none !important;
width:100% !important;
flex-direction:column !important;
align-items:flex-start !important;
gap:14px !important;
padding-top:10px !important;
}
.site-nav-right.otb-nav-open{
display:flex !important;
}
.site-navlinks{
width:100% !important;
display:flex !important;
flex-direction:column !important;
align-items:flex-start !important;
gap:10px !important;
}
.site-navlinks > a,
.dropdown{
width:100% !important;
}
.dropdown-toggle{
width:100% !important;
justify-content:flex-start !important;
}
.dropdown-menu{
position:static !important;
min-width:0 !important;
width:100% !important;
margin-top:8px !important;
}
}
/* ===== desktop nav force ===== */
@media (min-width: 1101px){
.otb-menu-toggle{
display:none !important;
}
.site-nav-right{
display:flex !important;
width:auto !important;
flex-direction:row !important;
align-items:center !important;
gap:16px !important;
padding-top:0 !important;
}
.site-navlinks{
display:flex !important;
flex-direction:row !important;
align-items:center !important;
width:auto !important;
gap:16px !important;
}
}
/* ===== OTB hamburger hard fix ===== */
.otb-menu-toggle{
display:none !important;
appearance:none !important;
-webkit-appearance:none !important;
background:transparent !important;
border:0 !important;
box-shadow:none !important;
outline:none !important;
padding:0 !important;
margin:0 0 0 auto !important;
width:46px !important;
height:42px !important;
align-items:center !important;
justify-content:center !important;
flex-direction:column !important;
gap:5px !important;
cursor:pointer !important;
}
.otb-menu-toggle::before,
.otb-menu-toggle::after{
content:none !important;
display:none !important;
}
.otb-menu-toggle span{
display:block !important;
width:20px !important;
height:2px !important;
min-height:2px !important;
max-height:2px !important;
background:var(--otb-text) !important;
border-radius:2px !important;
margin:0 !important;
padding:0 !important;
}
@media (min-width: 1101px){
.otb-menu-toggle{
display:none !important;
visibility:hidden !important;
pointer-events:none !important;
width:0 !important;
height:0 !important;
overflow:hidden !important;
}
.site-nav-right{
display:flex !important;
width:auto !important;
flex-direction:row !important;
align-items:center !important;
gap:16px !important;
padding-top:0 !important;
}
.site-navlinks{
display:flex !important;
flex-direction:row !important;
align-items:center !important;
width:auto !important;
gap:16px !important;
}
}
@media (max-width: 1100px){
.otb-menu-toggle{
display:flex !important;
visibility:visible !important;
pointer-events:auto !important;
width:46px !important;
height:42px !important;
overflow:visible !important;
border:1px solid var(--otb-border) !important;
background:rgba(255,255,255,0.04) !important;
border-radius:12px !important;
}
.site-nav{
display:flex !important;
align-items:center !important;
justify-content:space-between !important;
gap:14px !important;
flex-wrap:wrap !important;
}
.site-brand{
min-width:0 !important;
flex:1 1 auto !important;
}
.site-nav-right{
display:none !important;
width:100% !important;
flex-direction:column !important;
align-items:flex-start !important;
gap:14px !important;
padding-top:10px !important;
}
.site-nav-right.otb-nav-open{
display:flex !important;
}
.site-navlinks{
width:100% !important;
display:flex !important;
flex-direction:column !important;
align-items:flex-start !important;
gap:10px !important;
}
.site-navlinks > a,
.dropdown{
width:100% !important;
}
.dropdown-toggle{
width:100% !important;
justify-content:flex-start !important;
}
.dropdown-menu{
position:static !important;
min-width:0 !important;
width:100% !important;
margin-top:8px !important;
}
}

54
brand.js

@ -1,54 +0,0 @@
(function () {
const root = document.documentElement;
const KEY = "otb-theme";
function applyTheme(theme) {
const resolved = theme === "light" ? "light" : "dark";
root.setAttribute("data-theme", resolved);
document.body.classList.toggle("otb-dark", resolved === "dark");
document.body.classList.toggle("otb-light", resolved === "light");
const toggle = document.getElementById("otbThemeToggle") || document.getElementById("themeToggle");
if (toggle) toggle.checked = resolved === "light";
}
function savedTheme() {
try {
return localStorage.getItem(KEY) || "dark";
} catch (e) {
return "dark";
}
}
function saveTheme(theme) {
try {
localStorage.setItem(KEY, theme);
} catch (e) {}
}
function setupMenu() {
const btn = document.getElementById("otbMenuToggle");
const nav = document.getElementById("otbNavWrap");
if (!btn || !nav) return;
btn.addEventListener("click", function () {
const open = nav.classList.toggle("otb-nav-open");
btn.setAttribute("aria-expanded", open ? "true" : "false");
});
}
document.addEventListener("DOMContentLoaded", function () {
applyTheme(savedTheme());
const toggle = document.getElementById("otbThemeToggle") || document.getElementById("themeToggle");
if (toggle) {
toggle.addEventListener("change", function () {
const next = toggle.checked ? "light" : "dark";
saveTheme(next);
applyTheme(next);
});
}
setupMenu();
});
})();

51
deploy-mintme.sh

@ -1,51 +0,0 @@
#!/bin/bash
set -e
SITE_DIR="/var/www/outsidethebox.top"
cd "$SITE_DIR" || exit 1
STAMP="$(date +%Y%m%d-%H%M%S)"
BKDIR="backups/shared-brand-$STAMP"
mkdir -p "$BKDIR"
cp -av index.html pricing.html terms.html contact.html assets/style.css "$BKDIR"/
HEADER="$(cat /home/def/otb-shared-brand/header.html)"
FOOTER="$(cat /home/def/otb-shared-brand/footer.html | sed 's|__OTB_BRAND_JS__|/assets/brand.js|g')"
BRANDCSS="$(cat /home/def/otb-shared-brand/brand.css)"
cp -av /home/def/otb-shared-brand/brand.js assets/brand.js
python3 - <<PY2
from pathlib import Path
import re
header = '''$HEADER'''
footer = '''$FOOTER'''
brandcss = '''$BRANDCSS'''
for name in ["index.html", "pricing.html", "terms.html", "contact.html"]:
p = Path(name)
text = p.read_text(encoding="utf-8")
if '<header class="site-header">' in text:
text = re.sub(r'<header class="site-header">.*?</header>', header, text, count=1, flags=re.S)
elif '<header class="header">' in text:
text = re.sub(r'<header class="header">.*?</header>', header, text, count=1, flags=re.S)
else:
text = text.replace('<body>', '<body>\n' + header, 1)
if '<div class="otb-statusbar">' in text:
text = re.sub(r'<div class="otb-statusbar">.*?</script>', footer, text, count=1, flags=re.S)
else:
text = text.replace('</body>', footer + '\n</body>', 1)
p.write_text(text, encoding="utf-8")
cssp = Path("assets/style.css")
css = cssp.read_text(encoding="utf-8")
if "/* ===== OTB shared branding ===== */" in css:
css = re.sub(r'/\* ===== OTB shared branding ===== \*/.*', brandcss, css, flags=re.S)
else:
css += "\n\n" + brandcss
cssp.write_text(css, encoding="utf-8")
print("mintme deploy complete")
PY2

66
deploy-monitor.sh

@ -1,66 +0,0 @@
#!/bin/bash
set -e
APP_DIR="/home/def/monitor"
cd "$APP_DIR" || exit 1
STAMP="$(date +%Y%m%d-%H%M%S)"
BKDIR="backups/shared-brand-$STAMP"
mkdir -p "$BKDIR"
cp -av frontend/index.html frontend/styles.css "$BKDIR"/ || true
HEADER="$(cat /home/def/otb-shared-brand/header.html)"
FOOTER="$(cat /home/def/otb-shared-brand/footer.html | sed 's|__OTB_BRAND_JS__|/brand.js|g')"
BRANDCSS="$(cat /home/def/otb-shared-brand/brand.css)"
cp -av /home/def/otb-shared-brand/brand.js frontend/brand.js
cat > frontend/index.html <<HTML
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Monitor</title>
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
$HEADER
<div class="wrap">
<header class="top">
<div>
<div class="title">Monitor</div>
<div class="sub">7-day snapshot • rotating refresh</div>
</div>
<div class="top-right">
<div class="status-pill" id="status">Loading…</div>
<div class="cycle" id="cycle"></div>
</div>
</header>
<div class="card">
<div id="root"></div>
</div>
</div>
$FOOTER
</body>
</html>
HTML
python3 - <<PY2
from pathlib import Path
import re
p = Path("frontend/styles.css")
css = p.read_text(encoding="utf-8")
brandcss = '''$BRANDCSS'''
if "/* ===== OTB shared branding ===== */" in css:
css = re.sub(r'/\* ===== OTB shared branding ===== \*/.*', brandcss, css, flags=re.S)
else:
css = brandcss + "\n\n" + css
p.write_text(css, encoding="utf-8")
print("monitor branding css updated")
PY2
/home/def/monitor/deploy-monitor.sh

48
deploy-otb-tracker.sh

@ -1,48 +0,0 @@
#!/bin/bash
set -e
APP_DIR="/opt/otb_tracker"
cd "$APP_DIR" || exit 1
STAMP="$(date +%Y%m%d-%H%M%S)"
BKDIR="backups/shared-brand-$STAMP"
mkdir -p "$BKDIR"
cp -av backend/app.py "$BKDIR"/
HEADER="$(cat /home/def/otb-shared-brand/header.html)"
FOOTER="$(cat /home/def/otb-shared-brand/footer.html | sed 's|__OTB_BRAND_JS__|/static/brand.js|g')"
BRANDCSS="$(cat /home/def/otb-shared-brand/brand.css)"
BRANDJS="$(cat /home/def/otb-shared-brand/brand.js)"
mkdir -p static
printf '%s
' "$BRANDJS" > static/brand.js
python3 - <<PY2
from pathlib import Path
import re
app = Path("backend/app.py")
text = app.read_text(encoding="utf-8")
header = '''$HEADER'''
footer = '''$FOOTER'''
brandcss = '''$BRANDCSS'''
style_block = f"<style>\n{brandcss}\n</style>"
text = re.sub(r'<style>\s*/\* ===== OTB shared branding ===== \*/.*?</style>', '', text, flags=re.S)
if header not in text:
text = text.replace("<body>", "<body>\n" + header)
if footer not in text:
text = text.replace("</body>", footer + "\n</body>")
if style_block not in text:
text = text.replace("</head>", style_block + "\n</head>")
app.write_text(text, encoding="utf-8")
print("otb-tracker branding injected")
PY2
sudo systemctl restart otb-tracker.service || true

42
deploy-portal.sh

@ -1,42 +0,0 @@
#!/bin/bash
set -e
APP_DIR="/home/def/otb_billing"
cd "$APP_DIR" || exit 1
STAMP="$(date +%Y%m%d-%H%M%S)"
BKDIR="backups/shared-brand-$STAMP"
mkdir -p "$BKDIR"
cp -av templates/includes/site_nav.html static/css/style.css templates/portal_*.html "$BKDIR"/
cp -av /home/def/otb-shared-brand/header.html templates/includes/site_nav.html
cp -av /home/def/otb-shared-brand/brand.js static/brand.js
FOOTER="$(cat /home/def/otb-shared-brand/footer.html | sed 's|__OTB_BRAND_JS__|/static/brand.js|g')"
BRANDCSS="$(cat /home/def/otb-shared-brand/brand.css)"
python3 - <<PY2
from pathlib import Path
import re
footer = '''$FOOTER'''
brandcss = '''$BRANDCSS'''
for p in Path("templates").glob("portal_*.html"):
text = p.read_text(encoding="utf-8")
if '<div class="otb-statusbar">' in text:
text = re.sub(r'<div class="otb-statusbar">.*?</script>', footer, text, count=1, flags=re.S)
else:
text = text.replace('{% include "footer.html" %}', footer + '\n\n {% include "footer.html" %}')
p.write_text(text, encoding="utf-8")
cssp = Path("static/css/style.css")
css = cssp.read_text(encoding="utf-8")
if "/* ===== OTB shared branding ===== */" in css:
css = re.sub(r'/\* ===== OTB shared branding ===== \*/.*', brandcss, css, flags=re.S)
else:
css += "\n\n" + brandcss
cssp.write_text(css, encoding="utf-8")
print("portal deploy complete")
PY2
sudo systemctl restart otb_billing.service

2
fragments/statusbar.html → footer.html

@ -2,7 +2,7 @@
<div class="otb-statusbar-inner">
<strong>All billing is calculated in 🇨🇦 CAD</strong>
<span class="otb-dot"></span>
<span>Crypto conversions use the <a href="https://monitor.outsidethebox.top" target="_blank" rel="noopener noreferrer">OTB Oracle</a></span>
<span>Crypto conversions use the <a href="https://monitor.outsidethebox.top">OTB Oracle</a></span>
<span class="otb-dot"></span>
<span>
Methods:

2
fragments/footer.html

@ -1,2 +0,0 @@
{% include "includes/otb_statusbar.html" %}
<script src="/static/brand.js" defer></script>

42
fragments/header.html

@ -1,42 +0,0 @@
<header class="site-header">
<div class="site-container">
<div class="site-nav">
<a class="site-brand" href="https://outsidethebox.top">
<img src="https://outsidethebox.top/assets/favicon.png" alt="outsidethebox.top logo" />
<div class="site-title">
<strong>outsidethebox.top</strong>
<span>Managed hosting • no client server logins</span>
</div>
</a>
<button class="otb-menu-toggle" id="otbMenuToggle" aria-label="Toggle menu" aria-expanded="false" aria-controls="otbNavWrap">
<span></span>
<span></span>
<span></span>
</button>
<div class="site-nav-right" id="otbNavWrap">
<nav class="site-navlinks">
<a href="https://outsidethebox.top">Home</a>
<a href="https://outsidethebox.top/pricing.html">Pricing</a>
<a href="https://outsidethebox.top/terms.html">ToS</a>
<a href="https://outsidethebox.top/contact.html">Contact</a>
<div class="dropdown">
<a href="#" class="dropdown-toggle">Services</a>
<div class="dropdown-menu">
<a href="https://follow-me.outsidethebox.top">Follow-me Tracker</a>
<a href="https://monitor.outsidethebox.top">Oracle</a>
<a href="https://video.outsidethebox.top">Video</a>
</div>
</div>
<a href="https://otb-billing.outsidethebox.top/portal">Portal</a>
</nav>
<label class="otb-theme-switch" title="Toggle light / dark mode">
<input type="checkbox" id="otbThemeToggle" aria-label="Toggle theme" />
<span class="otb-theme-slider"></span>
</label>
</div>
</div>
</div>
</header>

30
header.html

@ -0,0 +1,30 @@
<header class="site-header">
<div class="site-container">
<div class="site-nav">
<a class="site-brand" href="https://outsidethebox.top">
<img src="https://outsidethebox.top/assets/favicon.png" />
<div class="site-title">
<strong>outsidethebox.top</strong>
<span>Managed hosting • no client server logins</span>
</div>
</a>
<nav class="site-navlinks">
<a href="https://outsidethebox.top">Home</a>
<a href="https://outsidethebox.top/pricing.html">Pricing</a>
<a href="https://outsidethebox.top/terms.html">ToS</a>
<a href="https://outsidethebox.top/contact.html">Contact</a>
<div class="dropdown">
<a href="#" class="dropdown-toggle">Services</a>
<div class="dropdown-menu">
<a href="https://follow-me.outsidethebox.top">Follow-me Tracker</a>
<a href="https://monitor.outsidethebox.top">Oracle</a>
</div>
</div>
<a href="https://otb-billing.outsidethebox.top/portal">Portal</a>
</nav>
</div>
</div>
</header>
Loading…
Cancel
Save